blob: 73143b2081a5f9e83118d990df468521cc88f6a3 [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
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000880/**
881 * xmlXPathDebugDumpCompExpr:
882 * @output: the FILE * for the output
883 * @comp: the precompiled XPath expression
884 * @depth: the indentation level.
885 *
886 * Dumps the tree of the compiled XPath expression.
887 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000888void
889xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
890 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000891 int i;
892 char shift[100];
893
894 for (i = 0;((i < depth) && (i < 25));i++)
895 shift[2 * i] = shift[2 * i + 1] = ' ';
896 shift[2 * i] = shift[2 * i + 1] = 0;
897
898 fprintf(output, shift);
899
900 if (comp == NULL) {
901 fprintf(output, "Compiled Expression is NULL\n");
902 return;
903 }
904 fprintf(output, "Compiled Expression : %d elements\n",
905 comp->nbStep);
906 i = comp->last;
907 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
908}
Daniel Veillard017b1082001-06-21 11:20:21 +0000909#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000910
911/************************************************************************
912 * *
913 * Parser stacks related functions and macros *
914 * *
915 ************************************************************************/
916
917/*
918 * Generic function for accessing stacks in the Parser Context
919 */
920
921#define PUSH_AND_POP(type, name) \
922extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
923 if (ctxt->name##Nr >= ctxt->name##Max) { \
924 ctxt->name##Max *= 2; \
925 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
926 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
927 if (ctxt->name##Tab == NULL) { \
928 xmlGenericError(xmlGenericErrorContext, \
929 "realloc failed !\n"); \
930 return(0); \
931 } \
932 } \
933 ctxt->name##Tab[ctxt->name##Nr] = value; \
934 ctxt->name = value; \
935 return(ctxt->name##Nr++); \
936} \
937extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
938 type ret; \
939 if (ctxt->name##Nr <= 0) return(0); \
940 ctxt->name##Nr--; \
941 if (ctxt->name##Nr > 0) \
942 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
943 else \
944 ctxt->name = NULL; \
945 ret = ctxt->name##Tab[ctxt->name##Nr]; \
946 ctxt->name##Tab[ctxt->name##Nr] = 0; \
947 return(ret); \
948} \
949
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000950/**
951 * valuePop:
952 * @ctxt: an XPath evaluation context
953 *
954 * Pops the top XPath object from the value stack
955 *
956 * Returns the XPath object just removed
957 */
958/**
959 * valuePush:
960 * @ctxt: an XPath evaluation context
961 * @value: the XPath object
962 *
963 * Pushes a new XPath object on top of the value stack
964 */
Owen Taylor3473f882001-02-23 17:55:21 +0000965PUSH_AND_POP(xmlXPathObjectPtr, value)
966
Thomas Broyerf06a3d82001-07-16 04:52:57 +0000967/**
968 * xmlXPathPopBoolean:
969 * @ctxt: an XPath parser context
970 *
971 * Pops a boolean from the stack, handling conversion if needed.
972 * Check error with #xmlXPathCheckError.
973 *
974 * Returns the boolean
975 */
976int
977xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
978 xmlXPathObjectPtr obj;
979 int ret;
980
981 obj = valuePop(ctxt);
982 if (obj == NULL) {
983 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
984 return(0);
985 }
986 ret = xmlXPathCastToBoolean(obj);
987 xmlXPathFreeObject(obj);
988 return(ret);
989}
990
991/**
992 * xmlXPathPopNumber:
993 * @ctxt: an XPath parser context
994 *
995 * Pops a number from the stack, handling conversion if needed.
996 * Check error with #xmlXPathCheckError.
997 *
998 * Returns the number
999 */
1000double
1001xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
1002 xmlXPathObjectPtr obj;
1003 double ret;
1004
1005 obj = valuePop(ctxt);
1006 if (obj == NULL) {
1007 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1008 return(0);
1009 }
1010 ret = xmlXPathCastToNumber(obj);
1011 xmlXPathFreeObject(obj);
1012 return(ret);
1013}
1014
1015/**
1016 * xmlXPathPopString:
1017 * @ctxt: an XPath parser context
1018 *
1019 * Pops a string from the stack, handling conversion if needed.
1020 * Check error with #xmlXPathCheckError.
1021 *
1022 * Returns the string
1023 */
1024xmlChar *
1025xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
1026 xmlXPathObjectPtr obj;
1027 xmlChar * ret;
1028
1029 obj = valuePop(ctxt);
1030 if (obj == NULL) {
1031 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1032 return(NULL);
1033 }
1034 ret = xmlXPathCastToString(obj);
1035 /* TODO: needs refactoring somewhere else */
1036 if (obj->stringval == ret)
1037 obj->stringval = NULL;
1038 xmlXPathFreeObject(obj);
1039 return(ret);
1040}
1041
1042/**
1043 * xmlXPathPopNodeSet:
1044 * @ctxt: an XPath parser context
1045 *
1046 * Pops a node-set from the stack, handling conversion if needed.
1047 * Check error with #xmlXPathCheckError.
1048 *
1049 * Returns the node-set
1050 */
1051xmlNodeSetPtr
1052xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1053 xmlXPathObjectPtr obj;
1054 xmlNodeSetPtr ret;
1055
1056 if (ctxt->value == NULL) {
1057 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1058 return(NULL);
1059 }
1060 if (!xmlXPathStackIsNodeSet(ctxt)) {
1061 xmlXPathSetTypeError(ctxt);
1062 return(NULL);
1063 }
1064 obj = valuePop(ctxt);
1065 ret = obj->nodesetval;
1066 xmlXPathFreeNodeSetList(obj);
1067 return(ret);
1068}
1069
1070/**
1071 * xmlXPathPopExternal:
1072 * @ctxt: an XPath parser context
1073 *
1074 * Pops an external oject from the stack, handling conversion if needed.
1075 * Check error with #xmlXPathCheckError.
1076 *
1077 * Returns the object
1078 */
1079void *
1080xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1081 xmlXPathObjectPtr obj;
1082 void * ret;
1083
1084 if (ctxt->value == NULL) {
1085 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1086 return(NULL);
1087 }
1088 if (ctxt->value->type != XPATH_USERS) {
1089 xmlXPathSetTypeError(ctxt);
1090 return(NULL);
1091 }
1092 obj = valuePop(ctxt);
1093 ret = obj->user;
1094 xmlXPathFreeObject(obj);
1095 return(ret);
1096}
1097
Owen Taylor3473f882001-02-23 17:55:21 +00001098/*
1099 * Macros for accessing the content. Those should be used only by the parser,
1100 * and not exported.
1101 *
1102 * Dirty macros, i.e. one need to make assumption on the context to use them
1103 *
1104 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1105 * CUR returns the current xmlChar value, i.e. a 8 bit value
1106 * in ISO-Latin or UTF-8.
1107 * This should be used internally by the parser
1108 * only to compare to ASCII values otherwise it would break when
1109 * running with UTF-8 encoding.
1110 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1111 * to compare on ASCII based substring.
1112 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1113 * strings within the parser.
1114 * CURRENT Returns the current char value, with the full decoding of
1115 * UTF-8 if we are using this mode. It returns an int.
1116 * NEXT Skip to the next character, this does the proper decoding
1117 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1118 * It returns the pointer to the current xmlChar.
1119 */
1120
1121#define CUR (*ctxt->cur)
1122#define SKIP(val) ctxt->cur += (val)
1123#define NXT(val) ctxt->cur[(val)]
1124#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001125#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1126
1127#define COPY_BUF(l,b,i,v) \
1128 if (l == 1) b[i++] = (xmlChar) v; \
1129 else i += xmlCopyChar(l,&b[i],v)
1130
1131#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001132
1133#define SKIP_BLANKS \
1134 while (IS_BLANK(*(ctxt->cur))) NEXT
1135
1136#define CURRENT (*ctxt->cur)
1137#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1138
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001139
1140#ifndef DBL_DIG
1141#define DBL_DIG 16
1142#endif
1143#ifndef DBL_EPSILON
1144#define DBL_EPSILON 1E-9
1145#endif
1146
1147#define UPPER_DOUBLE 1E9
1148#define LOWER_DOUBLE 1E-5
1149
1150#define INTEGER_DIGITS DBL_DIG
1151#define FRACTION_DIGITS (DBL_DIG + 1)
1152#define EXPONENT_DIGITS (3 + 2)
1153
1154/**
1155 * xmlXPathFormatNumber:
1156 * @number: number to format
1157 * @buffer: output buffer
1158 * @buffersize: size of output buffer
1159 *
1160 * Convert the number into a string representation.
1161 */
1162static void
1163xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1164{
1165 switch (isinf(number)) {
1166 case 1:
1167 if (buffersize > (int)sizeof("+Infinity"))
1168 sprintf(buffer, "+Infinity");
1169 break;
1170 case -1:
1171 if (buffersize > (int)sizeof("-Infinity"))
1172 sprintf(buffer, "-Infinity");
1173 break;
1174 default:
1175 if (isnan(number)) {
1176 if (buffersize > (int)sizeof("NaN"))
1177 sprintf(buffer, "NaN");
1178 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001179 /* 3 is sign, decimal point, and terminating zero */
1180 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1181 int integer_place, fraction_place;
1182 char *ptr;
1183 char *after_fraction;
1184 double absolute_value;
1185 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001186
Bjorn Reese70a9da52001-04-21 16:57:29 +00001187 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001188
Bjorn Reese70a9da52001-04-21 16:57:29 +00001189 /*
1190 * First choose format - scientific or regular floating point.
1191 * In either case, result is in work, and after_fraction points
1192 * just past the fractional part.
1193 */
1194 if ( ((absolute_value > UPPER_DOUBLE) ||
1195 (absolute_value < LOWER_DOUBLE)) &&
1196 (absolute_value != 0.0) ) {
1197 /* Use scientific notation */
1198 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1199 fraction_place = DBL_DIG - 1;
1200 snprintf(work, sizeof(work),"%*.*e",
1201 integer_place, fraction_place, number);
1202 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001203 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001204 else {
1205 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001206 if (absolute_value > 0.0)
1207 integer_place = 1 + (int)log10(absolute_value);
1208 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001209 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001210 fraction_place = (integer_place > 0)
1211 ? DBL_DIG - integer_place
1212 : DBL_DIG;
1213 size = snprintf(work, sizeof(work), "%0.*f",
1214 fraction_place, number);
1215 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001216 }
1217
Bjorn Reese70a9da52001-04-21 16:57:29 +00001218 /* Remove fractional trailing zeroes */
1219 ptr = after_fraction;
1220 while (*(--ptr) == '0')
1221 ;
1222 if (*ptr != '.')
1223 ptr++;
1224 strcpy(ptr, after_fraction);
1225
1226 /* Finally copy result back to caller */
1227 size = strlen(work) + 1;
1228 if (size > buffersize) {
1229 work[buffersize - 1] = 0;
1230 size = buffersize;
1231 }
1232 memcpy(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001233 }
1234 break;
1235 }
1236}
1237
Owen Taylor3473f882001-02-23 17:55:21 +00001238/************************************************************************
1239 * *
1240 * Error handling routines *
1241 * *
1242 ************************************************************************/
1243
1244
1245const char *xmlXPathErrorMessages[] = {
1246 "Ok",
1247 "Number encoding",
1248 "Unfinished litteral",
1249 "Start of litteral",
1250 "Expected $ for variable reference",
1251 "Undefined variable",
1252 "Invalid predicate",
1253 "Invalid expression",
1254 "Missing closing curly brace",
1255 "Unregistered function",
1256 "Invalid operand",
1257 "Invalid type",
1258 "Invalid number of arguments",
1259 "Invalid context size",
1260 "Invalid context position",
1261 "Memory allocation error",
1262 "Syntax error",
1263 "Resource error",
1264 "Sub resource error",
Daniel Veillard61d80a22001-04-27 17:13:01 +00001265 "Undefined namespace prefix",
1266 "Encoding error",
1267 "Char out of XML range"
Owen Taylor3473f882001-02-23 17:55:21 +00001268};
1269
1270/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001271 * xmlXPatherror:
Owen Taylor3473f882001-02-23 17:55:21 +00001272 * @ctxt: the XPath Parser context
1273 * @file: the file name
1274 * @line: the line number
1275 * @no: the error number
1276 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001277 * Formats an error message.
Owen Taylor3473f882001-02-23 17:55:21 +00001278 */
1279void
1280xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
1281 int line, int no) {
1282 int n;
1283 const xmlChar *cur;
1284 const xmlChar *base;
1285
1286 xmlGenericError(xmlGenericErrorContext,
1287 "Error %s:%d: %s\n", file, line,
1288 xmlXPathErrorMessages[no]);
1289
1290 cur = ctxt->cur;
1291 base = ctxt->base;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001292 if ((cur == NULL) || (base == NULL))
1293 return;
1294
Owen Taylor3473f882001-02-23 17:55:21 +00001295 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
1296 cur--;
1297 }
1298 n = 0;
1299 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
1300 cur--;
1301 if ((*cur == '\n') || (*cur == '\r')) cur++;
1302 base = cur;
1303 n = 0;
1304 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1305 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
1306 n++;
1307 }
1308 xmlGenericError(xmlGenericErrorContext, "\n");
1309 cur = ctxt->cur;
1310 while ((*cur == '\n') || (*cur == '\r'))
1311 cur--;
1312 n = 0;
1313 while ((cur != base) && (n++ < 80)) {
1314 xmlGenericError(xmlGenericErrorContext, " ");
1315 base++;
1316 }
1317 xmlGenericError(xmlGenericErrorContext,"^\n");
1318}
1319
1320
1321/************************************************************************
1322 * *
1323 * Routines to handle NodeSets *
1324 * *
1325 ************************************************************************/
1326
1327/**
1328 * xmlXPathCmpNodes:
1329 * @node1: the first node
1330 * @node2: the second node
1331 *
1332 * Compare two nodes w.r.t document order
1333 *
1334 * Returns -2 in case of error 1 if first point < second point, 0 if
1335 * that's the same node, -1 otherwise
1336 */
1337int
1338xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1339 int depth1, depth2;
1340 xmlNodePtr cur, root;
1341
1342 if ((node1 == NULL) || (node2 == NULL))
1343 return(-2);
1344 /*
1345 * a couple of optimizations which will avoid computations in most cases
1346 */
1347 if (node1 == node2)
1348 return(0);
Daniel Veillardb33c2012001-04-25 12:59:04 +00001349 if ((node1->type == XML_NAMESPACE_DECL) ||
1350 (node2->type == XML_NAMESPACE_DECL))
1351 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001352 if (node1 == node2->prev)
1353 return(1);
1354 if (node1 == node2->next)
1355 return(-1);
1356
1357 /*
1358 * compute depth to root
1359 */
1360 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1361 if (cur == node1)
1362 return(1);
1363 depth2++;
1364 }
1365 root = cur;
1366 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1367 if (cur == node2)
1368 return(-1);
1369 depth1++;
1370 }
1371 /*
1372 * Distinct document (or distinct entities :-( ) case.
1373 */
1374 if (root != cur) {
1375 return(-2);
1376 }
1377 /*
1378 * get the nearest common ancestor.
1379 */
1380 while (depth1 > depth2) {
1381 depth1--;
1382 node1 = node1->parent;
1383 }
1384 while (depth2 > depth1) {
1385 depth2--;
1386 node2 = node2->parent;
1387 }
1388 while (node1->parent != node2->parent) {
1389 node1 = node1->parent;
1390 node2 = node2->parent;
1391 /* should not happen but just in case ... */
1392 if ((node1 == NULL) || (node2 == NULL))
1393 return(-2);
1394 }
1395 /*
1396 * Find who's first.
1397 */
1398 if (node1 == node2->next)
1399 return(-1);
1400 for (cur = node1->next;cur != NULL;cur = cur->next)
1401 if (cur == node2)
1402 return(1);
1403 return(-1); /* assume there is no sibling list corruption */
1404}
1405
1406/**
1407 * xmlXPathNodeSetSort:
1408 * @set: the node set
1409 *
1410 * Sort the node set in document order
1411 */
1412void
1413xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001414 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001415 xmlNodePtr tmp;
1416
1417 if (set == NULL)
1418 return;
1419
1420 /* Use Shell's sort to sort the node-set */
1421 len = set->nodeNr;
1422 for (incr = len / 2; incr > 0; incr /= 2) {
1423 for (i = incr; i < len; i++) {
1424 j = i - incr;
1425 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001426 if (xmlXPathCmpNodes(set->nodeTab[j],
1427 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001428 tmp = set->nodeTab[j];
1429 set->nodeTab[j] = set->nodeTab[j + incr];
1430 set->nodeTab[j + incr] = tmp;
1431 j -= incr;
1432 } else
1433 break;
1434 }
1435 }
1436 }
1437}
1438
1439#define XML_NODESET_DEFAULT 10
1440/**
1441 * xmlXPathNodeSetCreate:
1442 * @val: an initial xmlNodePtr, or NULL
1443 *
1444 * Create a new xmlNodeSetPtr of type double and of value @val
1445 *
1446 * Returns the newly created object.
1447 */
1448xmlNodeSetPtr
1449xmlXPathNodeSetCreate(xmlNodePtr val) {
1450 xmlNodeSetPtr ret;
1451
1452 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1453 if (ret == NULL) {
1454 xmlGenericError(xmlGenericErrorContext,
1455 "xmlXPathNewNodeSet: out of memory\n");
1456 return(NULL);
1457 }
1458 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1459 if (val != NULL) {
1460 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1461 sizeof(xmlNodePtr));
1462 if (ret->nodeTab == NULL) {
1463 xmlGenericError(xmlGenericErrorContext,
1464 "xmlXPathNewNodeSet: out of memory\n");
1465 return(NULL);
1466 }
1467 memset(ret->nodeTab, 0 ,
1468 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1469 ret->nodeMax = XML_NODESET_DEFAULT;
1470 ret->nodeTab[ret->nodeNr++] = val;
1471 }
1472 return(ret);
1473}
1474
1475/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001476 * xmlXPathNodeSetContains:
1477 * @cur: the node-set
1478 * @val: the node
1479 *
1480 * checks whether @cur contains @val
1481 *
1482 * Returns true (1) if @cur contains @val, false (0) otherwise
1483 */
1484int
1485xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1486 int i;
1487
1488 for (i = 0; i < cur->nodeNr; i++) {
1489 if (cur->nodeTab[i] == val)
1490 return(1);
1491 }
1492 return(0);
1493}
1494
1495/**
Owen Taylor3473f882001-02-23 17:55:21 +00001496 * xmlXPathNodeSetAdd:
1497 * @cur: the initial node set
1498 * @val: a new xmlNodePtr
1499 *
1500 * add a new xmlNodePtr ot an existing NodeSet
1501 */
1502void
1503xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1504 int i;
1505
1506 if (val == NULL) return;
1507
1508 /*
1509 * check against doublons
1510 */
1511 for (i = 0;i < cur->nodeNr;i++)
1512 if (cur->nodeTab[i] == val) return;
1513
1514 /*
1515 * grow the nodeTab if needed
1516 */
1517 if (cur->nodeMax == 0) {
1518 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1519 sizeof(xmlNodePtr));
1520 if (cur->nodeTab == NULL) {
1521 xmlGenericError(xmlGenericErrorContext,
1522 "xmlXPathNodeSetAdd: out of memory\n");
1523 return;
1524 }
1525 memset(cur->nodeTab, 0 ,
1526 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1527 cur->nodeMax = XML_NODESET_DEFAULT;
1528 } else if (cur->nodeNr == cur->nodeMax) {
1529 xmlNodePtr *temp;
1530
1531 cur->nodeMax *= 2;
1532 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1533 sizeof(xmlNodePtr));
1534 if (temp == NULL) {
1535 xmlGenericError(xmlGenericErrorContext,
1536 "xmlXPathNodeSetAdd: out of memory\n");
1537 return;
1538 }
1539 cur->nodeTab = temp;
1540 }
1541 cur->nodeTab[cur->nodeNr++] = val;
1542}
1543
1544/**
1545 * xmlXPathNodeSetAddUnique:
1546 * @cur: the initial node set
1547 * @val: a new xmlNodePtr
1548 *
1549 * add a new xmlNodePtr ot an existing NodeSet, optimized version
1550 * when we are sure the node is not already in the set.
1551 */
1552void
1553xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1554 if (val == NULL) return;
1555
1556 /*
1557 * grow the nodeTab if needed
1558 */
1559 if (cur->nodeMax == 0) {
1560 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1561 sizeof(xmlNodePtr));
1562 if (cur->nodeTab == NULL) {
1563 xmlGenericError(xmlGenericErrorContext,
1564 "xmlXPathNodeSetAddUnique: out of memory\n");
1565 return;
1566 }
1567 memset(cur->nodeTab, 0 ,
1568 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1569 cur->nodeMax = XML_NODESET_DEFAULT;
1570 } else if (cur->nodeNr == cur->nodeMax) {
1571 xmlNodePtr *temp;
1572
1573 cur->nodeMax *= 2;
1574 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1575 sizeof(xmlNodePtr));
1576 if (temp == NULL) {
1577 xmlGenericError(xmlGenericErrorContext,
1578 "xmlXPathNodeSetAddUnique: out of memory\n");
1579 return;
1580 }
1581 cur->nodeTab = temp;
1582 }
1583 cur->nodeTab[cur->nodeNr++] = val;
1584}
1585
1586/**
1587 * xmlXPathNodeSetMerge:
1588 * @val1: the first NodeSet or NULL
1589 * @val2: the second NodeSet
1590 *
1591 * Merges two nodesets, all nodes from @val2 are added to @val1
1592 * if @val1 is NULL, a new set is created and copied from @val2
1593 *
1594 * Returns val1 once extended or NULL in case of error.
1595 */
1596xmlNodeSetPtr
1597xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001598 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001599
1600 if (val2 == NULL) return(val1);
1601 if (val1 == NULL) {
1602 val1 = xmlXPathNodeSetCreate(NULL);
1603 }
1604
1605 initNr = val1->nodeNr;
1606
1607 for (i = 0;i < val2->nodeNr;i++) {
1608 /*
1609 * check against doublons
1610 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001611 skip = 0;
1612 for (j = 0; j < initNr; j++) {
1613 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1614 skip = 1;
1615 break;
1616 }
1617 }
1618 if (skip)
1619 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001620
1621 /*
1622 * grow the nodeTab if needed
1623 */
1624 if (val1->nodeMax == 0) {
1625 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1626 sizeof(xmlNodePtr));
1627 if (val1->nodeTab == NULL) {
1628 xmlGenericError(xmlGenericErrorContext,
1629 "xmlXPathNodeSetMerge: out of memory\n");
1630 return(NULL);
1631 }
1632 memset(val1->nodeTab, 0 ,
1633 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1634 val1->nodeMax = XML_NODESET_DEFAULT;
1635 } else if (val1->nodeNr == val1->nodeMax) {
1636 xmlNodePtr *temp;
1637
1638 val1->nodeMax *= 2;
1639 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1640 sizeof(xmlNodePtr));
1641 if (temp == NULL) {
1642 xmlGenericError(xmlGenericErrorContext,
1643 "xmlXPathNodeSetMerge: out of memory\n");
1644 return(NULL);
1645 }
1646 val1->nodeTab = temp;
1647 }
1648 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1649 }
1650
1651 return(val1);
1652}
1653
1654/**
1655 * xmlXPathNodeSetDel:
1656 * @cur: the initial node set
1657 * @val: an xmlNodePtr
1658 *
1659 * Removes an xmlNodePtr from an existing NodeSet
1660 */
1661void
1662xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
1663 int i;
1664
1665 if (cur == NULL) return;
1666 if (val == NULL) return;
1667
1668 /*
1669 * check against doublons
1670 */
1671 for (i = 0;i < cur->nodeNr;i++)
1672 if (cur->nodeTab[i] == val) break;
1673
1674 if (i >= cur->nodeNr) {
1675#ifdef DEBUG
1676 xmlGenericError(xmlGenericErrorContext,
1677 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
1678 val->name);
1679#endif
1680 return;
1681 }
1682 cur->nodeNr--;
1683 for (;i < cur->nodeNr;i++)
1684 cur->nodeTab[i] = cur->nodeTab[i + 1];
1685 cur->nodeTab[cur->nodeNr] = NULL;
1686}
1687
1688/**
1689 * xmlXPathNodeSetRemove:
1690 * @cur: the initial node set
1691 * @val: the index to remove
1692 *
1693 * Removes an entry from an existing NodeSet list.
1694 */
1695void
1696xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
1697 if (cur == NULL) return;
1698 if (val >= cur->nodeNr) return;
1699 cur->nodeNr--;
1700 for (;val < cur->nodeNr;val++)
1701 cur->nodeTab[val] = cur->nodeTab[val + 1];
1702 cur->nodeTab[cur->nodeNr] = NULL;
1703}
1704
1705/**
1706 * xmlXPathFreeNodeSet:
1707 * @obj: the xmlNodeSetPtr to free
1708 *
1709 * Free the NodeSet compound (not the actual nodes !).
1710 */
1711void
1712xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
1713 if (obj == NULL) return;
1714 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001715 xmlFree(obj->nodeTab);
1716 }
Owen Taylor3473f882001-02-23 17:55:21 +00001717 xmlFree(obj);
1718}
1719
1720/**
1721 * xmlXPathFreeValueTree:
1722 * @obj: the xmlNodeSetPtr to free
1723 *
1724 * Free the NodeSet compound and the actual tree, this is different
1725 * from xmlXPathFreeNodeSet()
1726 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001727static void
Owen Taylor3473f882001-02-23 17:55:21 +00001728xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
1729 int i;
1730
1731 if (obj == NULL) return;
1732 for (i = 0;i < obj->nodeNr;i++)
1733 if (obj->nodeTab[i] != NULL)
Daniel Veillardbbd51d52001-02-24 03:07:03 +00001734 xmlFreeNodeList(obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001735
1736 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001737 xmlFree(obj->nodeTab);
1738 }
Owen Taylor3473f882001-02-23 17:55:21 +00001739 xmlFree(obj);
1740}
1741
1742#if defined(DEBUG) || defined(DEBUG_STEP)
1743/**
1744 * xmlGenericErrorContextNodeSet:
1745 * @output: a FILE * for the output
1746 * @obj: the xmlNodeSetPtr to free
1747 *
1748 * Quick display of a NodeSet
1749 */
1750void
1751xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
1752 int i;
1753
1754 if (output == NULL) output = xmlGenericErrorContext;
1755 if (obj == NULL) {
1756 fprintf(output, "NodeSet == NULL !\n");
1757 return;
1758 }
1759 if (obj->nodeNr == 0) {
1760 fprintf(output, "NodeSet is empty\n");
1761 return;
1762 }
1763 if (obj->nodeTab == NULL) {
1764 fprintf(output, " nodeTab == NULL !\n");
1765 return;
1766 }
1767 for (i = 0; i < obj->nodeNr; i++) {
1768 if (obj->nodeTab[i] == NULL) {
1769 fprintf(output, " NULL !\n");
1770 return;
1771 }
1772 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
1773 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
1774 fprintf(output, " /");
1775 else if (obj->nodeTab[i]->name == NULL)
1776 fprintf(output, " noname!");
1777 else fprintf(output, " %s", obj->nodeTab[i]->name);
1778 }
1779 fprintf(output, "\n");
1780}
1781#endif
1782
1783/**
1784 * xmlXPathNewNodeSet:
1785 * @val: the NodePtr value
1786 *
1787 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1788 * it with the single Node @val
1789 *
1790 * Returns the newly created object.
1791 */
1792xmlXPathObjectPtr
1793xmlXPathNewNodeSet(xmlNodePtr val) {
1794 xmlXPathObjectPtr ret;
1795
1796 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1797 if (ret == NULL) {
1798 xmlGenericError(xmlGenericErrorContext,
1799 "xmlXPathNewNodeSet: out of memory\n");
1800 return(NULL);
1801 }
1802 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1803 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00001804 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001805 ret->nodesetval = xmlXPathNodeSetCreate(val);
1806 return(ret);
1807}
1808
1809/**
1810 * xmlXPathNewValueTree:
1811 * @val: the NodePtr value
1812 *
1813 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
1814 * it with the tree root @val
1815 *
1816 * Returns the newly created object.
1817 */
1818xmlXPathObjectPtr
1819xmlXPathNewValueTree(xmlNodePtr val) {
1820 xmlXPathObjectPtr ret;
1821
1822 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1823 if (ret == NULL) {
1824 xmlGenericError(xmlGenericErrorContext,
1825 "xmlXPathNewNodeSet: out of memory\n");
1826 return(NULL);
1827 }
1828 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1829 ret->type = XPATH_XSLT_TREE;
1830 ret->nodesetval = xmlXPathNodeSetCreate(val);
1831 return(ret);
1832}
1833
1834/**
1835 * xmlXPathNewNodeSetList:
1836 * @val: an existing NodeSet
1837 *
1838 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1839 * it with the Nodeset @val
1840 *
1841 * Returns the newly created object.
1842 */
1843xmlXPathObjectPtr
1844xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
1845 xmlXPathObjectPtr ret;
1846 int i;
1847
1848 if (val == NULL)
1849 ret = NULL;
1850 else if (val->nodeTab == NULL)
1851 ret = xmlXPathNewNodeSet(NULL);
1852 else
1853 {
1854 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
1855 for (i = 1; i < val->nodeNr; ++i)
1856 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
1857 }
1858
1859 return(ret);
1860}
1861
1862/**
1863 * xmlXPathWrapNodeSet:
1864 * @val: the NodePtr value
1865 *
1866 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1867 *
1868 * Returns the newly created object.
1869 */
1870xmlXPathObjectPtr
1871xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
1872 xmlXPathObjectPtr ret;
1873
1874 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1875 if (ret == NULL) {
1876 xmlGenericError(xmlGenericErrorContext,
1877 "xmlXPathWrapNodeSet: out of memory\n");
1878 return(NULL);
1879 }
1880 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1881 ret->type = XPATH_NODESET;
1882 ret->nodesetval = val;
1883 return(ret);
1884}
1885
1886/**
1887 * xmlXPathFreeNodeSetList:
1888 * @obj: an existing NodeSetList object
1889 *
1890 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
1891 * the list contrary to xmlXPathFreeObject().
1892 */
1893void
1894xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
1895 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001896 xmlFree(obj);
1897}
1898
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001899/**
1900 * xmlXPathDifference:
1901 * @nodes1: a node-set
1902 * @nodes2: a node-set
1903 *
1904 * Implements the EXSLT - Sets difference() function:
1905 * node-set set:difference (node-set, node-set)
1906 *
1907 * Returns the difference between the two node sets, or nodes1 if
1908 * nodes2 is empty
1909 */
1910xmlNodeSetPtr
1911xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
1912 xmlNodeSetPtr ret;
1913 int i, l1;
1914 xmlNodePtr cur;
1915
1916 if (xmlXPathNodeSetIsEmpty(nodes2))
1917 return(nodes1);
1918
1919 ret = xmlXPathNodeSetCreate(NULL);
1920 if (xmlXPathNodeSetIsEmpty(nodes1))
1921 return(ret);
1922
1923 l1 = xmlXPathNodeSetGetLength(nodes1);
1924
1925 for (i = 0; i < l1; i++) {
1926 cur = xmlXPathNodeSetItem(nodes1, i);
1927 if (!xmlXPathNodeSetContains(nodes2, cur))
1928 xmlXPathNodeSetAddUnique(ret, cur);
1929 }
1930 return(ret);
1931}
1932
1933/**
1934 * xmlXPathIntersection:
1935 * @nodes1: a node-set
1936 * @nodes2: a node-set
1937 *
1938 * Implements the EXSLT - Sets intersection() function:
1939 * node-set set:intersection (node-set, node-set)
1940 *
1941 * Returns a node set comprising the nodes that are within both the
1942 * node sets passed as arguments
1943 */
1944xmlNodeSetPtr
1945xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
1946 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
1947 int i, l1;
1948 xmlNodePtr cur;
1949
1950 if (xmlXPathNodeSetIsEmpty(nodes1))
1951 return(ret);
1952 if (xmlXPathNodeSetIsEmpty(nodes2))
1953 return(ret);
1954
1955 l1 = xmlXPathNodeSetGetLength(nodes1);
1956
1957 for (i = 0; i < l1; i++) {
1958 cur = xmlXPathNodeSetItem(nodes1, i);
1959 if (xmlXPathNodeSetContains(nodes2, cur))
1960 xmlXPathNodeSetAddUnique(ret, cur);
1961 }
1962 return(ret);
1963}
1964
1965/**
1966 * xmlXPathDistinctSorted:
1967 * @nodes: a node-set, sorted by document order
1968 *
1969 * Implements the EXSLT - Sets distinct() function:
1970 * node-set set:distinct (node-set)
1971 *
1972 * Returns a subset of the nodes contained in @nodes, or @nodes if
1973 * it is empty
1974 */
1975xmlNodeSetPtr
1976xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
1977 xmlNodeSetPtr ret;
1978 xmlHashTablePtr hash;
1979 int i, l;
1980 xmlChar * strval;
1981 xmlNodePtr cur;
1982
1983 if (xmlXPathNodeSetIsEmpty(nodes))
1984 return(nodes);
1985
1986 ret = xmlXPathNodeSetCreate(NULL);
1987 l = xmlXPathNodeSetGetLength(nodes);
1988 hash = xmlHashCreate (l);
1989 for (i = 0; i < l; i++) {
1990 cur = xmlXPathNodeSetItem(nodes, i);
1991 strval = xmlXPathCastNodeToString(cur);
1992 if (xmlHashLookup(hash, strval) == NULL) {
1993 xmlHashAddEntry(hash, strval, strval);
1994 xmlXPathNodeSetAddUnique(ret, cur);
1995 } else {
1996 xmlFree(strval);
1997 }
1998 }
1999 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2000 return(ret);
2001}
2002
2003/**
2004 * xmlXPathDistinct:
2005 * @nodes: a node-set
2006 *
2007 * Implements the EXSLT - Sets distinct() function:
2008 * node-set set:distinct (node-set)
2009 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2010 * is called with the sorted node-set
2011 *
2012 * Returns a subset of the nodes contained in @nodes, or @nodes if
2013 * it is empty
2014 */
2015xmlNodeSetPtr
2016xmlXPathDistinct (xmlNodeSetPtr nodes) {
2017 if (xmlXPathNodeSetIsEmpty(nodes))
2018 return(nodes);
2019
2020 xmlXPathNodeSetSort(nodes);
2021 return(xmlXPathDistinctSorted(nodes));
2022}
2023
2024/**
2025 * xmlXPathHasSameNodes:
2026 * @nodes1: a node-set
2027 * @nodes2: a node-set
2028 *
2029 * Implements the EXSLT - Sets has-same-nodes function:
2030 * boolean set:has-same-node(node-set, node-set)
2031 *
2032 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2033 * otherwise
2034 */
2035int
2036xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2037 int i, l;
2038 xmlNodePtr cur;
2039
2040 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2041 xmlXPathNodeSetIsEmpty(nodes2))
2042 return(0);
2043
2044 l = xmlXPathNodeSetGetLength(nodes1);
2045 for (i = 0; i < l; i++) {
2046 cur = xmlXPathNodeSetItem(nodes1, i);
2047 if (xmlXPathNodeSetContains(nodes2, cur))
2048 return(1);
2049 }
2050 return(0);
2051}
2052
2053/**
2054 * xmlXPathNodeLeadingSorted:
2055 * @nodes: a node-set, sorted by document order
2056 * @node: a node
2057 *
2058 * Implements the EXSLT - Sets leading() function:
2059 * node-set set:leading (node-set, node-set)
2060 *
2061 * Returns the nodes in @nodes that precede @node in document order,
2062 * @nodes if @node is NULL or an empty node-set if @nodes
2063 * doesn't contain @node
2064 */
2065xmlNodeSetPtr
2066xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2067 int i, l;
2068 xmlNodePtr cur;
2069 xmlNodeSetPtr ret;
2070
2071 if (node == NULL)
2072 return(nodes);
2073
2074 ret = xmlXPathNodeSetCreate(NULL);
2075 if (xmlXPathNodeSetIsEmpty(nodes) ||
2076 (!xmlXPathNodeSetContains(nodes, node)))
2077 return(ret);
2078
2079 l = xmlXPathNodeSetGetLength(nodes);
2080 for (i = 0; i < l; i++) {
2081 cur = xmlXPathNodeSetItem(nodes, i);
2082 if (cur == node)
2083 break;
2084 xmlXPathNodeSetAddUnique(ret, cur);
2085 }
2086 return(ret);
2087}
2088
2089/**
2090 * xmlXPathNodeLeading:
2091 * @nodes: a node-set
2092 * @node: a node
2093 *
2094 * Implements the EXSLT - Sets leading() function:
2095 * node-set set:leading (node-set, node-set)
2096 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2097 * is called.
2098 *
2099 * Returns the nodes in @nodes that precede @node in document order,
2100 * @nodes if @node is NULL or an empty node-set if @nodes
2101 * doesn't contain @node
2102 */
2103xmlNodeSetPtr
2104xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2105 xmlXPathNodeSetSort(nodes);
2106 return(xmlXPathNodeLeadingSorted(nodes, node));
2107}
2108
2109/**
2110 * xmlXPathLeadingSorted:
2111 * @nodes1: a node-set, sorted by document order
2112 * @nodes2: a node-set, sorted by document order
2113 *
2114 * Implements the EXSLT - Sets leading() function:
2115 * node-set set:leading (node-set, node-set)
2116 *
2117 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2118 * in document order, @nodes1 if @nodes2 is NULL or empty or
2119 * an empty node-set if @nodes1 doesn't contain @nodes2
2120 */
2121xmlNodeSetPtr
2122xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2123 if (xmlXPathNodeSetIsEmpty(nodes2))
2124 return(nodes1);
2125 return(xmlXPathNodeLeadingSorted(nodes1,
2126 xmlXPathNodeSetItem(nodes2, 1)));
2127}
2128
2129/**
2130 * xmlXPathLeading:
2131 * @nodes1: a node-set
2132 * @nodes2: a node-set
2133 *
2134 * Implements the EXSLT - Sets leading() function:
2135 * node-set set:leading (node-set, node-set)
2136 * @nodes1 and @nodes2 are sorted by document order, then
2137 * #exslSetsLeadingSorted is called.
2138 *
2139 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2140 * in document order, @nodes1 if @nodes2 is NULL or empty or
2141 * an empty node-set if @nodes1 doesn't contain @nodes2
2142 */
2143xmlNodeSetPtr
2144xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2145 if (xmlXPathNodeSetIsEmpty(nodes2))
2146 return(nodes1);
2147 if (xmlXPathNodeSetIsEmpty(nodes1))
2148 return(xmlXPathNodeSetCreate(NULL));
2149 xmlXPathNodeSetSort(nodes1);
2150 xmlXPathNodeSetSort(nodes2);
2151 return(xmlXPathNodeLeadingSorted(nodes1,
2152 xmlXPathNodeSetItem(nodes2, 1)));
2153}
2154
2155/**
2156 * xmlXPathNodeTrailingSorted:
2157 * @nodes: a node-set, sorted by document order
2158 * @node: a node
2159 *
2160 * Implements the EXSLT - Sets trailing() function:
2161 * node-set set:trailing (node-set, node-set)
2162 *
2163 * Returns the nodes in @nodes that follow @node in document order,
2164 * @nodes if @node is NULL or an empty node-set if @nodes
2165 * doesn't contain @node
2166 */
2167xmlNodeSetPtr
2168xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2169 int i, l;
2170 xmlNodePtr cur;
2171 xmlNodeSetPtr ret;
2172
2173 if (node == NULL)
2174 return(nodes);
2175
2176 ret = xmlXPathNodeSetCreate(NULL);
2177 if (xmlXPathNodeSetIsEmpty(nodes) ||
2178 (!xmlXPathNodeSetContains(nodes, node)))
2179 return(ret);
2180
2181 l = xmlXPathNodeSetGetLength(nodes);
2182 for (i = 0; i < l; i++) {
2183 cur = xmlXPathNodeSetItem(nodes, i);
2184 if (cur == node)
2185 break;
2186 xmlXPathNodeSetAddUnique(ret, cur);
2187 }
2188 return(ret);
2189}
2190
2191/**
2192 * xmlXPathNodeTrailing:
2193 * @nodes: a node-set
2194 * @node: a node
2195 *
2196 * Implements the EXSLT - Sets trailing() function:
2197 * node-set set:trailing (node-set, node-set)
2198 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2199 * is called.
2200 *
2201 * Returns the nodes in @nodes that follow @node in document order,
2202 * @nodes if @node is NULL or an empty node-set if @nodes
2203 * doesn't contain @node
2204 */
2205xmlNodeSetPtr
2206xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2207 xmlXPathNodeSetSort(nodes);
2208 return(xmlXPathNodeTrailingSorted(nodes, node));
2209}
2210
2211/**
2212 * xmlXPathTrailingSorted:
2213 * @nodes1: a node-set, sorted by document order
2214 * @nodes2: a node-set, sorted by document order
2215 *
2216 * Implements the EXSLT - Sets trailing() function:
2217 * node-set set:trailing (node-set, node-set)
2218 *
2219 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2220 * in document order, @nodes1 if @nodes2 is NULL or empty or
2221 * an empty node-set if @nodes1 doesn't contain @nodes2
2222 */
2223xmlNodeSetPtr
2224xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2225 if (xmlXPathNodeSetIsEmpty(nodes2))
2226 return(nodes1);
2227 return(xmlXPathNodeTrailingSorted(nodes1,
2228 xmlXPathNodeSetItem(nodes2, 0)));
2229}
2230
2231/**
2232 * xmlXPathTrailing:
2233 * @nodes1: a node-set
2234 * @nodes2: a node-set
2235 *
2236 * Implements the EXSLT - Sets trailing() function:
2237 * node-set set:trailing (node-set, node-set)
2238 * @nodes1 and @nodes2 are sorted by document order, then
2239 * #xmlXPathTrailingSorted is called.
2240 *
2241 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2242 * in document order, @nodes1 if @nodes2 is NULL or empty or
2243 * an empty node-set if @nodes1 doesn't contain @nodes2
2244 */
2245xmlNodeSetPtr
2246xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2247 if (xmlXPathNodeSetIsEmpty(nodes2))
2248 return(nodes1);
2249 if (xmlXPathNodeSetIsEmpty(nodes1))
2250 return(xmlXPathNodeSetCreate(NULL));
2251 xmlXPathNodeSetSort(nodes1);
2252 xmlXPathNodeSetSort(nodes2);
2253 return(xmlXPathNodeTrailingSorted(nodes1,
2254 xmlXPathNodeSetItem(nodes2, 0)));
2255}
2256
Owen Taylor3473f882001-02-23 17:55:21 +00002257/************************************************************************
2258 * *
2259 * Routines to handle extra functions *
2260 * *
2261 ************************************************************************/
2262
2263/**
2264 * xmlXPathRegisterFunc:
2265 * @ctxt: the XPath context
2266 * @name: the function name
2267 * @f: the function implementation or NULL
2268 *
2269 * Register a new function. If @f is NULL it unregisters the function
2270 *
2271 * Returns 0 in case of success, -1 in case of error
2272 */
2273int
2274xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2275 xmlXPathFunction f) {
2276 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2277}
2278
2279/**
2280 * xmlXPathRegisterFuncNS:
2281 * @ctxt: the XPath context
2282 * @name: the function name
2283 * @ns_uri: the function namespace URI
2284 * @f: the function implementation or NULL
2285 *
2286 * Register a new function. If @f is NULL it unregisters the function
2287 *
2288 * Returns 0 in case of success, -1 in case of error
2289 */
2290int
2291xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2292 const xmlChar *ns_uri, xmlXPathFunction f) {
2293 if (ctxt == NULL)
2294 return(-1);
2295 if (name == NULL)
2296 return(-1);
2297
2298 if (ctxt->funcHash == NULL)
2299 ctxt->funcHash = xmlHashCreate(0);
2300 if (ctxt->funcHash == NULL)
2301 return(-1);
2302 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2303}
2304
2305/**
2306 * xmlXPathFunctionLookup:
2307 * @ctxt: the XPath context
2308 * @name: the function name
2309 *
2310 * Search in the Function array of the context for the given
2311 * function.
2312 *
2313 * Returns the xmlXPathFunction or NULL if not found
2314 */
2315xmlXPathFunction
2316xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2317 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2318}
2319
2320/**
2321 * xmlXPathFunctionLookupNS:
2322 * @ctxt: the XPath context
2323 * @name: the function name
2324 * @ns_uri: the function namespace URI
2325 *
2326 * Search in the Function array of the context for the given
2327 * function.
2328 *
2329 * Returns the xmlXPathFunction or NULL if not found
2330 */
2331xmlXPathFunction
2332xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2333 const xmlChar *ns_uri) {
2334 if (ctxt == NULL)
2335 return(NULL);
2336 if (ctxt->funcHash == NULL)
2337 return(NULL);
2338 if (name == NULL)
2339 return(NULL);
2340
2341 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2342}
2343
2344/**
2345 * xmlXPathRegisteredFuncsCleanup:
2346 * @ctxt: the XPath context
2347 *
2348 * Cleanup the XPath context data associated to registered functions
2349 */
2350void
2351xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2352 if (ctxt == NULL)
2353 return;
2354
2355 xmlHashFree(ctxt->funcHash, NULL);
2356 ctxt->funcHash = NULL;
2357}
2358
2359/************************************************************************
2360 * *
2361 * Routines to handle Variable *
2362 * *
2363 ************************************************************************/
2364
2365/**
2366 * xmlXPathRegisterVariable:
2367 * @ctxt: the XPath context
2368 * @name: the variable name
2369 * @value: the variable value or NULL
2370 *
2371 * Register a new variable value. If @value is NULL it unregisters
2372 * the variable
2373 *
2374 * Returns 0 in case of success, -1 in case of error
2375 */
2376int
2377xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2378 xmlXPathObjectPtr value) {
2379 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2380}
2381
2382/**
2383 * xmlXPathRegisterVariableNS:
2384 * @ctxt: the XPath context
2385 * @name: the variable name
2386 * @ns_uri: the variable namespace URI
2387 * @value: the variable value or NULL
2388 *
2389 * Register a new variable value. If @value is NULL it unregisters
2390 * the variable
2391 *
2392 * Returns 0 in case of success, -1 in case of error
2393 */
2394int
2395xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2396 const xmlChar *ns_uri,
2397 xmlXPathObjectPtr value) {
2398 if (ctxt == NULL)
2399 return(-1);
2400 if (name == NULL)
2401 return(-1);
2402
2403 if (ctxt->varHash == NULL)
2404 ctxt->varHash = xmlHashCreate(0);
2405 if (ctxt->varHash == NULL)
2406 return(-1);
2407 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2408 (void *) value,
2409 (xmlHashDeallocator)xmlXPathFreeObject));
2410}
2411
2412/**
2413 * xmlXPathRegisterVariableLookup:
2414 * @ctxt: the XPath context
2415 * @f: the lookup function
2416 * @data: the lookup data
2417 *
2418 * register an external mechanism to do variable lookup
2419 */
2420void
2421xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2422 xmlXPathVariableLookupFunc f, void *data) {
2423 if (ctxt == NULL)
2424 return;
2425 ctxt->varLookupFunc = (void *) f;
2426 ctxt->varLookupData = data;
2427}
2428
2429/**
2430 * xmlXPathVariableLookup:
2431 * @ctxt: the XPath context
2432 * @name: the variable name
2433 *
2434 * Search in the Variable array of the context for the given
2435 * variable value.
2436 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002437 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002438 */
2439xmlXPathObjectPtr
2440xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2441 if (ctxt == NULL)
2442 return(NULL);
2443
2444 if (ctxt->varLookupFunc != NULL) {
2445 xmlXPathObjectPtr ret;
2446
2447 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2448 (ctxt->varLookupData, name, NULL);
2449 if (ret != NULL) return(ret);
2450 }
2451 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2452}
2453
2454/**
2455 * xmlXPathVariableLookupNS:
2456 * @ctxt: the XPath context
2457 * @name: the variable name
2458 * @ns_uri: the variable namespace URI
2459 *
2460 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002461 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002462 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002463 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002464 */
2465xmlXPathObjectPtr
2466xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2467 const xmlChar *ns_uri) {
2468 if (ctxt == NULL)
2469 return(NULL);
2470
2471 if (ctxt->varLookupFunc != NULL) {
2472 xmlXPathObjectPtr ret;
2473
2474 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2475 (ctxt->varLookupData, name, ns_uri);
2476 if (ret != NULL) return(ret);
2477 }
2478
2479 if (ctxt->varHash == NULL)
2480 return(NULL);
2481 if (name == NULL)
2482 return(NULL);
2483
Daniel Veillard8c357d52001-07-03 23:43:33 +00002484 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2485 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002486}
2487
2488/**
2489 * xmlXPathRegisteredVariablesCleanup:
2490 * @ctxt: the XPath context
2491 *
2492 * Cleanup the XPath context data associated to registered variables
2493 */
2494void
2495xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2496 if (ctxt == NULL)
2497 return;
2498
Daniel Veillard76d66f42001-05-16 21:05:17 +00002499 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002500 ctxt->varHash = NULL;
2501}
2502
2503/**
2504 * xmlXPathRegisterNs:
2505 * @ctxt: the XPath context
2506 * @prefix: the namespace prefix
2507 * @ns_uri: the namespace name
2508 *
2509 * Register a new namespace. If @ns_uri is NULL it unregisters
2510 * the namespace
2511 *
2512 * Returns 0 in case of success, -1 in case of error
2513 */
2514int
2515xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2516 const xmlChar *ns_uri) {
2517 if (ctxt == NULL)
2518 return(-1);
2519 if (prefix == NULL)
2520 return(-1);
2521
2522 if (ctxt->nsHash == NULL)
2523 ctxt->nsHash = xmlHashCreate(10);
2524 if (ctxt->nsHash == NULL)
2525 return(-1);
2526 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) ns_uri,
2527 (xmlHashDeallocator)xmlFree));
2528}
2529
2530/**
2531 * xmlXPathNsLookup:
2532 * @ctxt: the XPath context
2533 * @prefix: the namespace prefix value
2534 *
2535 * Search in the namespace declaration array of the context for the given
2536 * namespace name associated to the given prefix
2537 *
2538 * Returns the value or NULL if not found
2539 */
2540const xmlChar *
2541xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2542 if (ctxt == NULL)
2543 return(NULL);
2544 if (prefix == NULL)
2545 return(NULL);
2546
2547#ifdef XML_XML_NAMESPACE
2548 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
2549 return(XML_XML_NAMESPACE);
2550#endif
2551
Daniel Veillardc8f620b2001-04-30 20:31:33 +00002552 if (ctxt->namespaces != NULL) {
2553 int i;
2554
2555 for (i = 0;i < ctxt->nsNr;i++) {
2556 if ((ctxt->namespaces[i] != NULL) &&
2557 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
2558 return(ctxt->namespaces[i]->href);
2559 }
2560 }
Owen Taylor3473f882001-02-23 17:55:21 +00002561
2562 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
2563}
2564
2565/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002566 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00002567 * @ctxt: the XPath context
2568 *
2569 * Cleanup the XPath context data associated to registered variables
2570 */
2571void
2572xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2573 if (ctxt == NULL)
2574 return;
2575
2576 xmlHashFree(ctxt->nsHash, NULL);
2577 ctxt->nsHash = NULL;
2578}
2579
2580/************************************************************************
2581 * *
2582 * Routines to handle Values *
2583 * *
2584 ************************************************************************/
2585
2586/* Allocations are terrible, one need to optimize all this !!! */
2587
2588/**
2589 * xmlXPathNewFloat:
2590 * @val: the double value
2591 *
2592 * Create a new xmlXPathObjectPtr of type double and of value @val
2593 *
2594 * Returns the newly created object.
2595 */
2596xmlXPathObjectPtr
2597xmlXPathNewFloat(double val) {
2598 xmlXPathObjectPtr ret;
2599
2600 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2601 if (ret == NULL) {
2602 xmlGenericError(xmlGenericErrorContext,
2603 "xmlXPathNewFloat: out of memory\n");
2604 return(NULL);
2605 }
2606 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2607 ret->type = XPATH_NUMBER;
2608 ret->floatval = val;
2609 return(ret);
2610}
2611
2612/**
2613 * xmlXPathNewBoolean:
2614 * @val: the boolean value
2615 *
2616 * Create a new xmlXPathObjectPtr of type boolean and of value @val
2617 *
2618 * Returns the newly created object.
2619 */
2620xmlXPathObjectPtr
2621xmlXPathNewBoolean(int val) {
2622 xmlXPathObjectPtr ret;
2623
2624 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2625 if (ret == NULL) {
2626 xmlGenericError(xmlGenericErrorContext,
2627 "xmlXPathNewBoolean: out of memory\n");
2628 return(NULL);
2629 }
2630 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2631 ret->type = XPATH_BOOLEAN;
2632 ret->boolval = (val != 0);
2633 return(ret);
2634}
2635
2636/**
2637 * xmlXPathNewString:
2638 * @val: the xmlChar * value
2639 *
2640 * Create a new xmlXPathObjectPtr of type string and of value @val
2641 *
2642 * Returns the newly created object.
2643 */
2644xmlXPathObjectPtr
2645xmlXPathNewString(const xmlChar *val) {
2646 xmlXPathObjectPtr ret;
2647
2648 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2649 if (ret == NULL) {
2650 xmlGenericError(xmlGenericErrorContext,
2651 "xmlXPathNewString: out of memory\n");
2652 return(NULL);
2653 }
2654 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2655 ret->type = XPATH_STRING;
2656 if (val != NULL)
2657 ret->stringval = xmlStrdup(val);
2658 else
2659 ret->stringval = xmlStrdup((const xmlChar *)"");
2660 return(ret);
2661}
2662
2663/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002664 * xmlXPathWrapString:
2665 * @val: the xmlChar * value
2666 *
2667 * Wraps the @val string into an XPath object.
2668 *
2669 * Returns the newly created object.
2670 */
2671xmlXPathObjectPtr
2672xmlXPathWrapString (xmlChar *val) {
2673 xmlXPathObjectPtr ret;
2674
2675 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2676 if (ret == NULL) {
2677 xmlGenericError(xmlGenericErrorContext,
2678 "xmlXPathWrapString: out of memory\n");
2679 return(NULL);
2680 }
2681 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2682 ret->type = XPATH_STRING;
2683 ret->stringval = val;
2684 return(ret);
2685}
2686
2687/**
Owen Taylor3473f882001-02-23 17:55:21 +00002688 * xmlXPathNewCString:
2689 * @val: the char * value
2690 *
2691 * Create a new xmlXPathObjectPtr of type string and of value @val
2692 *
2693 * Returns the newly created object.
2694 */
2695xmlXPathObjectPtr
2696xmlXPathNewCString(const char *val) {
2697 xmlXPathObjectPtr ret;
2698
2699 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2700 if (ret == NULL) {
2701 xmlGenericError(xmlGenericErrorContext,
2702 "xmlXPathNewCString: out of memory\n");
2703 return(NULL);
2704 }
2705 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2706 ret->type = XPATH_STRING;
2707 ret->stringval = xmlStrdup(BAD_CAST val);
2708 return(ret);
2709}
2710
2711/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002712 * xmlXPathWrapCString:
2713 * @val: the char * value
2714 *
2715 * Wraps a string into an XPath object.
2716 *
2717 * Returns the newly created object.
2718 */
2719xmlXPathObjectPtr
2720xmlXPathWrapCString (char * val) {
2721 return(xmlXPathWrapString((xmlChar *)(val)));
2722}
2723
2724/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002725 * xmlXPathWrapExternal:
2726 * @val: the user data
2727 *
2728 * Wraps the @val data into an XPath object.
2729 *
2730 * Returns the newly created object.
2731 */
2732xmlXPathObjectPtr
2733xmlXPathWrapExternal (void *val) {
2734 xmlXPathObjectPtr ret;
2735
2736 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2737 if (ret == NULL) {
2738 xmlGenericError(xmlGenericErrorContext,
2739 "xmlXPathWrapString: out of memory\n");
2740 return(NULL);
2741 }
2742 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2743 ret->type = XPATH_USERS;
2744 ret->user = val;
2745 return(ret);
2746}
2747
2748/**
Owen Taylor3473f882001-02-23 17:55:21 +00002749 * xmlXPathObjectCopy:
2750 * @val: the original object
2751 *
2752 * allocate a new copy of a given object
2753 *
2754 * Returns the newly created object.
2755 */
2756xmlXPathObjectPtr
2757xmlXPathObjectCopy(xmlXPathObjectPtr val) {
2758 xmlXPathObjectPtr ret;
2759
2760 if (val == NULL)
2761 return(NULL);
2762
2763 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2764 if (ret == NULL) {
2765 xmlGenericError(xmlGenericErrorContext,
2766 "xmlXPathObjectCopy: out of memory\n");
2767 return(NULL);
2768 }
2769 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
2770 switch (val->type) {
2771 case XPATH_BOOLEAN:
2772 case XPATH_NUMBER:
2773 case XPATH_POINT:
2774 case XPATH_RANGE:
2775 break;
2776 case XPATH_STRING:
2777 ret->stringval = xmlStrdup(val->stringval);
2778 break;
2779 case XPATH_XSLT_TREE:
2780 if ((val->nodesetval != NULL) &&
2781 (val->nodesetval->nodeTab != NULL))
2782 ret->nodesetval = xmlXPathNodeSetCreate(
2783 xmlCopyNode(val->nodesetval->nodeTab[0], 1));
2784 else
2785 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
2786 break;
2787 case XPATH_NODESET:
2788 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
2789 break;
2790 case XPATH_LOCATIONSET:
2791#ifdef LIBXML_XPTR_ENABLED
2792 {
2793 xmlLocationSetPtr loc = val->user;
2794 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
2795 break;
2796 }
2797#endif
2798 case XPATH_UNDEFINED:
2799 case XPATH_USERS:
2800 xmlGenericError(xmlGenericErrorContext,
2801 "xmlXPathObjectCopy: unsupported type %d\n",
2802 val->type);
2803 break;
2804 }
2805 return(ret);
2806}
2807
2808/**
2809 * xmlXPathFreeObject:
2810 * @obj: the object to free
2811 *
2812 * Free up an xmlXPathObjectPtr object.
2813 */
2814void
2815xmlXPathFreeObject(xmlXPathObjectPtr obj) {
2816 if (obj == NULL) return;
2817 if (obj->type == XPATH_NODESET) {
Daniel Veillard77851712001-02-27 21:54:07 +00002818 if (obj->boolval) {
2819 obj->type = XPATH_XSLT_TREE;
2820 if (obj->nodesetval != NULL)
2821 xmlXPathFreeValueTree(obj->nodesetval);
2822 } else {
2823 if (obj->nodesetval != NULL)
2824 xmlXPathFreeNodeSet(obj->nodesetval);
2825 }
Owen Taylor3473f882001-02-23 17:55:21 +00002826#ifdef LIBXML_XPTR_ENABLED
2827 } else if (obj->type == XPATH_LOCATIONSET) {
2828 if (obj->user != NULL)
2829 xmlXPtrFreeLocationSet(obj->user);
2830#endif
2831 } else if (obj->type == XPATH_STRING) {
2832 if (obj->stringval != NULL)
2833 xmlFree(obj->stringval);
2834 } else if (obj->type == XPATH_XSLT_TREE) {
2835 if (obj->nodesetval != NULL)
2836 xmlXPathFreeValueTree(obj->nodesetval);
2837 }
2838
Owen Taylor3473f882001-02-23 17:55:21 +00002839 xmlFree(obj);
2840}
2841
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002842
2843/************************************************************************
2844 * *
2845 * Type Casting Routines *
2846 * *
2847 ************************************************************************/
2848
2849/**
2850 * xmlXPathCastBooleanToString:
2851 * @val: a boolean
2852 *
2853 * Converts a boolean to its string value.
2854 *
2855 * Returns a newly allocated string.
2856 */
2857xmlChar *
2858xmlXPathCastBooleanToString (int val) {
2859 xmlChar *ret;
2860 if (val)
2861 ret = xmlStrdup((const xmlChar *) "true");
2862 else
2863 ret = xmlStrdup((const xmlChar *) "false");
2864 return(ret);
2865}
2866
2867/**
2868 * xmlXPathCastNumberToString:
2869 * @val: a number
2870 *
2871 * Converts a number to its string value.
2872 *
2873 * Returns a newly allocated string.
2874 */
2875xmlChar *
2876xmlXPathCastNumberToString (double val) {
2877 xmlChar *ret;
2878 switch (isinf(val)) {
2879 case 1:
2880 ret = xmlStrdup((const xmlChar *) "+Infinity");
2881 break;
2882 case -1:
2883 ret = xmlStrdup((const xmlChar *) "-Infinity");
2884 break;
2885 default:
2886 if (isnan(val)) {
2887 ret = xmlStrdup((const xmlChar *) "NaN");
2888 } else {
2889 /* could be improved */
2890 char buf[100];
2891 xmlXPathFormatNumber(val, buf, 100);
2892 ret = xmlStrdup((const xmlChar *) buf);
2893 }
2894 }
2895 return(ret);
2896}
2897
2898/**
2899 * xmlXPathCastNodeToString:
2900 * @node: a node
2901 *
2902 * Converts a node to its string value.
2903 *
2904 * Returns a newly allocated string.
2905 */
2906xmlChar *
2907xmlXPathCastNodeToString (xmlNodePtr node) {
2908 return(xmlNodeGetContent(node));
2909}
2910
2911/**
2912 * xmlXPathCastNodeSetToString:
2913 * @ns: a node-set
2914 *
2915 * Converts a node-set to its string value.
2916 *
2917 * Returns a newly allocated string.
2918 */
2919xmlChar *
2920xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
2921 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
2922 return(xmlStrdup((const xmlChar *) ""));
2923
2924 xmlXPathNodeSetSort(ns);
2925 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
2926}
2927
2928/**
2929 * xmlXPathCastToString:
2930 * @val: an XPath object
2931 *
2932 * Converts an existing object to its string() equivalent
2933 *
2934 * Returns the string value of the object, NULL in case of error.
2935 * A new string is allocated only if needed (val isn't a
2936 * string object).
2937 */
2938xmlChar *
2939xmlXPathCastToString(xmlXPathObjectPtr val) {
2940 xmlChar *ret = NULL;
2941
2942 if (val == NULL)
2943 return(xmlStrdup((const xmlChar *) ""));
2944 switch (val->type) {
2945 case XPATH_UNDEFINED:
2946#ifdef DEBUG_EXPR
2947 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
2948#endif
2949 ret = xmlStrdup((const xmlChar *) "");
2950 break;
2951 case XPATH_XSLT_TREE:
2952 case XPATH_NODESET:
2953 ret = xmlXPathCastNodeSetToString(val->nodesetval);
2954 break;
2955 case XPATH_STRING:
2956 return(val->stringval);
2957 case XPATH_BOOLEAN:
2958 ret = xmlXPathCastBooleanToString(val->boolval);
2959 break;
2960 case XPATH_NUMBER: {
2961 ret = xmlXPathCastNumberToString(val->floatval);
2962 break;
2963 }
2964 case XPATH_USERS:
2965 case XPATH_POINT:
2966 case XPATH_RANGE:
2967 case XPATH_LOCATIONSET:
2968 TODO
2969 ret = xmlStrdup((const xmlChar *) "");
2970 break;
2971 }
2972 return(ret);
2973}
2974
2975/**
2976 * xmlXPathConvertString:
2977 * @val: an XPath object
2978 *
2979 * Converts an existing object to its string() equivalent
2980 *
2981 * Returns the new object, the old one is freed (or the operation
2982 * is done directly on @val)
2983 */
2984xmlXPathObjectPtr
2985xmlXPathConvertString(xmlXPathObjectPtr val) {
2986 xmlChar *res = NULL;
2987
2988 if (val == NULL)
2989 return(xmlXPathNewCString(""));
2990
2991 switch (val->type) {
2992 case XPATH_UNDEFINED:
2993#ifdef DEBUG_EXPR
2994 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2995#endif
2996 break;
2997 case XPATH_XSLT_TREE:
2998 case XPATH_NODESET:
2999 res = xmlXPathCastNodeSetToString(val->nodesetval);
3000 break;
3001 case XPATH_STRING:
3002 return(val);
3003 case XPATH_BOOLEAN:
3004 res = xmlXPathCastBooleanToString(val->boolval);
3005 break;
3006 case XPATH_NUMBER:
3007 res = xmlXPathCastNumberToString(val->floatval);
3008 break;
3009 case XPATH_USERS:
3010 case XPATH_POINT:
3011 case XPATH_RANGE:
3012 case XPATH_LOCATIONSET:
3013 TODO;
3014 break;
3015 }
3016 xmlXPathFreeObject(val);
3017 if (res == NULL)
3018 return(xmlXPathNewCString(""));
3019 return(xmlXPathWrapString(res));
3020}
3021
3022/**
3023 * xmlXPathCastBooleanToNumber:
3024 * @val: a boolean
3025 *
3026 * Converts a boolean to its number value
3027 *
3028 * Returns the number value
3029 */
3030double
3031xmlXPathCastBooleanToNumber(int val) {
3032 if (val)
3033 return(1.0);
3034 return(0.0);
3035}
3036
3037/**
3038 * xmlXPathCastStringToNumber:
3039 * @val: a string
3040 *
3041 * Converts a string to its number value
3042 *
3043 * Returns the number value
3044 */
3045double
3046xmlXPathCastStringToNumber(const xmlChar * val) {
3047 return(xmlXPathStringEvalNumber(val));
3048}
3049
3050/**
3051 * xmlXPathCastNodeToNumber:
3052 * @node: a node
3053 *
3054 * Converts a node to its number value
3055 *
3056 * Returns the number value
3057 */
3058double
3059xmlXPathCastNodeToNumber (xmlNodePtr node) {
3060 xmlChar *strval;
3061 double ret;
3062
3063 if (node == NULL)
3064 return(xmlXPathNAN);
3065 strval = xmlXPathCastNodeToString(node);
3066 if (strval == NULL)
3067 return(xmlXPathNAN);
3068 ret = xmlXPathCastStringToNumber(strval);
3069 xmlFree(strval);
3070
3071 return(ret);
3072}
3073
3074/**
3075 * xmlXPathCastNodeSetToNumber:
3076 * @ns: a node-set
3077 *
3078 * Converts a node-set to its number value
3079 *
3080 * Returns the number value
3081 */
3082double
3083xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3084 xmlChar *str;
3085 double ret;
3086
3087 if (ns == NULL)
3088 return(xmlXPathNAN);
3089 str = xmlXPathCastNodeSetToString(ns);
3090 ret = xmlXPathCastStringToNumber(str);
3091 xmlFree(str);
3092 return(ret);
3093}
3094
3095/**
3096 * xmlXPathCastToNumber:
3097 * @val: an XPath object
3098 *
3099 * Converts an XPath object to its number value
3100 *
3101 * Returns the number value
3102 */
3103double
3104xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3105 double ret = 0.0;
3106
3107 if (val == NULL)
3108 return(xmlXPathNAN);
3109 switch (val->type) {
3110 case XPATH_UNDEFINED:
3111#ifdef DEGUB_EXPR
3112 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3113#endif
3114 ret = xmlXPathNAN;
3115 break;
3116 case XPATH_XSLT_TREE:
3117 case XPATH_NODESET:
3118 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3119 break;
3120 case XPATH_STRING:
3121 ret = xmlXPathCastStringToNumber(val->stringval);
3122 break;
3123 case XPATH_NUMBER:
3124 ret = val->floatval;
3125 break;
3126 case XPATH_BOOLEAN:
3127 ret = xmlXPathCastBooleanToNumber(val->boolval);
3128 break;
3129 case XPATH_USERS:
3130 case XPATH_POINT:
3131 case XPATH_RANGE:
3132 case XPATH_LOCATIONSET:
3133 TODO;
3134 ret = xmlXPathNAN;
3135 break;
3136 }
3137 return(ret);
3138}
3139
3140/**
3141 * xmlXPathConvertNumber:
3142 * @val: an XPath object
3143 *
3144 * Converts an existing object to its number() equivalent
3145 *
3146 * Returns the new object, the old one is freed (or the operation
3147 * is done directly on @val)
3148 */
3149xmlXPathObjectPtr
3150xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3151 xmlXPathObjectPtr ret;
3152
3153 if (val == NULL)
3154 return(xmlXPathNewFloat(0.0));
3155 if (val->type == XPATH_NUMBER)
3156 return(val);
3157 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3158 xmlXPathFreeObject(val);
3159 return(ret);
3160}
3161
3162/**
3163 * xmlXPathCastNumberToBoolean:
3164 * @val: a number
3165 *
3166 * Converts a number to its boolean value
3167 *
3168 * Returns the boolean value
3169 */
3170int
3171xmlXPathCastNumberToBoolean (double val) {
3172 if (isnan(val) || (val == 0.0))
3173 return(0);
3174 return(1);
3175}
3176
3177/**
3178 * xmlXPathCastStringToBoolean:
3179 * @val: a string
3180 *
3181 * Converts a string to its boolean value
3182 *
3183 * Returns the boolean value
3184 */
3185int
3186xmlXPathCastStringToBoolean (const xmlChar *val) {
3187 if ((val == NULL) || (xmlStrlen(val) == 0))
3188 return(0);
3189 return(1);
3190}
3191
3192/**
3193 * xmlXPathCastNodeSetToBoolean:
3194 * @ns: a node-set
3195 *
3196 * Converts a node-set to its boolean value
3197 *
3198 * Returns the boolean value
3199 */
3200int
3201xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3202 if ((ns == NULL) || (ns->nodeNr == 0))
3203 return(0);
3204 return(1);
3205}
3206
3207/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003208 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003209 * @val: an XPath object
3210 *
3211 * Converts an XPath object to its boolean value
3212 *
3213 * Returns the boolean value
3214 */
3215int
3216xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3217 int ret = 0;
3218
3219 if (val == NULL)
3220 return(0);
3221 switch (val->type) {
3222 case XPATH_UNDEFINED:
3223#ifdef DEBUG_EXPR
3224 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3225#endif
3226 ret = 0;
3227 break;
3228 case XPATH_XSLT_TREE:
3229 case XPATH_NODESET:
3230 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3231 break;
3232 case XPATH_STRING:
3233 ret = xmlXPathCastStringToBoolean(val->stringval);
3234 break;
3235 case XPATH_NUMBER:
3236 ret = xmlXPathCastNumberToBoolean(val->floatval);
3237 break;
3238 case XPATH_BOOLEAN:
3239 ret = val->boolval;
3240 break;
3241 case XPATH_USERS:
3242 case XPATH_POINT:
3243 case XPATH_RANGE:
3244 case XPATH_LOCATIONSET:
3245 TODO;
3246 ret = 0;
3247 break;
3248 }
3249 return(ret);
3250}
3251
3252
3253/**
3254 * xmlXPathConvertBoolean:
3255 * @val: an XPath object
3256 *
3257 * Converts an existing object to its boolean() equivalent
3258 *
3259 * Returns the new object, the old one is freed (or the operation
3260 * is done directly on @val)
3261 */
3262xmlXPathObjectPtr
3263xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3264 xmlXPathObjectPtr ret;
3265
3266 if (val == NULL)
3267 return(xmlXPathNewBoolean(0));
3268 if (val->type == XPATH_BOOLEAN)
3269 return(val);
3270 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3271 xmlXPathFreeObject(val);
3272 return(ret);
3273}
3274
Owen Taylor3473f882001-02-23 17:55:21 +00003275/************************************************************************
3276 * *
3277 * Routines to handle XPath contexts *
3278 * *
3279 ************************************************************************/
3280
3281/**
3282 * xmlXPathNewContext:
3283 * @doc: the XML document
3284 *
3285 * Create a new xmlXPathContext
3286 *
3287 * Returns the xmlXPathContext just allocated.
3288 */
3289xmlXPathContextPtr
3290xmlXPathNewContext(xmlDocPtr doc) {
3291 xmlXPathContextPtr ret;
3292
3293 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3294 if (ret == NULL) {
3295 xmlGenericError(xmlGenericErrorContext,
3296 "xmlXPathNewContext: out of memory\n");
3297 return(NULL);
3298 }
3299 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3300 ret->doc = doc;
3301 ret->node = NULL;
3302
3303 ret->varHash = NULL;
3304
3305 ret->nb_types = 0;
3306 ret->max_types = 0;
3307 ret->types = NULL;
3308
3309 ret->funcHash = xmlHashCreate(0);
3310
3311 ret->nb_axis = 0;
3312 ret->max_axis = 0;
3313 ret->axis = NULL;
3314
3315 ret->nsHash = NULL;
3316 ret->user = NULL;
3317
3318 ret->contextSize = -1;
3319 ret->proximityPosition = -1;
3320
3321 xmlXPathRegisterAllFunctions(ret);
3322
3323 return(ret);
3324}
3325
3326/**
3327 * xmlXPathFreeContext:
3328 * @ctxt: the context to free
3329 *
3330 * Free up an xmlXPathContext
3331 */
3332void
3333xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3334 xmlXPathRegisteredNsCleanup(ctxt);
3335 xmlXPathRegisteredFuncsCleanup(ctxt);
3336 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003337 xmlFree(ctxt);
3338}
3339
3340/************************************************************************
3341 * *
3342 * Routines to handle XPath parser contexts *
3343 * *
3344 ************************************************************************/
3345
3346#define CHECK_CTXT(ctxt) \
3347 if (ctxt == NULL) { \
3348 xmlGenericError(xmlGenericErrorContext, \
3349 "%s:%d Internal error: ctxt == NULL\n", \
3350 __FILE__, __LINE__); \
3351 } \
3352
3353
3354#define CHECK_CONTEXT(ctxt) \
3355 if (ctxt == NULL) { \
3356 xmlGenericError(xmlGenericErrorContext, \
3357 "%s:%d Internal error: no context\n", \
3358 __FILE__, __LINE__); \
3359 } \
3360 else if (ctxt->doc == NULL) { \
3361 xmlGenericError(xmlGenericErrorContext, \
3362 "%s:%d Internal error: no document\n", \
3363 __FILE__, __LINE__); \
3364 } \
3365 else if (ctxt->doc->children == NULL) { \
3366 xmlGenericError(xmlGenericErrorContext, \
3367 "%s:%d Internal error: document without root\n", \
3368 __FILE__, __LINE__); \
3369 } \
3370
3371
3372/**
3373 * xmlXPathNewParserContext:
3374 * @str: the XPath expression
3375 * @ctxt: the XPath context
3376 *
3377 * Create a new xmlXPathParserContext
3378 *
3379 * Returns the xmlXPathParserContext just allocated.
3380 */
3381xmlXPathParserContextPtr
3382xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3383 xmlXPathParserContextPtr ret;
3384
3385 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3386 if (ret == NULL) {
3387 xmlGenericError(xmlGenericErrorContext,
3388 "xmlXPathNewParserContext: out of memory\n");
3389 return(NULL);
3390 }
3391 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3392 ret->cur = ret->base = str;
3393 ret->context = ctxt;
3394
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003395 ret->comp = xmlXPathNewCompExpr();
3396 if (ret->comp == NULL) {
3397 xmlFree(ret->valueTab);
3398 xmlFree(ret);
3399 return(NULL);
3400 }
3401
3402 return(ret);
3403}
3404
3405/**
3406 * xmlXPathCompParserContext:
3407 * @comp: the XPath compiled expression
3408 * @ctxt: the XPath context
3409 *
3410 * Create a new xmlXPathParserContext when processing a compiled expression
3411 *
3412 * Returns the xmlXPathParserContext just allocated.
3413 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003414static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003415xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3416 xmlXPathParserContextPtr ret;
3417
3418 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3419 if (ret == NULL) {
3420 xmlGenericError(xmlGenericErrorContext,
3421 "xmlXPathNewParserContext: out of memory\n");
3422 return(NULL);
3423 }
3424 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3425
Owen Taylor3473f882001-02-23 17:55:21 +00003426 /* Allocate the value stack */
3427 ret->valueTab = (xmlXPathObjectPtr *)
3428 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003429 if (ret->valueTab == NULL) {
3430 xmlFree(ret);
3431 xmlGenericError(xmlGenericErrorContext,
3432 "xmlXPathNewParserContext: out of memory\n");
3433 return(NULL);
3434 }
Owen Taylor3473f882001-02-23 17:55:21 +00003435 ret->valueNr = 0;
3436 ret->valueMax = 10;
3437 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003438
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003439 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003440 ret->comp = comp;
3441
Owen Taylor3473f882001-02-23 17:55:21 +00003442 return(ret);
3443}
3444
3445/**
3446 * xmlXPathFreeParserContext:
3447 * @ctxt: the context to free
3448 *
3449 * Free up an xmlXPathParserContext
3450 */
3451void
3452xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3453 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003454 xmlFree(ctxt->valueTab);
3455 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003456 if (ctxt->comp)
3457 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003458 xmlFree(ctxt);
3459}
3460
3461/************************************************************************
3462 * *
3463 * The implicit core function library *
3464 * *
3465 ************************************************************************/
3466
Owen Taylor3473f882001-02-23 17:55:21 +00003467/**
Daniel Veillardf06307e2001-07-03 10:35:50 +00003468 * xmlXPathNodeStringHash:
3469 * @node: a node pointer
3470 *
3471 * Function computing the beginning of the string value of the node,
3472 * used to speed up comparisons
3473 *
3474 * Returns an int usable as a hash
3475 */
3476static unsigned int
3477xmlXPathNodeValHash(xmlNodePtr node) {
3478 int len = 2;
3479 const xmlChar * string = NULL;
3480 xmlNodePtr tmp = NULL;
3481 unsigned int ret = 0;
3482
3483 if (node == NULL)
3484 return(0);
3485
3486
3487 switch (node->type) {
3488 case XML_COMMENT_NODE:
3489 case XML_PI_NODE:
3490 case XML_CDATA_SECTION_NODE:
3491 case XML_TEXT_NODE:
3492 string = node->content;
3493 if (string == NULL)
3494 return(0);
3495 if (string[0] == 0)
3496 return(0);
3497 return(((unsigned int) string[0]) +
3498 (((unsigned int) string[1]) << 8));
3499 case XML_NAMESPACE_DECL:
3500 string = ((xmlNsPtr)node)->href;
3501 if (string == NULL)
3502 return(0);
3503 if (string[0] == 0)
3504 return(0);
3505 return(((unsigned int) string[0]) +
3506 (((unsigned int) string[1]) << 8));
3507 case XML_ATTRIBUTE_NODE:
3508 tmp = ((xmlAttrPtr) node)->children;
3509 break;
3510 case XML_ELEMENT_NODE:
3511 tmp = node->children;
3512 break;
3513 default:
3514 return(0);
3515 }
3516 while (tmp != NULL) {
3517 switch (tmp->type) {
3518 case XML_COMMENT_NODE:
3519 case XML_PI_NODE:
3520 case XML_CDATA_SECTION_NODE:
3521 case XML_TEXT_NODE:
3522 string = tmp->content;
3523 break;
3524 case XML_NAMESPACE_DECL:
3525 string = ((xmlNsPtr)tmp)->href;
3526 break;
3527 default:
3528 break;
3529 }
3530 if ((string != NULL) && (string[0] != 0)) {
3531 if (string[0] == 0)
3532 return(0);
3533 if (len == 1) {
3534 return(ret + (((unsigned int) string[0]) << 8));
3535 }
3536 if (string[1] == 0) {
3537 len = 1;
3538 ret = (unsigned int) string[0];
3539 } else {
3540 return(((unsigned int) string[0]) +
3541 (((unsigned int) string[1]) << 8));
3542 }
3543 }
3544 /*
3545 * Skip to next node
3546 */
3547 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
3548 if (tmp->children->type != XML_ENTITY_DECL) {
3549 tmp = tmp->children;
3550 continue;
3551 }
3552 }
3553 if (tmp == node)
3554 break;
3555
3556 if (tmp->next != NULL) {
3557 tmp = tmp->next;
3558 continue;
3559 }
3560
3561 do {
3562 tmp = tmp->parent;
3563 if (tmp == NULL)
3564 break;
3565 if (tmp == node) {
3566 tmp = NULL;
3567 break;
3568 }
3569 if (tmp->next != NULL) {
3570 tmp = tmp->next;
3571 break;
3572 }
3573 } while (tmp != NULL);
3574 }
3575 return(ret);
3576}
3577
3578/**
3579 * xmlXPathStringHash:
3580 * @string: a string
3581 *
3582 * Function computing the beginning of the string value of the node,
3583 * used to speed up comparisons
3584 *
3585 * Returns an int usable as a hash
3586 */
3587static unsigned int
3588xmlXPathStringHash(const xmlChar * string) {
3589 if (string == NULL)
3590 return((unsigned int) 0);
3591 if (string[0] == 0)
3592 return(0);
3593 return(((unsigned int) string[0]) +
3594 (((unsigned int) string[1]) << 8));
3595}
3596
3597/**
Owen Taylor3473f882001-02-23 17:55:21 +00003598 * xmlXPathCompareNodeSetFloat:
3599 * @ctxt: the XPath Parser context
3600 * @inf: less than (1) or greater than (0)
3601 * @strict: is the comparison strict
3602 * @arg: the node set
3603 * @f: the value
3604 *
3605 * Implement the compare operation between a nodeset and a number
3606 * @ns < @val (1, 1, ...
3607 * @ns <= @val (1, 0, ...
3608 * @ns > @val (0, 1, ...
3609 * @ns >= @val (0, 0, ...
3610 *
3611 * If one object to be compared is a node-set and the other is a number,
3612 * then the comparison will be true if and only if there is a node in the
3613 * node-set such that the result of performing the comparison on the number
3614 * to be compared and on the result of converting the string-value of that
3615 * node to a number using the number function is true.
3616 *
3617 * Returns 0 or 1 depending on the results of the test.
3618 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003619static int
Owen Taylor3473f882001-02-23 17:55:21 +00003620xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
3621 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
3622 int i, ret = 0;
3623 xmlNodeSetPtr ns;
3624 xmlChar *str2;
3625
3626 if ((f == NULL) || (arg == NULL) ||
3627 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3628 xmlXPathFreeObject(arg);
3629 xmlXPathFreeObject(f);
3630 return(0);
3631 }
3632 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003633 if (ns != NULL) {
3634 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003635 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003636 if (str2 != NULL) {
3637 valuePush(ctxt,
3638 xmlXPathNewString(str2));
3639 xmlFree(str2);
3640 xmlXPathNumberFunction(ctxt, 1);
3641 valuePush(ctxt, xmlXPathObjectCopy(f));
3642 ret = xmlXPathCompareValues(ctxt, inf, strict);
3643 if (ret)
3644 break;
3645 }
3646 }
Owen Taylor3473f882001-02-23 17:55:21 +00003647 }
3648 xmlXPathFreeObject(arg);
3649 xmlXPathFreeObject(f);
3650 return(ret);
3651}
3652
3653/**
3654 * xmlXPathCompareNodeSetString:
3655 * @ctxt: the XPath Parser context
3656 * @inf: less than (1) or greater than (0)
3657 * @strict: is the comparison strict
3658 * @arg: the node set
3659 * @s: the value
3660 *
3661 * Implement the compare operation between a nodeset and a string
3662 * @ns < @val (1, 1, ...
3663 * @ns <= @val (1, 0, ...
3664 * @ns > @val (0, 1, ...
3665 * @ns >= @val (0, 0, ...
3666 *
3667 * If one object to be compared is a node-set and the other is a string,
3668 * then the comparison will be true if and only if there is a node in
3669 * the node-set such that the result of performing the comparison on the
3670 * string-value of the node and the other string is true.
3671 *
3672 * Returns 0 or 1 depending on the results of the test.
3673 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003674static int
Owen Taylor3473f882001-02-23 17:55:21 +00003675xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
3676 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
3677 int i, ret = 0;
3678 xmlNodeSetPtr ns;
3679 xmlChar *str2;
3680
3681 if ((s == NULL) || (arg == NULL) ||
3682 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3683 xmlXPathFreeObject(arg);
3684 xmlXPathFreeObject(s);
3685 return(0);
3686 }
3687 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003688 if (ns != NULL) {
3689 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003690 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003691 if (str2 != NULL) {
3692 valuePush(ctxt,
3693 xmlXPathNewString(str2));
3694 xmlFree(str2);
3695 valuePush(ctxt, xmlXPathObjectCopy(s));
3696 ret = xmlXPathCompareValues(ctxt, inf, strict);
3697 if (ret)
3698 break;
3699 }
3700 }
Owen Taylor3473f882001-02-23 17:55:21 +00003701 }
3702 xmlXPathFreeObject(arg);
3703 xmlXPathFreeObject(s);
3704 return(ret);
3705}
3706
3707/**
3708 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003709 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00003710 * @strict: is the comparison strict
3711 * @arg1: the fist node set object
3712 * @arg2: the second node set object
3713 *
3714 * Implement the compare operation on nodesets:
3715 *
3716 * If both objects to be compared are node-sets, then the comparison
3717 * will be true if and only if there is a node in the first node-set
3718 * and a node in the second node-set such that the result of performing
3719 * the comparison on the string-values of the two nodes is true.
3720 * ....
3721 * When neither object to be compared is a node-set and the operator
3722 * is <=, <, >= or >, then the objects are compared by converting both
3723 * objects to numbers and comparing the numbers according to IEEE 754.
3724 * ....
3725 * The number function converts its argument to a number as follows:
3726 * - a string that consists of optional whitespace followed by an
3727 * optional minus sign followed by a Number followed by whitespace
3728 * is converted to the IEEE 754 number that is nearest (according
3729 * to the IEEE 754 round-to-nearest rule) to the mathematical value
3730 * represented by the string; any other string is converted to NaN
3731 *
3732 * Conclusion all nodes need to be converted first to their string value
3733 * and then the comparison must be done when possible
3734 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003735static int
3736xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00003737 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3738 int i, j, init = 0;
3739 double val1;
3740 double *values2;
3741 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003742 xmlNodeSetPtr ns1;
3743 xmlNodeSetPtr ns2;
3744
3745 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003746 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
3747 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003748 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003749 }
Owen Taylor3473f882001-02-23 17:55:21 +00003750 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003751 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
3752 xmlXPathFreeObject(arg1);
3753 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003754 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003755 }
Owen Taylor3473f882001-02-23 17:55:21 +00003756
3757 ns1 = arg1->nodesetval;
3758 ns2 = arg2->nodesetval;
3759
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003760 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003761 xmlXPathFreeObject(arg1);
3762 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003763 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003764 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003765 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003766 xmlXPathFreeObject(arg1);
3767 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003768 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003769 }
Owen Taylor3473f882001-02-23 17:55:21 +00003770
3771 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
3772 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003773 xmlXPathFreeObject(arg1);
3774 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003775 return(0);
3776 }
3777 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003778 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00003779 if (isnan(val1))
3780 continue;
3781 for (j = 0;j < ns2->nodeNr;j++) {
3782 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003783 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00003784 }
3785 if (isnan(values2[j]))
3786 continue;
3787 if (inf && strict)
3788 ret = (val1 < values2[j]);
3789 else if (inf && !strict)
3790 ret = (val1 <= values2[j]);
3791 else if (!inf && strict)
3792 ret = (val1 > values2[j]);
3793 else if (!inf && !strict)
3794 ret = (val1 >= values2[j]);
3795 if (ret)
3796 break;
3797 }
3798 if (ret)
3799 break;
3800 init = 1;
3801 }
3802 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003803 xmlXPathFreeObject(arg1);
3804 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003805 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003806}
3807
3808/**
3809 * xmlXPathCompareNodeSetValue:
3810 * @ctxt: the XPath Parser context
3811 * @inf: less than (1) or greater than (0)
3812 * @strict: is the comparison strict
3813 * @arg: the node set
3814 * @val: the value
3815 *
3816 * Implement the compare operation between a nodeset and a value
3817 * @ns < @val (1, 1, ...
3818 * @ns <= @val (1, 0, ...
3819 * @ns > @val (0, 1, ...
3820 * @ns >= @val (0, 0, ...
3821 *
3822 * If one object to be compared is a node-set and the other is a boolean,
3823 * then the comparison will be true if and only if the result of performing
3824 * the comparison on the boolean and on the result of converting
3825 * the node-set to a boolean using the boolean function is true.
3826 *
3827 * Returns 0 or 1 depending on the results of the test.
3828 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003829static int
Owen Taylor3473f882001-02-23 17:55:21 +00003830xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
3831 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
3832 if ((val == NULL) || (arg == NULL) ||
3833 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3834 return(0);
3835
3836 switch(val->type) {
3837 case XPATH_NUMBER:
3838 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
3839 case XPATH_NODESET:
3840 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003841 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00003842 case XPATH_STRING:
3843 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
3844 case XPATH_BOOLEAN:
3845 valuePush(ctxt, arg);
3846 xmlXPathBooleanFunction(ctxt, 1);
3847 valuePush(ctxt, val);
3848 return(xmlXPathCompareValues(ctxt, inf, strict));
3849 default:
3850 TODO
3851 return(0);
3852 }
3853 return(0);
3854}
3855
3856/**
3857 * xmlXPathEqualNodeSetString
3858 * @arg: the nodeset object argument
3859 * @str: the string to compare to.
3860 *
3861 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3862 * If one object to be compared is a node-set and the other is a string,
3863 * then the comparison will be true if and only if there is a node in
3864 * the node-set such that the result of performing the comparison on the
3865 * string-value of the node and the other string is true.
3866 *
3867 * Returns 0 or 1 depending on the results of the test.
3868 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003869static int
Daniel Veillardf06307e2001-07-03 10:35:50 +00003870xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str)
3871{
Owen Taylor3473f882001-02-23 17:55:21 +00003872 int i;
3873 xmlNodeSetPtr ns;
3874 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003875 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00003876
3877 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00003878 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3879 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00003880 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003881 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003882 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00003883 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00003884 if (ns->nodeNr <= 0) {
3885 if (hash == 0)
3886 return(1);
3887 return(0);
3888 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003889 for (i = 0; i < ns->nodeNr; i++) {
3890 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
3891 str2 = xmlNodeGetContent(ns->nodeTab[i]);
3892 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
3893 xmlFree(str2);
3894 return (1);
3895 }
3896 if (str2 != NULL)
3897 xmlFree(str2);
3898 }
Owen Taylor3473f882001-02-23 17:55:21 +00003899 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003900 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00003901}
3902
3903/**
3904 * xmlXPathEqualNodeSetFloat
3905 * @arg: the nodeset object argument
3906 * @f: the float to compare to
3907 *
3908 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3909 * If one object to be compared is a node-set and the other is a number,
3910 * then the comparison will be true if and only if there is a node in
3911 * the node-set such that the result of performing the comparison on the
3912 * number to be compared and on the result of converting the string-value
3913 * of that node to a number using the number function is true.
3914 *
3915 * Returns 0 or 1 depending on the results of the test.
3916 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003917static int
Owen Taylor3473f882001-02-23 17:55:21 +00003918xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) {
3919 char buf[100] = "";
3920
3921 if ((arg == NULL) ||
3922 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3923 return(0);
3924
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003925 xmlXPathFormatNumber(f, buf, sizeof(buf));
Owen Taylor3473f882001-02-23 17:55:21 +00003926 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
3927}
3928
3929
3930/**
3931 * xmlXPathEqualNodeSets
3932 * @arg1: first nodeset object argument
3933 * @arg2: second nodeset object argument
3934 *
3935 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
3936 * If both objects to be compared are node-sets, then the comparison
3937 * will be true if and only if there is a node in the first node-set and
3938 * a node in the second node-set such that the result of performing the
3939 * comparison on the string-values of the two nodes is true.
3940 *
3941 * (needless to say, this is a costly operation)
3942 *
3943 * Returns 0 or 1 depending on the results of the test.
3944 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003945static int
Owen Taylor3473f882001-02-23 17:55:21 +00003946xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3947 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003948 unsigned int *hashs1;
3949 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00003950 xmlChar **values1;
3951 xmlChar **values2;
3952 int ret = 0;
3953 xmlNodeSetPtr ns1;
3954 xmlNodeSetPtr ns2;
3955
3956 if ((arg1 == NULL) ||
3957 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
3958 return(0);
3959 if ((arg2 == NULL) ||
3960 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
3961 return(0);
3962
3963 ns1 = arg1->nodesetval;
3964 ns2 = arg2->nodesetval;
3965
Daniel Veillard911f49a2001-04-07 15:39:35 +00003966 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00003967 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003968 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00003969 return(0);
3970
3971 /*
3972 * check if there is a node pertaining to both sets
3973 */
3974 for (i = 0;i < ns1->nodeNr;i++)
3975 for (j = 0;j < ns2->nodeNr;j++)
3976 if (ns1->nodeTab[i] == ns2->nodeTab[j])
3977 return(1);
3978
3979 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
3980 if (values1 == NULL)
3981 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00003982 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
3983 if (hashs1 == NULL) {
3984 xmlFree(values1);
3985 return(0);
3986 }
Owen Taylor3473f882001-02-23 17:55:21 +00003987 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
3988 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
3989 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00003990 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00003991 xmlFree(values1);
3992 return(0);
3993 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003994 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
3995 if (hashs2 == NULL) {
3996 xmlFree(hashs1);
3997 xmlFree(values1);
3998 xmlFree(values2);
3999 return(0);
4000 }
Owen Taylor3473f882001-02-23 17:55:21 +00004001 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4002 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004003 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004004 for (j = 0;j < ns2->nodeNr;j++) {
4005 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004006 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
4007 if (hashs1[i] == hashs2[j]) {
4008 if (values1[i] == NULL)
4009 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4010 if (values2[j] == NULL)
4011 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
4012 ret = xmlStrEqual(values1[i], values2[j]);
4013 if (ret)
4014 break;
4015 }
Owen Taylor3473f882001-02-23 17:55:21 +00004016 }
4017 if (ret)
4018 break;
4019 }
4020 for (i = 0;i < ns1->nodeNr;i++)
4021 if (values1[i] != NULL)
4022 xmlFree(values1[i]);
4023 for (j = 0;j < ns2->nodeNr;j++)
4024 if (values2[j] != NULL)
4025 xmlFree(values2[j]);
4026 xmlFree(values1);
4027 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004028 xmlFree(hashs1);
4029 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004030 return(ret);
4031}
4032
4033/**
4034 * xmlXPathEqualValues:
4035 * @ctxt: the XPath Parser context
4036 *
4037 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4038 *
4039 * Returns 0 or 1 depending on the results of the test.
4040 */
4041int
4042xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4043 xmlXPathObjectPtr arg1, arg2;
4044 int ret = 0;
4045
4046 arg1 = valuePop(ctxt);
4047 if (arg1 == NULL)
4048 XP_ERROR0(XPATH_INVALID_OPERAND);
4049
4050 arg2 = valuePop(ctxt);
4051 if (arg2 == NULL) {
4052 xmlXPathFreeObject(arg1);
4053 XP_ERROR0(XPATH_INVALID_OPERAND);
4054 }
4055
4056 if (arg1 == arg2) {
4057#ifdef DEBUG_EXPR
4058 xmlGenericError(xmlGenericErrorContext,
4059 "Equal: by pointer\n");
4060#endif
4061 return(1);
4062 }
4063
4064 switch (arg1->type) {
4065 case XPATH_UNDEFINED:
4066#ifdef DEBUG_EXPR
4067 xmlGenericError(xmlGenericErrorContext,
4068 "Equal: undefined\n");
4069#endif
4070 break;
4071 case XPATH_XSLT_TREE:
4072 case XPATH_NODESET:
4073 switch (arg2->type) {
4074 case XPATH_UNDEFINED:
4075#ifdef DEBUG_EXPR
4076 xmlGenericError(xmlGenericErrorContext,
4077 "Equal: undefined\n");
4078#endif
4079 break;
4080 case XPATH_XSLT_TREE:
4081 case XPATH_NODESET:
4082 ret = xmlXPathEqualNodeSets(arg1, arg2);
4083 break;
4084 case XPATH_BOOLEAN:
4085 if ((arg1->nodesetval == NULL) ||
4086 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4087 else
4088 ret = 1;
4089 ret = (ret == arg2->boolval);
4090 break;
4091 case XPATH_NUMBER:
4092 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
4093 break;
4094 case XPATH_STRING:
4095 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
4096 break;
4097 case XPATH_USERS:
4098 case XPATH_POINT:
4099 case XPATH_RANGE:
4100 case XPATH_LOCATIONSET:
4101 TODO
4102 break;
4103 }
4104 break;
4105 case XPATH_BOOLEAN:
4106 switch (arg2->type) {
4107 case XPATH_UNDEFINED:
4108#ifdef DEBUG_EXPR
4109 xmlGenericError(xmlGenericErrorContext,
4110 "Equal: undefined\n");
4111#endif
4112 break;
4113 case XPATH_NODESET:
4114 case XPATH_XSLT_TREE:
4115 if ((arg2->nodesetval == NULL) ||
4116 (arg2->nodesetval->nodeNr == 0)) ret = 0;
4117 else
4118 ret = 1;
4119 break;
4120 case XPATH_BOOLEAN:
4121#ifdef DEBUG_EXPR
4122 xmlGenericError(xmlGenericErrorContext,
4123 "Equal: %d boolean %d \n",
4124 arg1->boolval, arg2->boolval);
4125#endif
4126 ret = (arg1->boolval == arg2->boolval);
4127 break;
4128 case XPATH_NUMBER:
4129 if (arg2->floatval) ret = 1;
4130 else ret = 0;
4131 ret = (arg1->boolval == ret);
4132 break;
4133 case XPATH_STRING:
4134 if ((arg2->stringval == NULL) ||
4135 (arg2->stringval[0] == 0)) ret = 0;
4136 else
4137 ret = 1;
4138 ret = (arg1->boolval == ret);
4139 break;
4140 case XPATH_USERS:
4141 case XPATH_POINT:
4142 case XPATH_RANGE:
4143 case XPATH_LOCATIONSET:
4144 TODO
4145 break;
4146 }
4147 break;
4148 case XPATH_NUMBER:
4149 switch (arg2->type) {
4150 case XPATH_UNDEFINED:
4151#ifdef DEBUG_EXPR
4152 xmlGenericError(xmlGenericErrorContext,
4153 "Equal: undefined\n");
4154#endif
4155 break;
4156 case XPATH_NODESET:
4157 case XPATH_XSLT_TREE:
4158 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
4159 break;
4160 case XPATH_BOOLEAN:
4161 if (arg1->floatval) ret = 1;
4162 else ret = 0;
4163 ret = (arg2->boolval == ret);
4164 break;
4165 case XPATH_STRING:
4166 valuePush(ctxt, arg2);
4167 xmlXPathNumberFunction(ctxt, 1);
4168 arg2 = valuePop(ctxt);
4169 /* no break on purpose */
4170 case XPATH_NUMBER:
4171 ret = (arg1->floatval == arg2->floatval);
4172 break;
4173 case XPATH_USERS:
4174 case XPATH_POINT:
4175 case XPATH_RANGE:
4176 case XPATH_LOCATIONSET:
4177 TODO
4178 break;
4179 }
4180 break;
4181 case XPATH_STRING:
4182 switch (arg2->type) {
4183 case XPATH_UNDEFINED:
4184#ifdef DEBUG_EXPR
4185 xmlGenericError(xmlGenericErrorContext,
4186 "Equal: undefined\n");
4187#endif
4188 break;
4189 case XPATH_NODESET:
4190 case XPATH_XSLT_TREE:
4191 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
4192 break;
4193 case XPATH_BOOLEAN:
4194 if ((arg1->stringval == NULL) ||
4195 (arg1->stringval[0] == 0)) ret = 0;
4196 else
4197 ret = 1;
4198 ret = (arg2->boolval == ret);
4199 break;
4200 case XPATH_STRING:
4201 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4202 break;
4203 case XPATH_NUMBER:
4204 valuePush(ctxt, arg1);
4205 xmlXPathNumberFunction(ctxt, 1);
4206 arg1 = valuePop(ctxt);
4207 ret = (arg1->floatval == arg2->floatval);
4208 break;
4209 case XPATH_USERS:
4210 case XPATH_POINT:
4211 case XPATH_RANGE:
4212 case XPATH_LOCATIONSET:
4213 TODO
4214 break;
4215 }
4216 break;
4217 case XPATH_USERS:
4218 case XPATH_POINT:
4219 case XPATH_RANGE:
4220 case XPATH_LOCATIONSET:
4221 TODO
4222 break;
4223 }
4224 xmlXPathFreeObject(arg1);
4225 xmlXPathFreeObject(arg2);
4226 return(ret);
4227}
4228
4229
4230/**
4231 * xmlXPathCompareValues:
4232 * @ctxt: the XPath Parser context
4233 * @inf: less than (1) or greater than (0)
4234 * @strict: is the comparison strict
4235 *
4236 * Implement the compare operation on XPath objects:
4237 * @arg1 < @arg2 (1, 1, ...
4238 * @arg1 <= @arg2 (1, 0, ...
4239 * @arg1 > @arg2 (0, 1, ...
4240 * @arg1 >= @arg2 (0, 0, ...
4241 *
4242 * When neither object to be compared is a node-set and the operator is
4243 * <=, <, >=, >, then the objects are compared by converted both objects
4244 * to numbers and comparing the numbers according to IEEE 754. The <
4245 * comparison will be true if and only if the first number is less than the
4246 * second number. The <= comparison will be true if and only if the first
4247 * number is less than or equal to the second number. The > comparison
4248 * will be true if and only if the first number is greater than the second
4249 * number. The >= comparison will be true if and only if the first number
4250 * is greater than or equal to the second number.
4251 *
4252 * Returns 1 if the comparaison succeeded, 0 if it failed
4253 */
4254int
4255xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
4256 int ret = 0;
4257 xmlXPathObjectPtr arg1, arg2;
4258
4259 arg2 = valuePop(ctxt);
4260 if (arg2 == NULL) {
4261 XP_ERROR0(XPATH_INVALID_OPERAND);
4262 }
4263
4264 arg1 = valuePop(ctxt);
4265 if (arg1 == NULL) {
4266 xmlXPathFreeObject(arg2);
4267 XP_ERROR0(XPATH_INVALID_OPERAND);
4268 }
4269
4270 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
4271 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004272 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004273 } else {
4274 if (arg1->type == XPATH_NODESET) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004275 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4276 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004277 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004278 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4279 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004280 }
4281 }
4282 return(ret);
4283 }
4284
4285 if (arg1->type != XPATH_NUMBER) {
4286 valuePush(ctxt, arg1);
4287 xmlXPathNumberFunction(ctxt, 1);
4288 arg1 = valuePop(ctxt);
4289 }
4290 if (arg1->type != XPATH_NUMBER) {
4291 xmlXPathFreeObject(arg1);
4292 xmlXPathFreeObject(arg2);
4293 XP_ERROR0(XPATH_INVALID_OPERAND);
4294 }
4295 if (arg2->type != XPATH_NUMBER) {
4296 valuePush(ctxt, arg2);
4297 xmlXPathNumberFunction(ctxt, 1);
4298 arg2 = valuePop(ctxt);
4299 }
4300 if (arg2->type != XPATH_NUMBER) {
4301 xmlXPathFreeObject(arg1);
4302 xmlXPathFreeObject(arg2);
4303 XP_ERROR0(XPATH_INVALID_OPERAND);
4304 }
4305 /*
4306 * Add tests for infinity and nan
4307 * => feedback on 3.4 for Inf and NaN
4308 */
4309 if (inf && strict)
4310 ret = (arg1->floatval < arg2->floatval);
4311 else if (inf && !strict)
4312 ret = (arg1->floatval <= arg2->floatval);
4313 else if (!inf && strict)
4314 ret = (arg1->floatval > arg2->floatval);
4315 else if (!inf && !strict)
4316 ret = (arg1->floatval >= arg2->floatval);
4317 xmlXPathFreeObject(arg1);
4318 xmlXPathFreeObject(arg2);
4319 return(ret);
4320}
4321
4322/**
4323 * xmlXPathValueFlipSign:
4324 * @ctxt: the XPath Parser context
4325 *
4326 * Implement the unary - operation on an XPath object
4327 * The numeric operators convert their operands to numbers as if
4328 * by calling the number function.
4329 */
4330void
4331xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004332 CAST_TO_NUMBER;
4333 CHECK_TYPE(XPATH_NUMBER);
4334 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00004335}
4336
4337/**
4338 * xmlXPathAddValues:
4339 * @ctxt: the XPath Parser context
4340 *
4341 * Implement the add operation on XPath objects:
4342 * The numeric operators convert their operands to numbers as if
4343 * by calling the number function.
4344 */
4345void
4346xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
4347 xmlXPathObjectPtr arg;
4348 double val;
4349
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004350 arg = valuePop(ctxt);
4351 if (arg == NULL)
4352 XP_ERROR(XPATH_INVALID_OPERAND);
4353 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004354 xmlXPathFreeObject(arg);
4355
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004356 CAST_TO_NUMBER;
4357 CHECK_TYPE(XPATH_NUMBER);
4358 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00004359}
4360
4361/**
4362 * xmlXPathSubValues:
4363 * @ctxt: the XPath Parser context
4364 *
4365 * Implement the substraction operation on XPath objects:
4366 * The numeric operators convert their operands to numbers as if
4367 * by calling the number function.
4368 */
4369void
4370xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
4371 xmlXPathObjectPtr arg;
4372 double val;
4373
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004374 arg = valuePop(ctxt);
4375 if (arg == NULL)
4376 XP_ERROR(XPATH_INVALID_OPERAND);
4377 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004378 xmlXPathFreeObject(arg);
4379
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004380 CAST_TO_NUMBER;
4381 CHECK_TYPE(XPATH_NUMBER);
4382 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004383}
4384
4385/**
4386 * xmlXPathMultValues:
4387 * @ctxt: the XPath Parser context
4388 *
4389 * Implement the multiply operation on XPath objects:
4390 * The numeric operators convert their operands to numbers as if
4391 * by calling the number function.
4392 */
4393void
4394xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
4395 xmlXPathObjectPtr arg;
4396 double val;
4397
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004398 arg = valuePop(ctxt);
4399 if (arg == NULL)
4400 XP_ERROR(XPATH_INVALID_OPERAND);
4401 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004402 xmlXPathFreeObject(arg);
4403
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004404 CAST_TO_NUMBER;
4405 CHECK_TYPE(XPATH_NUMBER);
4406 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004407}
4408
4409/**
4410 * xmlXPathDivValues:
4411 * @ctxt: the XPath Parser context
4412 *
4413 * Implement the div operation on XPath objects @arg1 / @arg2:
4414 * The numeric operators convert their operands to numbers as if
4415 * by calling the number function.
4416 */
4417void
4418xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
4419 xmlXPathObjectPtr arg;
4420 double val;
4421
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004422 arg = valuePop(ctxt);
4423 if (arg == NULL)
4424 XP_ERROR(XPATH_INVALID_OPERAND);
4425 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004426 xmlXPathFreeObject(arg);
4427
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004428 CAST_TO_NUMBER;
4429 CHECK_TYPE(XPATH_NUMBER);
4430 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004431}
4432
4433/**
4434 * xmlXPathModValues:
4435 * @ctxt: the XPath Parser context
4436 *
4437 * Implement the mod operation on XPath objects: @arg1 / @arg2
4438 * The numeric operators convert their operands to numbers as if
4439 * by calling the number function.
4440 */
4441void
4442xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
4443 xmlXPathObjectPtr arg;
4444 int arg1, arg2;
4445
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004446 arg = valuePop(ctxt);
4447 if (arg == NULL)
4448 XP_ERROR(XPATH_INVALID_OPERAND);
4449 arg2 = (int) xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004450 xmlXPathFreeObject(arg);
4451
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004452 CAST_TO_NUMBER;
4453 CHECK_TYPE(XPATH_NUMBER);
4454 arg1 = (int) ctxt->value->floatval;
4455 ctxt->value->floatval = arg1 % arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00004456}
4457
4458/************************************************************************
4459 * *
4460 * The traversal functions *
4461 * *
4462 ************************************************************************/
4463
Owen Taylor3473f882001-02-23 17:55:21 +00004464/*
4465 * A traversal function enumerates nodes along an axis.
4466 * Initially it must be called with NULL, and it indicates
4467 * termination on the axis by returning NULL.
4468 */
4469typedef xmlNodePtr (*xmlXPathTraversalFunction)
4470 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
4471
4472/**
4473 * xmlXPathNextSelf:
4474 * @ctxt: the XPath Parser context
4475 * @cur: the current node in the traversal
4476 *
4477 * Traversal function for the "self" direction
4478 * The self axis contains just the context node itself
4479 *
4480 * Returns the next element following that axis
4481 */
4482xmlNodePtr
4483xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4484 if (cur == NULL)
4485 return(ctxt->context->node);
4486 return(NULL);
4487}
4488
4489/**
4490 * xmlXPathNextChild:
4491 * @ctxt: the XPath Parser context
4492 * @cur: the current node in the traversal
4493 *
4494 * Traversal function for the "child" direction
4495 * The child axis contains the children of the context node in document order.
4496 *
4497 * Returns the next element following that axis
4498 */
4499xmlNodePtr
4500xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4501 if (cur == NULL) {
4502 if (ctxt->context->node == NULL) return(NULL);
4503 switch (ctxt->context->node->type) {
4504 case XML_ELEMENT_NODE:
4505 case XML_TEXT_NODE:
4506 case XML_CDATA_SECTION_NODE:
4507 case XML_ENTITY_REF_NODE:
4508 case XML_ENTITY_NODE:
4509 case XML_PI_NODE:
4510 case XML_COMMENT_NODE:
4511 case XML_NOTATION_NODE:
4512 case XML_DTD_NODE:
4513 return(ctxt->context->node->children);
4514 case XML_DOCUMENT_NODE:
4515 case XML_DOCUMENT_TYPE_NODE:
4516 case XML_DOCUMENT_FRAG_NODE:
4517 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004518#ifdef LIBXML_DOCB_ENABLED
4519 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004520#endif
4521 return(((xmlDocPtr) ctxt->context->node)->children);
4522 case XML_ELEMENT_DECL:
4523 case XML_ATTRIBUTE_DECL:
4524 case XML_ENTITY_DECL:
4525 case XML_ATTRIBUTE_NODE:
4526 case XML_NAMESPACE_DECL:
4527 case XML_XINCLUDE_START:
4528 case XML_XINCLUDE_END:
4529 return(NULL);
4530 }
4531 return(NULL);
4532 }
4533 if ((cur->type == XML_DOCUMENT_NODE) ||
4534 (cur->type == XML_HTML_DOCUMENT_NODE))
4535 return(NULL);
4536 return(cur->next);
4537}
4538
4539/**
4540 * xmlXPathNextDescendant:
4541 * @ctxt: the XPath Parser context
4542 * @cur: the current node in the traversal
4543 *
4544 * Traversal function for the "descendant" direction
4545 * the descendant axis contains the descendants of the context node in document
4546 * order; a descendant is a child or a child of a child and so on.
4547 *
4548 * Returns the next element following that axis
4549 */
4550xmlNodePtr
4551xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4552 if (cur == NULL) {
4553 if (ctxt->context->node == NULL)
4554 return(NULL);
4555 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4556 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4557 return(NULL);
4558
4559 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
4560 return(ctxt->context->doc->children);
4561 return(ctxt->context->node->children);
4562 }
4563
4564 if (cur->children != NULL)
4565 {
4566 if (cur->children->type != XML_ENTITY_DECL)
4567 return(cur->children);
4568 }
4569 if (cur->next != NULL) return(cur->next);
4570
4571 do {
4572 cur = cur->parent;
4573 if (cur == NULL) return(NULL);
4574 if (cur == ctxt->context->node) return(NULL);
4575 if (cur->next != NULL) {
4576 cur = cur->next;
4577 return(cur);
4578 }
4579 } while (cur != NULL);
4580 return(cur);
4581}
4582
4583/**
4584 * xmlXPathNextDescendantOrSelf:
4585 * @ctxt: the XPath Parser context
4586 * @cur: the current node in the traversal
4587 *
4588 * Traversal function for the "descendant-or-self" direction
4589 * the descendant-or-self axis contains the context node and the descendants
4590 * of the context node in document order; thus the context node is the first
4591 * node on the axis, and the first child of the context node is the second node
4592 * on the axis
4593 *
4594 * Returns the next element following that axis
4595 */
4596xmlNodePtr
4597xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4598 if (cur == NULL) {
4599 if (ctxt->context->node == NULL)
4600 return(NULL);
4601 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4602 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4603 return(NULL);
4604 return(ctxt->context->node);
4605 }
4606
4607 return(xmlXPathNextDescendant(ctxt, cur));
4608}
4609
4610/**
4611 * xmlXPathNextParent:
4612 * @ctxt: the XPath Parser context
4613 * @cur: the current node in the traversal
4614 *
4615 * Traversal function for the "parent" direction
4616 * The parent axis contains the parent of the context node, if there is one.
4617 *
4618 * Returns the next element following that axis
4619 */
4620xmlNodePtr
4621xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4622 /*
4623 * the parent of an attribute or namespace node is the element
4624 * to which the attribute or namespace node is attached
4625 * Namespace handling !!!
4626 */
4627 if (cur == NULL) {
4628 if (ctxt->context->node == NULL) return(NULL);
4629 switch (ctxt->context->node->type) {
4630 case XML_ELEMENT_NODE:
4631 case XML_TEXT_NODE:
4632 case XML_CDATA_SECTION_NODE:
4633 case XML_ENTITY_REF_NODE:
4634 case XML_ENTITY_NODE:
4635 case XML_PI_NODE:
4636 case XML_COMMENT_NODE:
4637 case XML_NOTATION_NODE:
4638 case XML_DTD_NODE:
4639 case XML_ELEMENT_DECL:
4640 case XML_ATTRIBUTE_DECL:
4641 case XML_XINCLUDE_START:
4642 case XML_XINCLUDE_END:
4643 case XML_ENTITY_DECL:
4644 if (ctxt->context->node->parent == NULL)
4645 return((xmlNodePtr) ctxt->context->doc);
4646 return(ctxt->context->node->parent);
4647 case XML_ATTRIBUTE_NODE: {
4648 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4649
4650 return(att->parent);
4651 }
4652 case XML_DOCUMENT_NODE:
4653 case XML_DOCUMENT_TYPE_NODE:
4654 case XML_DOCUMENT_FRAG_NODE:
4655 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004656#ifdef LIBXML_DOCB_ENABLED
4657 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004658#endif
4659 return(NULL);
4660 case XML_NAMESPACE_DECL:
4661 /*
4662 * TODO !!! may require extending struct _xmlNs with
4663 * parent field
4664 * C.f. Infoset case...
4665 */
4666 return(NULL);
4667 }
4668 }
4669 return(NULL);
4670}
4671
4672/**
4673 * xmlXPathNextAncestor:
4674 * @ctxt: the XPath Parser context
4675 * @cur: the current node in the traversal
4676 *
4677 * Traversal function for the "ancestor" direction
4678 * the ancestor axis contains the ancestors of the context node; the ancestors
4679 * of the context node consist of the parent of context node and the parent's
4680 * parent and so on; the nodes are ordered in reverse document order; thus the
4681 * parent is the first node on the axis, and the parent's parent is the second
4682 * node on the axis
4683 *
4684 * Returns the next element following that axis
4685 */
4686xmlNodePtr
4687xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4688 /*
4689 * the parent of an attribute or namespace node is the element
4690 * to which the attribute or namespace node is attached
4691 * !!!!!!!!!!!!!
4692 */
4693 if (cur == NULL) {
4694 if (ctxt->context->node == NULL) return(NULL);
4695 switch (ctxt->context->node->type) {
4696 case XML_ELEMENT_NODE:
4697 case XML_TEXT_NODE:
4698 case XML_CDATA_SECTION_NODE:
4699 case XML_ENTITY_REF_NODE:
4700 case XML_ENTITY_NODE:
4701 case XML_PI_NODE:
4702 case XML_COMMENT_NODE:
4703 case XML_DTD_NODE:
4704 case XML_ELEMENT_DECL:
4705 case XML_ATTRIBUTE_DECL:
4706 case XML_ENTITY_DECL:
4707 case XML_NOTATION_NODE:
4708 case XML_XINCLUDE_START:
4709 case XML_XINCLUDE_END:
4710 if (ctxt->context->node->parent == NULL)
4711 return((xmlNodePtr) ctxt->context->doc);
4712 return(ctxt->context->node->parent);
4713 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004714 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00004715
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004716 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00004717 }
4718 case XML_DOCUMENT_NODE:
4719 case XML_DOCUMENT_TYPE_NODE:
4720 case XML_DOCUMENT_FRAG_NODE:
4721 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004722#ifdef LIBXML_DOCB_ENABLED
4723 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004724#endif
4725 return(NULL);
4726 case XML_NAMESPACE_DECL:
4727 /*
4728 * TODO !!! may require extending struct _xmlNs with
4729 * parent field
4730 * C.f. Infoset case...
4731 */
4732 return(NULL);
4733 }
4734 return(NULL);
4735 }
4736 if (cur == ctxt->context->doc->children)
4737 return((xmlNodePtr) ctxt->context->doc);
4738 if (cur == (xmlNodePtr) ctxt->context->doc)
4739 return(NULL);
4740 switch (cur->type) {
4741 case XML_ELEMENT_NODE:
4742 case XML_TEXT_NODE:
4743 case XML_CDATA_SECTION_NODE:
4744 case XML_ENTITY_REF_NODE:
4745 case XML_ENTITY_NODE:
4746 case XML_PI_NODE:
4747 case XML_COMMENT_NODE:
4748 case XML_NOTATION_NODE:
4749 case XML_DTD_NODE:
4750 case XML_ELEMENT_DECL:
4751 case XML_ATTRIBUTE_DECL:
4752 case XML_ENTITY_DECL:
4753 case XML_XINCLUDE_START:
4754 case XML_XINCLUDE_END:
4755 return(cur->parent);
4756 case XML_ATTRIBUTE_NODE: {
4757 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4758
4759 return(att->parent);
4760 }
4761 case XML_DOCUMENT_NODE:
4762 case XML_DOCUMENT_TYPE_NODE:
4763 case XML_DOCUMENT_FRAG_NODE:
4764 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004765#ifdef LIBXML_DOCB_ENABLED
4766 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004767#endif
4768 return(NULL);
4769 case XML_NAMESPACE_DECL:
4770 /*
4771 * TODO !!! may require extending struct _xmlNs with
4772 * parent field
4773 * C.f. Infoset case...
4774 */
4775 return(NULL);
4776 }
4777 return(NULL);
4778}
4779
4780/**
4781 * xmlXPathNextAncestorOrSelf:
4782 * @ctxt: the XPath Parser context
4783 * @cur: the current node in the traversal
4784 *
4785 * Traversal function for the "ancestor-or-self" direction
4786 * he ancestor-or-self axis contains the context node and ancestors of
4787 * the context node in reverse document order; thus the context node is
4788 * the first node on the axis, and the context node's parent the second;
4789 * parent here is defined the same as with the parent axis.
4790 *
4791 * Returns the next element following that axis
4792 */
4793xmlNodePtr
4794xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4795 if (cur == NULL)
4796 return(ctxt->context->node);
4797 return(xmlXPathNextAncestor(ctxt, cur));
4798}
4799
4800/**
4801 * xmlXPathNextFollowingSibling:
4802 * @ctxt: the XPath Parser context
4803 * @cur: the current node in the traversal
4804 *
4805 * Traversal function for the "following-sibling" direction
4806 * The following-sibling axis contains the following siblings of the context
4807 * node in document order.
4808 *
4809 * Returns the next element following that axis
4810 */
4811xmlNodePtr
4812xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4813 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4814 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4815 return(NULL);
4816 if (cur == (xmlNodePtr) ctxt->context->doc)
4817 return(NULL);
4818 if (cur == NULL)
4819 return(ctxt->context->node->next);
4820 return(cur->next);
4821}
4822
4823/**
4824 * xmlXPathNextPrecedingSibling:
4825 * @ctxt: the XPath Parser context
4826 * @cur: the current node in the traversal
4827 *
4828 * Traversal function for the "preceding-sibling" direction
4829 * The preceding-sibling axis contains the preceding siblings of the context
4830 * node in reverse document order; the first preceding sibling is first on the
4831 * axis; the sibling preceding that node is the second on the axis and so on.
4832 *
4833 * Returns the next element following that axis
4834 */
4835xmlNodePtr
4836xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4837 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4838 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4839 return(NULL);
4840 if (cur == (xmlNodePtr) ctxt->context->doc)
4841 return(NULL);
4842 if (cur == NULL)
4843 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004844 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
4845 cur = cur->prev;
4846 if (cur == NULL)
4847 return(ctxt->context->node->prev);
4848 }
Owen Taylor3473f882001-02-23 17:55:21 +00004849 return(cur->prev);
4850}
4851
4852/**
4853 * xmlXPathNextFollowing:
4854 * @ctxt: the XPath Parser context
4855 * @cur: the current node in the traversal
4856 *
4857 * Traversal function for the "following" direction
4858 * The following axis contains all nodes in the same document as the context
4859 * node that are after the context node in document order, excluding any
4860 * descendants and excluding attribute nodes and namespace nodes; the nodes
4861 * are ordered in document order
4862 *
4863 * Returns the next element following that axis
4864 */
4865xmlNodePtr
4866xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4867 if (cur != NULL && cur->children != NULL)
4868 return cur->children ;
4869 if (cur == NULL) cur = ctxt->context->node;
4870 if (cur == NULL) return(NULL) ; /* ERROR */
4871 if (cur->next != NULL) return(cur->next) ;
4872 do {
4873 cur = cur->parent;
4874 if (cur == NULL) return(NULL);
4875 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
4876 if (cur->next != NULL) return(cur->next);
4877 } while (cur != NULL);
4878 return(cur);
4879}
4880
4881/*
4882 * xmlXPathIsAncestor:
4883 * @ancestor: the ancestor node
4884 * @node: the current node
4885 *
4886 * Check that @ancestor is a @node's ancestor
4887 *
4888 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
4889 */
4890static int
4891xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
4892 if ((ancestor == NULL) || (node == NULL)) return(0);
4893 /* nodes need to be in the same document */
4894 if (ancestor->doc != node->doc) return(0);
4895 /* avoid searching if ancestor or node is the root node */
4896 if (ancestor == (xmlNodePtr) node->doc) return(1);
4897 if (node == (xmlNodePtr) ancestor->doc) return(0);
4898 while (node->parent != NULL) {
4899 if (node->parent == ancestor)
4900 return(1);
4901 node = node->parent;
4902 }
4903 return(0);
4904}
4905
4906/**
4907 * xmlXPathNextPreceding:
4908 * @ctxt: the XPath Parser context
4909 * @cur: the current node in the traversal
4910 *
4911 * Traversal function for the "preceding" direction
4912 * the preceding axis contains all nodes in the same document as the context
4913 * node that are before the context node in document order, excluding any
4914 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4915 * ordered in reverse document order
4916 *
4917 * Returns the next element following that axis
4918 */
4919xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00004920xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
4921{
Owen Taylor3473f882001-02-23 17:55:21 +00004922 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004923 cur = ctxt->context->node;
4924 if (cur == NULL)
4925 return (NULL);
4926 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
4927 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00004928 do {
4929 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004930 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
4931 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004932 }
4933
4934 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004935 if (cur == NULL)
4936 return (NULL);
4937 if (cur == ctxt->context->doc->children)
4938 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004939 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00004940 return (cur);
4941}
4942
4943/**
4944 * xmlXPathNextPrecedingInternal:
4945 * @ctxt: the XPath Parser context
4946 * @cur: the current node in the traversal
4947 *
4948 * Traversal function for the "preceding" direction
4949 * the preceding axis contains all nodes in the same document as the context
4950 * node that are before the context node in document order, excluding any
4951 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4952 * ordered in reverse document order
4953 * This is a faster implementation but internal only since it requires a
4954 * state kept in the parser context: ctxt->ancestor.
4955 *
4956 * Returns the next element following that axis
4957 */
4958static xmlNodePtr
4959xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
4960 xmlNodePtr cur)
4961{
4962 if (cur == NULL) {
4963 cur = ctxt->context->node;
4964 if (cur == NULL)
4965 return (NULL);
4966 ctxt->ancestor = cur->parent;
4967 }
4968 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
4969 cur = cur->prev;
4970 while (cur->prev == NULL) {
4971 cur = cur->parent;
4972 if (cur == NULL)
4973 return (NULL);
4974 if (cur == ctxt->context->doc->children)
4975 return (NULL);
4976 if (cur != ctxt->ancestor)
4977 return (cur);
4978 ctxt->ancestor = cur->parent;
4979 }
4980 cur = cur->prev;
4981 while (cur->last != NULL)
4982 cur = cur->last;
4983 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004984}
4985
4986/**
4987 * xmlXPathNextNamespace:
4988 * @ctxt: the XPath Parser context
4989 * @cur: the current attribute in the traversal
4990 *
4991 * Traversal function for the "namespace" direction
4992 * the namespace axis contains the namespace nodes of the context node;
4993 * the order of nodes on this axis is implementation-defined; the axis will
4994 * be empty unless the context node is an element
4995 *
4996 * Returns the next element following that axis
4997 */
4998xmlNodePtr
4999xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5000 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
5001 if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
5002 if (ctxt->context->namespaces != NULL)
5003 xmlFree(ctxt->context->namespaces);
5004 ctxt->context->namespaces =
5005 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
5006 if (ctxt->context->namespaces == NULL) return(NULL);
5007 ctxt->context->nsNr = 0;
5008 }
5009 return((xmlNodePtr)ctxt->context->namespaces[ctxt->context->nsNr++]);
5010}
5011
5012/**
5013 * xmlXPathNextAttribute:
5014 * @ctxt: the XPath Parser context
5015 * @cur: the current attribute in the traversal
5016 *
5017 * Traversal function for the "attribute" direction
5018 * TODO: support DTD inherited default attributes
5019 *
5020 * Returns the next element following that axis
5021 */
5022xmlNodePtr
5023xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005024 if (ctxt->context->node == NULL)
5025 return(NULL);
5026 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5027 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005028 if (cur == NULL) {
5029 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5030 return(NULL);
5031 return((xmlNodePtr)ctxt->context->node->properties);
5032 }
5033 return((xmlNodePtr)cur->next);
5034}
5035
5036/************************************************************************
5037 * *
5038 * NodeTest Functions *
5039 * *
5040 ************************************************************************/
5041
Owen Taylor3473f882001-02-23 17:55:21 +00005042#define IS_FUNCTION 200
5043
Owen Taylor3473f882001-02-23 17:55:21 +00005044
5045/************************************************************************
5046 * *
5047 * Implicit tree core function library *
5048 * *
5049 ************************************************************************/
5050
5051/**
5052 * xmlXPathRoot:
5053 * @ctxt: the XPath Parser context
5054 *
5055 * Initialize the context to the root of the document
5056 */
5057void
5058xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5059 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5060 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5061}
5062
5063/************************************************************************
5064 * *
5065 * The explicit core function library *
5066 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5067 * *
5068 ************************************************************************/
5069
5070
5071/**
5072 * xmlXPathLastFunction:
5073 * @ctxt: the XPath Parser context
5074 * @nargs: the number of arguments
5075 *
5076 * Implement the last() XPath function
5077 * number last()
5078 * The last function returns the number of nodes in the context node list.
5079 */
5080void
5081xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5082 CHECK_ARITY(0);
5083 if (ctxt->context->contextSize >= 0) {
5084 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5085#ifdef DEBUG_EXPR
5086 xmlGenericError(xmlGenericErrorContext,
5087 "last() : %d\n", ctxt->context->contextSize);
5088#endif
5089 } else {
5090 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5091 }
5092}
5093
5094/**
5095 * xmlXPathPositionFunction:
5096 * @ctxt: the XPath Parser context
5097 * @nargs: the number of arguments
5098 *
5099 * Implement the position() XPath function
5100 * number position()
5101 * The position function returns the position of the context node in the
5102 * context node list. The first position is 1, and so the last positionr
5103 * will be equal to last().
5104 */
5105void
5106xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5107 CHECK_ARITY(0);
5108 if (ctxt->context->proximityPosition >= 0) {
5109 valuePush(ctxt,
5110 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5111#ifdef DEBUG_EXPR
5112 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5113 ctxt->context->proximityPosition);
5114#endif
5115 } else {
5116 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5117 }
5118}
5119
5120/**
5121 * xmlXPathCountFunction:
5122 * @ctxt: the XPath Parser context
5123 * @nargs: the number of arguments
5124 *
5125 * Implement the count() XPath function
5126 * number count(node-set)
5127 */
5128void
5129xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5130 xmlXPathObjectPtr cur;
5131
5132 CHECK_ARITY(1);
5133 if ((ctxt->value == NULL) ||
5134 ((ctxt->value->type != XPATH_NODESET) &&
5135 (ctxt->value->type != XPATH_XSLT_TREE)))
5136 XP_ERROR(XPATH_INVALID_TYPE);
5137 cur = valuePop(ctxt);
5138
Daniel Veillard911f49a2001-04-07 15:39:35 +00005139 if ((cur == NULL) || (cur->nodesetval == NULL))
5140 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5141 else
5142 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Owen Taylor3473f882001-02-23 17:55:21 +00005143 xmlXPathFreeObject(cur);
5144}
5145
5146/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005147 * xmlXPathGetElementsByIds:
5148 * @doc: the document
5149 * @ids: a whitespace separated list of IDs
5150 *
5151 * Selects elements by their unique ID.
5152 *
5153 * Returns a node-set of selected elements.
5154 */
5155static xmlNodeSetPtr
5156xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5157 xmlNodeSetPtr ret;
5158 const xmlChar *cur = ids;
5159 xmlChar *ID;
5160 xmlAttrPtr attr;
5161 xmlNodePtr elem = NULL;
5162
5163 ret = xmlXPathNodeSetCreate(NULL);
5164
5165 while (IS_BLANK(*cur)) cur++;
5166 while (*cur != 0) {
5167 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
5168 (*cur == '.') || (*cur == '-') ||
5169 (*cur == '_') || (*cur == ':') ||
5170 (IS_COMBINING(*cur)) ||
5171 (IS_EXTENDER(*cur)))
5172 cur++;
5173
5174 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
5175
5176 ID = xmlStrndup(ids, cur - ids);
5177 attr = xmlGetID(doc, ID);
5178 if (attr != NULL) {
5179 elem = attr->parent;
5180 xmlXPathNodeSetAdd(ret, elem);
5181 }
5182 if (ID != NULL)
5183 xmlFree(ID);
5184
5185 while (IS_BLANK(*cur)) cur++;
5186 ids = cur;
5187 }
5188 return(ret);
5189}
5190
5191/**
Owen Taylor3473f882001-02-23 17:55:21 +00005192 * xmlXPathIdFunction:
5193 * @ctxt: the XPath Parser context
5194 * @nargs: the number of arguments
5195 *
5196 * Implement the id() XPath function
5197 * node-set id(object)
5198 * The id function selects elements by their unique ID
5199 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5200 * then the result is the union of the result of applying id to the
5201 * string value of each of the nodes in the argument node-set. When the
5202 * argument to id is of any other type, the argument is converted to a
5203 * string as if by a call to the string function; the string is split
5204 * into a whitespace-separated list of tokens (whitespace is any sequence
5205 * of characters matching the production S); the result is a node-set
5206 * containing the elements in the same document as the context node that
5207 * have a unique ID equal to any of the tokens in the list.
5208 */
5209void
5210xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005211 xmlChar *tokens;
5212 xmlNodeSetPtr ret;
5213 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00005214
5215 CHECK_ARITY(1);
5216 obj = valuePop(ctxt);
5217 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
5218 if (obj->type == XPATH_NODESET) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005219 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00005220 int i;
5221
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005222 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005223
Daniel Veillard911f49a2001-04-07 15:39:35 +00005224 if (obj->nodesetval != NULL) {
5225 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005226 tokens =
5227 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
5228 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
5229 ret = xmlXPathNodeSetMerge(ret, ns);
5230 xmlXPathFreeNodeSet(ns);
5231 if (tokens != NULL)
5232 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00005233 }
Owen Taylor3473f882001-02-23 17:55:21 +00005234 }
5235
5236 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005237 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005238 return;
5239 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005240 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00005241
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005242 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
5243 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005244
Owen Taylor3473f882001-02-23 17:55:21 +00005245 xmlXPathFreeObject(obj);
5246 return;
5247}
5248
5249/**
5250 * xmlXPathLocalNameFunction:
5251 * @ctxt: the XPath Parser context
5252 * @nargs: the number of arguments
5253 *
5254 * Implement the local-name() XPath function
5255 * string local-name(node-set?)
5256 * The local-name function returns a string containing the local part
5257 * of the name of the node in the argument node-set that is first in
5258 * document order. If the node-set is empty or the first node has no
5259 * name, an empty string is returned. If the argument is omitted it
5260 * defaults to the context node.
5261 */
5262void
5263xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5264 xmlXPathObjectPtr cur;
5265
5266 if (nargs == 0) {
5267 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5268 nargs = 1;
5269 }
5270
5271 CHECK_ARITY(1);
5272 if ((ctxt->value == NULL) ||
5273 ((ctxt->value->type != XPATH_NODESET) &&
5274 (ctxt->value->type != XPATH_XSLT_TREE)))
5275 XP_ERROR(XPATH_INVALID_TYPE);
5276 cur = valuePop(ctxt);
5277
Daniel Veillard911f49a2001-04-07 15:39:35 +00005278 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005279 valuePush(ctxt, xmlXPathNewCString(""));
5280 } else {
5281 int i = 0; /* Should be first in document order !!!!! */
5282 switch (cur->nodesetval->nodeTab[i]->type) {
5283 case XML_ELEMENT_NODE:
5284 case XML_ATTRIBUTE_NODE:
5285 case XML_PI_NODE:
5286 valuePush(ctxt,
5287 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
5288 break;
5289 case XML_NAMESPACE_DECL:
5290 valuePush(ctxt, xmlXPathNewString(
5291 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
5292 break;
5293 default:
5294 valuePush(ctxt, xmlXPathNewCString(""));
5295 }
5296 }
5297 xmlXPathFreeObject(cur);
5298}
5299
5300/**
5301 * xmlXPathNamespaceURIFunction:
5302 * @ctxt: the XPath Parser context
5303 * @nargs: the number of arguments
5304 *
5305 * Implement the namespace-uri() XPath function
5306 * string namespace-uri(node-set?)
5307 * The namespace-uri function returns a string containing the
5308 * namespace URI of the expanded name of the node in the argument
5309 * node-set that is first in document order. If the node-set is empty,
5310 * the first node has no name, or the expanded name has no namespace
5311 * URI, an empty string is returned. If the argument is omitted it
5312 * defaults to the context node.
5313 */
5314void
5315xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5316 xmlXPathObjectPtr cur;
5317
5318 if (nargs == 0) {
5319 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5320 nargs = 1;
5321 }
5322 CHECK_ARITY(1);
5323 if ((ctxt->value == NULL) ||
5324 ((ctxt->value->type != XPATH_NODESET) &&
5325 (ctxt->value->type != XPATH_XSLT_TREE)))
5326 XP_ERROR(XPATH_INVALID_TYPE);
5327 cur = valuePop(ctxt);
5328
Daniel Veillard911f49a2001-04-07 15:39:35 +00005329 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005330 valuePush(ctxt, xmlXPathNewCString(""));
5331 } else {
5332 int i = 0; /* Should be first in document order !!!!! */
5333 switch (cur->nodesetval->nodeTab[i]->type) {
5334 case XML_ELEMENT_NODE:
5335 case XML_ATTRIBUTE_NODE:
5336 if (cur->nodesetval->nodeTab[i]->ns == NULL)
5337 valuePush(ctxt, xmlXPathNewCString(""));
5338 else
5339 valuePush(ctxt, xmlXPathNewString(
5340 cur->nodesetval->nodeTab[i]->ns->href));
5341 break;
5342 default:
5343 valuePush(ctxt, xmlXPathNewCString(""));
5344 }
5345 }
5346 xmlXPathFreeObject(cur);
5347}
5348
5349/**
5350 * xmlXPathNameFunction:
5351 * @ctxt: the XPath Parser context
5352 * @nargs: the number of arguments
5353 *
5354 * Implement the name() XPath function
5355 * string name(node-set?)
5356 * The name function returns a string containing a QName representing
5357 * the name of the node in the argument node-set that is first in documenti
5358 * order. The QName must represent the name with respect to the namespace
5359 * declarations in effect on the node whose name is being represented.
5360 * Typically, this will be the form in which the name occurred in the XML
5361 * source. This need not be the case if there are namespace declarations
5362 * in effect on the node that associate multiple prefixes with the same
5363 * namespace. However, an implementation may include information about
5364 * the original prefix in its representation of nodes; in this case, an
5365 * implementation can ensure that the returned string is always the same
5366 * as the QName used in the XML source. If the argument it omitted it
5367 * defaults to the context node.
5368 * Libxml keep the original prefix so the "real qualified name" used is
5369 * returned.
5370 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005371static void
Daniel Veillard04383752001-07-08 14:27:15 +00005372xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
5373{
Owen Taylor3473f882001-02-23 17:55:21 +00005374 xmlXPathObjectPtr cur;
5375
5376 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00005377 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5378 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00005379 }
5380
5381 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00005382 if ((ctxt->value == NULL) ||
5383 ((ctxt->value->type != XPATH_NODESET) &&
5384 (ctxt->value->type != XPATH_XSLT_TREE)))
5385 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00005386 cur = valuePop(ctxt);
5387
Daniel Veillard911f49a2001-04-07 15:39:35 +00005388 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00005389 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00005390 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00005391 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005392
Daniel Veillard04383752001-07-08 14:27:15 +00005393 switch (cur->nodesetval->nodeTab[i]->type) {
5394 case XML_ELEMENT_NODE:
5395 case XML_ATTRIBUTE_NODE:
5396 if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
5397 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL))
5398 valuePush(ctxt,
5399 xmlXPathNewString(cur->nodesetval->
5400 nodeTab[i]->name));
5401
5402 else {
5403 char name[2000];
5404
5405 snprintf(name, sizeof(name), "%s:%s",
5406 (char *) cur->nodesetval->nodeTab[i]->ns->
5407 prefix,
5408 (char *) cur->nodesetval->nodeTab[i]->name);
5409 name[sizeof(name) - 1] = 0;
5410 valuePush(ctxt, xmlXPathNewCString(name));
5411 }
5412 break;
5413 default:
5414 valuePush(ctxt,
5415 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
5416 xmlXPathLocalNameFunction(ctxt, 1);
5417 }
Owen Taylor3473f882001-02-23 17:55:21 +00005418 }
5419 xmlXPathFreeObject(cur);
5420}
5421
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005422
5423/**
Owen Taylor3473f882001-02-23 17:55:21 +00005424 * xmlXPathStringFunction:
5425 * @ctxt: the XPath Parser context
5426 * @nargs: the number of arguments
5427 *
5428 * Implement the string() XPath function
5429 * string string(object?)
5430 * he string function converts an object to a string as follows:
5431 * - A node-set is converted to a string by returning the value of
5432 * the node in the node-set that is first in document order.
5433 * If the node-set is empty, an empty string is returned.
5434 * - A number is converted to a string as follows
5435 * + NaN is converted to the string NaN
5436 * + positive zero is converted to the string 0
5437 * + negative zero is converted to the string 0
5438 * + positive infinity is converted to the string Infinity
5439 * + negative infinity is converted to the string -Infinity
5440 * + if the number is an integer, the number is represented in
5441 * decimal form as a Number with no decimal point and no leading
5442 * zeros, preceded by a minus sign (-) if the number is negative
5443 * + otherwise, the number is represented in decimal form as a
5444 * Number including a decimal point with at least one digit
5445 * before the decimal point and at least one digit after the
5446 * decimal point, preceded by a minus sign (-) if the number
5447 * is negative; there must be no leading zeros before the decimal
5448 * point apart possibly from the one required digit immediatelyi
5449 * before the decimal point; beyond the one required digit
5450 * after the decimal point there must be as many, but only as
5451 * many, more digits as are needed to uniquely distinguish the
5452 * number from all other IEEE 754 numeric values.
5453 * - The boolean false value is converted to the string false.
5454 * The boolean true value is converted to the string true.
5455 *
5456 * If the argument is omitted, it defaults to a node-set with the
5457 * context node as its only member.
5458 */
5459void
5460xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5461 xmlXPathObjectPtr cur;
5462
5463 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005464 valuePush(ctxt,
5465 xmlXPathWrapString(
5466 xmlXPathCastNodeToString(ctxt->context->node)));
5467 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005468 }
5469
5470 CHECK_ARITY(1);
5471 cur = valuePop(ctxt);
5472 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005473 cur = xmlXPathConvertString(cur);
5474 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005475}
5476
5477/**
5478 * xmlXPathStringLengthFunction:
5479 * @ctxt: the XPath Parser context
5480 * @nargs: the number of arguments
5481 *
5482 * Implement the string-length() XPath function
5483 * number string-length(string?)
5484 * The string-length returns the number of characters in the string
5485 * (see [3.6 Strings]). If the argument is omitted, it defaults to
5486 * the context node converted to a string, in other words the value
5487 * of the context node.
5488 */
5489void
5490xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5491 xmlXPathObjectPtr cur;
5492
5493 if (nargs == 0) {
5494 if (ctxt->context->node == NULL) {
5495 valuePush(ctxt, xmlXPathNewFloat(0));
5496 } else {
5497 xmlChar *content;
5498
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005499 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005500 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00005501 xmlFree(content);
5502 }
5503 return;
5504 }
5505 CHECK_ARITY(1);
5506 CAST_TO_STRING;
5507 CHECK_TYPE(XPATH_STRING);
5508 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005509 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00005510 xmlXPathFreeObject(cur);
5511}
5512
5513/**
5514 * xmlXPathConcatFunction:
5515 * @ctxt: the XPath Parser context
5516 * @nargs: the number of arguments
5517 *
5518 * Implement the concat() XPath function
5519 * string concat(string, string, string*)
5520 * The concat function returns the concatenation of its arguments.
5521 */
5522void
5523xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5524 xmlXPathObjectPtr cur, newobj;
5525 xmlChar *tmp;
5526
5527 if (nargs < 2) {
5528 CHECK_ARITY(2);
5529 }
5530
5531 CAST_TO_STRING;
5532 cur = valuePop(ctxt);
5533 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
5534 xmlXPathFreeObject(cur);
5535 return;
5536 }
5537 nargs--;
5538
5539 while (nargs > 0) {
5540 CAST_TO_STRING;
5541 newobj = valuePop(ctxt);
5542 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
5543 xmlXPathFreeObject(newobj);
5544 xmlXPathFreeObject(cur);
5545 XP_ERROR(XPATH_INVALID_TYPE);
5546 }
5547 tmp = xmlStrcat(newobj->stringval, cur->stringval);
5548 newobj->stringval = cur->stringval;
5549 cur->stringval = tmp;
5550
5551 xmlXPathFreeObject(newobj);
5552 nargs--;
5553 }
5554 valuePush(ctxt, cur);
5555}
5556
5557/**
5558 * xmlXPathContainsFunction:
5559 * @ctxt: the XPath Parser context
5560 * @nargs: the number of arguments
5561 *
5562 * Implement the contains() XPath function
5563 * boolean contains(string, string)
5564 * The contains function returns true if the first argument string
5565 * contains the second argument string, and otherwise returns false.
5566 */
5567void
5568xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5569 xmlXPathObjectPtr hay, needle;
5570
5571 CHECK_ARITY(2);
5572 CAST_TO_STRING;
5573 CHECK_TYPE(XPATH_STRING);
5574 needle = valuePop(ctxt);
5575 CAST_TO_STRING;
5576 hay = valuePop(ctxt);
5577 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5578 xmlXPathFreeObject(hay);
5579 xmlXPathFreeObject(needle);
5580 XP_ERROR(XPATH_INVALID_TYPE);
5581 }
5582 if (xmlStrstr(hay->stringval, needle->stringval))
5583 valuePush(ctxt, xmlXPathNewBoolean(1));
5584 else
5585 valuePush(ctxt, xmlXPathNewBoolean(0));
5586 xmlXPathFreeObject(hay);
5587 xmlXPathFreeObject(needle);
5588}
5589
5590/**
5591 * xmlXPathStartsWithFunction:
5592 * @ctxt: the XPath Parser context
5593 * @nargs: the number of arguments
5594 *
5595 * Implement the starts-with() XPath function
5596 * boolean starts-with(string, string)
5597 * The starts-with function returns true if the first argument string
5598 * starts with the second argument string, and otherwise returns false.
5599 */
5600void
5601xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5602 xmlXPathObjectPtr hay, needle;
5603 int n;
5604
5605 CHECK_ARITY(2);
5606 CAST_TO_STRING;
5607 CHECK_TYPE(XPATH_STRING);
5608 needle = valuePop(ctxt);
5609 CAST_TO_STRING;
5610 hay = valuePop(ctxt);
5611 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5612 xmlXPathFreeObject(hay);
5613 xmlXPathFreeObject(needle);
5614 XP_ERROR(XPATH_INVALID_TYPE);
5615 }
5616 n = xmlStrlen(needle->stringval);
5617 if (xmlStrncmp(hay->stringval, needle->stringval, n))
5618 valuePush(ctxt, xmlXPathNewBoolean(0));
5619 else
5620 valuePush(ctxt, xmlXPathNewBoolean(1));
5621 xmlXPathFreeObject(hay);
5622 xmlXPathFreeObject(needle);
5623}
5624
5625/**
5626 * xmlXPathSubstringFunction:
5627 * @ctxt: the XPath Parser context
5628 * @nargs: the number of arguments
5629 *
5630 * Implement the substring() XPath function
5631 * string substring(string, number, number?)
5632 * The substring function returns the substring of the first argument
5633 * starting at the position specified in the second argument with
5634 * length specified in the third argument. For example,
5635 * substring("12345",2,3) returns "234". If the third argument is not
5636 * specified, it returns the substring starting at the position specified
5637 * in the second argument and continuing to the end of the string. For
5638 * example, substring("12345",2) returns "2345". More precisely, each
5639 * character in the string (see [3.6 Strings]) is considered to have a
5640 * numeric position: the position of the first character is 1, the position
5641 * of the second character is 2 and so on. The returned substring contains
5642 * those characters for which the position of the character is greater than
5643 * or equal to the second argument and, if the third argument is specified,
5644 * less than the sum of the second and third arguments; the comparisons
5645 * and addition used for the above follow the standard IEEE 754 rules. Thus:
5646 * - substring("12345", 1.5, 2.6) returns "234"
5647 * - substring("12345", 0, 3) returns "12"
5648 * - substring("12345", 0 div 0, 3) returns ""
5649 * - substring("12345", 1, 0 div 0) returns ""
5650 * - substring("12345", -42, 1 div 0) returns "12345"
5651 * - substring("12345", -1 div 0, 1 div 0) returns ""
5652 */
5653void
5654xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5655 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005656 double le=0, in;
5657 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00005658 xmlChar *ret;
5659
Owen Taylor3473f882001-02-23 17:55:21 +00005660 if (nargs < 2) {
5661 CHECK_ARITY(2);
5662 }
5663 if (nargs > 3) {
5664 CHECK_ARITY(3);
5665 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005666 /*
5667 * take care of possible last (position) argument
5668 */
Owen Taylor3473f882001-02-23 17:55:21 +00005669 if (nargs == 3) {
5670 CAST_TO_NUMBER;
5671 CHECK_TYPE(XPATH_NUMBER);
5672 len = valuePop(ctxt);
5673 le = len->floatval;
5674 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00005675 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005676
Owen Taylor3473f882001-02-23 17:55:21 +00005677 CAST_TO_NUMBER;
5678 CHECK_TYPE(XPATH_NUMBER);
5679 start = valuePop(ctxt);
5680 in = start->floatval;
5681 xmlXPathFreeObject(start);
5682 CAST_TO_STRING;
5683 CHECK_TYPE(XPATH_STRING);
5684 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00005685 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005686
Daniel Veillard97ac1312001-05-30 19:14:17 +00005687 /*
5688 * If last pos not present, calculate last position
5689 */
5690 if (nargs != 3)
5691 le = m;
5692
5693 /*
5694 * To meet our requirements, initial index calculations
5695 * must be done before we convert to integer format
5696 *
5697 * First we normalize indices
5698 */
5699 in -= 1.0;
5700 le += in;
5701 if (in < 0.0)
5702 in = 0.0;
5703 if (le > (double)m)
5704 le = (double)m;
5705
5706 /*
5707 * Now we go to integer form, rounding up
5708 */
Owen Taylor3473f882001-02-23 17:55:21 +00005709 i = (int) in;
5710 if (((double)i) != in) i++;
5711
Owen Taylor3473f882001-02-23 17:55:21 +00005712 l = (int) le;
5713 if (((double)l) != le) l++;
5714
Daniel Veillard97ac1312001-05-30 19:14:17 +00005715 if (l > m) l=m;
Owen Taylor3473f882001-02-23 17:55:21 +00005716
5717 /* number of chars to copy */
5718 l -= i;
5719
Daniel Veillard97ac1312001-05-30 19:14:17 +00005720 ret = xmlUTF8Strsub(str->stringval, i, l);
Owen Taylor3473f882001-02-23 17:55:21 +00005721 if (ret == NULL)
5722 valuePush(ctxt, xmlXPathNewCString(""));
5723 else {
5724 valuePush(ctxt, xmlXPathNewString(ret));
5725 xmlFree(ret);
5726 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005727
Owen Taylor3473f882001-02-23 17:55:21 +00005728 xmlXPathFreeObject(str);
5729}
5730
5731/**
5732 * xmlXPathSubstringBeforeFunction:
5733 * @ctxt: the XPath Parser context
5734 * @nargs: the number of arguments
5735 *
5736 * Implement the substring-before() XPath function
5737 * string substring-before(string, string)
5738 * The substring-before function returns the substring of the first
5739 * argument string that precedes the first occurrence of the second
5740 * argument string in the first argument string, or the empty string
5741 * if the first argument string does not contain the second argument
5742 * string. For example, substring-before("1999/04/01","/") returns 1999.
5743 */
5744void
5745xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5746 xmlXPathObjectPtr str;
5747 xmlXPathObjectPtr find;
5748 xmlBufferPtr target;
5749 const xmlChar *point;
5750 int offset;
5751
5752 CHECK_ARITY(2);
5753 CAST_TO_STRING;
5754 find = valuePop(ctxt);
5755 CAST_TO_STRING;
5756 str = valuePop(ctxt);
5757
5758 target = xmlBufferCreate();
5759 if (target) {
5760 point = xmlStrstr(str->stringval, find->stringval);
5761 if (point) {
5762 offset = (int)(point - str->stringval);
5763 xmlBufferAdd(target, str->stringval, offset);
5764 }
5765 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5766 xmlBufferFree(target);
5767 }
5768
5769 xmlXPathFreeObject(str);
5770 xmlXPathFreeObject(find);
5771}
5772
5773/**
5774 * xmlXPathSubstringAfterFunction:
5775 * @ctxt: the XPath Parser context
5776 * @nargs: the number of arguments
5777 *
5778 * Implement the substring-after() XPath function
5779 * string substring-after(string, string)
5780 * The substring-after function returns the substring of the first
5781 * argument string that follows the first occurrence of the second
5782 * argument string in the first argument string, or the empty stringi
5783 * if the first argument string does not contain the second argument
5784 * string. For example, substring-after("1999/04/01","/") returns 04/01,
5785 * and substring-after("1999/04/01","19") returns 99/04/01.
5786 */
5787void
5788xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5789 xmlXPathObjectPtr str;
5790 xmlXPathObjectPtr find;
5791 xmlBufferPtr target;
5792 const xmlChar *point;
5793 int offset;
5794
5795 CHECK_ARITY(2);
5796 CAST_TO_STRING;
5797 find = valuePop(ctxt);
5798 CAST_TO_STRING;
5799 str = valuePop(ctxt);
5800
5801 target = xmlBufferCreate();
5802 if (target) {
5803 point = xmlStrstr(str->stringval, find->stringval);
5804 if (point) {
5805 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
5806 xmlBufferAdd(target, &str->stringval[offset],
5807 xmlStrlen(str->stringval) - offset);
5808 }
5809 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5810 xmlBufferFree(target);
5811 }
5812
5813 xmlXPathFreeObject(str);
5814 xmlXPathFreeObject(find);
5815}
5816
5817/**
5818 * xmlXPathNormalizeFunction:
5819 * @ctxt: the XPath Parser context
5820 * @nargs: the number of arguments
5821 *
5822 * Implement the normalize-space() XPath function
5823 * string normalize-space(string?)
5824 * The normalize-space function returns the argument string with white
5825 * space normalized by stripping leading and trailing whitespace
5826 * and replacing sequences of whitespace characters by a single
5827 * space. Whitespace characters are the same allowed by the S production
5828 * in XML. If the argument is omitted, it defaults to the context
5829 * node converted to a string, in other words the value of the context node.
5830 */
5831void
5832xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5833 xmlXPathObjectPtr obj = NULL;
5834 xmlChar *source = NULL;
5835 xmlBufferPtr target;
5836 xmlChar blank;
5837
5838 if (nargs == 0) {
5839 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005840 valuePush(ctxt,
5841 xmlXPathWrapString(
5842 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00005843 nargs = 1;
5844 }
5845
5846 CHECK_ARITY(1);
5847 CAST_TO_STRING;
5848 CHECK_TYPE(XPATH_STRING);
5849 obj = valuePop(ctxt);
5850 source = obj->stringval;
5851
5852 target = xmlBufferCreate();
5853 if (target && source) {
5854
5855 /* Skip leading whitespaces */
5856 while (IS_BLANK(*source))
5857 source++;
5858
5859 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
5860 blank = 0;
5861 while (*source) {
5862 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005863 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00005864 } else {
5865 if (blank) {
5866 xmlBufferAdd(target, &blank, 1);
5867 blank = 0;
5868 }
5869 xmlBufferAdd(target, source, 1);
5870 }
5871 source++;
5872 }
5873
5874 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5875 xmlBufferFree(target);
5876 }
5877 xmlXPathFreeObject(obj);
5878}
5879
5880/**
5881 * xmlXPathTranslateFunction:
5882 * @ctxt: the XPath Parser context
5883 * @nargs: the number of arguments
5884 *
5885 * Implement the translate() XPath function
5886 * string translate(string, string, string)
5887 * The translate function returns the first argument string with
5888 * occurrences of characters in the second argument string replaced
5889 * by the character at the corresponding position in the third argument
5890 * string. For example, translate("bar","abc","ABC") returns the string
5891 * BAr. If there is a character in the second argument string with no
5892 * character at a corresponding position in the third argument string
5893 * (because the second argument string is longer than the third argument
5894 * string), then occurrences of that character in the first argument
5895 * string are removed. For example, translate("--aaa--","abc-","ABC")
5896 * returns "AAA". If a character occurs more than once in second
5897 * argument string, then the first occurrence determines the replacement
5898 * character. If the third argument string is longer than the second
5899 * argument string, then excess characters are ignored.
5900 */
5901void
5902xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00005903 xmlXPathObjectPtr str;
5904 xmlXPathObjectPtr from;
5905 xmlXPathObjectPtr to;
5906 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005907 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00005908 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005909 xmlChar *point;
5910 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00005911
Daniel Veillarde043ee12001-04-16 14:08:07 +00005912 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00005913
Daniel Veillarde043ee12001-04-16 14:08:07 +00005914 CAST_TO_STRING;
5915 to = valuePop(ctxt);
5916 CAST_TO_STRING;
5917 from = valuePop(ctxt);
5918 CAST_TO_STRING;
5919 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005920
Daniel Veillarde043ee12001-04-16 14:08:07 +00005921 target = xmlBufferCreate();
5922 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005923 max = xmlUTF8Strlen(to->stringval);
5924 for (cptr = str->stringval; (ch=*cptr); ) {
5925 offset = xmlUTF8Strloc(from->stringval, cptr);
5926 if (offset >= 0) {
5927 if (offset < max) {
5928 point = xmlUTF8Strpos(to->stringval, offset);
5929 if (point)
5930 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
5931 }
5932 } else
5933 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
5934
5935 /* Step to next character in input */
5936 cptr++;
5937 if ( ch & 0x80 ) {
5938 /* if not simple ascii, verify proper format */
5939 if ( (ch & 0xc0) != 0xc0 ) {
5940 xmlGenericError(xmlGenericErrorContext,
5941 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5942 break;
5943 }
5944 /* then skip over remaining bytes for this char */
5945 while ( (ch <<= 1) & 0x80 )
5946 if ( (*cptr++ & 0xc0) != 0x80 ) {
5947 xmlGenericError(xmlGenericErrorContext,
5948 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5949 break;
5950 }
5951 if (ch & 0x80) /* must have had error encountered */
5952 break;
5953 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005954 }
Owen Taylor3473f882001-02-23 17:55:21 +00005955 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005956 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5957 xmlBufferFree(target);
5958 xmlXPathFreeObject(str);
5959 xmlXPathFreeObject(from);
5960 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00005961}
5962
5963/**
5964 * xmlXPathBooleanFunction:
5965 * @ctxt: the XPath Parser context
5966 * @nargs: the number of arguments
5967 *
5968 * Implement the boolean() XPath function
5969 * boolean boolean(object)
5970 * he boolean function converts its argument to a boolean as follows:
5971 * - a number is true if and only if it is neither positive or
5972 * negative zero nor NaN
5973 * - a node-set is true if and only if it is non-empty
5974 * - a string is true if and only if its length is non-zero
5975 */
5976void
5977xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5978 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00005979
5980 CHECK_ARITY(1);
5981 cur = valuePop(ctxt);
5982 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005983 cur = xmlXPathConvertBoolean(cur);
5984 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005985}
5986
5987/**
5988 * xmlXPathNotFunction:
5989 * @ctxt: the XPath Parser context
5990 * @nargs: the number of arguments
5991 *
5992 * Implement the not() XPath function
5993 * boolean not(boolean)
5994 * The not function returns true if its argument is false,
5995 * and false otherwise.
5996 */
5997void
5998xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5999 CHECK_ARITY(1);
6000 CAST_TO_BOOLEAN;
6001 CHECK_TYPE(XPATH_BOOLEAN);
6002 ctxt->value->boolval = ! ctxt->value->boolval;
6003}
6004
6005/**
6006 * xmlXPathTrueFunction:
6007 * @ctxt: the XPath Parser context
6008 * @nargs: the number of arguments
6009 *
6010 * Implement the true() XPath function
6011 * boolean true()
6012 */
6013void
6014xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6015 CHECK_ARITY(0);
6016 valuePush(ctxt, xmlXPathNewBoolean(1));
6017}
6018
6019/**
6020 * xmlXPathFalseFunction:
6021 * @ctxt: the XPath Parser context
6022 * @nargs: the number of arguments
6023 *
6024 * Implement the false() XPath function
6025 * boolean false()
6026 */
6027void
6028xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6029 CHECK_ARITY(0);
6030 valuePush(ctxt, xmlXPathNewBoolean(0));
6031}
6032
6033/**
6034 * xmlXPathLangFunction:
6035 * @ctxt: the XPath Parser context
6036 * @nargs: the number of arguments
6037 *
6038 * Implement the lang() XPath function
6039 * boolean lang(string)
6040 * The lang function returns true or false depending on whether the
6041 * language of the context node as specified by xml:lang attributes
6042 * is the same as or is a sublanguage of the language specified by
6043 * the argument string. The language of the context node is determined
6044 * by the value of the xml:lang attribute on the context node, or, if
6045 * the context node has no xml:lang attribute, by the value of the
6046 * xml:lang attribute on the nearest ancestor of the context node that
6047 * has an xml:lang attribute. If there is no such attribute, then lang
6048 * returns false. If there is such an attribute, then lang returns
6049 * true if the attribute value is equal to the argument ignoring case,
6050 * or if there is some suffix starting with - such that the attribute
6051 * value is equal to the argument ignoring that suffix of the attribute
6052 * value and ignoring case.
6053 */
6054void
6055xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6056 xmlXPathObjectPtr val;
6057 const xmlChar *theLang;
6058 const xmlChar *lang;
6059 int ret = 0;
6060 int i;
6061
6062 CHECK_ARITY(1);
6063 CAST_TO_STRING;
6064 CHECK_TYPE(XPATH_STRING);
6065 val = valuePop(ctxt);
6066 lang = val->stringval;
6067 theLang = xmlNodeGetLang(ctxt->context->node);
6068 if ((theLang != NULL) && (lang != NULL)) {
6069 for (i = 0;lang[i] != 0;i++)
6070 if (toupper(lang[i]) != toupper(theLang[i]))
6071 goto not_equal;
6072 ret = 1;
6073 }
6074not_equal:
6075 xmlXPathFreeObject(val);
6076 valuePush(ctxt, xmlXPathNewBoolean(ret));
6077}
6078
6079/**
6080 * xmlXPathNumberFunction:
6081 * @ctxt: the XPath Parser context
6082 * @nargs: the number of arguments
6083 *
6084 * Implement the number() XPath function
6085 * number number(object?)
6086 */
6087void
6088xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6089 xmlXPathObjectPtr cur;
6090 double res;
6091
6092 if (nargs == 0) {
6093 if (ctxt->context->node == NULL) {
6094 valuePush(ctxt, xmlXPathNewFloat(0.0));
6095 } else {
6096 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6097
6098 res = xmlXPathStringEvalNumber(content);
6099 valuePush(ctxt, xmlXPathNewFloat(res));
6100 xmlFree(content);
6101 }
6102 return;
6103 }
6104
6105 CHECK_ARITY(1);
6106 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006107 cur = xmlXPathConvertNumber(cur);
6108 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006109}
6110
6111/**
6112 * xmlXPathSumFunction:
6113 * @ctxt: the XPath Parser context
6114 * @nargs: the number of arguments
6115 *
6116 * Implement the sum() XPath function
6117 * number sum(node-set)
6118 * The sum function returns the sum of the values of the nodes in
6119 * the argument node-set.
6120 */
6121void
6122xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6123 xmlXPathObjectPtr cur;
6124 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006125 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006126
6127 CHECK_ARITY(1);
6128 if ((ctxt->value == NULL) ||
6129 ((ctxt->value->type != XPATH_NODESET) &&
6130 (ctxt->value->type != XPATH_XSLT_TREE)))
6131 XP_ERROR(XPATH_INVALID_TYPE);
6132 cur = valuePop(ctxt);
6133
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006134 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006135 valuePush(ctxt, xmlXPathNewFloat(0.0));
6136 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006137 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6138 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006139 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006140 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006141 }
6142 xmlXPathFreeObject(cur);
6143}
6144
6145/**
6146 * xmlXPathFloorFunction:
6147 * @ctxt: the XPath Parser context
6148 * @nargs: the number of arguments
6149 *
6150 * Implement the floor() XPath function
6151 * number floor(number)
6152 * The floor function returns the largest (closest to positive infinity)
6153 * number that is not greater than the argument and that is an integer.
6154 */
6155void
6156xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6157 CHECK_ARITY(1);
6158 CAST_TO_NUMBER;
6159 CHECK_TYPE(XPATH_NUMBER);
6160#if 0
6161 ctxt->value->floatval = floor(ctxt->value->floatval);
6162#else
6163 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
6164 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
6165#endif
6166}
6167
6168/**
6169 * xmlXPathCeilingFunction:
6170 * @ctxt: the XPath Parser context
6171 * @nargs: the number of arguments
6172 *
6173 * Implement the ceiling() XPath function
6174 * number ceiling(number)
6175 * The ceiling function returns the smallest (closest to negative infinity)
6176 * number that is not less than the argument and that is an integer.
6177 */
6178void
6179xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6180 double f;
6181
6182 CHECK_ARITY(1);
6183 CAST_TO_NUMBER;
6184 CHECK_TYPE(XPATH_NUMBER);
6185
6186#if 0
6187 ctxt->value->floatval = ceil(ctxt->value->floatval);
6188#else
6189 f = (double)((int) ctxt->value->floatval);
6190 if (f != ctxt->value->floatval)
6191 ctxt->value->floatval = f + 1;
6192#endif
6193}
6194
6195/**
6196 * xmlXPathRoundFunction:
6197 * @ctxt: the XPath Parser context
6198 * @nargs: the number of arguments
6199 *
6200 * Implement the round() XPath function
6201 * number round(number)
6202 * The round function returns the number that is closest to the
6203 * argument and that is an integer. If there are two such numbers,
6204 * then the one that is even is returned.
6205 */
6206void
6207xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6208 double f;
6209
6210 CHECK_ARITY(1);
6211 CAST_TO_NUMBER;
6212 CHECK_TYPE(XPATH_NUMBER);
6213
6214 if ((ctxt->value->floatval == xmlXPathNAN) ||
6215 (ctxt->value->floatval == xmlXPathPINF) ||
6216 (ctxt->value->floatval == xmlXPathNINF) ||
6217 (ctxt->value->floatval == 0.0))
6218 return;
6219
6220#if 0
6221 f = floor(ctxt->value->floatval);
6222#else
6223 f = (double)((int) ctxt->value->floatval);
6224#endif
6225 if (ctxt->value->floatval < f + 0.5)
6226 ctxt->value->floatval = f;
6227 else
6228 ctxt->value->floatval = f + 1;
6229}
6230
6231/************************************************************************
6232 * *
6233 * The Parser *
6234 * *
6235 ************************************************************************/
6236
6237/*
6238 * a couple of forward declarations since we use a recursive call based
6239 * implementation.
6240 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006241static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006242static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006243static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006244#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006245static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
6246#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006247#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006248static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006249#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00006250static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
6251 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00006252
6253/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00006254 * xmlXPathCurrentChar:
6255 * @ctxt: the XPath parser context
6256 * @cur: pointer to the beginning of the char
6257 * @len: pointer to the length of the char read
6258 *
6259 * The current char value, if using UTF-8 this may actaully span multiple
6260 * bytes in the input buffer.
6261 *
6262 * Returns the current char value and its lenght
6263 */
6264
6265static int
6266xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
6267 unsigned char c;
6268 unsigned int val;
6269 const xmlChar *cur;
6270
6271 if (ctxt == NULL)
6272 return(0);
6273 cur = ctxt->cur;
6274
6275 /*
6276 * We are supposed to handle UTF8, check it's valid
6277 * From rfc2044: encoding of the Unicode values on UTF-8:
6278 *
6279 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
6280 * 0000 0000-0000 007F 0xxxxxxx
6281 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
6282 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
6283 *
6284 * Check for the 0x110000 limit too
6285 */
6286 c = *cur;
6287 if (c & 0x80) {
6288 if ((cur[1] & 0xc0) != 0x80)
6289 goto encoding_error;
6290 if ((c & 0xe0) == 0xe0) {
6291
6292 if ((cur[2] & 0xc0) != 0x80)
6293 goto encoding_error;
6294 if ((c & 0xf0) == 0xf0) {
6295 if (((c & 0xf8) != 0xf0) ||
6296 ((cur[3] & 0xc0) != 0x80))
6297 goto encoding_error;
6298 /* 4-byte code */
6299 *len = 4;
6300 val = (cur[0] & 0x7) << 18;
6301 val |= (cur[1] & 0x3f) << 12;
6302 val |= (cur[2] & 0x3f) << 6;
6303 val |= cur[3] & 0x3f;
6304 } else {
6305 /* 3-byte code */
6306 *len = 3;
6307 val = (cur[0] & 0xf) << 12;
6308 val |= (cur[1] & 0x3f) << 6;
6309 val |= cur[2] & 0x3f;
6310 }
6311 } else {
6312 /* 2-byte code */
6313 *len = 2;
6314 val = (cur[0] & 0x1f) << 6;
6315 val |= cur[1] & 0x3f;
6316 }
6317 if (!IS_CHAR(val)) {
6318 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
6319 }
6320 return(val);
6321 } else {
6322 /* 1-byte code */
6323 *len = 1;
6324 return((int) *cur);
6325 }
6326encoding_error:
6327 /*
6328 * If we detect an UTF8 error that probably mean that the
6329 * input encoding didn't get properly advertized in the
6330 * declaration header. Report the error and switch the encoding
6331 * to ISO-Latin-1 (if you don't like this policy, just declare the
6332 * encoding !)
6333 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00006334 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00006335 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006336}
6337
6338/**
Owen Taylor3473f882001-02-23 17:55:21 +00006339 * xmlXPathParseNCName:
6340 * @ctxt: the XPath Parser context
6341 *
6342 * parse an XML namespace non qualified name.
6343 *
6344 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
6345 *
6346 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
6347 * CombiningChar | Extender
6348 *
6349 * Returns the namespace name or NULL
6350 */
6351
6352xmlChar *
6353xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00006354 const xmlChar *in;
6355 xmlChar *ret;
6356 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006357
Daniel Veillard2156a562001-04-28 12:24:34 +00006358 /*
6359 * Accelerator for simple ASCII names
6360 */
6361 in = ctxt->cur;
6362 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6363 ((*in >= 0x41) && (*in <= 0x5A)) ||
6364 (*in == '_')) {
6365 in++;
6366 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6367 ((*in >= 0x41) && (*in <= 0x5A)) ||
6368 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00006369 (*in == '_') || (*in == '.') ||
6370 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00006371 in++;
6372 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
6373 (*in == '[') || (*in == ']') || (*in == ':') ||
6374 (*in == '@') || (*in == '*')) {
6375 count = in - ctxt->cur;
6376 if (count == 0)
6377 return(NULL);
6378 ret = xmlStrndup(ctxt->cur, count);
6379 ctxt->cur = in;
6380 return(ret);
6381 }
6382 }
6383 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00006384}
6385
Daniel Veillard2156a562001-04-28 12:24:34 +00006386
Owen Taylor3473f882001-02-23 17:55:21 +00006387/**
6388 * xmlXPathParseQName:
6389 * @ctxt: the XPath Parser context
6390 * @prefix: a xmlChar **
6391 *
6392 * parse an XML qualified name
6393 *
6394 * [NS 5] QName ::= (Prefix ':')? LocalPart
6395 *
6396 * [NS 6] Prefix ::= NCName
6397 *
6398 * [NS 7] LocalPart ::= NCName
6399 *
6400 * Returns the function returns the local part, and prefix is updated
6401 * to get the Prefix if any.
6402 */
6403
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006404static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006405xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
6406 xmlChar *ret = NULL;
6407
6408 *prefix = NULL;
6409 ret = xmlXPathParseNCName(ctxt);
6410 if (CUR == ':') {
6411 *prefix = ret;
6412 NEXT;
6413 ret = xmlXPathParseNCName(ctxt);
6414 }
6415 return(ret);
6416}
6417
6418/**
6419 * xmlXPathParseName:
6420 * @ctxt: the XPath Parser context
6421 *
6422 * parse an XML name
6423 *
6424 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6425 * CombiningChar | Extender
6426 *
6427 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6428 *
6429 * Returns the namespace name or NULL
6430 */
6431
6432xmlChar *
6433xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006434 const xmlChar *in;
6435 xmlChar *ret;
6436 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006437
Daniel Veillard61d80a22001-04-27 17:13:01 +00006438 /*
6439 * Accelerator for simple ASCII names
6440 */
6441 in = ctxt->cur;
6442 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6443 ((*in >= 0x41) && (*in <= 0x5A)) ||
6444 (*in == '_') || (*in == ':')) {
6445 in++;
6446 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6447 ((*in >= 0x41) && (*in <= 0x5A)) ||
6448 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00006449 (*in == '_') || (*in == '-') ||
6450 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00006451 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00006452 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006453 count = in - ctxt->cur;
6454 ret = xmlStrndup(ctxt->cur, count);
6455 ctxt->cur = in;
6456 return(ret);
6457 }
6458 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006459 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00006460}
6461
Daniel Veillard61d80a22001-04-27 17:13:01 +00006462static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00006463xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006464 xmlChar buf[XML_MAX_NAMELEN + 5];
6465 int len = 0, l;
6466 int c;
6467
6468 /*
6469 * Handler for more complex cases
6470 */
6471 c = CUR_CHAR(l);
6472 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00006473 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
6474 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00006475 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00006476 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006477 return(NULL);
6478 }
6479
6480 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
6481 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
6482 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006483 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006484 (IS_COMBINING(c)) ||
6485 (IS_EXTENDER(c)))) {
6486 COPY_BUF(l,buf,len,c);
6487 NEXTL(l);
6488 c = CUR_CHAR(l);
6489 if (len >= XML_MAX_NAMELEN) {
6490 /*
6491 * Okay someone managed to make a huge name, so he's ready to pay
6492 * for the processing speed.
6493 */
6494 xmlChar *buffer;
6495 int max = len * 2;
6496
6497 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
6498 if (buffer == NULL) {
6499 XP_ERROR0(XPATH_MEMORY_ERROR);
6500 }
6501 memcpy(buffer, buf, len);
6502 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
6503 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006504 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006505 (IS_COMBINING(c)) ||
6506 (IS_EXTENDER(c))) {
6507 if (len + 10 > max) {
6508 max *= 2;
6509 buffer = (xmlChar *) xmlRealloc(buffer,
6510 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00006511 if (buffer == NULL) {
6512 XP_ERROR0(XPATH_MEMORY_ERROR);
6513 }
6514 }
6515 COPY_BUF(l,buffer,len,c);
6516 NEXTL(l);
6517 c = CUR_CHAR(l);
6518 }
6519 buffer[len] = 0;
6520 return(buffer);
6521 }
6522 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006523 if (len == 0)
6524 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006525 return(xmlStrndup(buf, len));
6526}
Owen Taylor3473f882001-02-23 17:55:21 +00006527/**
6528 * xmlXPathStringEvalNumber:
6529 * @str: A string to scan
6530 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00006531 * [30a] Float ::= Number ('e' Digits?)?
6532 *
Owen Taylor3473f882001-02-23 17:55:21 +00006533 * [30] Number ::= Digits ('.' Digits?)?
6534 * | '.' Digits
6535 * [31] Digits ::= [0-9]+
6536 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006537 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00006538 * In complement of the Number expression, this function also handles
6539 * negative values : '-' Number.
6540 *
6541 * Returns the double value.
6542 */
6543double
6544xmlXPathStringEvalNumber(const xmlChar *str) {
6545 const xmlChar *cur = str;
6546 double ret = 0.0;
6547 double mult = 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006548 int ok = 0, tmp = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006549 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006550 int exponent = 0;
6551 int is_exponent_negative = 0;
6552
Owen Taylor3473f882001-02-23 17:55:21 +00006553 while (IS_BLANK(*cur)) cur++;
6554 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
6555 return(xmlXPathNAN);
6556 }
6557 if (*cur == '-') {
6558 isneg = 1;
6559 cur++;
6560 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006561 /*
6562 * tmp is a workaroudn against a gcc compiler bug
6563 */
Owen Taylor3473f882001-02-23 17:55:21 +00006564 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006565 tmp = tmp * 10 + (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00006566 ok = 1;
6567 cur++;
6568 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006569 ret = (double) tmp;
6570
Owen Taylor3473f882001-02-23 17:55:21 +00006571 if (*cur == '.') {
6572 cur++;
6573 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
6574 return(xmlXPathNAN);
6575 }
6576 while ((*cur >= '0') && (*cur <= '9')) {
6577 mult /= 10;
6578 ret = ret + (*cur - '0') * mult;
6579 cur++;
6580 }
6581 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006582 if ((*cur == 'e') || (*cur == 'E')) {
6583 cur++;
6584 if (*cur == '-') {
6585 is_exponent_negative = 1;
6586 cur++;
6587 }
6588 while ((*cur >= '0') && (*cur <= '9')) {
6589 exponent = exponent * 10 + (*cur - '0');
6590 cur++;
6591 }
6592 }
Owen Taylor3473f882001-02-23 17:55:21 +00006593 while (IS_BLANK(*cur)) cur++;
6594 if (*cur != 0) return(xmlXPathNAN);
6595 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006596 if (is_exponent_negative) exponent = -exponent;
6597 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00006598 return(ret);
6599}
6600
6601/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006602 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00006603 * @ctxt: the XPath Parser context
6604 *
6605 * [30] Number ::= Digits ('.' Digits?)?
6606 * | '.' Digits
6607 * [31] Digits ::= [0-9]+
6608 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006609 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00006610 *
6611 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006612static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006613xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
6614{
Owen Taylor3473f882001-02-23 17:55:21 +00006615 double ret = 0.0;
6616 double mult = 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006617 int ok = 0, tmp = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006618 int exponent = 0;
6619 int is_exponent_negative = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006620
6621 CHECK_ERROR;
6622 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
6623 XP_ERROR(XPATH_NUMBER_ERROR);
6624 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006625 /*
6626 * Try to work around a gcc optimizer bug
6627 */
Owen Taylor3473f882001-02-23 17:55:21 +00006628 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006629 tmp = tmp * 10 + (CUR - '0');
6630 ok = 1;
6631 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +00006632 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006633 ret = (double) tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00006634 if (CUR == '.') {
6635 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006636 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
6637 XP_ERROR(XPATH_NUMBER_ERROR);
6638 }
6639 while ((CUR >= '0') && (CUR <= '9')) {
6640 mult /= 10;
6641 ret = ret + (CUR - '0') * mult;
6642 NEXT;
6643 }
Owen Taylor3473f882001-02-23 17:55:21 +00006644 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006645 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006646 NEXT;
6647 if (CUR == '-') {
6648 is_exponent_negative = 1;
6649 NEXT;
6650 }
6651 while ((CUR >= '0') && (CUR <= '9')) {
6652 exponent = exponent * 10 + (CUR - '0');
6653 NEXT;
6654 }
6655 if (is_exponent_negative)
6656 exponent = -exponent;
6657 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006658 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006659 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006660 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006661}
6662
6663/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006664 * xmlXPathParseLiteral:
6665 * @ctxt: the XPath Parser context
6666 *
6667 * Parse a Literal
6668 *
6669 * [29] Literal ::= '"' [^"]* '"'
6670 * | "'" [^']* "'"
6671 *
6672 * Returns the value found or NULL in case of error
6673 */
6674static xmlChar *
6675xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
6676 const xmlChar *q;
6677 xmlChar *ret = NULL;
6678
6679 if (CUR == '"') {
6680 NEXT;
6681 q = CUR_PTR;
6682 while ((IS_CHAR(CUR)) && (CUR != '"'))
6683 NEXT;
6684 if (!IS_CHAR(CUR)) {
6685 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6686 } else {
6687 ret = xmlStrndup(q, CUR_PTR - q);
6688 NEXT;
6689 }
6690 } else if (CUR == '\'') {
6691 NEXT;
6692 q = CUR_PTR;
6693 while ((IS_CHAR(CUR)) && (CUR != '\''))
6694 NEXT;
6695 if (!IS_CHAR(CUR)) {
6696 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6697 } else {
6698 ret = xmlStrndup(q, CUR_PTR - q);
6699 NEXT;
6700 }
6701 } else {
6702 XP_ERROR0(XPATH_START_LITERAL_ERROR);
6703 }
6704 return(ret);
6705}
6706
6707/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006708 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00006709 * @ctxt: the XPath Parser context
6710 *
6711 * Parse a Literal and push it on the stack.
6712 *
6713 * [29] Literal ::= '"' [^"]* '"'
6714 * | "'" [^']* "'"
6715 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006716 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00006717 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006718static void
6719xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006720 const xmlChar *q;
6721 xmlChar *ret = NULL;
6722
6723 if (CUR == '"') {
6724 NEXT;
6725 q = CUR_PTR;
6726 while ((IS_CHAR(CUR)) && (CUR != '"'))
6727 NEXT;
6728 if (!IS_CHAR(CUR)) {
6729 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
6730 } else {
6731 ret = xmlStrndup(q, CUR_PTR - q);
6732 NEXT;
6733 }
6734 } else if (CUR == '\'') {
6735 NEXT;
6736 q = CUR_PTR;
6737 while ((IS_CHAR(CUR)) && (CUR != '\''))
6738 NEXT;
6739 if (!IS_CHAR(CUR)) {
6740 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
6741 } else {
6742 ret = xmlStrndup(q, CUR_PTR - q);
6743 NEXT;
6744 }
6745 } else {
6746 XP_ERROR(XPATH_START_LITERAL_ERROR);
6747 }
6748 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006749 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
6750 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006751 xmlFree(ret);
6752}
6753
6754/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006755 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00006756 * @ctxt: the XPath Parser context
6757 *
6758 * Parse a VariableReference, evaluate it and push it on the stack.
6759 *
6760 * The variable bindings consist of a mapping from variable names
6761 * to variable values. The value of a variable is an object, which
6762 * of any of the types that are possible for the value of an expression,
6763 * and may also be of additional types not specified here.
6764 *
6765 * Early evaluation is possible since:
6766 * The variable bindings [...] used to evaluate a subexpression are
6767 * always the same as those used to evaluate the containing expression.
6768 *
6769 * [36] VariableReference ::= '$' QName
6770 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006771static void
6772xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006773 xmlChar *name;
6774 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006775
6776 SKIP_BLANKS;
6777 if (CUR != '$') {
6778 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
6779 }
6780 NEXT;
6781 name = xmlXPathParseQName(ctxt, &prefix);
6782 if (name == NULL) {
6783 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
6784 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006785 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006786 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
6787 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006788 SKIP_BLANKS;
6789}
6790
6791/**
6792 * xmlXPathIsNodeType:
6793 * @ctxt: the XPath Parser context
6794 * @name: a name string
6795 *
6796 * Is the name given a NodeType one.
6797 *
6798 * [38] NodeType ::= 'comment'
6799 * | 'text'
6800 * | 'processing-instruction'
6801 * | 'node'
6802 *
6803 * Returns 1 if true 0 otherwise
6804 */
6805int
6806xmlXPathIsNodeType(const xmlChar *name) {
6807 if (name == NULL)
6808 return(0);
6809
6810 if (xmlStrEqual(name, BAD_CAST "comment"))
6811 return(1);
6812 if (xmlStrEqual(name, BAD_CAST "text"))
6813 return(1);
6814 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
6815 return(1);
6816 if (xmlStrEqual(name, BAD_CAST "node"))
6817 return(1);
6818 return(0);
6819}
6820
6821/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006822 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00006823 * @ctxt: the XPath Parser context
6824 *
6825 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
6826 * [17] Argument ::= Expr
6827 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006828 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00006829 * pushed on the stack
6830 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006831static void
6832xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006833 xmlChar *name;
6834 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006835 int nbargs = 0;
6836
6837 name = xmlXPathParseQName(ctxt, &prefix);
6838 if (name == NULL) {
6839 XP_ERROR(XPATH_EXPR_ERROR);
6840 }
6841 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006842#ifdef DEBUG_EXPR
6843 if (prefix == NULL)
6844 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
6845 name);
6846 else
6847 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
6848 prefix, name);
6849#endif
6850
Owen Taylor3473f882001-02-23 17:55:21 +00006851 if (CUR != '(') {
6852 XP_ERROR(XPATH_EXPR_ERROR);
6853 }
6854 NEXT;
6855 SKIP_BLANKS;
6856
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006857 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006858 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006859 int op1 = ctxt->comp->last;
6860 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006861 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006862 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006863 nbargs++;
6864 if (CUR == ')') break;
6865 if (CUR != ',') {
6866 XP_ERROR(XPATH_EXPR_ERROR);
6867 }
6868 NEXT;
6869 SKIP_BLANKS;
6870 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006871 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
6872 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006873 NEXT;
6874 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006875}
6876
6877/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006878 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006879 * @ctxt: the XPath Parser context
6880 *
6881 * [15] PrimaryExpr ::= VariableReference
6882 * | '(' Expr ')'
6883 * | Literal
6884 * | Number
6885 * | FunctionCall
6886 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006887 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006888 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006889static void
6890xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006891 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006892 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006893 else if (CUR == '(') {
6894 NEXT;
6895 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006896 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006897 if (CUR != ')') {
6898 XP_ERROR(XPATH_EXPR_ERROR);
6899 }
6900 NEXT;
6901 SKIP_BLANKS;
6902 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006903 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006904 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006905 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006906 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006907 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006908 }
6909 SKIP_BLANKS;
6910}
6911
6912/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006913 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006914 * @ctxt: the XPath Parser context
6915 *
6916 * [20] FilterExpr ::= PrimaryExpr
6917 * | FilterExpr Predicate
6918 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006919 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006920 * Square brackets are used to filter expressions in the same way that
6921 * they are used in location paths. It is an error if the expression to
6922 * be filtered does not evaluate to a node-set. The context node list
6923 * used for evaluating the expression in square brackets is the node-set
6924 * to be filtered listed in document order.
6925 */
6926
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006927static void
6928xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
6929 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006930 CHECK_ERROR;
6931 SKIP_BLANKS;
6932
6933 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006934 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00006935 SKIP_BLANKS;
6936 }
6937
6938
6939}
6940
6941/**
6942 * xmlXPathScanName:
6943 * @ctxt: the XPath Parser context
6944 *
6945 * Trickery: parse an XML name but without consuming the input flow
6946 * Needed to avoid insanity in the parser state.
6947 *
6948 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6949 * CombiningChar | Extender
6950 *
6951 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6952 *
6953 * [6] Names ::= Name (S Name)*
6954 *
6955 * Returns the Name parsed or NULL
6956 */
6957
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006958static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006959xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
6960 xmlChar buf[XML_MAX_NAMELEN];
6961 int len = 0;
6962
6963 SKIP_BLANKS;
6964 if (!IS_LETTER(CUR) && (CUR != '_') &&
6965 (CUR != ':')) {
6966 return(NULL);
6967 }
6968
6969 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
6970 (NXT(len) == '.') || (NXT(len) == '-') ||
6971 (NXT(len) == '_') || (NXT(len) == ':') ||
6972 (IS_COMBINING(NXT(len))) ||
6973 (IS_EXTENDER(NXT(len)))) {
6974 buf[len] = NXT(len);
6975 len++;
6976 if (len >= XML_MAX_NAMELEN) {
6977 xmlGenericError(xmlGenericErrorContext,
6978 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
6979 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
6980 (NXT(len) == '.') || (NXT(len) == '-') ||
6981 (NXT(len) == '_') || (NXT(len) == ':') ||
6982 (IS_COMBINING(NXT(len))) ||
6983 (IS_EXTENDER(NXT(len))))
6984 len++;
6985 break;
6986 }
6987 }
6988 return(xmlStrndup(buf, len));
6989}
6990
6991/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006992 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006993 * @ctxt: the XPath Parser context
6994 *
6995 * [19] PathExpr ::= LocationPath
6996 * | FilterExpr
6997 * | FilterExpr '/' RelativeLocationPath
6998 * | FilterExpr '//' RelativeLocationPath
6999 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007000 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007001 * The / operator and // operators combine an arbitrary expression
7002 * and a relative location path. It is an error if the expression
7003 * does not evaluate to a node-set.
7004 * The / operator does composition in the same way as when / is
7005 * used in a location path. As in location paths, // is short for
7006 * /descendant-or-self::node()/.
7007 */
7008
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007009static void
7010xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007011 int lc = 1; /* Should we branch to LocationPath ? */
7012 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7013
7014 SKIP_BLANKS;
7015 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
7016 (CUR == '\'') || (CUR == '"')) {
7017 lc = 0;
7018 } else if (CUR == '*') {
7019 /* relative or absolute location path */
7020 lc = 1;
7021 } else if (CUR == '/') {
7022 /* relative or absolute location path */
7023 lc = 1;
7024 } else if (CUR == '@') {
7025 /* relative abbreviated attribute location path */
7026 lc = 1;
7027 } else if (CUR == '.') {
7028 /* relative abbreviated attribute location path */
7029 lc = 1;
7030 } else {
7031 /*
7032 * Problem is finding if we have a name here whether it's:
7033 * - a nodetype
7034 * - a function call in which case it's followed by '('
7035 * - an axis in which case it's followed by ':'
7036 * - a element name
7037 * We do an a priori analysis here rather than having to
7038 * maintain parsed token content through the recursive function
7039 * calls. This looks uglier but makes the code quite easier to
7040 * read/write/debug.
7041 */
7042 SKIP_BLANKS;
7043 name = xmlXPathScanName(ctxt);
7044 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7045#ifdef DEBUG_STEP
7046 xmlGenericError(xmlGenericErrorContext,
7047 "PathExpr: Axis\n");
7048#endif
7049 lc = 1;
7050 xmlFree(name);
7051 } else if (name != NULL) {
7052 int len =xmlStrlen(name);
7053 int blank = 0;
7054
7055
7056 while (NXT(len) != 0) {
7057 if (NXT(len) == '/') {
7058 /* element name */
7059#ifdef DEBUG_STEP
7060 xmlGenericError(xmlGenericErrorContext,
7061 "PathExpr: AbbrRelLocation\n");
7062#endif
7063 lc = 1;
7064 break;
7065 } else if (IS_BLANK(NXT(len))) {
7066 /* skip to next */
7067 blank = 1;
7068 } else if (NXT(len) == ':') {
7069#ifdef DEBUG_STEP
7070 xmlGenericError(xmlGenericErrorContext,
7071 "PathExpr: AbbrRelLocation\n");
7072#endif
7073 lc = 1;
7074 break;
7075 } else if ((NXT(len) == '(')) {
7076 /* Note Type or Function */
7077 if (xmlXPathIsNodeType(name)) {
7078#ifdef DEBUG_STEP
7079 xmlGenericError(xmlGenericErrorContext,
7080 "PathExpr: Type search\n");
7081#endif
7082 lc = 1;
7083 } else {
7084#ifdef DEBUG_STEP
7085 xmlGenericError(xmlGenericErrorContext,
7086 "PathExpr: function call\n");
7087#endif
7088 lc = 0;
7089 }
7090 break;
7091 } else if ((NXT(len) == '[')) {
7092 /* element name */
7093#ifdef DEBUG_STEP
7094 xmlGenericError(xmlGenericErrorContext,
7095 "PathExpr: AbbrRelLocation\n");
7096#endif
7097 lc = 1;
7098 break;
7099 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7100 (NXT(len) == '=')) {
7101 lc = 1;
7102 break;
7103 } else {
7104 lc = 1;
7105 break;
7106 }
7107 len++;
7108 }
7109 if (NXT(len) == 0) {
7110#ifdef DEBUG_STEP
7111 xmlGenericError(xmlGenericErrorContext,
7112 "PathExpr: AbbrRelLocation\n");
7113#endif
7114 /* element name */
7115 lc = 1;
7116 }
7117 xmlFree(name);
7118 } else {
7119 /* make sure all cases are covered explicitely */
7120 XP_ERROR(XPATH_EXPR_ERROR);
7121 }
7122 }
7123
7124 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007125 if (CUR == '/') {
7126 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7127 } else {
7128 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007129 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007130 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007131 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007132 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007133 CHECK_ERROR;
7134 if ((CUR == '/') && (NXT(1) == '/')) {
7135 SKIP(2);
7136 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007137
7138 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7139 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7140 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7141
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007142 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007143 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007144 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007145 }
7146 }
7147 SKIP_BLANKS;
7148}
7149
7150/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007151 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007152 * @ctxt: the XPath Parser context
7153 *
7154 * [18] UnionExpr ::= PathExpr
7155 * | UnionExpr '|' PathExpr
7156 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007157 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007158 */
7159
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007160static void
7161xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7162 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007163 CHECK_ERROR;
7164 SKIP_BLANKS;
7165 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007166 int op1 = ctxt->comp->last;
7167 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007168
7169 NEXT;
7170 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007171 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007172
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007173 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
7174
Owen Taylor3473f882001-02-23 17:55:21 +00007175 SKIP_BLANKS;
7176 }
Owen Taylor3473f882001-02-23 17:55:21 +00007177}
7178
7179/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007180 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007181 * @ctxt: the XPath Parser context
7182 *
7183 * [27] UnaryExpr ::= UnionExpr
7184 * | '-' UnaryExpr
7185 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007186 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007187 */
7188
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007189static void
7190xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007191 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007192 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007193
7194 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00007195 while (CUR == '-') {
7196 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007197 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007198 NEXT;
7199 SKIP_BLANKS;
7200 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007201
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007202 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007203 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007204 if (found) {
7205 if (minus)
7206 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
7207 else
7208 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007209 }
7210}
7211
7212/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007213 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007214 * @ctxt: the XPath Parser context
7215 *
7216 * [26] MultiplicativeExpr ::= UnaryExpr
7217 * | MultiplicativeExpr MultiplyOperator UnaryExpr
7218 * | MultiplicativeExpr 'div' UnaryExpr
7219 * | MultiplicativeExpr 'mod' UnaryExpr
7220 * [34] MultiplyOperator ::= '*'
7221 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007222 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007223 */
7224
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007225static void
7226xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
7227 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007228 CHECK_ERROR;
7229 SKIP_BLANKS;
7230 while ((CUR == '*') ||
7231 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
7232 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
7233 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007234 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007235
7236 if (CUR == '*') {
7237 op = 0;
7238 NEXT;
7239 } else if (CUR == 'd') {
7240 op = 1;
7241 SKIP(3);
7242 } else if (CUR == 'm') {
7243 op = 2;
7244 SKIP(3);
7245 }
7246 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007247 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007248 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007249 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007250 SKIP_BLANKS;
7251 }
7252}
7253
7254/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007255 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007256 * @ctxt: the XPath Parser context
7257 *
7258 * [25] AdditiveExpr ::= MultiplicativeExpr
7259 * | AdditiveExpr '+' MultiplicativeExpr
7260 * | AdditiveExpr '-' MultiplicativeExpr
7261 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007262 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007263 */
7264
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007265static void
7266xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007267
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007268 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007269 CHECK_ERROR;
7270 SKIP_BLANKS;
7271 while ((CUR == '+') || (CUR == '-')) {
7272 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007273 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007274
7275 if (CUR == '+') plus = 1;
7276 else plus = 0;
7277 NEXT;
7278 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007279 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007280 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007281 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007282 SKIP_BLANKS;
7283 }
7284}
7285
7286/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007287 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007288 * @ctxt: the XPath Parser context
7289 *
7290 * [24] RelationalExpr ::= AdditiveExpr
7291 * | RelationalExpr '<' AdditiveExpr
7292 * | RelationalExpr '>' AdditiveExpr
7293 * | RelationalExpr '<=' AdditiveExpr
7294 * | RelationalExpr '>=' AdditiveExpr
7295 *
7296 * A <= B > C is allowed ? Answer from James, yes with
7297 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
7298 * which is basically what got implemented.
7299 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007300 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00007301 * on the stack
7302 */
7303
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007304static void
7305xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
7306 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007307 CHECK_ERROR;
7308 SKIP_BLANKS;
7309 while ((CUR == '<') ||
7310 (CUR == '>') ||
7311 ((CUR == '<') && (NXT(1) == '=')) ||
7312 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007313 int inf, strict;
7314 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007315
7316 if (CUR == '<') inf = 1;
7317 else inf = 0;
7318 if (NXT(1) == '=') strict = 0;
7319 else strict = 1;
7320 NEXT;
7321 if (!strict) NEXT;
7322 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007323 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007324 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007325 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00007326 SKIP_BLANKS;
7327 }
7328}
7329
7330/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007331 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007332 * @ctxt: the XPath Parser context
7333 *
7334 * [23] EqualityExpr ::= RelationalExpr
7335 * | EqualityExpr '=' RelationalExpr
7336 * | EqualityExpr '!=' RelationalExpr
7337 *
7338 * A != B != C is allowed ? Answer from James, yes with
7339 * (RelationalExpr = RelationalExpr) = RelationalExpr
7340 * (RelationalExpr != RelationalExpr) != RelationalExpr
7341 * which is basically what got implemented.
7342 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007343 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007344 *
7345 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007346static void
7347xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
7348 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007349 CHECK_ERROR;
7350 SKIP_BLANKS;
7351 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007352 int eq;
7353 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007354
7355 if (CUR == '=') eq = 1;
7356 else eq = 0;
7357 NEXT;
7358 if (!eq) NEXT;
7359 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007360 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007361 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007362 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007363 SKIP_BLANKS;
7364 }
7365}
7366
7367/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007368 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007369 * @ctxt: the XPath Parser context
7370 *
7371 * [22] AndExpr ::= EqualityExpr
7372 * | AndExpr 'and' EqualityExpr
7373 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007374 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007375 *
7376 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007377static void
7378xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
7379 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007380 CHECK_ERROR;
7381 SKIP_BLANKS;
7382 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007383 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007384 SKIP(3);
7385 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007386 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007387 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007388 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007389 SKIP_BLANKS;
7390 }
7391}
7392
7393/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007394 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007395 * @ctxt: the XPath Parser context
7396 *
7397 * [14] Expr ::= OrExpr
7398 * [21] OrExpr ::= AndExpr
7399 * | OrExpr 'or' AndExpr
7400 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007401 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00007402 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007403static void
7404xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
7405 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007406 CHECK_ERROR;
7407 SKIP_BLANKS;
7408 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007409 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007410 SKIP(2);
7411 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007412 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007413 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007414 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
7415 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00007416 SKIP_BLANKS;
7417 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007418 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
7419 /* more ops could be optimized too */
7420 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
7421 }
Owen Taylor3473f882001-02-23 17:55:21 +00007422}
7423
7424/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007425 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00007426 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007427 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00007428 *
7429 * [8] Predicate ::= '[' PredicateExpr ']'
7430 * [9] PredicateExpr ::= Expr
7431 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007432 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00007433 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007434static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007435xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007436 int op1 = ctxt->comp->last;
7437
7438 SKIP_BLANKS;
7439 if (CUR != '[') {
7440 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7441 }
7442 NEXT;
7443 SKIP_BLANKS;
7444
7445 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007446 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007447 CHECK_ERROR;
7448
7449 if (CUR != ']') {
7450 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7451 }
7452
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007453 if (filter)
7454 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
7455 else
7456 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007457
7458 NEXT;
7459 SKIP_BLANKS;
7460}
7461
7462/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007463 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00007464 * @ctxt: the XPath Parser context
7465 * @test: pointer to a xmlXPathTestVal
7466 * @type: pointer to a xmlXPathTypeVal
7467 * @prefix: placeholder for a possible name prefix
7468 *
7469 * [7] NodeTest ::= NameTest
7470 * | NodeType '(' ')'
7471 * | 'processing-instruction' '(' Literal ')'
7472 *
7473 * [37] NameTest ::= '*'
7474 * | NCName ':' '*'
7475 * | QName
7476 * [38] NodeType ::= 'comment'
7477 * | 'text'
7478 * | 'processing-instruction'
7479 * | 'node'
7480 *
7481 * Returns the name found and update @test, @type and @prefix appropriately
7482 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007483static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007484xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
7485 xmlXPathTypeVal *type, const xmlChar **prefix,
7486 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00007487 int blanks;
7488
7489 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
7490 STRANGE;
7491 return(NULL);
7492 }
7493 *type = 0;
7494 *test = 0;
7495 *prefix = NULL;
7496 SKIP_BLANKS;
7497
7498 if ((name == NULL) && (CUR == '*')) {
7499 /*
7500 * All elements
7501 */
7502 NEXT;
7503 *test = NODE_TEST_ALL;
7504 return(NULL);
7505 }
7506
7507 if (name == NULL)
7508 name = xmlXPathParseNCName(ctxt);
7509 if (name == NULL) {
7510 XP_ERROR0(XPATH_EXPR_ERROR);
7511 }
7512
7513 blanks = IS_BLANK(CUR);
7514 SKIP_BLANKS;
7515 if (CUR == '(') {
7516 NEXT;
7517 /*
7518 * NodeType or PI search
7519 */
7520 if (xmlStrEqual(name, BAD_CAST "comment"))
7521 *type = NODE_TYPE_COMMENT;
7522 else if (xmlStrEqual(name, BAD_CAST "node"))
7523 *type = NODE_TYPE_NODE;
7524 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
7525 *type = NODE_TYPE_PI;
7526 else if (xmlStrEqual(name, BAD_CAST "text"))
7527 *type = NODE_TYPE_TEXT;
7528 else {
7529 if (name != NULL)
7530 xmlFree(name);
7531 XP_ERROR0(XPATH_EXPR_ERROR);
7532 }
7533
7534 *test = NODE_TEST_TYPE;
7535
7536 SKIP_BLANKS;
7537 if (*type == NODE_TYPE_PI) {
7538 /*
7539 * Specific case: search a PI by name.
7540 */
Owen Taylor3473f882001-02-23 17:55:21 +00007541 if (name != NULL)
7542 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00007543 name = NULL;
7544 if (CUR != ')') {
7545 name = xmlXPathParseLiteral(ctxt);
7546 CHECK_ERROR 0;
7547 SKIP_BLANKS;
7548 }
Owen Taylor3473f882001-02-23 17:55:21 +00007549 }
7550 if (CUR != ')') {
7551 if (name != NULL)
7552 xmlFree(name);
7553 XP_ERROR0(XPATH_UNCLOSED_ERROR);
7554 }
7555 NEXT;
7556 return(name);
7557 }
7558 *test = NODE_TEST_NAME;
7559 if ((!blanks) && (CUR == ':')) {
7560 NEXT;
7561
7562 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007563 * Since currently the parser context don't have a
7564 * namespace list associated:
7565 * The namespace name for this prefix can be computed
7566 * only at evaluation time. The compilation is done
7567 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00007568 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007569#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00007570 *prefix = xmlXPathNsLookup(ctxt->context, name);
7571 if (name != NULL)
7572 xmlFree(name);
7573 if (*prefix == NULL) {
7574 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
7575 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007576#else
7577 *prefix = name;
7578#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007579
7580 if (CUR == '*') {
7581 /*
7582 * All elements
7583 */
7584 NEXT;
7585 *test = NODE_TEST_ALL;
7586 return(NULL);
7587 }
7588
7589 name = xmlXPathParseNCName(ctxt);
7590 if (name == NULL) {
7591 XP_ERROR0(XPATH_EXPR_ERROR);
7592 }
7593 }
7594 return(name);
7595}
7596
7597/**
7598 * xmlXPathIsAxisName:
7599 * @name: a preparsed name token
7600 *
7601 * [6] AxisName ::= 'ancestor'
7602 * | 'ancestor-or-self'
7603 * | 'attribute'
7604 * | 'child'
7605 * | 'descendant'
7606 * | 'descendant-or-self'
7607 * | 'following'
7608 * | 'following-sibling'
7609 * | 'namespace'
7610 * | 'parent'
7611 * | 'preceding'
7612 * | 'preceding-sibling'
7613 * | 'self'
7614 *
7615 * Returns the axis or 0
7616 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007617static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00007618xmlXPathIsAxisName(const xmlChar *name) {
7619 xmlXPathAxisVal ret = 0;
7620 switch (name[0]) {
7621 case 'a':
7622 if (xmlStrEqual(name, BAD_CAST "ancestor"))
7623 ret = AXIS_ANCESTOR;
7624 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
7625 ret = AXIS_ANCESTOR_OR_SELF;
7626 if (xmlStrEqual(name, BAD_CAST "attribute"))
7627 ret = AXIS_ATTRIBUTE;
7628 break;
7629 case 'c':
7630 if (xmlStrEqual(name, BAD_CAST "child"))
7631 ret = AXIS_CHILD;
7632 break;
7633 case 'd':
7634 if (xmlStrEqual(name, BAD_CAST "descendant"))
7635 ret = AXIS_DESCENDANT;
7636 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
7637 ret = AXIS_DESCENDANT_OR_SELF;
7638 break;
7639 case 'f':
7640 if (xmlStrEqual(name, BAD_CAST "following"))
7641 ret = AXIS_FOLLOWING;
7642 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
7643 ret = AXIS_FOLLOWING_SIBLING;
7644 break;
7645 case 'n':
7646 if (xmlStrEqual(name, BAD_CAST "namespace"))
7647 ret = AXIS_NAMESPACE;
7648 break;
7649 case 'p':
7650 if (xmlStrEqual(name, BAD_CAST "parent"))
7651 ret = AXIS_PARENT;
7652 if (xmlStrEqual(name, BAD_CAST "preceding"))
7653 ret = AXIS_PRECEDING;
7654 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
7655 ret = AXIS_PRECEDING_SIBLING;
7656 break;
7657 case 's':
7658 if (xmlStrEqual(name, BAD_CAST "self"))
7659 ret = AXIS_SELF;
7660 break;
7661 }
7662 return(ret);
7663}
7664
7665/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007666 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00007667 * @ctxt: the XPath Parser context
7668 *
7669 * [4] Step ::= AxisSpecifier NodeTest Predicate*
7670 * | AbbreviatedStep
7671 *
7672 * [12] AbbreviatedStep ::= '.' | '..'
7673 *
7674 * [5] AxisSpecifier ::= AxisName '::'
7675 * | AbbreviatedAxisSpecifier
7676 *
7677 * [13] AbbreviatedAxisSpecifier ::= '@'?
7678 *
7679 * Modified for XPtr range support as:
7680 *
7681 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
7682 * | AbbreviatedStep
7683 * | 'range-to' '(' Expr ')' Predicate*
7684 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007685 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00007686 * A location step of . is short for self::node(). This is
7687 * particularly useful in conjunction with //. For example, the
7688 * location path .//para is short for
7689 * self::node()/descendant-or-self::node()/child::para
7690 * and so will select all para descendant elements of the context
7691 * node.
7692 * Similarly, a location step of .. is short for parent::node().
7693 * For example, ../title is short for parent::node()/child::title
7694 * and so will select the title children of the parent of the context
7695 * node.
7696 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007697static void
7698xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007699#ifdef LIBXML_XPTR_ENABLED
7700 int rangeto = 0;
7701 int op2 = -1;
7702#endif
7703
Owen Taylor3473f882001-02-23 17:55:21 +00007704 SKIP_BLANKS;
7705 if ((CUR == '.') && (NXT(1) == '.')) {
7706 SKIP(2);
7707 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007708 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
7709 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007710 } else if (CUR == '.') {
7711 NEXT;
7712 SKIP_BLANKS;
7713 } else {
7714 xmlChar *name = NULL;
7715 const xmlChar *prefix = NULL;
7716 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007717 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007718 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007719 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00007720
7721 /*
7722 * The modification needed for XPointer change to the production
7723 */
7724#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007725 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00007726 name = xmlXPathParseNCName(ctxt);
7727 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007728 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007729 xmlFree(name);
7730 SKIP_BLANKS;
7731 if (CUR != '(') {
7732 XP_ERROR(XPATH_EXPR_ERROR);
7733 }
7734 NEXT;
7735 SKIP_BLANKS;
7736
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007737 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007738 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00007739 CHECK_ERROR;
7740
7741 SKIP_BLANKS;
7742 if (CUR != ')') {
7743 XP_ERROR(XPATH_EXPR_ERROR);
7744 }
7745 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007746 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007747 goto eval_predicates;
7748 }
7749 }
7750#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00007751 if (CUR == '*') {
7752 axis = AXIS_CHILD;
7753 } else {
7754 if (name == NULL)
7755 name = xmlXPathParseNCName(ctxt);
7756 if (name != NULL) {
7757 axis = xmlXPathIsAxisName(name);
7758 if (axis != 0) {
7759 SKIP_BLANKS;
7760 if ((CUR == ':') && (NXT(1) == ':')) {
7761 SKIP(2);
7762 xmlFree(name);
7763 name = NULL;
7764 } else {
7765 /* an element name can conflict with an axis one :-\ */
7766 axis = AXIS_CHILD;
7767 }
Owen Taylor3473f882001-02-23 17:55:21 +00007768 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00007769 axis = AXIS_CHILD;
7770 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007771 } else if (CUR == '@') {
7772 NEXT;
7773 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00007774 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00007775 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00007776 }
Owen Taylor3473f882001-02-23 17:55:21 +00007777 }
7778
7779 CHECK_ERROR;
7780
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007781 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00007782 if (test == 0)
7783 return;
7784
7785#ifdef DEBUG_STEP
7786 xmlGenericError(xmlGenericErrorContext,
7787 "Basis : computing new set\n");
7788#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007789
Owen Taylor3473f882001-02-23 17:55:21 +00007790#ifdef DEBUG_STEP
7791 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007792 if (ctxt->value == NULL)
7793 xmlGenericError(xmlGenericErrorContext, "no value\n");
7794 else if (ctxt->value->nodesetval == NULL)
7795 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7796 else
7797 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007798#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007799
7800eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007801 op1 = ctxt->comp->last;
7802 ctxt->comp->last = -1;
7803
Owen Taylor3473f882001-02-23 17:55:21 +00007804 SKIP_BLANKS;
7805 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007806 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007807 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007808
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007809#ifdef LIBXML_XPTR_ENABLED
7810 if (rangeto) {
7811 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
7812 } else
7813#endif
7814 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
7815 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007816
Owen Taylor3473f882001-02-23 17:55:21 +00007817 }
7818#ifdef DEBUG_STEP
7819 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007820 if (ctxt->value == NULL)
7821 xmlGenericError(xmlGenericErrorContext, "no value\n");
7822 else if (ctxt->value->nodesetval == NULL)
7823 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7824 else
7825 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
7826 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007827#endif
7828}
7829
7830/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007831 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007832 * @ctxt: the XPath Parser context
7833 *
7834 * [3] RelativeLocationPath ::= Step
7835 * | RelativeLocationPath '/' Step
7836 * | AbbreviatedRelativeLocationPath
7837 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
7838 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007839 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00007840 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007841static void
Owen Taylor3473f882001-02-23 17:55:21 +00007842#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007843xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007844#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007845xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007846#endif
7847(xmlXPathParserContextPtr ctxt) {
7848 SKIP_BLANKS;
7849 if ((CUR == '/') && (NXT(1) == '/')) {
7850 SKIP(2);
7851 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007852 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7853 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007854 } else if (CUR == '/') {
7855 NEXT;
7856 SKIP_BLANKS;
7857 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007858 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007859 SKIP_BLANKS;
7860 while (CUR == '/') {
7861 if ((CUR == '/') && (NXT(1) == '/')) {
7862 SKIP(2);
7863 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007864 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00007865 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007866 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007867 } else if (CUR == '/') {
7868 NEXT;
7869 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007870 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007871 }
7872 SKIP_BLANKS;
7873 }
7874}
7875
7876/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007877 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007878 * @ctxt: the XPath Parser context
7879 *
7880 * [1] LocationPath ::= RelativeLocationPath
7881 * | AbsoluteLocationPath
7882 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
7883 * | AbbreviatedAbsoluteLocationPath
7884 * [10] AbbreviatedAbsoluteLocationPath ::=
7885 * '//' RelativeLocationPath
7886 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007887 * Compile a location path
7888 *
Owen Taylor3473f882001-02-23 17:55:21 +00007889 * // is short for /descendant-or-self::node()/. For example,
7890 * //para is short for /descendant-or-self::node()/child::para and
7891 * so will select any para element in the document (even a para element
7892 * that is a document element will be selected by //para since the
7893 * document element node is a child of the root node); div//para is
7894 * short for div/descendant-or-self::node()/child::para and so will
7895 * select all para descendants of div children.
7896 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007897static void
7898xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007899 SKIP_BLANKS;
7900 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007901 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007902 } else {
7903 while (CUR == '/') {
7904 if ((CUR == '/') && (NXT(1) == '/')) {
7905 SKIP(2);
7906 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007907 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7908 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007909 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007910 } else if (CUR == '/') {
7911 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00007912 SKIP_BLANKS;
7913 if ((CUR != 0 ) &&
7914 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
7915 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007916 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007917 }
7918 }
7919 }
7920}
7921
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007922/************************************************************************
7923 * *
7924 * XPath precompiled expression evaluation *
7925 * *
7926 ************************************************************************/
7927
Daniel Veillardf06307e2001-07-03 10:35:50 +00007928static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007929xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
7930
7931/**
7932 * xmlXPathNodeCollectAndTest:
7933 * @ctxt: the XPath Parser context
7934 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00007935 * @first: pointer to the first element in document order
7936 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007937 *
7938 * This is the function implementing a step: based on the current list
7939 * of nodes, it builds up a new list, looking at all nodes under that
7940 * axis and selecting them it also do the predicate filtering
7941 *
7942 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00007943 *
7944 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007945 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00007946static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007947xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00007948 xmlXPathStepOpPtr op,
7949 xmlNodePtr * first, xmlNodePtr * last)
7950{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007951 xmlXPathAxisVal axis = op->value;
7952 xmlXPathTestVal test = op->value2;
7953 xmlXPathTypeVal type = op->value3;
7954 const xmlChar *prefix = op->value4;
7955 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00007956 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007957
7958#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007959 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007960#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007961 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007962 xmlNodeSetPtr ret, list;
7963 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00007964 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007965 xmlNodePtr cur = NULL;
7966 xmlXPathObjectPtr obj;
7967 xmlNodeSetPtr nodelist;
7968 xmlNodePtr tmp;
7969
Daniel Veillardf06307e2001-07-03 10:35:50 +00007970 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007971 obj = valuePop(ctxt);
7972 addNode = xmlXPathNodeSetAdd;
Daniel Veillarde043ee12001-04-16 14:08:07 +00007973 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00007974 URI = xmlXPathNsLookup(ctxt->context, prefix);
7975 if (URI == NULL)
7976 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00007977 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007978#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007979 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007980#endif
7981 switch (axis) {
7982 case AXIS_ANCESTOR:
7983#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007984 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007985#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007986 first = NULL;
7987 next = xmlXPathNextAncestor;
7988 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007989 case AXIS_ANCESTOR_OR_SELF:
7990#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007991 xmlGenericError(xmlGenericErrorContext,
7992 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007993#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007994 first = NULL;
7995 next = xmlXPathNextAncestorOrSelf;
7996 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007997 case AXIS_ATTRIBUTE:
7998#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007999 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008000#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008001 first = NULL;
8002 last = NULL;
8003 next = xmlXPathNextAttribute;
8004 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008005 case AXIS_CHILD:
8006#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008007 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008008#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008009 last = NULL;
8010 next = xmlXPathNextChild;
8011 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008012 case AXIS_DESCENDANT:
8013#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008014 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008015#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008016 last = NULL;
8017 next = xmlXPathNextDescendant;
8018 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008019 case AXIS_DESCENDANT_OR_SELF:
8020#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008021 xmlGenericError(xmlGenericErrorContext,
8022 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008023#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008024 last = NULL;
8025 next = xmlXPathNextDescendantOrSelf;
8026 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008027 case AXIS_FOLLOWING:
8028#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008029 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008030#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008031 last = NULL;
8032 next = xmlXPathNextFollowing;
8033 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008034 case AXIS_FOLLOWING_SIBLING:
8035#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008036 xmlGenericError(xmlGenericErrorContext,
8037 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008038#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008039 last = NULL;
8040 next = xmlXPathNextFollowingSibling;
8041 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008042 case AXIS_NAMESPACE:
8043#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008044 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008045#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008046 first = NULL;
8047 last = NULL;
8048 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8049 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008050 case AXIS_PARENT:
8051#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008052 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008053#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008054 first = NULL;
8055 next = xmlXPathNextParent;
8056 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008057 case AXIS_PRECEDING:
8058#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008059 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008060#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008061 first = NULL;
8062 next = xmlXPathNextPrecedingInternal;
8063 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008064 case AXIS_PRECEDING_SIBLING:
8065#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008066 xmlGenericError(xmlGenericErrorContext,
8067 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008068#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008069 first = NULL;
8070 next = xmlXPathNextPrecedingSibling;
8071 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008072 case AXIS_SELF:
8073#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008074 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008075#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008076 first = NULL;
8077 last = NULL;
8078 next = xmlXPathNextSelf;
8079 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008080 }
8081 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008082 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008083
8084 nodelist = obj->nodesetval;
8085 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008086 xmlXPathFreeObject(obj);
8087 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8088 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008089 }
8090 addNode = xmlXPathNodeSetAddUnique;
8091 ret = NULL;
8092#ifdef DEBUG_STEP
8093 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008094 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008095 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008096 case NODE_TEST_NONE:
8097 xmlGenericError(xmlGenericErrorContext,
8098 " searching for none !!!\n");
8099 break;
8100 case NODE_TEST_TYPE:
8101 xmlGenericError(xmlGenericErrorContext,
8102 " searching for type %d\n", type);
8103 break;
8104 case NODE_TEST_PI:
8105 xmlGenericError(xmlGenericErrorContext,
8106 " searching for PI !!!\n");
8107 break;
8108 case NODE_TEST_ALL:
8109 xmlGenericError(xmlGenericErrorContext,
8110 " searching for *\n");
8111 break;
8112 case NODE_TEST_NS:
8113 xmlGenericError(xmlGenericErrorContext,
8114 " searching for namespace %s\n",
8115 prefix);
8116 break;
8117 case NODE_TEST_NAME:
8118 xmlGenericError(xmlGenericErrorContext,
8119 " searching for name %s\n", name);
8120 if (prefix != NULL)
8121 xmlGenericError(xmlGenericErrorContext,
8122 " with namespace %s\n", prefix);
8123 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008124 }
8125 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8126#endif
8127 /*
8128 * 2.3 Node Tests
8129 * - For the attribute axis, the principal node type is attribute.
8130 * - For the namespace axis, the principal node type is namespace.
8131 * - For other axes, the principal node type is element.
8132 *
8133 * A node test * is true for any node of the
8134 * principal node type. For example, child::* willi
8135 * select all element children of the context node
8136 */
8137 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008138 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008139 ctxt->context->node = nodelist->nodeTab[i];
8140
Daniel Veillardf06307e2001-07-03 10:35:50 +00008141 cur = NULL;
8142 list = xmlXPathNodeSetCreate(NULL);
8143 do {
8144 cur = next(ctxt, cur);
8145 if (cur == NULL)
8146 break;
8147 if ((first != NULL) && (*first == cur))
8148 break;
8149 if (((t % 256) == 0) &&
8150 (first != NULL) && (*first != NULL) &&
8151 (xmlXPathCmpNodes(*first, cur) >= 0))
8152 break;
8153 if ((last != NULL) && (*last == cur))
8154 break;
8155 if (((t % 256) == 0) &&
8156 (last != NULL) && (*last != NULL) &&
8157 (xmlXPathCmpNodes(cur, *last) >= 0))
8158 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008159 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008160#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008161 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8162#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008163 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008164 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008165 ctxt->context->node = tmp;
8166 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008167 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008168 if ((cur->type == type) ||
8169 ((type == NODE_TYPE_NODE) &&
8170 ((cur->type == XML_DOCUMENT_NODE) ||
8171 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8172 (cur->type == XML_ELEMENT_NODE) ||
8173 (cur->type == XML_PI_NODE) ||
8174 (cur->type == XML_COMMENT_NODE) ||
8175 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00008176 (cur->type == XML_TEXT_NODE))) ||
8177 ((type == NODE_TYPE_TEXT) &&
8178 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008179#ifdef DEBUG_STEP
8180 n++;
8181#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008182 addNode(list, cur);
8183 }
8184 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008185 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008186 if (cur->type == XML_PI_NODE) {
8187 if ((name != NULL) &&
8188 (!xmlStrEqual(name, cur->name)))
8189 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008190#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008191 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008192#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008193 addNode(list, cur);
8194 }
8195 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008196 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008197 if (axis == AXIS_ATTRIBUTE) {
8198 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008199#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008200 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008201#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008202 addNode(list, cur);
8203 }
8204 } else if (axis == AXIS_NAMESPACE) {
8205 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008206#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008207 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008208#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008209 addNode(list, cur);
8210 }
8211 } else {
8212 if (cur->type == XML_ELEMENT_NODE) {
8213 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008214#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008215 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008216#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008217 addNode(list, cur);
8218 } else if ((cur->ns != NULL) &&
8219 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008220#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008221 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008222#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008223 addNode(list, cur);
8224 }
8225 }
8226 }
8227 break;
8228 case NODE_TEST_NS:{
8229 TODO;
8230 break;
8231 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008232 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008233 switch (cur->type) {
8234 case XML_ELEMENT_NODE:
8235 if (xmlStrEqual(name, cur->name)) {
8236 if (prefix == NULL) {
8237 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008238#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008239 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008240#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008241 addNode(list, cur);
8242 }
8243 } else {
8244 if ((cur->ns != NULL) &&
8245 (xmlStrEqual(URI,
8246 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008247#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008248 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008249#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008250 addNode(list, cur);
8251 }
8252 }
8253 }
8254 break;
8255 case XML_ATTRIBUTE_NODE:{
8256 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008257
Daniel Veillardf06307e2001-07-03 10:35:50 +00008258 if (xmlStrEqual(name, attr->name)) {
8259 if (prefix == NULL) {
8260 if ((attr->ns == NULL) ||
8261 (attr->ns->prefix == NULL)) {
8262#ifdef DEBUG_STEP
8263 n++;
8264#endif
8265 addNode(list,
8266 (xmlNodePtr) attr);
8267 }
8268 } else {
8269 if ((attr->ns != NULL) &&
8270 (xmlStrEqual(URI,
8271 attr->ns->
8272 href))) {
8273#ifdef DEBUG_STEP
8274 n++;
8275#endif
8276 addNode(list,
8277 (xmlNodePtr) attr);
8278 }
8279 }
8280 }
8281 break;
8282 }
8283 case XML_NAMESPACE_DECL:
8284 if (cur->type == XML_NAMESPACE_DECL) {
8285 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008286
Daniel Veillardf06307e2001-07-03 10:35:50 +00008287 if ((ns->prefix != NULL) && (name != NULL)
8288 && (xmlStrEqual(ns->prefix, name))) {
8289#ifdef DEBUG_STEP
8290 n++;
8291#endif
8292 addNode(list, cur);
8293 }
8294 }
8295 break;
8296 default:
8297 break;
8298 }
8299 break;
8300 break;
8301 }
8302 } while (cur != NULL);
8303
8304 /*
8305 * If there is some predicate filtering do it now
8306 */
8307 if (op->ch2 != -1) {
8308 xmlXPathObjectPtr obj2;
8309
8310 valuePush(ctxt, xmlXPathWrapNodeSet(list));
8311 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
8312 CHECK_TYPE0(XPATH_NODESET);
8313 obj2 = valuePop(ctxt);
8314 list = obj2->nodesetval;
8315 obj2->nodesetval = NULL;
8316 xmlXPathFreeObject(obj2);
8317 }
8318 if (ret == NULL) {
8319 ret = list;
8320 } else {
8321 ret = xmlXPathNodeSetMerge(ret, list);
8322 xmlXPathFreeNodeSet(list);
8323 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008324 }
8325 ctxt->context->node = tmp;
8326#ifdef DEBUG_STEP
8327 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008328 "\nExamined %d nodes, found %d nodes at that step\n",
8329 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008330#endif
8331 xmlXPathFreeObject(obj);
8332 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillardf06307e2001-07-03 10:35:50 +00008333 return(t);
8334}
8335
8336/**
8337 * xmlXPathNodeCollectAndTestNth:
8338 * @ctxt: the XPath Parser context
8339 * @op: the XPath precompiled step operation
8340 * @indx: the index to collect
8341 * @first: pointer to the first element in document order
8342 * @last: pointer to the last element in document order
8343 *
8344 * This is the function implementing a step: based on the current list
8345 * of nodes, it builds up a new list, looking at all nodes under that
8346 * axis and selecting them it also do the predicate filtering
8347 *
8348 * Pushes the new NodeSet resulting from the search.
8349 * Returns the number of node traversed
8350 */
8351static int
8352xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
8353 xmlXPathStepOpPtr op, int indx,
8354 xmlNodePtr * first, xmlNodePtr * last)
8355{
8356 xmlXPathAxisVal axis = op->value;
8357 xmlXPathTestVal test = op->value2;
8358 xmlXPathTypeVal type = op->value3;
8359 const xmlChar *prefix = op->value4;
8360 const xmlChar *name = op->value5;
8361 const xmlChar *URI = NULL;
8362 int n = 0, t = 0;
8363
8364 int i;
8365 xmlNodeSetPtr list;
8366 xmlXPathTraversalFunction next = NULL;
8367 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
8368 xmlNodePtr cur = NULL;
8369 xmlXPathObjectPtr obj;
8370 xmlNodeSetPtr nodelist;
8371 xmlNodePtr tmp;
8372
8373 CHECK_TYPE0(XPATH_NODESET);
8374 obj = valuePop(ctxt);
8375 addNode = xmlXPathNodeSetAdd;
8376 if (prefix != NULL) {
8377 URI = xmlXPathNsLookup(ctxt->context, prefix);
8378 if (URI == NULL)
8379 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8380 }
8381#ifdef DEBUG_STEP_NTH
8382 xmlGenericError(xmlGenericErrorContext, "new step : ");
8383 if (first != NULL) {
8384 if (*first != NULL)
8385 xmlGenericError(xmlGenericErrorContext, "first = %s ",
8386 (*first)->name);
8387 else
8388 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
8389 }
8390 if (last != NULL) {
8391 if (*last != NULL)
8392 xmlGenericError(xmlGenericErrorContext, "last = %s ",
8393 (*last)->name);
8394 else
8395 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
8396 }
8397#endif
8398 switch (axis) {
8399 case AXIS_ANCESTOR:
8400#ifdef DEBUG_STEP_NTH
8401 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
8402#endif
8403 first = NULL;
8404 next = xmlXPathNextAncestor;
8405 break;
8406 case AXIS_ANCESTOR_OR_SELF:
8407#ifdef DEBUG_STEP_NTH
8408 xmlGenericError(xmlGenericErrorContext,
8409 "axis 'ancestors-or-self' ");
8410#endif
8411 first = NULL;
8412 next = xmlXPathNextAncestorOrSelf;
8413 break;
8414 case AXIS_ATTRIBUTE:
8415#ifdef DEBUG_STEP_NTH
8416 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
8417#endif
8418 first = NULL;
8419 last = NULL;
8420 next = xmlXPathNextAttribute;
8421 break;
8422 case AXIS_CHILD:
8423#ifdef DEBUG_STEP_NTH
8424 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
8425#endif
8426 last = NULL;
8427 next = xmlXPathNextChild;
8428 break;
8429 case AXIS_DESCENDANT:
8430#ifdef DEBUG_STEP_NTH
8431 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
8432#endif
8433 last = NULL;
8434 next = xmlXPathNextDescendant;
8435 break;
8436 case AXIS_DESCENDANT_OR_SELF:
8437#ifdef DEBUG_STEP_NTH
8438 xmlGenericError(xmlGenericErrorContext,
8439 "axis 'descendant-or-self' ");
8440#endif
8441 last = NULL;
8442 next = xmlXPathNextDescendantOrSelf;
8443 break;
8444 case AXIS_FOLLOWING:
8445#ifdef DEBUG_STEP_NTH
8446 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
8447#endif
8448 last = NULL;
8449 next = xmlXPathNextFollowing;
8450 break;
8451 case AXIS_FOLLOWING_SIBLING:
8452#ifdef DEBUG_STEP_NTH
8453 xmlGenericError(xmlGenericErrorContext,
8454 "axis 'following-siblings' ");
8455#endif
8456 last = NULL;
8457 next = xmlXPathNextFollowingSibling;
8458 break;
8459 case AXIS_NAMESPACE:
8460#ifdef DEBUG_STEP_NTH
8461 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
8462#endif
8463 last = NULL;
8464 first = NULL;
8465 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8466 break;
8467 case AXIS_PARENT:
8468#ifdef DEBUG_STEP_NTH
8469 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
8470#endif
8471 first = NULL;
8472 next = xmlXPathNextParent;
8473 break;
8474 case AXIS_PRECEDING:
8475#ifdef DEBUG_STEP_NTH
8476 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
8477#endif
8478 first = NULL;
8479 next = xmlXPathNextPrecedingInternal;
8480 break;
8481 case AXIS_PRECEDING_SIBLING:
8482#ifdef DEBUG_STEP_NTH
8483 xmlGenericError(xmlGenericErrorContext,
8484 "axis 'preceding-sibling' ");
8485#endif
8486 first = NULL;
8487 next = xmlXPathNextPrecedingSibling;
8488 break;
8489 case AXIS_SELF:
8490#ifdef DEBUG_STEP_NTH
8491 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
8492#endif
8493 first = NULL;
8494 last = NULL;
8495 next = xmlXPathNextSelf;
8496 break;
8497 }
8498 if (next == NULL)
8499 return(0);
8500
8501 nodelist = obj->nodesetval;
8502 if (nodelist == NULL) {
8503 xmlXPathFreeObject(obj);
8504 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8505 return(0);
8506 }
8507 addNode = xmlXPathNodeSetAddUnique;
8508#ifdef DEBUG_STEP_NTH
8509 xmlGenericError(xmlGenericErrorContext,
8510 " context contains %d nodes\n", nodelist->nodeNr);
8511 switch (test) {
8512 case NODE_TEST_NONE:
8513 xmlGenericError(xmlGenericErrorContext,
8514 " searching for none !!!\n");
8515 break;
8516 case NODE_TEST_TYPE:
8517 xmlGenericError(xmlGenericErrorContext,
8518 " searching for type %d\n", type);
8519 break;
8520 case NODE_TEST_PI:
8521 xmlGenericError(xmlGenericErrorContext,
8522 " searching for PI !!!\n");
8523 break;
8524 case NODE_TEST_ALL:
8525 xmlGenericError(xmlGenericErrorContext,
8526 " searching for *\n");
8527 break;
8528 case NODE_TEST_NS:
8529 xmlGenericError(xmlGenericErrorContext,
8530 " searching for namespace %s\n",
8531 prefix);
8532 break;
8533 case NODE_TEST_NAME:
8534 xmlGenericError(xmlGenericErrorContext,
8535 " searching for name %s\n", name);
8536 if (prefix != NULL)
8537 xmlGenericError(xmlGenericErrorContext,
8538 " with namespace %s\n", prefix);
8539 break;
8540 }
8541 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8542#endif
8543 /*
8544 * 2.3 Node Tests
8545 * - For the attribute axis, the principal node type is attribute.
8546 * - For the namespace axis, the principal node type is namespace.
8547 * - For other axes, the principal node type is element.
8548 *
8549 * A node test * is true for any node of the
8550 * principal node type. For example, child::* willi
8551 * select all element children of the context node
8552 */
8553 tmp = ctxt->context->node;
8554 list = xmlXPathNodeSetCreate(NULL);
8555 for (i = 0; i < nodelist->nodeNr; i++) {
8556 ctxt->context->node = nodelist->nodeTab[i];
8557
8558 cur = NULL;
8559 n = 0;
8560 do {
8561 cur = next(ctxt, cur);
8562 if (cur == NULL)
8563 break;
8564 if ((first != NULL) && (*first == cur))
8565 break;
8566 if (((t % 256) == 0) &&
8567 (first != NULL) && (*first != NULL) &&
8568 (xmlXPathCmpNodes(*first, cur) >= 0))
8569 break;
8570 if ((last != NULL) && (*last == cur))
8571 break;
8572 if (((t % 256) == 0) &&
8573 (last != NULL) && (*last != NULL) &&
8574 (xmlXPathCmpNodes(cur, *last) >= 0))
8575 break;
8576 t++;
8577 switch (test) {
8578 case NODE_TEST_NONE:
8579 ctxt->context->node = tmp;
8580 STRANGE return(0);
8581 case NODE_TEST_TYPE:
8582 if ((cur->type == type) ||
8583 ((type == NODE_TYPE_NODE) &&
8584 ((cur->type == XML_DOCUMENT_NODE) ||
8585 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8586 (cur->type == XML_ELEMENT_NODE) ||
8587 (cur->type == XML_PI_NODE) ||
8588 (cur->type == XML_COMMENT_NODE) ||
8589 (cur->type == XML_CDATA_SECTION_NODE) ||
8590 (cur->type == XML_TEXT_NODE)))) {
8591 n++;
8592 if (n == indx)
8593 addNode(list, cur);
8594 }
8595 break;
8596 case NODE_TEST_PI:
8597 if (cur->type == XML_PI_NODE) {
8598 if ((name != NULL) &&
8599 (!xmlStrEqual(name, cur->name)))
8600 break;
8601 n++;
8602 if (n == indx)
8603 addNode(list, cur);
8604 }
8605 break;
8606 case NODE_TEST_ALL:
8607 if (axis == AXIS_ATTRIBUTE) {
8608 if (cur->type == XML_ATTRIBUTE_NODE) {
8609 n++;
8610 if (n == indx)
8611 addNode(list, cur);
8612 }
8613 } else if (axis == AXIS_NAMESPACE) {
8614 if (cur->type == XML_NAMESPACE_DECL) {
8615 n++;
8616 if (n == indx)
8617 addNode(list, cur);
8618 }
8619 } else {
8620 if (cur->type == XML_ELEMENT_NODE) {
8621 if (prefix == NULL) {
8622 n++;
8623 if (n == indx)
8624 addNode(list, cur);
8625 } else if ((cur->ns != NULL) &&
8626 (xmlStrEqual(URI, cur->ns->href))) {
8627 n++;
8628 if (n == indx)
8629 addNode(list, cur);
8630 }
8631 }
8632 }
8633 break;
8634 case NODE_TEST_NS:{
8635 TODO;
8636 break;
8637 }
8638 case NODE_TEST_NAME:
8639 switch (cur->type) {
8640 case XML_ELEMENT_NODE:
8641 if (xmlStrEqual(name, cur->name)) {
8642 if (prefix == NULL) {
8643 if (cur->ns == NULL) {
8644 n++;
8645 if (n == indx)
8646 addNode(list, cur);
8647 }
8648 } else {
8649 if ((cur->ns != NULL) &&
8650 (xmlStrEqual(URI,
8651 cur->ns->href))) {
8652 n++;
8653 if (n == indx)
8654 addNode(list, cur);
8655 }
8656 }
8657 }
8658 break;
8659 case XML_ATTRIBUTE_NODE:{
8660 xmlAttrPtr attr = (xmlAttrPtr) cur;
8661
8662 if (xmlStrEqual(name, attr->name)) {
8663 if (prefix == NULL) {
8664 if ((attr->ns == NULL) ||
8665 (attr->ns->prefix == NULL)) {
8666 n++;
8667 if (n == indx)
8668 addNode(list, cur);
8669 }
8670 } else {
8671 if ((attr->ns != NULL) &&
8672 (xmlStrEqual(URI,
8673 attr->ns->
8674 href))) {
8675 n++;
8676 if (n == indx)
8677 addNode(list, cur);
8678 }
8679 }
8680 }
8681 break;
8682 }
8683 case XML_NAMESPACE_DECL:
8684 if (cur->type == XML_NAMESPACE_DECL) {
8685 xmlNsPtr ns = (xmlNsPtr) cur;
8686
8687 if ((ns->prefix != NULL) && (name != NULL)
8688 && (xmlStrEqual(ns->prefix, name))) {
8689 n++;
8690 if (n == indx)
8691 addNode(list, cur);
8692 }
8693 }
8694 break;
8695 default:
8696 break;
8697 }
8698 break;
8699 break;
8700 }
8701 } while (n < indx);
8702 }
8703 ctxt->context->node = tmp;
8704#ifdef DEBUG_STEP_NTH
8705 xmlGenericError(xmlGenericErrorContext,
8706 "\nExamined %d nodes, found %d nodes at that step\n",
8707 t, list->nodeNr);
8708#endif
8709 xmlXPathFreeObject(obj);
8710 valuePush(ctxt, xmlXPathWrapNodeSet(list));
8711 return(t);
8712}
8713
8714/**
8715 * xmlXPathCompOpEvalFirst:
8716 * @ctxt: the XPath parser context with the compiled expression
8717 * @op: an XPath compiled operation
8718 * @first: the first elem found so far
8719 *
8720 * Evaluate the Precompiled XPath operation searching only the first
8721 * element in document order
8722 *
8723 * Returns the number of examined objects.
8724 */
8725static int
8726xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
8727 xmlXPathStepOpPtr op, xmlNodePtr * first)
8728{
8729 int total = 0, cur;
8730 xmlXPathCompExprPtr comp;
8731 xmlXPathObjectPtr arg1, arg2;
8732
8733 comp = ctxt->comp;
8734 switch (op->op) {
8735 case XPATH_OP_END:
8736 return (0);
8737 case XPATH_OP_UNION:
8738 total =
8739 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
8740 first);
8741 if ((ctxt->value != NULL)
8742 && (ctxt->value->type == XPATH_NODESET)
8743 && (ctxt->value->nodesetval != NULL)
8744 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8745 /*
8746 * limit tree traversing to first node in the result
8747 */
8748 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8749 *first = ctxt->value->nodesetval->nodeTab[0];
8750 }
8751 cur =
8752 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
8753 first);
8754 CHECK_TYPE0(XPATH_NODESET);
8755 arg2 = valuePop(ctxt);
8756
8757 CHECK_TYPE0(XPATH_NODESET);
8758 arg1 = valuePop(ctxt);
8759
8760 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8761 arg2->nodesetval);
8762 valuePush(ctxt, arg1);
8763 xmlXPathFreeObject(arg2);
8764 /* optimizer */
8765 if (total > cur)
8766 xmlXPathCompSwap(op);
8767 return (total + cur);
8768 case XPATH_OP_ROOT:
8769 xmlXPathRoot(ctxt);
8770 return (0);
8771 case XPATH_OP_NODE:
8772 if (op->ch1 != -1)
8773 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8774 if (op->ch2 != -1)
8775 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8776 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8777 return (total);
8778 case XPATH_OP_RESET:
8779 if (op->ch1 != -1)
8780 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8781 if (op->ch2 != -1)
8782 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8783 ctxt->context->node = NULL;
8784 return (total);
8785 case XPATH_OP_COLLECT:{
8786 if (op->ch1 == -1)
8787 return (total);
8788
8789 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8790
8791 /*
8792 * Optimization for [n] selection where n is a number
8793 */
8794 if ((op->ch2 != -1) &&
8795 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8796 (comp->steps[op->ch2].ch1 == -1) &&
8797 (comp->steps[op->ch2].ch2 != -1) &&
8798 (comp->steps[comp->steps[op->ch2].ch2].op ==
8799 XPATH_OP_VALUE)) {
8800 xmlXPathObjectPtr val;
8801
8802 val = comp->steps[comp->steps[op->ch2].ch2].value4;
8803 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
8804 int indx = (int) val->floatval;
8805
8806 if (val->floatval == (float) indx) {
8807 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
8808 first, NULL);
8809 return (total);
8810 }
8811 }
8812 }
8813 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
8814 return (total);
8815 }
8816 case XPATH_OP_VALUE:
8817 valuePush(ctxt,
8818 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
8819 return (0);
8820 case XPATH_OP_SORT:
8821 if (op->ch1 != -1)
8822 total +=
8823 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
8824 first);
8825 if ((ctxt->value != NULL)
8826 && (ctxt->value->type == XPATH_NODESET)
8827 && (ctxt->value->nodesetval != NULL))
8828 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8829 return (total);
8830 default:
8831 return (xmlXPathCompOpEval(ctxt, op));
8832 }
8833}
8834
8835/**
8836 * xmlXPathCompOpEvalLast:
8837 * @ctxt: the XPath parser context with the compiled expression
8838 * @op: an XPath compiled operation
8839 * @last: the last elem found so far
8840 *
8841 * Evaluate the Precompiled XPath operation searching only the last
8842 * element in document order
8843 *
8844 * Returns the number of node traversed
8845 */
8846static int
8847xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
8848 xmlNodePtr * last)
8849{
8850 int total = 0, cur;
8851 xmlXPathCompExprPtr comp;
8852 xmlXPathObjectPtr arg1, arg2;
8853
8854 comp = ctxt->comp;
8855 switch (op->op) {
8856 case XPATH_OP_END:
8857 return (0);
8858 case XPATH_OP_UNION:
8859 total =
8860 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
8861 if ((ctxt->value != NULL)
8862 && (ctxt->value->type == XPATH_NODESET)
8863 && (ctxt->value->nodesetval != NULL)
8864 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8865 /*
8866 * limit tree traversing to first node in the result
8867 */
8868 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8869 *last =
8870 ctxt->value->nodesetval->nodeTab[ctxt->value->
8871 nodesetval->nodeNr -
8872 1];
8873 }
8874 cur =
8875 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
8876 if ((ctxt->value != NULL)
8877 && (ctxt->value->type == XPATH_NODESET)
8878 && (ctxt->value->nodesetval != NULL)
8879 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8880 }
8881 CHECK_TYPE0(XPATH_NODESET);
8882 arg2 = valuePop(ctxt);
8883
8884 CHECK_TYPE0(XPATH_NODESET);
8885 arg1 = valuePop(ctxt);
8886
8887 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8888 arg2->nodesetval);
8889 valuePush(ctxt, arg1);
8890 xmlXPathFreeObject(arg2);
8891 /* optimizer */
8892 if (total > cur)
8893 xmlXPathCompSwap(op);
8894 return (total + cur);
8895 case XPATH_OP_ROOT:
8896 xmlXPathRoot(ctxt);
8897 return (0);
8898 case XPATH_OP_NODE:
8899 if (op->ch1 != -1)
8900 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8901 if (op->ch2 != -1)
8902 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8903 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8904 return (total);
8905 case XPATH_OP_RESET:
8906 if (op->ch1 != -1)
8907 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8908 if (op->ch2 != -1)
8909 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8910 ctxt->context->node = NULL;
8911 return (total);
8912 case XPATH_OP_COLLECT:{
8913 if (op->ch1 == -1)
8914 return (0);
8915
8916 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8917
8918 /*
8919 * Optimization for [n] selection where n is a number
8920 */
8921 if ((op->ch2 != -1) &&
8922 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8923 (comp->steps[op->ch2].ch1 == -1) &&
8924 (comp->steps[op->ch2].ch2 != -1) &&
8925 (comp->steps[comp->steps[op->ch2].ch2].op ==
8926 XPATH_OP_VALUE)) {
8927 xmlXPathObjectPtr val;
8928
8929 val = comp->steps[comp->steps[op->ch2].ch2].value4;
8930 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
8931 int indx = (int) val->floatval;
8932
8933 if (val->floatval == (float) indx) {
8934 total +=
8935 xmlXPathNodeCollectAndTestNth(ctxt, op,
8936 indx, NULL,
8937 last);
8938 return (total);
8939 }
8940 }
8941 }
8942 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
8943 return (total);
8944 }
8945 case XPATH_OP_VALUE:
8946 valuePush(ctxt,
8947 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
8948 return (0);
8949 case XPATH_OP_SORT:
8950 if (op->ch1 != -1)
8951 total +=
8952 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
8953 last);
8954 if ((ctxt->value != NULL)
8955 && (ctxt->value->type == XPATH_NODESET)
8956 && (ctxt->value->nodesetval != NULL))
8957 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8958 return (total);
8959 default:
8960 return (xmlXPathCompOpEval(ctxt, op));
8961 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008962}
8963
Owen Taylor3473f882001-02-23 17:55:21 +00008964/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008965 * xmlXPathCompOpEval:
8966 * @ctxt: the XPath parser context with the compiled expression
8967 * @op: an XPath compiled operation
8968 *
8969 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008970 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008971 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008972static int
8973xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
8974{
8975 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008976 int equal, ret;
8977 xmlXPathCompExprPtr comp;
8978 xmlXPathObjectPtr arg1, arg2;
8979
8980 comp = ctxt->comp;
8981 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008982 case XPATH_OP_END:
8983 return (0);
8984 case XPATH_OP_AND:
8985 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8986 xmlXPathBooleanFunction(ctxt, 1);
8987 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
8988 return (total);
8989 arg2 = valuePop(ctxt);
8990 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8991 xmlXPathBooleanFunction(ctxt, 1);
8992 arg1 = valuePop(ctxt);
8993 arg1->boolval &= arg2->boolval;
8994 valuePush(ctxt, arg1);
8995 xmlXPathFreeObject(arg2);
8996 return (total);
8997 case XPATH_OP_OR:
8998 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8999 xmlXPathBooleanFunction(ctxt, 1);
9000 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9001 return (total);
9002 arg2 = valuePop(ctxt);
9003 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9004 xmlXPathBooleanFunction(ctxt, 1);
9005 arg1 = valuePop(ctxt);
9006 arg1->boolval |= arg2->boolval;
9007 valuePush(ctxt, arg1);
9008 xmlXPathFreeObject(arg2);
9009 return (total);
9010 case XPATH_OP_EQUAL:
9011 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9012 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9013 equal = xmlXPathEqualValues(ctxt);
9014 if (op->value)
9015 valuePush(ctxt, xmlXPathNewBoolean(equal));
9016 else
9017 valuePush(ctxt, xmlXPathNewBoolean(!equal));
9018 return (total);
9019 case XPATH_OP_CMP:
9020 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9021 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9022 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9023 valuePush(ctxt, xmlXPathNewBoolean(ret));
9024 return (total);
9025 case XPATH_OP_PLUS:
9026 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9027 if (op->ch2 != -1)
9028 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9029 if (op->value == 0)
9030 xmlXPathSubValues(ctxt);
9031 else if (op->value == 1)
9032 xmlXPathAddValues(ctxt);
9033 else if (op->value == 2)
9034 xmlXPathValueFlipSign(ctxt);
9035 else if (op->value == 3) {
9036 CAST_TO_NUMBER;
9037 CHECK_TYPE0(XPATH_NUMBER);
9038 }
9039 return (total);
9040 case XPATH_OP_MULT:
9041 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9042 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9043 if (op->value == 0)
9044 xmlXPathMultValues(ctxt);
9045 else if (op->value == 1)
9046 xmlXPathDivValues(ctxt);
9047 else if (op->value == 2)
9048 xmlXPathModValues(ctxt);
9049 return (total);
9050 case XPATH_OP_UNION:
9051 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9052 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9053 CHECK_TYPE0(XPATH_NODESET);
9054 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009055
Daniel Veillardf06307e2001-07-03 10:35:50 +00009056 CHECK_TYPE0(XPATH_NODESET);
9057 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009058
Daniel Veillardf06307e2001-07-03 10:35:50 +00009059 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9060 arg2->nodesetval);
9061 valuePush(ctxt, arg1);
9062 xmlXPathFreeObject(arg2);
9063 return (total);
9064 case XPATH_OP_ROOT:
9065 xmlXPathRoot(ctxt);
9066 return (total);
9067 case XPATH_OP_NODE:
9068 if (op->ch1 != -1)
9069 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9070 if (op->ch2 != -1)
9071 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9072 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9073 return (total);
9074 case XPATH_OP_RESET:
9075 if (op->ch1 != -1)
9076 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9077 if (op->ch2 != -1)
9078 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9079 ctxt->context->node = NULL;
9080 return (total);
9081 case XPATH_OP_COLLECT:{
9082 if (op->ch1 == -1)
9083 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009084
Daniel Veillardf06307e2001-07-03 10:35:50 +00009085 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009086
Daniel Veillardf06307e2001-07-03 10:35:50 +00009087 /*
9088 * Optimization for [n] selection where n is a number
9089 */
9090 if ((op->ch2 != -1) &&
9091 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9092 (comp->steps[op->ch2].ch1 == -1) &&
9093 (comp->steps[op->ch2].ch2 != -1) &&
9094 (comp->steps[comp->steps[op->ch2].ch2].op ==
9095 XPATH_OP_VALUE)) {
9096 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00009097
Daniel Veillardf06307e2001-07-03 10:35:50 +00009098 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9099 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9100 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009101
Daniel Veillardf06307e2001-07-03 10:35:50 +00009102 if (val->floatval == (float) indx) {
9103 total +=
9104 xmlXPathNodeCollectAndTestNth(ctxt, op,
9105 indx, NULL,
9106 NULL);
9107 return (total);
9108 }
9109 }
9110 }
9111 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
9112 return (total);
9113 }
9114 case XPATH_OP_VALUE:
9115 valuePush(ctxt,
9116 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9117 return (total);
9118 case XPATH_OP_VARIABLE:{
9119 if (op->ch1 != -1)
9120 total +=
9121 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9122 if (op->value5 == NULL)
9123 valuePush(ctxt,
9124 xmlXPathVariableLookup(ctxt->context,
9125 op->value4));
9126 else {
9127 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009128
Daniel Veillardf06307e2001-07-03 10:35:50 +00009129 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9130 if (URI == NULL) {
9131 xmlGenericError(xmlGenericErrorContext,
9132 "xmlXPathRunEval: variable %s bound to undefined prefix %s\n",
9133 op->value4, op->value5);
9134 return (total);
9135 }
9136 valuePush(ctxt,
9137 xmlXPathVariableLookupNS(ctxt->context,
9138 op->value4, URI));
9139 }
9140 return (total);
9141 }
9142 case XPATH_OP_FUNCTION:{
9143 xmlXPathFunction func;
9144 const xmlChar *oldFunc, *oldFuncURI;
9145
9146 if (op->ch1 != -1)
9147 total +=
9148 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9149 if (op->cache != NULL)
9150 func = (xmlXPathFunction) op->cache;
9151 else {
9152 const xmlChar *URI = NULL;
9153
9154 if (op->value5 == NULL)
9155 func =
9156 xmlXPathFunctionLookup(ctxt->context,
9157 op->value4);
9158 else {
9159 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9160 if (URI == NULL) {
9161 xmlGenericError(xmlGenericErrorContext,
9162 "xmlXPathRunEval: function %s bound to undefined prefix %s\n",
9163 op->value4, op->value5);
9164 return (total);
9165 }
9166 func = xmlXPathFunctionLookupNS(ctxt->context,
9167 op->value4, URI);
9168 }
9169 if (func == NULL) {
9170 xmlGenericError(xmlGenericErrorContext,
9171 "xmlXPathRunEval: function %s not found\n",
9172 op->value4);
9173 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
9174 return (total);
9175 }
9176 op->cache = (void *) func;
9177 op->cacheURI = (void *) URI;
9178 }
9179 oldFunc = ctxt->context->function;
9180 oldFuncURI = ctxt->context->functionURI;
9181 ctxt->context->function = op->value4;
9182 ctxt->context->functionURI = op->cacheURI;
9183 func(ctxt, op->value);
9184 ctxt->context->function = oldFunc;
9185 ctxt->context->functionURI = oldFuncURI;
9186 return (total);
9187 }
9188 case XPATH_OP_ARG:
9189 if (op->ch1 != -1)
9190 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9191 if (op->ch2 != -1)
9192 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9193 return (total);
9194 case XPATH_OP_PREDICATE:
9195 case XPATH_OP_FILTER:{
9196 xmlXPathObjectPtr res;
9197 xmlXPathObjectPtr obj, tmp;
9198 xmlNodeSetPtr newset = NULL;
9199 xmlNodeSetPtr oldset;
9200 xmlNodePtr oldnode;
9201 int i;
9202
9203 /*
9204 * Optimization for ()[1] selection i.e. the first elem
9205 */
9206 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9207 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9208 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
9209 xmlXPathObjectPtr val;
9210
9211 val = comp->steps[op->ch2].value4;
9212 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
9213 (val->floatval == 1.0)) {
9214 xmlNodePtr first = NULL;
9215
9216 total +=
9217 xmlXPathCompOpEvalFirst(ctxt,
9218 &comp->steps[op->ch1],
9219 &first);
9220 /*
9221 * The nodeset should be in document order,
9222 * Keep only the first value
9223 */
9224 if ((ctxt->value != NULL) &&
9225 (ctxt->value->type == XPATH_NODESET) &&
9226 (ctxt->value->nodesetval != NULL) &&
9227 (ctxt->value->nodesetval->nodeNr > 1))
9228 ctxt->value->nodesetval->nodeNr = 1;
9229 return (total);
9230 }
9231 }
9232 /*
9233 * Optimization for ()[last()] selection i.e. the last elem
9234 */
9235 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9236 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9237 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
9238 int f = comp->steps[op->ch2].ch1;
9239
9240 if ((f != -1) &&
9241 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
9242 (comp->steps[f].value5 == NULL) &&
9243 (comp->steps[f].value == 0) &&
9244 (comp->steps[f].value4 != NULL) &&
9245 (xmlStrEqual
9246 (comp->steps[f].value4, BAD_CAST "last"))) {
9247 xmlNodePtr last = NULL;
9248
9249 total +=
9250 xmlXPathCompOpEvalLast(ctxt,
9251 &comp->steps[op->ch1],
9252 &last);
9253 /*
9254 * The nodeset should be in document order,
9255 * Keep only the last value
9256 */
9257 if ((ctxt->value != NULL) &&
9258 (ctxt->value->type == XPATH_NODESET) &&
9259 (ctxt->value->nodesetval != NULL) &&
9260 (ctxt->value->nodesetval->nodeTab != NULL) &&
9261 (ctxt->value->nodesetval->nodeNr > 1)) {
9262 ctxt->value->nodesetval->nodeTab[0] =
9263 ctxt->value->nodesetval->nodeTab[ctxt->
9264 value->
9265 nodesetval->
9266 nodeNr -
9267 1];
9268 ctxt->value->nodesetval->nodeNr = 1;
9269 }
9270 return (total);
9271 }
9272 }
9273
9274 if (op->ch1 != -1)
9275 total +=
9276 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9277 if (op->ch2 == -1)
9278 return (total);
9279 if (ctxt->value == NULL)
9280 return (total);
9281
9282 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009283
9284#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009285 /*
9286 * Hum are we filtering the result of an XPointer expression
9287 */
9288 if (ctxt->value->type == XPATH_LOCATIONSET) {
9289 xmlLocationSetPtr newlocset = NULL;
9290 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009291
Daniel Veillardf06307e2001-07-03 10:35:50 +00009292 /*
9293 * Extract the old locset, and then evaluate the result of the
9294 * expression for all the element in the locset. use it to grow
9295 * up a new locset.
9296 */
9297 CHECK_TYPE0(XPATH_LOCATIONSET);
9298 obj = valuePop(ctxt);
9299 oldlocset = obj->user;
9300 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009301
Daniel Veillardf06307e2001-07-03 10:35:50 +00009302 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
9303 ctxt->context->contextSize = 0;
9304 ctxt->context->proximityPosition = 0;
9305 if (op->ch2 != -1)
9306 total +=
9307 xmlXPathCompOpEval(ctxt,
9308 &comp->steps[op->ch2]);
9309 res = valuePop(ctxt);
9310 if (res != NULL)
9311 xmlXPathFreeObject(res);
9312 valuePush(ctxt, obj);
9313 CHECK_ERROR0;
9314 return (total);
9315 }
9316 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009317
Daniel Veillardf06307e2001-07-03 10:35:50 +00009318 for (i = 0; i < oldlocset->locNr; i++) {
9319 /*
9320 * Run the evaluation with a node list made of a
9321 * single item in the nodelocset.
9322 */
9323 ctxt->context->node = oldlocset->locTab[i]->user;
9324 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9325 valuePush(ctxt, tmp);
9326 ctxt->context->contextSize = oldlocset->locNr;
9327 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009328
Daniel Veillardf06307e2001-07-03 10:35:50 +00009329 if (op->ch2 != -1)
9330 total +=
9331 xmlXPathCompOpEval(ctxt,
9332 &comp->steps[op->ch2]);
9333 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009334
Daniel Veillardf06307e2001-07-03 10:35:50 +00009335 /*
9336 * The result of the evaluation need to be tested to
9337 * decided whether the filter succeeded or not
9338 */
9339 res = valuePop(ctxt);
9340 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9341 xmlXPtrLocationSetAdd(newlocset,
9342 xmlXPathObjectCopy
9343 (oldlocset->locTab[i]));
9344 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009345
Daniel Veillardf06307e2001-07-03 10:35:50 +00009346 /*
9347 * Cleanup
9348 */
9349 if (res != NULL)
9350 xmlXPathFreeObject(res);
9351 if (ctxt->value == tmp) {
9352 res = valuePop(ctxt);
9353 xmlXPathFreeObject(res);
9354 }
9355
9356 ctxt->context->node = NULL;
9357 }
9358
9359 /*
9360 * The result is used as the new evaluation locset.
9361 */
9362 xmlXPathFreeObject(obj);
9363 ctxt->context->node = NULL;
9364 ctxt->context->contextSize = -1;
9365 ctxt->context->proximityPosition = -1;
9366 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
9367 ctxt->context->node = oldnode;
9368 return (total);
9369 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009370#endif /* LIBXML_XPTR_ENABLED */
9371
Daniel Veillardf06307e2001-07-03 10:35:50 +00009372 /*
9373 * Extract the old set, and then evaluate the result of the
9374 * expression for all the element in the set. use it to grow
9375 * up a new set.
9376 */
9377 CHECK_TYPE0(XPATH_NODESET);
9378 obj = valuePop(ctxt);
9379 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00009380
Daniel Veillardf06307e2001-07-03 10:35:50 +00009381 oldnode = ctxt->context->node;
9382 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009383
Daniel Veillardf06307e2001-07-03 10:35:50 +00009384 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
9385 ctxt->context->contextSize = 0;
9386 ctxt->context->proximityPosition = 0;
9387 if (op->ch2 != -1)
9388 total +=
9389 xmlXPathCompOpEval(ctxt,
9390 &comp->steps[op->ch2]);
9391 res = valuePop(ctxt);
9392 if (res != NULL)
9393 xmlXPathFreeObject(res);
9394 valuePush(ctxt, obj);
9395 ctxt->context->node = oldnode;
9396 CHECK_ERROR0;
9397 } else {
9398 /*
9399 * Initialize the new set.
9400 */
9401 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009402
Daniel Veillardf06307e2001-07-03 10:35:50 +00009403 for (i = 0; i < oldset->nodeNr; i++) {
9404 /*
9405 * Run the evaluation with a node list made of
9406 * a single item in the nodeset.
9407 */
9408 ctxt->context->node = oldset->nodeTab[i];
9409 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9410 valuePush(ctxt, tmp);
9411 ctxt->context->contextSize = oldset->nodeNr;
9412 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009413
Daniel Veillardf06307e2001-07-03 10:35:50 +00009414 if (op->ch2 != -1)
9415 total +=
9416 xmlXPathCompOpEval(ctxt,
9417 &comp->steps[op->ch2]);
9418 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009419
Daniel Veillardf06307e2001-07-03 10:35:50 +00009420 /*
9421 * The result of the evaluation need to be tested to
9422 * decided whether the filter succeeded or not
9423 */
9424 res = valuePop(ctxt);
9425 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9426 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
9427 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009428
Daniel Veillardf06307e2001-07-03 10:35:50 +00009429 /*
9430 * Cleanup
9431 */
9432 if (res != NULL)
9433 xmlXPathFreeObject(res);
9434 if (ctxt->value == tmp) {
9435 res = valuePop(ctxt);
9436 xmlXPathFreeObject(res);
9437 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009438
Daniel Veillardf06307e2001-07-03 10:35:50 +00009439 ctxt->context->node = NULL;
9440 }
9441
9442 /*
9443 * The result is used as the new evaluation set.
9444 */
9445 xmlXPathFreeObject(obj);
9446 ctxt->context->node = NULL;
9447 ctxt->context->contextSize = -1;
9448 ctxt->context->proximityPosition = -1;
9449 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
9450 }
9451 ctxt->context->node = oldnode;
9452 return (total);
9453 }
9454 case XPATH_OP_SORT:
9455 if (op->ch1 != -1)
9456 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9457 if ((ctxt->value != NULL) &&
9458 (ctxt->value->type == XPATH_NODESET) &&
9459 (ctxt->value->nodesetval != NULL))
9460 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9461 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009462#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009463 case XPATH_OP_RANGETO:{
9464 xmlXPathObjectPtr range;
9465 xmlXPathObjectPtr res, obj;
9466 xmlXPathObjectPtr tmp;
9467 xmlLocationSetPtr newset = NULL;
9468 xmlNodeSetPtr oldset;
9469 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009470
Daniel Veillardf06307e2001-07-03 10:35:50 +00009471 if (op->ch1 != -1)
9472 total +=
9473 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9474 if (op->ch2 == -1)
9475 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009476
Daniel Veillardf06307e2001-07-03 10:35:50 +00009477 CHECK_TYPE0(XPATH_NODESET);
9478 obj = valuePop(ctxt);
9479 oldset = obj->nodesetval;
9480 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009481
Daniel Veillardf06307e2001-07-03 10:35:50 +00009482 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009483
Daniel Veillardf06307e2001-07-03 10:35:50 +00009484 if (oldset != NULL) {
9485 for (i = 0; i < oldset->nodeNr; i++) {
9486 /*
9487 * Run the evaluation with a node list made of a single item
9488 * in the nodeset.
9489 */
9490 ctxt->context->node = oldset->nodeTab[i];
9491 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9492 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009493
Daniel Veillardf06307e2001-07-03 10:35:50 +00009494 if (op->ch2 != -1)
9495 total +=
9496 xmlXPathCompOpEval(ctxt,
9497 &comp->steps[op->ch2]);
9498 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009499
Daniel Veillardf06307e2001-07-03 10:35:50 +00009500 /*
9501 * The result of the evaluation need to be tested to
9502 * decided whether the filter succeeded or not
9503 */
9504 res = valuePop(ctxt);
9505 range =
9506 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
9507 res);
9508 if (range != NULL) {
9509 xmlXPtrLocationSetAdd(newset, range);
9510 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009511
Daniel Veillardf06307e2001-07-03 10:35:50 +00009512 /*
9513 * Cleanup
9514 */
9515 if (res != NULL)
9516 xmlXPathFreeObject(res);
9517 if (ctxt->value == tmp) {
9518 res = valuePop(ctxt);
9519 xmlXPathFreeObject(res);
9520 }
9521
9522 ctxt->context->node = NULL;
9523 }
9524 }
9525
9526 /*
9527 * The result is used as the new evaluation set.
9528 */
9529 xmlXPathFreeObject(obj);
9530 ctxt->context->node = NULL;
9531 ctxt->context->contextSize = -1;
9532 ctxt->context->proximityPosition = -1;
9533 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
9534 return (total);
9535 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009536#endif /* LIBXML_XPTR_ENABLED */
9537 }
9538 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009539 "XPath: unknown precompiled operation %d\n", op->op);
9540 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009541}
9542
9543/**
9544 * xmlXPathRunEval:
9545 * @ctxt: the XPath parser context with the compiled expression
9546 *
9547 * Evaluate the Precompiled XPath expression in the given context.
9548 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009549static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009550xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
9551 xmlXPathCompExprPtr comp;
9552
9553 if ((ctxt == NULL) || (ctxt->comp == NULL))
9554 return;
9555
9556 if (ctxt->valueTab == NULL) {
9557 /* Allocate the value stack */
9558 ctxt->valueTab = (xmlXPathObjectPtr *)
9559 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
9560 if (ctxt->valueTab == NULL) {
9561 xmlFree(ctxt);
9562 xmlGenericError(xmlGenericErrorContext,
9563 "xmlXPathRunEval: out of memory\n");
9564 return;
9565 }
9566 ctxt->valueNr = 0;
9567 ctxt->valueMax = 10;
9568 ctxt->value = NULL;
9569 }
9570 comp = ctxt->comp;
9571 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
9572}
9573
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009574/************************************************************************
9575 * *
9576 * Public interfaces *
9577 * *
9578 ************************************************************************/
9579
9580/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009581 * xmlXPathEvalPredicate:
9582 * @ctxt: the XPath context
9583 * @res: the Predicate Expression evaluation result
9584 *
9585 * Evaluate a predicate result for the current node.
9586 * A PredicateExpr is evaluated by evaluating the Expr and converting
9587 * the result to a boolean. If the result is a number, the result will
9588 * be converted to true if the number is equal to the position of the
9589 * context node in the context node list (as returned by the position
9590 * function) and will be converted to false otherwise; if the result
9591 * is not a number, then the result will be converted as if by a call
9592 * to the boolean function.
9593 *
9594 * Return 1 if predicate is true, 0 otherwise
9595 */
9596int
9597xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
9598 if (res == NULL) return(0);
9599 switch (res->type) {
9600 case XPATH_BOOLEAN:
9601 return(res->boolval);
9602 case XPATH_NUMBER:
9603 return(res->floatval == ctxt->proximityPosition);
9604 case XPATH_NODESET:
9605 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009606 if (res->nodesetval == NULL)
9607 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009608 return(res->nodesetval->nodeNr != 0);
9609 case XPATH_STRING:
9610 return((res->stringval != NULL) &&
9611 (xmlStrlen(res->stringval) != 0));
9612 default:
9613 STRANGE
9614 }
9615 return(0);
9616}
9617
9618/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009619 * xmlXPathEvaluatePredicateResult:
9620 * @ctxt: the XPath Parser context
9621 * @res: the Predicate Expression evaluation result
9622 *
9623 * Evaluate a predicate result for the current node.
9624 * A PredicateExpr is evaluated by evaluating the Expr and converting
9625 * the result to a boolean. If the result is a number, the result will
9626 * be converted to true if the number is equal to the position of the
9627 * context node in the context node list (as returned by the position
9628 * function) and will be converted to false otherwise; if the result
9629 * is not a number, then the result will be converted as if by a call
9630 * to the boolean function.
9631 *
9632 * Return 1 if predicate is true, 0 otherwise
9633 */
9634int
9635xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
9636 xmlXPathObjectPtr res) {
9637 if (res == NULL) return(0);
9638 switch (res->type) {
9639 case XPATH_BOOLEAN:
9640 return(res->boolval);
9641 case XPATH_NUMBER:
9642 return(res->floatval == ctxt->context->proximityPosition);
9643 case XPATH_NODESET:
9644 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +00009645 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +00009646 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009647 return(res->nodesetval->nodeNr != 0);
9648 case XPATH_STRING:
9649 return((res->stringval != NULL) &&
9650 (xmlStrlen(res->stringval) != 0));
9651 default:
9652 STRANGE
9653 }
9654 return(0);
9655}
9656
9657/**
9658 * xmlXPathCompile:
9659 * @str: the XPath expression
9660 *
9661 * Compile an XPath expression
9662 *
9663 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9664 * the caller has to free the object.
9665 */
9666xmlXPathCompExprPtr
9667xmlXPathCompile(const xmlChar *str) {
9668 xmlXPathParserContextPtr ctxt;
9669 xmlXPathCompExprPtr comp;
9670
9671 xmlXPathInit();
9672
9673 ctxt = xmlXPathNewParserContext(str, NULL);
9674 xmlXPathCompileExpr(ctxt);
9675
Daniel Veillard40af6492001-04-22 08:50:55 +00009676 if (*ctxt->cur != 0) {
9677 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9678 comp = NULL;
9679 } else {
9680 comp = ctxt->comp;
9681 ctxt->comp = NULL;
9682 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009683 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009684#ifdef DEBUG_EVAL_COUNTS
9685 if (comp != NULL) {
9686 comp->string = xmlStrdup(str);
9687 comp->nb = 0;
9688 }
9689#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009690 return(comp);
9691}
9692
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009693/**
9694 * xmlXPathCompiledEval:
9695 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +00009696 * @ctx: the XPath context
9697 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009698 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +00009699 *
9700 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9701 * the caller has to free the object.
9702 */
9703xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009704xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +00009705 xmlXPathParserContextPtr ctxt;
9706 xmlXPathObjectPtr res, tmp, init = NULL;
9707 int stack = 0;
9708
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009709 if ((comp == NULL) || (ctx == NULL))
9710 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00009711 xmlXPathInit();
9712
9713 CHECK_CONTEXT(ctx)
9714
Daniel Veillardf06307e2001-07-03 10:35:50 +00009715#ifdef DEBUG_EVAL_COUNTS
9716 comp->nb++;
9717 if ((comp->string != NULL) && (comp->nb > 100)) {
9718 fprintf(stderr, "100 x %s\n", comp->string);
9719 comp->nb = 0;
9720 }
9721#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009722 ctxt = xmlXPathCompParserContext(comp, ctx);
9723 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009724
9725 if (ctxt->value == NULL) {
9726 xmlGenericError(xmlGenericErrorContext,
9727 "xmlXPathEval: evaluation failed\n");
9728 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009729 } else {
9730 res = valuePop(ctxt);
9731 }
9732
Daniel Veillardf06307e2001-07-03 10:35:50 +00009733
Owen Taylor3473f882001-02-23 17:55:21 +00009734 do {
9735 tmp = valuePop(ctxt);
9736 if (tmp != NULL) {
9737 if (tmp != init)
9738 stack++;
9739 xmlXPathFreeObject(tmp);
9740 }
9741 } while (tmp != NULL);
9742 if ((stack != 0) && (res != NULL)) {
9743 xmlGenericError(xmlGenericErrorContext,
9744 "xmlXPathEval: %d object left on the stack\n",
9745 stack);
9746 }
9747 if (ctxt->error != XPATH_EXPRESSION_OK) {
9748 xmlXPathFreeObject(res);
9749 res = NULL;
9750 }
9751
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009752
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009753 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009754 xmlXPathFreeParserContext(ctxt);
9755 return(res);
9756}
9757
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009758/**
9759 * xmlXPathEvalExpr:
9760 * @ctxt: the XPath Parser context
9761 *
9762 * Parse and evaluate an XPath expression in the given context,
9763 * then push the result on the context stack
9764 */
9765void
9766xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
9767 xmlXPathCompileExpr(ctxt);
9768 xmlXPathRunEval(ctxt);
9769}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009770
9771/**
9772 * xmlXPathEval:
9773 * @str: the XPath expression
9774 * @ctx: the XPath context
9775 *
9776 * Evaluate the XPath Location Path in the given context.
9777 *
9778 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9779 * the caller has to free the object.
9780 */
9781xmlXPathObjectPtr
9782xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
9783 xmlXPathParserContextPtr ctxt;
9784 xmlXPathObjectPtr res, tmp, init = NULL;
9785 int stack = 0;
9786
9787 xmlXPathInit();
9788
9789 CHECK_CONTEXT(ctx)
9790
9791 ctxt = xmlXPathNewParserContext(str, ctx);
9792 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009793
9794 if (ctxt->value == NULL) {
9795 xmlGenericError(xmlGenericErrorContext,
9796 "xmlXPathEval: evaluation failed\n");
9797 res = NULL;
9798 } else if (*ctxt->cur != 0) {
9799 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9800 res = NULL;
9801 } else {
9802 res = valuePop(ctxt);
9803 }
9804
9805 do {
9806 tmp = valuePop(ctxt);
9807 if (tmp != NULL) {
9808 if (tmp != init)
9809 stack++;
9810 xmlXPathFreeObject(tmp);
9811 }
9812 } while (tmp != NULL);
9813 if ((stack != 0) && (res != NULL)) {
9814 xmlGenericError(xmlGenericErrorContext,
9815 "xmlXPathEval: %d object left on the stack\n",
9816 stack);
9817 }
9818 if (ctxt->error != XPATH_EXPRESSION_OK) {
9819 xmlXPathFreeObject(res);
9820 res = NULL;
9821 }
9822
Owen Taylor3473f882001-02-23 17:55:21 +00009823 xmlXPathFreeParserContext(ctxt);
9824 return(res);
9825}
9826
9827/**
9828 * xmlXPathEvalExpression:
9829 * @str: the XPath expression
9830 * @ctxt: the XPath context
9831 *
9832 * Evaluate the XPath expression in the given context.
9833 *
9834 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
9835 * the caller has to free the object.
9836 */
9837xmlXPathObjectPtr
9838xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
9839 xmlXPathParserContextPtr pctxt;
9840 xmlXPathObjectPtr res, tmp;
9841 int stack = 0;
9842
9843 xmlXPathInit();
9844
9845 CHECK_CONTEXT(ctxt)
9846
9847 pctxt = xmlXPathNewParserContext(str, ctxt);
9848 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009849
9850 if (*pctxt->cur != 0) {
9851 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9852 res = NULL;
9853 } else {
9854 res = valuePop(pctxt);
9855 }
9856 do {
9857 tmp = valuePop(pctxt);
9858 if (tmp != NULL) {
9859 xmlXPathFreeObject(tmp);
9860 stack++;
9861 }
9862 } while (tmp != NULL);
9863 if ((stack != 0) && (res != NULL)) {
9864 xmlGenericError(xmlGenericErrorContext,
9865 "xmlXPathEvalExpression: %d object left on the stack\n",
9866 stack);
9867 }
9868 xmlXPathFreeParserContext(pctxt);
9869 return(res);
9870}
9871
9872/**
9873 * xmlXPathRegisterAllFunctions:
9874 * @ctxt: the XPath context
9875 *
9876 * Registers all default XPath functions in this context
9877 */
9878void
9879xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
9880{
9881 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
9882 xmlXPathBooleanFunction);
9883 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
9884 xmlXPathCeilingFunction);
9885 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
9886 xmlXPathCountFunction);
9887 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
9888 xmlXPathConcatFunction);
9889 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
9890 xmlXPathContainsFunction);
9891 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
9892 xmlXPathIdFunction);
9893 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
9894 xmlXPathFalseFunction);
9895 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
9896 xmlXPathFloorFunction);
9897 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
9898 xmlXPathLastFunction);
9899 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
9900 xmlXPathLangFunction);
9901 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
9902 xmlXPathLocalNameFunction);
9903 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
9904 xmlXPathNotFunction);
9905 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
9906 xmlXPathNameFunction);
9907 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
9908 xmlXPathNamespaceURIFunction);
9909 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
9910 xmlXPathNormalizeFunction);
9911 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
9912 xmlXPathNumberFunction);
9913 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
9914 xmlXPathPositionFunction);
9915 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
9916 xmlXPathRoundFunction);
9917 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
9918 xmlXPathStringFunction);
9919 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
9920 xmlXPathStringLengthFunction);
9921 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
9922 xmlXPathStartsWithFunction);
9923 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
9924 xmlXPathSubstringFunction);
9925 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
9926 xmlXPathSubstringBeforeFunction);
9927 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
9928 xmlXPathSubstringAfterFunction);
9929 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
9930 xmlXPathSumFunction);
9931 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
9932 xmlXPathTrueFunction);
9933 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
9934 xmlXPathTranslateFunction);
9935}
9936
9937#endif /* LIBXML_XPATH_ENABLED */