blob: 1fb3eea4606bff1d165a8058ec7c9eb0faaed864 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
5 *
6 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
11 * See COPYRIGHT for the status of this software
12 *
Daniel Veillardc5d64342001-06-24 12:13:24 +000013 * Author: daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000014 *
15 * 14 Nov 2000 ht - truncated declaration of xmlXPathEvalRelativeLocationPath
16 * for VMS
17 */
18
Bjorn Reese70a9da52001-04-21 16:57:29 +000019#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000020#ifdef LIBXML_XPATH_ENABLED
21
Owen Taylor3473f882001-02-23 17:55:21 +000022#include <string.h>
23
24#ifdef HAVE_SYS_TYPES_H
25#include <sys/types.h>
26#endif
27#ifdef HAVE_MATH_H
28#include <math.h>
29#endif
30#ifdef HAVE_FLOAT_H
31#include <float.h>
32#endif
33#ifdef HAVE_IEEEFP_H
34#include <ieeefp.h>
35#endif
36#ifdef HAVE_NAN_H
37#include <nan.h>
38#endif
39#ifdef HAVE_CTYPE_H
40#include <ctype.h>
41#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000042#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000043#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000044#endif
Owen Taylor3473f882001-02-23 17:55:21 +000045
46#include <libxml/xmlmemory.h>
47#include <libxml/tree.h>
48#include <libxml/valid.h>
49#include <libxml/xpath.h>
50#include <libxml/xpathInternals.h>
51#include <libxml/parserInternals.h>
52#include <libxml/hash.h>
53#ifdef LIBXML_XPTR_ENABLED
54#include <libxml/xpointer.h>
55#endif
56#ifdef LIBXML_DEBUG_ENABLED
57#include <libxml/debugXML.h>
58#endif
59#include <libxml/xmlerror.h>
60
61/* #define DEBUG */
62/* #define DEBUG_STEP */
Daniel Veillardf06307e2001-07-03 10:35:50 +000063/* #define DEBUG_STEP_NTH */
Owen Taylor3473f882001-02-23 17:55:21 +000064/* #define DEBUG_EXPR */
Daniel Veillardf06307e2001-07-03 10:35:50 +000065/* #define DEBUG_EVAL_COUNTS */
Owen Taylor3473f882001-02-23 17:55:21 +000066
67void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
68double xmlXPathStringEvalNumber(const xmlChar *str);
Daniel Veillard5792e162001-04-30 17:44:45 +000069double xmlXPathDivideBy(double f, double fzero);
Owen Taylor3473f882001-02-23 17:55:21 +000070
Daniel Veillard9e7160d2001-03-18 23:17:47 +000071/************************************************************************
72 * *
73 * Floating point stuff *
74 * *
75 ************************************************************************/
76
Owen Taylor3473f882001-02-23 17:55:21 +000077/*
Owen Taylor3473f882001-02-23 17:55:21 +000078 * The lack of portability of this section of the libc is annoying !
79 */
80double xmlXPathNAN = 0;
81double xmlXPathPINF = 1;
82double xmlXPathNINF = -1;
83
84#ifndef isinf
85#ifndef HAVE_ISINF
86
87#if HAVE_FPCLASS
88
89int isinf(double d) {
90 fpclass_t type = fpclass(d);
91 switch (type) {
92 case FP_NINF:
93 return(-1);
94 case FP_PINF:
95 return(1);
96 }
97 return(0);
98}
99
100#elif defined(HAVE_FP_CLASS) || defined(HAVE_FP_CLASS_D)
101
102#if HAVE_FP_CLASS_H
103#include <fp_class.h>
104#endif
105
106int isinf(double d) {
107#if HAVE_FP_CLASS
108 int fpclass = fp_class(d);
109#else
110 int fpclass = fp_class_d(d);
111#endif
112 if (fpclass == FP_POS_INF)
113 return(1);
114 if (fpclass == FP_NEG_INF)
115 return(-1);
116 return(0);
117}
118
119#elif defined(HAVE_CLASS)
120
121int isinf(double d) {
122 int fpclass = class(d);
123 if (fpclass == FP_PLUS_INF)
124 return(1);
125 if (fpclass == FP_MINUS_INF)
126 return(-1);
127 return(0);
128}
129#elif defined(finite) || defined(HAVE_FINITE)
130int isinf(double x) { return !finite(x) && x==x; }
131#elif defined(HUGE_VAL)
132int isinf(double x)
133{
134 if (x == HUGE_VAL)
135 return(1);
136 if (x == -HUGE_VAL)
137 return(-1);
138 return(0);
139}
140#endif
141
142#endif /* ! HAVE_ISINF */
143#endif /* ! defined(isinf) */
144
145#ifndef isnan
146#ifndef HAVE_ISNAN
147
148#ifdef HAVE_ISNAND
149#define isnan(f) isnand(f)
150#endif /* HAVE_iSNAND */
151
152#endif /* ! HAVE_iSNAN */
153#endif /* ! defined(isnan) */
154
Daniel Veillard5792e162001-04-30 17:44:45 +0000155
156/**
157 * xmlXPathDivideBy:
158 *
159 * The best way found so far to generate the NAN, +-INF
160 * without hitting a compiler bug or optimization :-\
161 *
162 * Returns the double resulting from the division
163 */
164double
165xmlXPathDivideBy(double f, double fzero) {
Daniel Veillard81418e32001-05-22 15:08:55 +0000166 double ret;
Daniel Veillard5792e162001-04-30 17:44:45 +0000167#ifdef HAVE_SIGNAL
168#ifdef SIGFPE
169#ifdef SIG_IGN
170 void (*sighandler)(int);
171 sighandler = signal(SIGFPE, SIG_IGN);
172#endif
173#endif
174#endif
175 ret = f / fzero;
176#ifdef HAVE_SIGNAL
177#ifdef SIGFPE
178#ifdef SIG_IGN
179 signal(SIGFPE, sighandler);
180#endif
181#endif
182#endif
183 return(ret);
184}
185
Owen Taylor3473f882001-02-23 17:55:21 +0000186/**
187 * xmlXPathInit:
188 *
189 * Initialize the XPath environment
190 */
191void
192xmlXPathInit(void) {
193 static int initialized = 0;
194
195 if (initialized) return;
196
Daniel Veillard5792e162001-04-30 17:44:45 +0000197 xmlXPathNAN = xmlXPathDivideBy(0.0, 0.0);
198 xmlXPathPINF = xmlXPathDivideBy(1.0, 0.0);
Daniel Veillard541d6552001-06-07 14:20:01 +0000199 xmlXPathNINF = xmlXPathDivideBy(-1.0, 0.0);
Owen Taylor3473f882001-02-23 17:55:21 +0000200
201 initialized = 1;
202}
203
204/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000205 * *
206 * Parser Types *
207 * *
208 ************************************************************************/
209
210/*
211 * Types are private:
212 */
213
214typedef enum {
215 XPATH_OP_END=0,
216 XPATH_OP_AND,
217 XPATH_OP_OR,
218 XPATH_OP_EQUAL,
219 XPATH_OP_CMP,
220 XPATH_OP_PLUS,
221 XPATH_OP_MULT,
222 XPATH_OP_UNION,
223 XPATH_OP_ROOT,
224 XPATH_OP_NODE,
225 XPATH_OP_RESET,
226 XPATH_OP_COLLECT,
227 XPATH_OP_VALUE,
228 XPATH_OP_VARIABLE,
229 XPATH_OP_FUNCTION,
230 XPATH_OP_ARG,
231 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000232 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000233 XPATH_OP_SORT
234#ifdef LIBXML_XPTR_ENABLED
235 ,XPATH_OP_RANGETO
236#endif
237} xmlXPathOp;
238
239typedef enum {
240 AXIS_ANCESTOR = 1,
241 AXIS_ANCESTOR_OR_SELF,
242 AXIS_ATTRIBUTE,
243 AXIS_CHILD,
244 AXIS_DESCENDANT,
245 AXIS_DESCENDANT_OR_SELF,
246 AXIS_FOLLOWING,
247 AXIS_FOLLOWING_SIBLING,
248 AXIS_NAMESPACE,
249 AXIS_PARENT,
250 AXIS_PRECEDING,
251 AXIS_PRECEDING_SIBLING,
252 AXIS_SELF
253} xmlXPathAxisVal;
254
255typedef enum {
256 NODE_TEST_NONE = 0,
257 NODE_TEST_TYPE = 1,
258 NODE_TEST_PI = 2,
259 NODE_TEST_ALL = 3,
260 NODE_TEST_NS = 4,
261 NODE_TEST_NAME = 5
262} xmlXPathTestVal;
263
264typedef enum {
265 NODE_TYPE_NODE = 0,
266 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
267 NODE_TYPE_TEXT = XML_TEXT_NODE,
268 NODE_TYPE_PI = XML_PI_NODE
269} xmlXPathTypeVal;
270
271
272typedef struct _xmlXPathStepOp xmlXPathStepOp;
273typedef xmlXPathStepOp *xmlXPathStepOpPtr;
274struct _xmlXPathStepOp {
275 xmlXPathOp op;
276 int ch1;
277 int ch2;
278 int value;
279 int value2;
280 int value3;
281 void *value4;
282 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000283 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000284 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000285};
286
287struct _xmlXPathCompExpr {
288 int nbStep;
289 int maxStep;
290 xmlXPathStepOp *steps; /* ops for computation */
291 int last;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000292#ifdef DEBUG_EVAL_COUNTS
293 int nb;
294 xmlChar *string;
295#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000296};
297
298/************************************************************************
299 * *
300 * Parser Type functions *
301 * *
302 ************************************************************************/
303
304/**
305 * xmlXPathNewCompExpr:
306 *
307 * Create a new Xpath component
308 *
309 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
310 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000311static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000312xmlXPathNewCompExpr(void) {
313 xmlXPathCompExprPtr cur;
314
315 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
316 if (cur == NULL) {
317 xmlGenericError(xmlGenericErrorContext,
318 "xmlXPathNewCompExpr : malloc failed\n");
319 return(NULL);
320 }
321 memset(cur, 0, sizeof(xmlXPathCompExpr));
322 cur->maxStep = 10;
323 cur->nbStep = 0;
324 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
325 sizeof(xmlXPathStepOp));
326 if (cur->steps == NULL) {
327 xmlGenericError(xmlGenericErrorContext,
328 "xmlXPathNewCompExpr : malloc failed\n");
329 xmlFree(cur);
330 return(NULL);
331 }
332 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
333 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000334#ifdef DEBUG_EVAL_COUNTS
335 cur->nb = 0;
336#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000337 return(cur);
338}
339
340/**
341 * xmlXPathFreeCompExpr:
342 * @comp: an XPATH comp
343 *
344 * Free up the memory allocated by @comp
345 */
346void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000347xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
348{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000349 xmlXPathStepOpPtr op;
350 int i;
351
352 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000353 return;
354 for (i = 0; i < comp->nbStep; i++) {
355 op = &comp->steps[i];
356 if (op->value4 != NULL) {
357 if (op->op == XPATH_OP_VALUE)
358 xmlXPathFreeObject(op->value4);
359 else
360 xmlFree(op->value4);
361 }
362 if (op->value5 != NULL)
363 xmlFree(op->value5);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000364 }
365 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000366 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000367 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000368#ifdef DEBUG_EVAL_COUNTS
369 if (comp->string != NULL) {
370 xmlFree(comp->string);
371 }
372#endif
373
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000374 xmlFree(comp);
375}
376
377/**
378 * xmlXPathCompExprAdd:
379 * @comp: the compiled expression
380 * @ch1: first child index
381 * @ch2: second child index
382 * @op: an op
383 * @value: the first int value
384 * @value2: the second int value
385 * @value3: the third int value
386 * @value4: the first string value
387 * @value5: the second string value
388 *
389 * Add an step to an XPath Compiled Expression
390 *
391 * Returns -1 in case of failure, the index otherwise
392 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000393static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000394xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
395 xmlXPathOp op, int value,
396 int value2, int value3, void *value4, void *value5) {
397 if (comp->nbStep >= comp->maxStep) {
398 xmlXPathStepOp *real;
399
400 comp->maxStep *= 2;
401 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
402 comp->maxStep * sizeof(xmlXPathStepOp));
403 if (real == NULL) {
404 comp->maxStep /= 2;
405 xmlGenericError(xmlGenericErrorContext,
406 "xmlXPathCompExprAdd : realloc failed\n");
407 return(-1);
408 }
409 comp->steps = real;
410 }
411 comp->last = comp->nbStep;
412 comp->steps[comp->nbStep].ch1 = ch1;
413 comp->steps[comp->nbStep].ch2 = ch2;
414 comp->steps[comp->nbStep].op = op;
415 comp->steps[comp->nbStep].value = value;
416 comp->steps[comp->nbStep].value2 = value2;
417 comp->steps[comp->nbStep].value3 = value3;
418 comp->steps[comp->nbStep].value4 = value4;
419 comp->steps[comp->nbStep].value5 = value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000420 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000421 return(comp->nbStep++);
422}
423
Daniel Veillardf06307e2001-07-03 10:35:50 +0000424/**
425 * xmlXPathCompSwap:
426 * @comp: the compiled expression
427 * @op: operation index
428 *
429 * Swaps 2 operations in the compiled expression
430 * TODO: not thread safe, disable for multi-thread operations
431 *
432 * Returns -1 in case of failure, the index otherwise
433 */
434static void
435xmlXPathCompSwap(xmlXPathStepOpPtr op) {
436 int tmp;
437
438 tmp = op->ch1;
439 op->ch1 = op->ch2;
440 op->ch2 = tmp;
441}
442
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000443#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
444 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
445 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000446#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
447 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
448 (op), (val), (val2), (val3), (val4), (val5))
449
450#define PUSH_LEAVE_EXPR(op, val, val2) \
451xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
452
453#define PUSH_UNARY_EXPR(op, ch, val, val2) \
454xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
455
456#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
457xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
458
459/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000460 * *
461 * Debugging related functions *
462 * *
463 ************************************************************************/
464
465#define TODO \
466 xmlGenericError(xmlGenericErrorContext, \
467 "Unimplemented block at %s:%d\n", \
468 __FILE__, __LINE__);
469
470#define STRANGE \
471 xmlGenericError(xmlGenericErrorContext, \
472 "Internal error at %s:%d\n", \
473 __FILE__, __LINE__);
474
475#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000476static void
477xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000478 int i;
479 char shift[100];
480
481 for (i = 0;((i < depth) && (i < 25));i++)
482 shift[2 * i] = shift[2 * i + 1] = ' ';
483 shift[2 * i] = shift[2 * i + 1] = 0;
484 if (cur == NULL) {
485 fprintf(output, shift);
486 fprintf(output, "Node is NULL !\n");
487 return;
488
489 }
490
491 if ((cur->type == XML_DOCUMENT_NODE) ||
492 (cur->type == XML_HTML_DOCUMENT_NODE)) {
493 fprintf(output, shift);
494 fprintf(output, " /\n");
495 } else if (cur->type == XML_ATTRIBUTE_NODE)
496 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
497 else
498 xmlDebugDumpOneNode(output, cur, depth);
499}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000500static void
501xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000502 xmlNodePtr tmp;
503 int i;
504 char shift[100];
505
506 for (i = 0;((i < depth) && (i < 25));i++)
507 shift[2 * i] = shift[2 * i + 1] = ' ';
508 shift[2 * i] = shift[2 * i + 1] = 0;
509 if (cur == NULL) {
510 fprintf(output, shift);
511 fprintf(output, "Node is NULL !\n");
512 return;
513
514 }
515
516 while (cur != NULL) {
517 tmp = cur;
518 cur = cur->next;
519 xmlDebugDumpOneNode(output, tmp, depth);
520 }
521}
Owen Taylor3473f882001-02-23 17:55:21 +0000522
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000523static void
524xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000525 int i;
526 char shift[100];
527
528 for (i = 0;((i < depth) && (i < 25));i++)
529 shift[2 * i] = shift[2 * i + 1] = ' ';
530 shift[2 * i] = shift[2 * i + 1] = 0;
531
532 if (cur == NULL) {
533 fprintf(output, shift);
534 fprintf(output, "NodeSet is NULL !\n");
535 return;
536
537 }
538
Daniel Veillard911f49a2001-04-07 15:39:35 +0000539 if (cur != NULL) {
540 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
541 for (i = 0;i < cur->nodeNr;i++) {
542 fprintf(output, shift);
543 fprintf(output, "%d", i + 1);
544 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
545 }
Owen Taylor3473f882001-02-23 17:55:21 +0000546 }
547}
548
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000549static void
550xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000551 int i;
552 char shift[100];
553
554 for (i = 0;((i < depth) && (i < 25));i++)
555 shift[2 * i] = shift[2 * i + 1] = ' ';
556 shift[2 * i] = shift[2 * i + 1] = 0;
557
558 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
559 fprintf(output, shift);
560 fprintf(output, "Value Tree is NULL !\n");
561 return;
562
563 }
564
565 fprintf(output, shift);
566 fprintf(output, "%d", i + 1);
567 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
568}
Owen Taylor3473f882001-02-23 17:55:21 +0000569#if defined(LIBXML_XPTR_ENABLED)
570void xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth);
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000571static void
572xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000573 int i;
574 char shift[100];
575
576 for (i = 0;((i < depth) && (i < 25));i++)
577 shift[2 * i] = shift[2 * i + 1] = ' ';
578 shift[2 * i] = shift[2 * i + 1] = 0;
579
580 if (cur == NULL) {
581 fprintf(output, shift);
582 fprintf(output, "LocationSet is NULL !\n");
583 return;
584
585 }
586
587 for (i = 0;i < cur->locNr;i++) {
588 fprintf(output, shift);
589 fprintf(output, "%d : ", i + 1);
590 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
591 }
592}
Daniel Veillard017b1082001-06-21 11:20:21 +0000593#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000594
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000595/**
596 * xmlXPathDebugDumpObject:
597 * @output: the FILE * to dump the output
598 * @cur: the object to inspect
599 * @depth: indentation level
600 *
601 * Dump the content of the object for debugging purposes
602 */
603void
604xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000605 int i;
606 char shift[100];
607
608 for (i = 0;((i < depth) && (i < 25));i++)
609 shift[2 * i] = shift[2 * i + 1] = ' ';
610 shift[2 * i] = shift[2 * i + 1] = 0;
611
612 fprintf(output, shift);
613
614 if (cur == NULL) {
615 fprintf(output, "Object is empty (NULL)\n");
616 return;
617 }
618 switch(cur->type) {
619 case XPATH_UNDEFINED:
620 fprintf(output, "Object is uninitialized\n");
621 break;
622 case XPATH_NODESET:
623 fprintf(output, "Object is a Node Set :\n");
624 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
625 break;
626 case XPATH_XSLT_TREE:
627 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000628 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000629 break;
630 case XPATH_BOOLEAN:
631 fprintf(output, "Object is a Boolean : ");
632 if (cur->boolval) fprintf(output, "true\n");
633 else fprintf(output, "false\n");
634 break;
635 case XPATH_NUMBER:
Daniel Veillard357c9602001-05-03 10:49:20 +0000636 switch (isinf(cur->floatval)) {
637 case 1:
638 fprintf(output, "Object is a number : +Infinity\n");
639 break;
640 case -1:
641 fprintf(output, "Object is a number : -Infinity\n");
642 break;
643 default:
644 if (isnan(cur->floatval)) {
645 fprintf(output, "Object is a number : NaN\n");
646 } else {
647 fprintf(output, "Object is a number : %0g\n", cur->floatval);
648 }
649 }
Owen Taylor3473f882001-02-23 17:55:21 +0000650 break;
651 case XPATH_STRING:
652 fprintf(output, "Object is a string : ");
653 xmlDebugDumpString(output, cur->stringval);
654 fprintf(output, "\n");
655 break;
656 case XPATH_POINT:
657 fprintf(output, "Object is a point : index %d in node", cur->index);
658 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
659 fprintf(output, "\n");
660 break;
661 case XPATH_RANGE:
662 if ((cur->user2 == NULL) ||
663 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
664 fprintf(output, "Object is a collapsed range :\n");
665 fprintf(output, shift);
666 if (cur->index >= 0)
667 fprintf(output, "index %d in ", cur->index);
668 fprintf(output, "node\n");
669 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
670 depth + 1);
671 } else {
672 fprintf(output, "Object is a range :\n");
673 fprintf(output, shift);
674 fprintf(output, "From ");
675 if (cur->index >= 0)
676 fprintf(output, "index %d in ", cur->index);
677 fprintf(output, "node\n");
678 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
679 depth + 1);
680 fprintf(output, shift);
681 fprintf(output, "To ");
682 if (cur->index2 >= 0)
683 fprintf(output, "index %d in ", cur->index2);
684 fprintf(output, "node\n");
685 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
686 depth + 1);
687 fprintf(output, "\n");
688 }
689 break;
690 case XPATH_LOCATIONSET:
691#if defined(LIBXML_XPTR_ENABLED)
692 fprintf(output, "Object is a Location Set:\n");
693 xmlXPathDebugDumpLocationSet(output,
694 (xmlLocationSetPtr) cur->user, depth);
695#endif
696 break;
697 case XPATH_USERS:
698 fprintf(output, "Object is user defined\n");
699 break;
700 }
701}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000702
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000703static void
704xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000705 xmlXPathStepOpPtr op, int depth) {
706 int i;
707 char shift[100];
708
709 for (i = 0;((i < depth) && (i < 25));i++)
710 shift[2 * i] = shift[2 * i + 1] = ' ';
711 shift[2 * i] = shift[2 * i + 1] = 0;
712
713 fprintf(output, shift);
714 if (op == NULL) {
715 fprintf(output, "Step is NULL\n");
716 return;
717 }
718 switch (op->op) {
719 case XPATH_OP_END:
720 fprintf(output, "END"); break;
721 case XPATH_OP_AND:
722 fprintf(output, "AND"); break;
723 case XPATH_OP_OR:
724 fprintf(output, "OR"); break;
725 case XPATH_OP_EQUAL:
726 if (op->value)
727 fprintf(output, "EQUAL =");
728 else
729 fprintf(output, "EQUAL !=");
730 break;
731 case XPATH_OP_CMP:
732 if (op->value)
733 fprintf(output, "CMP <");
734 else
735 fprintf(output, "CMP >");
736 if (!op->value2)
737 fprintf(output, "=");
738 break;
739 case XPATH_OP_PLUS:
740 if (op->value == 0)
741 fprintf(output, "PLUS -");
742 else if (op->value == 1)
743 fprintf(output, "PLUS +");
744 else if (op->value == 2)
745 fprintf(output, "PLUS unary -");
746 else if (op->value == 3)
747 fprintf(output, "PLUS unary - -");
748 break;
749 case XPATH_OP_MULT:
750 if (op->value == 0)
751 fprintf(output, "MULT *");
752 else if (op->value == 1)
753 fprintf(output, "MULT div");
754 else
755 fprintf(output, "MULT mod");
756 break;
757 case XPATH_OP_UNION:
758 fprintf(output, "UNION"); break;
759 case XPATH_OP_ROOT:
760 fprintf(output, "ROOT"); break;
761 case XPATH_OP_NODE:
762 fprintf(output, "NODE"); break;
763 case XPATH_OP_RESET:
764 fprintf(output, "RESET"); break;
765 case XPATH_OP_SORT:
766 fprintf(output, "SORT"); break;
767 case XPATH_OP_COLLECT: {
768 xmlXPathAxisVal axis = op->value;
769 xmlXPathTestVal test = op->value2;
770 xmlXPathTypeVal type = op->value3;
771 const xmlChar *prefix = op->value4;
772 const xmlChar *name = op->value5;
773
774 fprintf(output, "COLLECT ");
775 switch (axis) {
776 case AXIS_ANCESTOR:
777 fprintf(output, " 'ancestors' "); break;
778 case AXIS_ANCESTOR_OR_SELF:
779 fprintf(output, " 'ancestors-or-self' "); break;
780 case AXIS_ATTRIBUTE:
781 fprintf(output, " 'attributes' "); break;
782 case AXIS_CHILD:
783 fprintf(output, " 'child' "); break;
784 case AXIS_DESCENDANT:
785 fprintf(output, " 'descendant' "); break;
786 case AXIS_DESCENDANT_OR_SELF:
787 fprintf(output, " 'descendant-or-self' "); break;
788 case AXIS_FOLLOWING:
789 fprintf(output, " 'following' "); break;
790 case AXIS_FOLLOWING_SIBLING:
791 fprintf(output, " 'following-siblings' "); break;
792 case AXIS_NAMESPACE:
793 fprintf(output, " 'namespace' "); break;
794 case AXIS_PARENT:
795 fprintf(output, " 'parent' "); break;
796 case AXIS_PRECEDING:
797 fprintf(output, " 'preceding' "); break;
798 case AXIS_PRECEDING_SIBLING:
799 fprintf(output, " 'preceding-sibling' "); break;
800 case AXIS_SELF:
801 fprintf(output, " 'self' "); break;
802 }
803 switch (test) {
804 case NODE_TEST_NONE:
805 fprintf(output, "'none' "); break;
806 case NODE_TEST_TYPE:
807 fprintf(output, "'type' "); break;
808 case NODE_TEST_PI:
809 fprintf(output, "'PI' "); break;
810 case NODE_TEST_ALL:
811 fprintf(output, "'all' "); break;
812 case NODE_TEST_NS:
813 fprintf(output, "'namespace' "); break;
814 case NODE_TEST_NAME:
815 fprintf(output, "'name' "); break;
816 }
817 switch (type) {
818 case NODE_TYPE_NODE:
819 fprintf(output, "'node' "); break;
820 case NODE_TYPE_COMMENT:
821 fprintf(output, "'comment' "); break;
822 case NODE_TYPE_TEXT:
823 fprintf(output, "'text' "); break;
824 case NODE_TYPE_PI:
825 fprintf(output, "'PI' "); break;
826 }
827 if (prefix != NULL)
828 fprintf(output, "%s:", prefix);
829 if (name != NULL)
830 fprintf(output, "%s", name);
831 break;
832
833 }
834 case XPATH_OP_VALUE: {
835 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
836
837 fprintf(output, "ELEM ");
838 xmlXPathDebugDumpObject(output, object, 0);
839 goto finish;
840 }
841 case XPATH_OP_VARIABLE: {
842 const xmlChar *prefix = op->value5;
843 const xmlChar *name = op->value4;
844
845 if (prefix != NULL)
846 fprintf(output, "VARIABLE %s:%s", prefix, name);
847 else
848 fprintf(output, "VARIABLE %s", name);
849 break;
850 }
851 case XPATH_OP_FUNCTION: {
852 int nbargs = op->value;
853 const xmlChar *prefix = op->value5;
854 const xmlChar *name = op->value4;
855
856 if (prefix != NULL)
857 fprintf(output, "FUNCTION %s:%s(%d args)",
858 prefix, name, nbargs);
859 else
860 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
861 break;
862 }
863 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
864 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000865 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +0000866#ifdef LIBXML_XPTR_ENABLED
867 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
868#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000869 default:
870 fprintf(output, "UNKNOWN %d\n", op->op); return;
871 }
872 fprintf(output, "\n");
873finish:
874 if (op->ch1 >= 0)
875 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
876 if (op->ch2 >= 0)
877 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
878}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000879
880void
881xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
882 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000883 int i;
884 char shift[100];
885
886 for (i = 0;((i < depth) && (i < 25));i++)
887 shift[2 * i] = shift[2 * i + 1] = ' ';
888 shift[2 * i] = shift[2 * i + 1] = 0;
889
890 fprintf(output, shift);
891
892 if (comp == NULL) {
893 fprintf(output, "Compiled Expression is NULL\n");
894 return;
895 }
896 fprintf(output, "Compiled Expression : %d elements\n",
897 comp->nbStep);
898 i = comp->last;
899 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
900}
Daniel Veillard017b1082001-06-21 11:20:21 +0000901#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000902
903/************************************************************************
904 * *
905 * Parser stacks related functions and macros *
906 * *
907 ************************************************************************/
908
909/*
910 * Generic function for accessing stacks in the Parser Context
911 */
912
913#define PUSH_AND_POP(type, name) \
914extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
915 if (ctxt->name##Nr >= ctxt->name##Max) { \
916 ctxt->name##Max *= 2; \
917 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
918 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
919 if (ctxt->name##Tab == NULL) { \
920 xmlGenericError(xmlGenericErrorContext, \
921 "realloc failed !\n"); \
922 return(0); \
923 } \
924 } \
925 ctxt->name##Tab[ctxt->name##Nr] = value; \
926 ctxt->name = value; \
927 return(ctxt->name##Nr++); \
928} \
929extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
930 type ret; \
931 if (ctxt->name##Nr <= 0) return(0); \
932 ctxt->name##Nr--; \
933 if (ctxt->name##Nr > 0) \
934 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
935 else \
936 ctxt->name = NULL; \
937 ret = ctxt->name##Tab[ctxt->name##Nr]; \
938 ctxt->name##Tab[ctxt->name##Nr] = 0; \
939 return(ret); \
940} \
941
942PUSH_AND_POP(xmlXPathObjectPtr, value)
943
944/*
945 * Macros for accessing the content. Those should be used only by the parser,
946 * and not exported.
947 *
948 * Dirty macros, i.e. one need to make assumption on the context to use them
949 *
950 * CUR_PTR return the current pointer to the xmlChar to be parsed.
951 * CUR returns the current xmlChar value, i.e. a 8 bit value
952 * in ISO-Latin or UTF-8.
953 * This should be used internally by the parser
954 * only to compare to ASCII values otherwise it would break when
955 * running with UTF-8 encoding.
956 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
957 * to compare on ASCII based substring.
958 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
959 * strings within the parser.
960 * CURRENT Returns the current char value, with the full decoding of
961 * UTF-8 if we are using this mode. It returns an int.
962 * NEXT Skip to the next character, this does the proper decoding
963 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
964 * It returns the pointer to the current xmlChar.
965 */
966
967#define CUR (*ctxt->cur)
968#define SKIP(val) ctxt->cur += (val)
969#define NXT(val) ctxt->cur[(val)]
970#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +0000971#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
972
973#define COPY_BUF(l,b,i,v) \
974 if (l == 1) b[i++] = (xmlChar) v; \
975 else i += xmlCopyChar(l,&b[i],v)
976
977#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +0000978
979#define SKIP_BLANKS \
980 while (IS_BLANK(*(ctxt->cur))) NEXT
981
982#define CURRENT (*ctxt->cur)
983#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
984
Bjorn Reesee1dc0112001-03-03 12:09:03 +0000985
986#ifndef DBL_DIG
987#define DBL_DIG 16
988#endif
989#ifndef DBL_EPSILON
990#define DBL_EPSILON 1E-9
991#endif
992
993#define UPPER_DOUBLE 1E9
994#define LOWER_DOUBLE 1E-5
995
996#define INTEGER_DIGITS DBL_DIG
997#define FRACTION_DIGITS (DBL_DIG + 1)
998#define EXPONENT_DIGITS (3 + 2)
999
1000/**
1001 * xmlXPathFormatNumber:
1002 * @number: number to format
1003 * @buffer: output buffer
1004 * @buffersize: size of output buffer
1005 *
1006 * Convert the number into a string representation.
1007 */
1008static void
1009xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1010{
1011 switch (isinf(number)) {
1012 case 1:
1013 if (buffersize > (int)sizeof("+Infinity"))
1014 sprintf(buffer, "+Infinity");
1015 break;
1016 case -1:
1017 if (buffersize > (int)sizeof("-Infinity"))
1018 sprintf(buffer, "-Infinity");
1019 break;
1020 default:
1021 if (isnan(number)) {
1022 if (buffersize > (int)sizeof("NaN"))
1023 sprintf(buffer, "NaN");
1024 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001025 /* 3 is sign, decimal point, and terminating zero */
1026 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1027 int integer_place, fraction_place;
1028 char *ptr;
1029 char *after_fraction;
1030 double absolute_value;
1031 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001032
Bjorn Reese70a9da52001-04-21 16:57:29 +00001033 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001034
Bjorn Reese70a9da52001-04-21 16:57:29 +00001035 /*
1036 * First choose format - scientific or regular floating point.
1037 * In either case, result is in work, and after_fraction points
1038 * just past the fractional part.
1039 */
1040 if ( ((absolute_value > UPPER_DOUBLE) ||
1041 (absolute_value < LOWER_DOUBLE)) &&
1042 (absolute_value != 0.0) ) {
1043 /* Use scientific notation */
1044 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1045 fraction_place = DBL_DIG - 1;
1046 snprintf(work, sizeof(work),"%*.*e",
1047 integer_place, fraction_place, number);
1048 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001049 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001050 else {
1051 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001052 if (absolute_value > 0.0)
1053 integer_place = 1 + (int)log10(absolute_value);
1054 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001055 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001056 fraction_place = (integer_place > 0)
1057 ? DBL_DIG - integer_place
1058 : DBL_DIG;
1059 size = snprintf(work, sizeof(work), "%0.*f",
1060 fraction_place, number);
1061 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001062 }
1063
Bjorn Reese70a9da52001-04-21 16:57:29 +00001064 /* Remove fractional trailing zeroes */
1065 ptr = after_fraction;
1066 while (*(--ptr) == '0')
1067 ;
1068 if (*ptr != '.')
1069 ptr++;
1070 strcpy(ptr, after_fraction);
1071
1072 /* Finally copy result back to caller */
1073 size = strlen(work) + 1;
1074 if (size > buffersize) {
1075 work[buffersize - 1] = 0;
1076 size = buffersize;
1077 }
1078 memcpy(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001079 }
1080 break;
1081 }
1082}
1083
Owen Taylor3473f882001-02-23 17:55:21 +00001084/************************************************************************
1085 * *
1086 * Error handling routines *
1087 * *
1088 ************************************************************************/
1089
1090
1091const char *xmlXPathErrorMessages[] = {
1092 "Ok",
1093 "Number encoding",
1094 "Unfinished litteral",
1095 "Start of litteral",
1096 "Expected $ for variable reference",
1097 "Undefined variable",
1098 "Invalid predicate",
1099 "Invalid expression",
1100 "Missing closing curly brace",
1101 "Unregistered function",
1102 "Invalid operand",
1103 "Invalid type",
1104 "Invalid number of arguments",
1105 "Invalid context size",
1106 "Invalid context position",
1107 "Memory allocation error",
1108 "Syntax error",
1109 "Resource error",
1110 "Sub resource error",
Daniel Veillard61d80a22001-04-27 17:13:01 +00001111 "Undefined namespace prefix",
1112 "Encoding error",
1113 "Char out of XML range"
Owen Taylor3473f882001-02-23 17:55:21 +00001114};
1115
1116/**
1117 * xmlXPathError:
1118 * @ctxt: the XPath Parser context
1119 * @file: the file name
1120 * @line: the line number
1121 * @no: the error number
1122 *
1123 * Create a new xmlNodeSetPtr of type double and of value @val
1124 *
1125 * Returns the newly created object.
1126 */
1127void
1128xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
1129 int line, int no) {
1130 int n;
1131 const xmlChar *cur;
1132 const xmlChar *base;
1133
1134 xmlGenericError(xmlGenericErrorContext,
1135 "Error %s:%d: %s\n", file, line,
1136 xmlXPathErrorMessages[no]);
1137
1138 cur = ctxt->cur;
1139 base = ctxt->base;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001140 if ((cur == NULL) || (base == NULL))
1141 return;
1142
Owen Taylor3473f882001-02-23 17:55:21 +00001143 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
1144 cur--;
1145 }
1146 n = 0;
1147 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
1148 cur--;
1149 if ((*cur == '\n') || (*cur == '\r')) cur++;
1150 base = cur;
1151 n = 0;
1152 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1153 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
1154 n++;
1155 }
1156 xmlGenericError(xmlGenericErrorContext, "\n");
1157 cur = ctxt->cur;
1158 while ((*cur == '\n') || (*cur == '\r'))
1159 cur--;
1160 n = 0;
1161 while ((cur != base) && (n++ < 80)) {
1162 xmlGenericError(xmlGenericErrorContext, " ");
1163 base++;
1164 }
1165 xmlGenericError(xmlGenericErrorContext,"^\n");
1166}
1167
1168
1169/************************************************************************
1170 * *
1171 * Routines to handle NodeSets *
1172 * *
1173 ************************************************************************/
1174
1175/**
1176 * xmlXPathCmpNodes:
1177 * @node1: the first node
1178 * @node2: the second node
1179 *
1180 * Compare two nodes w.r.t document order
1181 *
1182 * Returns -2 in case of error 1 if first point < second point, 0 if
1183 * that's the same node, -1 otherwise
1184 */
1185int
1186xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1187 int depth1, depth2;
1188 xmlNodePtr cur, root;
1189
1190 if ((node1 == NULL) || (node2 == NULL))
1191 return(-2);
1192 /*
1193 * a couple of optimizations which will avoid computations in most cases
1194 */
1195 if (node1 == node2)
1196 return(0);
Daniel Veillardb33c2012001-04-25 12:59:04 +00001197 if ((node1->type == XML_NAMESPACE_DECL) ||
1198 (node2->type == XML_NAMESPACE_DECL))
1199 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001200 if (node1 == node2->prev)
1201 return(1);
1202 if (node1 == node2->next)
1203 return(-1);
1204
1205 /*
1206 * compute depth to root
1207 */
1208 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1209 if (cur == node1)
1210 return(1);
1211 depth2++;
1212 }
1213 root = cur;
1214 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1215 if (cur == node2)
1216 return(-1);
1217 depth1++;
1218 }
1219 /*
1220 * Distinct document (or distinct entities :-( ) case.
1221 */
1222 if (root != cur) {
1223 return(-2);
1224 }
1225 /*
1226 * get the nearest common ancestor.
1227 */
1228 while (depth1 > depth2) {
1229 depth1--;
1230 node1 = node1->parent;
1231 }
1232 while (depth2 > depth1) {
1233 depth2--;
1234 node2 = node2->parent;
1235 }
1236 while (node1->parent != node2->parent) {
1237 node1 = node1->parent;
1238 node2 = node2->parent;
1239 /* should not happen but just in case ... */
1240 if ((node1 == NULL) || (node2 == NULL))
1241 return(-2);
1242 }
1243 /*
1244 * Find who's first.
1245 */
1246 if (node1 == node2->next)
1247 return(-1);
1248 for (cur = node1->next;cur != NULL;cur = cur->next)
1249 if (cur == node2)
1250 return(1);
1251 return(-1); /* assume there is no sibling list corruption */
1252}
1253
1254/**
1255 * xmlXPathNodeSetSort:
1256 * @set: the node set
1257 *
1258 * Sort the node set in document order
1259 */
1260void
1261xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001262 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001263 xmlNodePtr tmp;
1264
1265 if (set == NULL)
1266 return;
1267
1268 /* Use Shell's sort to sort the node-set */
1269 len = set->nodeNr;
1270 for (incr = len / 2; incr > 0; incr /= 2) {
1271 for (i = incr; i < len; i++) {
1272 j = i - incr;
1273 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001274 if (xmlXPathCmpNodes(set->nodeTab[j],
1275 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001276 tmp = set->nodeTab[j];
1277 set->nodeTab[j] = set->nodeTab[j + incr];
1278 set->nodeTab[j + incr] = tmp;
1279 j -= incr;
1280 } else
1281 break;
1282 }
1283 }
1284 }
1285}
1286
1287#define XML_NODESET_DEFAULT 10
1288/**
1289 * xmlXPathNodeSetCreate:
1290 * @val: an initial xmlNodePtr, or NULL
1291 *
1292 * Create a new xmlNodeSetPtr of type double and of value @val
1293 *
1294 * Returns the newly created object.
1295 */
1296xmlNodeSetPtr
1297xmlXPathNodeSetCreate(xmlNodePtr val) {
1298 xmlNodeSetPtr ret;
1299
1300 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1301 if (ret == NULL) {
1302 xmlGenericError(xmlGenericErrorContext,
1303 "xmlXPathNewNodeSet: out of memory\n");
1304 return(NULL);
1305 }
1306 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1307 if (val != NULL) {
1308 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1309 sizeof(xmlNodePtr));
1310 if (ret->nodeTab == NULL) {
1311 xmlGenericError(xmlGenericErrorContext,
1312 "xmlXPathNewNodeSet: out of memory\n");
1313 return(NULL);
1314 }
1315 memset(ret->nodeTab, 0 ,
1316 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1317 ret->nodeMax = XML_NODESET_DEFAULT;
1318 ret->nodeTab[ret->nodeNr++] = val;
1319 }
1320 return(ret);
1321}
1322
1323/**
1324 * xmlXPathNodeSetAdd:
1325 * @cur: the initial node set
1326 * @val: a new xmlNodePtr
1327 *
1328 * add a new xmlNodePtr ot an existing NodeSet
1329 */
1330void
1331xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1332 int i;
1333
1334 if (val == NULL) return;
1335
1336 /*
1337 * check against doublons
1338 */
1339 for (i = 0;i < cur->nodeNr;i++)
1340 if (cur->nodeTab[i] == val) return;
1341
1342 /*
1343 * grow the nodeTab if needed
1344 */
1345 if (cur->nodeMax == 0) {
1346 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1347 sizeof(xmlNodePtr));
1348 if (cur->nodeTab == NULL) {
1349 xmlGenericError(xmlGenericErrorContext,
1350 "xmlXPathNodeSetAdd: out of memory\n");
1351 return;
1352 }
1353 memset(cur->nodeTab, 0 ,
1354 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1355 cur->nodeMax = XML_NODESET_DEFAULT;
1356 } else if (cur->nodeNr == cur->nodeMax) {
1357 xmlNodePtr *temp;
1358
1359 cur->nodeMax *= 2;
1360 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1361 sizeof(xmlNodePtr));
1362 if (temp == NULL) {
1363 xmlGenericError(xmlGenericErrorContext,
1364 "xmlXPathNodeSetAdd: out of memory\n");
1365 return;
1366 }
1367 cur->nodeTab = temp;
1368 }
1369 cur->nodeTab[cur->nodeNr++] = val;
1370}
1371
1372/**
1373 * xmlXPathNodeSetAddUnique:
1374 * @cur: the initial node set
1375 * @val: a new xmlNodePtr
1376 *
1377 * add a new xmlNodePtr ot an existing NodeSet, optimized version
1378 * when we are sure the node is not already in the set.
1379 */
1380void
1381xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1382 if (val == NULL) return;
1383
1384 /*
1385 * grow the nodeTab if needed
1386 */
1387 if (cur->nodeMax == 0) {
1388 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1389 sizeof(xmlNodePtr));
1390 if (cur->nodeTab == NULL) {
1391 xmlGenericError(xmlGenericErrorContext,
1392 "xmlXPathNodeSetAddUnique: out of memory\n");
1393 return;
1394 }
1395 memset(cur->nodeTab, 0 ,
1396 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1397 cur->nodeMax = XML_NODESET_DEFAULT;
1398 } else if (cur->nodeNr == cur->nodeMax) {
1399 xmlNodePtr *temp;
1400
1401 cur->nodeMax *= 2;
1402 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1403 sizeof(xmlNodePtr));
1404 if (temp == NULL) {
1405 xmlGenericError(xmlGenericErrorContext,
1406 "xmlXPathNodeSetAddUnique: out of memory\n");
1407 return;
1408 }
1409 cur->nodeTab = temp;
1410 }
1411 cur->nodeTab[cur->nodeNr++] = val;
1412}
1413
1414/**
1415 * xmlXPathNodeSetMerge:
1416 * @val1: the first NodeSet or NULL
1417 * @val2: the second NodeSet
1418 *
1419 * Merges two nodesets, all nodes from @val2 are added to @val1
1420 * if @val1 is NULL, a new set is created and copied from @val2
1421 *
1422 * Returns val1 once extended or NULL in case of error.
1423 */
1424xmlNodeSetPtr
1425xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001426 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001427
1428 if (val2 == NULL) return(val1);
1429 if (val1 == NULL) {
1430 val1 = xmlXPathNodeSetCreate(NULL);
1431 }
1432
1433 initNr = val1->nodeNr;
1434
1435 for (i = 0;i < val2->nodeNr;i++) {
1436 /*
1437 * check against doublons
1438 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001439 skip = 0;
1440 for (j = 0; j < initNr; j++) {
1441 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1442 skip = 1;
1443 break;
1444 }
1445 }
1446 if (skip)
1447 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001448
1449 /*
1450 * grow the nodeTab if needed
1451 */
1452 if (val1->nodeMax == 0) {
1453 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1454 sizeof(xmlNodePtr));
1455 if (val1->nodeTab == NULL) {
1456 xmlGenericError(xmlGenericErrorContext,
1457 "xmlXPathNodeSetMerge: out of memory\n");
1458 return(NULL);
1459 }
1460 memset(val1->nodeTab, 0 ,
1461 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1462 val1->nodeMax = XML_NODESET_DEFAULT;
1463 } else if (val1->nodeNr == val1->nodeMax) {
1464 xmlNodePtr *temp;
1465
1466 val1->nodeMax *= 2;
1467 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1468 sizeof(xmlNodePtr));
1469 if (temp == NULL) {
1470 xmlGenericError(xmlGenericErrorContext,
1471 "xmlXPathNodeSetMerge: out of memory\n");
1472 return(NULL);
1473 }
1474 val1->nodeTab = temp;
1475 }
1476 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1477 }
1478
1479 return(val1);
1480}
1481
1482/**
1483 * xmlXPathNodeSetDel:
1484 * @cur: the initial node set
1485 * @val: an xmlNodePtr
1486 *
1487 * Removes an xmlNodePtr from an existing NodeSet
1488 */
1489void
1490xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
1491 int i;
1492
1493 if (cur == NULL) return;
1494 if (val == NULL) return;
1495
1496 /*
1497 * check against doublons
1498 */
1499 for (i = 0;i < cur->nodeNr;i++)
1500 if (cur->nodeTab[i] == val) break;
1501
1502 if (i >= cur->nodeNr) {
1503#ifdef DEBUG
1504 xmlGenericError(xmlGenericErrorContext,
1505 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
1506 val->name);
1507#endif
1508 return;
1509 }
1510 cur->nodeNr--;
1511 for (;i < cur->nodeNr;i++)
1512 cur->nodeTab[i] = cur->nodeTab[i + 1];
1513 cur->nodeTab[cur->nodeNr] = NULL;
1514}
1515
1516/**
1517 * xmlXPathNodeSetRemove:
1518 * @cur: the initial node set
1519 * @val: the index to remove
1520 *
1521 * Removes an entry from an existing NodeSet list.
1522 */
1523void
1524xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
1525 if (cur == NULL) return;
1526 if (val >= cur->nodeNr) return;
1527 cur->nodeNr--;
1528 for (;val < cur->nodeNr;val++)
1529 cur->nodeTab[val] = cur->nodeTab[val + 1];
1530 cur->nodeTab[cur->nodeNr] = NULL;
1531}
1532
1533/**
1534 * xmlXPathFreeNodeSet:
1535 * @obj: the xmlNodeSetPtr to free
1536 *
1537 * Free the NodeSet compound (not the actual nodes !).
1538 */
1539void
1540xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
1541 if (obj == NULL) return;
1542 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001543 xmlFree(obj->nodeTab);
1544 }
Owen Taylor3473f882001-02-23 17:55:21 +00001545 xmlFree(obj);
1546}
1547
1548/**
1549 * xmlXPathFreeValueTree:
1550 * @obj: the xmlNodeSetPtr to free
1551 *
1552 * Free the NodeSet compound and the actual tree, this is different
1553 * from xmlXPathFreeNodeSet()
1554 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001555static void
Owen Taylor3473f882001-02-23 17:55:21 +00001556xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
1557 int i;
1558
1559 if (obj == NULL) return;
1560 for (i = 0;i < obj->nodeNr;i++)
1561 if (obj->nodeTab[i] != NULL)
Daniel Veillardbbd51d52001-02-24 03:07:03 +00001562 xmlFreeNodeList(obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001563
1564 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001565 xmlFree(obj->nodeTab);
1566 }
Owen Taylor3473f882001-02-23 17:55:21 +00001567 xmlFree(obj);
1568}
1569
1570#if defined(DEBUG) || defined(DEBUG_STEP)
1571/**
1572 * xmlGenericErrorContextNodeSet:
1573 * @output: a FILE * for the output
1574 * @obj: the xmlNodeSetPtr to free
1575 *
1576 * Quick display of a NodeSet
1577 */
1578void
1579xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
1580 int i;
1581
1582 if (output == NULL) output = xmlGenericErrorContext;
1583 if (obj == NULL) {
1584 fprintf(output, "NodeSet == NULL !\n");
1585 return;
1586 }
1587 if (obj->nodeNr == 0) {
1588 fprintf(output, "NodeSet is empty\n");
1589 return;
1590 }
1591 if (obj->nodeTab == NULL) {
1592 fprintf(output, " nodeTab == NULL !\n");
1593 return;
1594 }
1595 for (i = 0; i < obj->nodeNr; i++) {
1596 if (obj->nodeTab[i] == NULL) {
1597 fprintf(output, " NULL !\n");
1598 return;
1599 }
1600 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
1601 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
1602 fprintf(output, " /");
1603 else if (obj->nodeTab[i]->name == NULL)
1604 fprintf(output, " noname!");
1605 else fprintf(output, " %s", obj->nodeTab[i]->name);
1606 }
1607 fprintf(output, "\n");
1608}
1609#endif
1610
1611/**
1612 * xmlXPathNewNodeSet:
1613 * @val: the NodePtr value
1614 *
1615 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1616 * it with the single Node @val
1617 *
1618 * Returns the newly created object.
1619 */
1620xmlXPathObjectPtr
1621xmlXPathNewNodeSet(xmlNodePtr val) {
1622 xmlXPathObjectPtr ret;
1623
1624 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1625 if (ret == NULL) {
1626 xmlGenericError(xmlGenericErrorContext,
1627 "xmlXPathNewNodeSet: out of memory\n");
1628 return(NULL);
1629 }
1630 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1631 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00001632 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001633 ret->nodesetval = xmlXPathNodeSetCreate(val);
1634 return(ret);
1635}
1636
1637/**
1638 * xmlXPathNewValueTree:
1639 * @val: the NodePtr value
1640 *
1641 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
1642 * it with the tree root @val
1643 *
1644 * Returns the newly created object.
1645 */
1646xmlXPathObjectPtr
1647xmlXPathNewValueTree(xmlNodePtr val) {
1648 xmlXPathObjectPtr ret;
1649
1650 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1651 if (ret == NULL) {
1652 xmlGenericError(xmlGenericErrorContext,
1653 "xmlXPathNewNodeSet: out of memory\n");
1654 return(NULL);
1655 }
1656 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1657 ret->type = XPATH_XSLT_TREE;
1658 ret->nodesetval = xmlXPathNodeSetCreate(val);
1659 return(ret);
1660}
1661
1662/**
1663 * xmlXPathNewNodeSetList:
1664 * @val: an existing NodeSet
1665 *
1666 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1667 * it with the Nodeset @val
1668 *
1669 * Returns the newly created object.
1670 */
1671xmlXPathObjectPtr
1672xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
1673 xmlXPathObjectPtr ret;
1674 int i;
1675
1676 if (val == NULL)
1677 ret = NULL;
1678 else if (val->nodeTab == NULL)
1679 ret = xmlXPathNewNodeSet(NULL);
1680 else
1681 {
1682 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
1683 for (i = 1; i < val->nodeNr; ++i)
1684 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
1685 }
1686
1687 return(ret);
1688}
1689
1690/**
1691 * xmlXPathWrapNodeSet:
1692 * @val: the NodePtr value
1693 *
1694 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1695 *
1696 * Returns the newly created object.
1697 */
1698xmlXPathObjectPtr
1699xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
1700 xmlXPathObjectPtr ret;
1701
1702 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1703 if (ret == NULL) {
1704 xmlGenericError(xmlGenericErrorContext,
1705 "xmlXPathWrapNodeSet: out of memory\n");
1706 return(NULL);
1707 }
1708 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1709 ret->type = XPATH_NODESET;
1710 ret->nodesetval = val;
1711 return(ret);
1712}
1713
1714/**
1715 * xmlXPathFreeNodeSetList:
1716 * @obj: an existing NodeSetList object
1717 *
1718 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
1719 * the list contrary to xmlXPathFreeObject().
1720 */
1721void
1722xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
1723 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001724 xmlFree(obj);
1725}
1726
1727/************************************************************************
1728 * *
1729 * Routines to handle extra functions *
1730 * *
1731 ************************************************************************/
1732
1733/**
1734 * xmlXPathRegisterFunc:
1735 * @ctxt: the XPath context
1736 * @name: the function name
1737 * @f: the function implementation or NULL
1738 *
1739 * Register a new function. If @f is NULL it unregisters the function
1740 *
1741 * Returns 0 in case of success, -1 in case of error
1742 */
1743int
1744xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
1745 xmlXPathFunction f) {
1746 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
1747}
1748
1749/**
1750 * xmlXPathRegisterFuncNS:
1751 * @ctxt: the XPath context
1752 * @name: the function name
1753 * @ns_uri: the function namespace URI
1754 * @f: the function implementation or NULL
1755 *
1756 * Register a new function. If @f is NULL it unregisters the function
1757 *
1758 * Returns 0 in case of success, -1 in case of error
1759 */
1760int
1761xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1762 const xmlChar *ns_uri, xmlXPathFunction f) {
1763 if (ctxt == NULL)
1764 return(-1);
1765 if (name == NULL)
1766 return(-1);
1767
1768 if (ctxt->funcHash == NULL)
1769 ctxt->funcHash = xmlHashCreate(0);
1770 if (ctxt->funcHash == NULL)
1771 return(-1);
1772 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
1773}
1774
1775/**
1776 * xmlXPathFunctionLookup:
1777 * @ctxt: the XPath context
1778 * @name: the function name
1779 *
1780 * Search in the Function array of the context for the given
1781 * function.
1782 *
1783 * Returns the xmlXPathFunction or NULL if not found
1784 */
1785xmlXPathFunction
1786xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
1787 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
1788}
1789
1790/**
1791 * xmlXPathFunctionLookupNS:
1792 * @ctxt: the XPath context
1793 * @name: the function name
1794 * @ns_uri: the function namespace URI
1795 *
1796 * Search in the Function array of the context for the given
1797 * function.
1798 *
1799 * Returns the xmlXPathFunction or NULL if not found
1800 */
1801xmlXPathFunction
1802xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1803 const xmlChar *ns_uri) {
1804 if (ctxt == NULL)
1805 return(NULL);
1806 if (ctxt->funcHash == NULL)
1807 return(NULL);
1808 if (name == NULL)
1809 return(NULL);
1810
1811 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
1812}
1813
1814/**
1815 * xmlXPathRegisteredFuncsCleanup:
1816 * @ctxt: the XPath context
1817 *
1818 * Cleanup the XPath context data associated to registered functions
1819 */
1820void
1821xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
1822 if (ctxt == NULL)
1823 return;
1824
1825 xmlHashFree(ctxt->funcHash, NULL);
1826 ctxt->funcHash = NULL;
1827}
1828
1829/************************************************************************
1830 * *
1831 * Routines to handle Variable *
1832 * *
1833 ************************************************************************/
1834
1835/**
1836 * xmlXPathRegisterVariable:
1837 * @ctxt: the XPath context
1838 * @name: the variable name
1839 * @value: the variable value or NULL
1840 *
1841 * Register a new variable value. If @value is NULL it unregisters
1842 * the variable
1843 *
1844 * Returns 0 in case of success, -1 in case of error
1845 */
1846int
1847xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
1848 xmlXPathObjectPtr value) {
1849 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
1850}
1851
1852/**
1853 * xmlXPathRegisterVariableNS:
1854 * @ctxt: the XPath context
1855 * @name: the variable name
1856 * @ns_uri: the variable namespace URI
1857 * @value: the variable value or NULL
1858 *
1859 * Register a new variable value. If @value is NULL it unregisters
1860 * the variable
1861 *
1862 * Returns 0 in case of success, -1 in case of error
1863 */
1864int
1865xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1866 const xmlChar *ns_uri,
1867 xmlXPathObjectPtr value) {
1868 if (ctxt == NULL)
1869 return(-1);
1870 if (name == NULL)
1871 return(-1);
1872
1873 if (ctxt->varHash == NULL)
1874 ctxt->varHash = xmlHashCreate(0);
1875 if (ctxt->varHash == NULL)
1876 return(-1);
1877 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
1878 (void *) value,
1879 (xmlHashDeallocator)xmlXPathFreeObject));
1880}
1881
1882/**
1883 * xmlXPathRegisterVariableLookup:
1884 * @ctxt: the XPath context
1885 * @f: the lookup function
1886 * @data: the lookup data
1887 *
1888 * register an external mechanism to do variable lookup
1889 */
1890void
1891xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
1892 xmlXPathVariableLookupFunc f, void *data) {
1893 if (ctxt == NULL)
1894 return;
1895 ctxt->varLookupFunc = (void *) f;
1896 ctxt->varLookupData = data;
1897}
1898
1899/**
1900 * xmlXPathVariableLookup:
1901 * @ctxt: the XPath context
1902 * @name: the variable name
1903 *
1904 * Search in the Variable array of the context for the given
1905 * variable value.
1906 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00001907 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00001908 */
1909xmlXPathObjectPtr
1910xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
1911 if (ctxt == NULL)
1912 return(NULL);
1913
1914 if (ctxt->varLookupFunc != NULL) {
1915 xmlXPathObjectPtr ret;
1916
1917 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
1918 (ctxt->varLookupData, name, NULL);
1919 if (ret != NULL) return(ret);
1920 }
1921 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
1922}
1923
1924/**
1925 * xmlXPathVariableLookupNS:
1926 * @ctxt: the XPath context
1927 * @name: the variable name
1928 * @ns_uri: the variable namespace URI
1929 *
1930 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00001931 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00001932 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00001933 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00001934 */
1935xmlXPathObjectPtr
1936xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1937 const xmlChar *ns_uri) {
1938 if (ctxt == NULL)
1939 return(NULL);
1940
1941 if (ctxt->varLookupFunc != NULL) {
1942 xmlXPathObjectPtr ret;
1943
1944 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
1945 (ctxt->varLookupData, name, ns_uri);
1946 if (ret != NULL) return(ret);
1947 }
1948
1949 if (ctxt->varHash == NULL)
1950 return(NULL);
1951 if (name == NULL)
1952 return(NULL);
1953
Daniel Veillard8c357d52001-07-03 23:43:33 +00001954 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
1955 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00001956}
1957
1958/**
1959 * xmlXPathRegisteredVariablesCleanup:
1960 * @ctxt: the XPath context
1961 *
1962 * Cleanup the XPath context data associated to registered variables
1963 */
1964void
1965xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
1966 if (ctxt == NULL)
1967 return;
1968
Daniel Veillard76d66f42001-05-16 21:05:17 +00001969 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00001970 ctxt->varHash = NULL;
1971}
1972
1973/**
1974 * xmlXPathRegisterNs:
1975 * @ctxt: the XPath context
1976 * @prefix: the namespace prefix
1977 * @ns_uri: the namespace name
1978 *
1979 * Register a new namespace. If @ns_uri is NULL it unregisters
1980 * the namespace
1981 *
1982 * Returns 0 in case of success, -1 in case of error
1983 */
1984int
1985xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
1986 const xmlChar *ns_uri) {
1987 if (ctxt == NULL)
1988 return(-1);
1989 if (prefix == NULL)
1990 return(-1);
1991
1992 if (ctxt->nsHash == NULL)
1993 ctxt->nsHash = xmlHashCreate(10);
1994 if (ctxt->nsHash == NULL)
1995 return(-1);
1996 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) ns_uri,
1997 (xmlHashDeallocator)xmlFree));
1998}
1999
2000/**
2001 * xmlXPathNsLookup:
2002 * @ctxt: the XPath context
2003 * @prefix: the namespace prefix value
2004 *
2005 * Search in the namespace declaration array of the context for the given
2006 * namespace name associated to the given prefix
2007 *
2008 * Returns the value or NULL if not found
2009 */
2010const xmlChar *
2011xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2012 if (ctxt == NULL)
2013 return(NULL);
2014 if (prefix == NULL)
2015 return(NULL);
2016
2017#ifdef XML_XML_NAMESPACE
2018 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
2019 return(XML_XML_NAMESPACE);
2020#endif
2021
Daniel Veillardc8f620b2001-04-30 20:31:33 +00002022 if (ctxt->namespaces != NULL) {
2023 int i;
2024
2025 for (i = 0;i < ctxt->nsNr;i++) {
2026 if ((ctxt->namespaces[i] != NULL) &&
2027 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
2028 return(ctxt->namespaces[i]->href);
2029 }
2030 }
Owen Taylor3473f882001-02-23 17:55:21 +00002031
2032 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
2033}
2034
2035/**
2036 * xmlXPathRegisteredVariablesCleanup:
2037 * @ctxt: the XPath context
2038 *
2039 * Cleanup the XPath context data associated to registered variables
2040 */
2041void
2042xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2043 if (ctxt == NULL)
2044 return;
2045
2046 xmlHashFree(ctxt->nsHash, NULL);
2047 ctxt->nsHash = NULL;
2048}
2049
2050/************************************************************************
2051 * *
2052 * Routines to handle Values *
2053 * *
2054 ************************************************************************/
2055
2056/* Allocations are terrible, one need to optimize all this !!! */
2057
2058/**
2059 * xmlXPathNewFloat:
2060 * @val: the double value
2061 *
2062 * Create a new xmlXPathObjectPtr of type double and of value @val
2063 *
2064 * Returns the newly created object.
2065 */
2066xmlXPathObjectPtr
2067xmlXPathNewFloat(double val) {
2068 xmlXPathObjectPtr ret;
2069
2070 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2071 if (ret == NULL) {
2072 xmlGenericError(xmlGenericErrorContext,
2073 "xmlXPathNewFloat: out of memory\n");
2074 return(NULL);
2075 }
2076 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2077 ret->type = XPATH_NUMBER;
2078 ret->floatval = val;
2079 return(ret);
2080}
2081
2082/**
2083 * xmlXPathNewBoolean:
2084 * @val: the boolean value
2085 *
2086 * Create a new xmlXPathObjectPtr of type boolean and of value @val
2087 *
2088 * Returns the newly created object.
2089 */
2090xmlXPathObjectPtr
2091xmlXPathNewBoolean(int val) {
2092 xmlXPathObjectPtr ret;
2093
2094 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2095 if (ret == NULL) {
2096 xmlGenericError(xmlGenericErrorContext,
2097 "xmlXPathNewBoolean: out of memory\n");
2098 return(NULL);
2099 }
2100 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2101 ret->type = XPATH_BOOLEAN;
2102 ret->boolval = (val != 0);
2103 return(ret);
2104}
2105
2106/**
2107 * xmlXPathNewString:
2108 * @val: the xmlChar * value
2109 *
2110 * Create a new xmlXPathObjectPtr of type string and of value @val
2111 *
2112 * Returns the newly created object.
2113 */
2114xmlXPathObjectPtr
2115xmlXPathNewString(const xmlChar *val) {
2116 xmlXPathObjectPtr ret;
2117
2118 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2119 if (ret == NULL) {
2120 xmlGenericError(xmlGenericErrorContext,
2121 "xmlXPathNewString: out of memory\n");
2122 return(NULL);
2123 }
2124 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2125 ret->type = XPATH_STRING;
2126 if (val != NULL)
2127 ret->stringval = xmlStrdup(val);
2128 else
2129 ret->stringval = xmlStrdup((const xmlChar *)"");
2130 return(ret);
2131}
2132
2133/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002134 * xmlXPathWrapString:
2135 * @val: the xmlChar * value
2136 *
2137 * Wraps the @val string into an XPath object.
2138 *
2139 * Returns the newly created object.
2140 */
2141xmlXPathObjectPtr
2142xmlXPathWrapString (xmlChar *val) {
2143 xmlXPathObjectPtr ret;
2144
2145 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2146 if (ret == NULL) {
2147 xmlGenericError(xmlGenericErrorContext,
2148 "xmlXPathWrapString: out of memory\n");
2149 return(NULL);
2150 }
2151 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2152 ret->type = XPATH_STRING;
2153 ret->stringval = val;
2154 return(ret);
2155}
2156
2157/**
Owen Taylor3473f882001-02-23 17:55:21 +00002158 * xmlXPathNewCString:
2159 * @val: the char * value
2160 *
2161 * Create a new xmlXPathObjectPtr of type string and of value @val
2162 *
2163 * Returns the newly created object.
2164 */
2165xmlXPathObjectPtr
2166xmlXPathNewCString(const char *val) {
2167 xmlXPathObjectPtr ret;
2168
2169 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2170 if (ret == NULL) {
2171 xmlGenericError(xmlGenericErrorContext,
2172 "xmlXPathNewCString: out of memory\n");
2173 return(NULL);
2174 }
2175 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2176 ret->type = XPATH_STRING;
2177 ret->stringval = xmlStrdup(BAD_CAST val);
2178 return(ret);
2179}
2180
2181/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002182 * xmlXPathWrapCString:
2183 * @val: the char * value
2184 *
2185 * Wraps a string into an XPath object.
2186 *
2187 * Returns the newly created object.
2188 */
2189xmlXPathObjectPtr
2190xmlXPathWrapCString (char * val) {
2191 return(xmlXPathWrapString((xmlChar *)(val)));
2192}
2193
2194/**
Owen Taylor3473f882001-02-23 17:55:21 +00002195 * xmlXPathObjectCopy:
2196 * @val: the original object
2197 *
2198 * allocate a new copy of a given object
2199 *
2200 * Returns the newly created object.
2201 */
2202xmlXPathObjectPtr
2203xmlXPathObjectCopy(xmlXPathObjectPtr val) {
2204 xmlXPathObjectPtr ret;
2205
2206 if (val == NULL)
2207 return(NULL);
2208
2209 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2210 if (ret == NULL) {
2211 xmlGenericError(xmlGenericErrorContext,
2212 "xmlXPathObjectCopy: out of memory\n");
2213 return(NULL);
2214 }
2215 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
2216 switch (val->type) {
2217 case XPATH_BOOLEAN:
2218 case XPATH_NUMBER:
2219 case XPATH_POINT:
2220 case XPATH_RANGE:
2221 break;
2222 case XPATH_STRING:
2223 ret->stringval = xmlStrdup(val->stringval);
2224 break;
2225 case XPATH_XSLT_TREE:
2226 if ((val->nodesetval != NULL) &&
2227 (val->nodesetval->nodeTab != NULL))
2228 ret->nodesetval = xmlXPathNodeSetCreate(
2229 xmlCopyNode(val->nodesetval->nodeTab[0], 1));
2230 else
2231 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
2232 break;
2233 case XPATH_NODESET:
2234 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
2235 break;
2236 case XPATH_LOCATIONSET:
2237#ifdef LIBXML_XPTR_ENABLED
2238 {
2239 xmlLocationSetPtr loc = val->user;
2240 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
2241 break;
2242 }
2243#endif
2244 case XPATH_UNDEFINED:
2245 case XPATH_USERS:
2246 xmlGenericError(xmlGenericErrorContext,
2247 "xmlXPathObjectCopy: unsupported type %d\n",
2248 val->type);
2249 break;
2250 }
2251 return(ret);
2252}
2253
2254/**
2255 * xmlXPathFreeObject:
2256 * @obj: the object to free
2257 *
2258 * Free up an xmlXPathObjectPtr object.
2259 */
2260void
2261xmlXPathFreeObject(xmlXPathObjectPtr obj) {
2262 if (obj == NULL) return;
2263 if (obj->type == XPATH_NODESET) {
Daniel Veillard77851712001-02-27 21:54:07 +00002264 if (obj->boolval) {
2265 obj->type = XPATH_XSLT_TREE;
2266 if (obj->nodesetval != NULL)
2267 xmlXPathFreeValueTree(obj->nodesetval);
2268 } else {
2269 if (obj->nodesetval != NULL)
2270 xmlXPathFreeNodeSet(obj->nodesetval);
2271 }
Owen Taylor3473f882001-02-23 17:55:21 +00002272#ifdef LIBXML_XPTR_ENABLED
2273 } else if (obj->type == XPATH_LOCATIONSET) {
2274 if (obj->user != NULL)
2275 xmlXPtrFreeLocationSet(obj->user);
2276#endif
2277 } else if (obj->type == XPATH_STRING) {
2278 if (obj->stringval != NULL)
2279 xmlFree(obj->stringval);
2280 } else if (obj->type == XPATH_XSLT_TREE) {
2281 if (obj->nodesetval != NULL)
2282 xmlXPathFreeValueTree(obj->nodesetval);
2283 }
2284
Owen Taylor3473f882001-02-23 17:55:21 +00002285 xmlFree(obj);
2286}
2287
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002288
2289/************************************************************************
2290 * *
2291 * Type Casting Routines *
2292 * *
2293 ************************************************************************/
2294
2295/**
2296 * xmlXPathCastBooleanToString:
2297 * @val: a boolean
2298 *
2299 * Converts a boolean to its string value.
2300 *
2301 * Returns a newly allocated string.
2302 */
2303xmlChar *
2304xmlXPathCastBooleanToString (int val) {
2305 xmlChar *ret;
2306 if (val)
2307 ret = xmlStrdup((const xmlChar *) "true");
2308 else
2309 ret = xmlStrdup((const xmlChar *) "false");
2310 return(ret);
2311}
2312
2313/**
2314 * xmlXPathCastNumberToString:
2315 * @val: a number
2316 *
2317 * Converts a number to its string value.
2318 *
2319 * Returns a newly allocated string.
2320 */
2321xmlChar *
2322xmlXPathCastNumberToString (double val) {
2323 xmlChar *ret;
2324 switch (isinf(val)) {
2325 case 1:
2326 ret = xmlStrdup((const xmlChar *) "+Infinity");
2327 break;
2328 case -1:
2329 ret = xmlStrdup((const xmlChar *) "-Infinity");
2330 break;
2331 default:
2332 if (isnan(val)) {
2333 ret = xmlStrdup((const xmlChar *) "NaN");
2334 } else {
2335 /* could be improved */
2336 char buf[100];
2337 xmlXPathFormatNumber(val, buf, 100);
2338 ret = xmlStrdup((const xmlChar *) buf);
2339 }
2340 }
2341 return(ret);
2342}
2343
2344/**
2345 * xmlXPathCastNodeToString:
2346 * @node: a node
2347 *
2348 * Converts a node to its string value.
2349 *
2350 * Returns a newly allocated string.
2351 */
2352xmlChar *
2353xmlXPathCastNodeToString (xmlNodePtr node) {
2354 return(xmlNodeGetContent(node));
2355}
2356
2357/**
2358 * xmlXPathCastNodeSetToString:
2359 * @ns: a node-set
2360 *
2361 * Converts a node-set to its string value.
2362 *
2363 * Returns a newly allocated string.
2364 */
2365xmlChar *
2366xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
2367 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
2368 return(xmlStrdup((const xmlChar *) ""));
2369
2370 xmlXPathNodeSetSort(ns);
2371 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
2372}
2373
2374/**
2375 * xmlXPathCastToString:
2376 * @val: an XPath object
2377 *
2378 * Converts an existing object to its string() equivalent
2379 *
2380 * Returns the string value of the object, NULL in case of error.
2381 * A new string is allocated only if needed (val isn't a
2382 * string object).
2383 */
2384xmlChar *
2385xmlXPathCastToString(xmlXPathObjectPtr val) {
2386 xmlChar *ret = NULL;
2387
2388 if (val == NULL)
2389 return(xmlStrdup((const xmlChar *) ""));
2390 switch (val->type) {
2391 case XPATH_UNDEFINED:
2392#ifdef DEBUG_EXPR
2393 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
2394#endif
2395 ret = xmlStrdup((const xmlChar *) "");
2396 break;
2397 case XPATH_XSLT_TREE:
2398 case XPATH_NODESET:
2399 ret = xmlXPathCastNodeSetToString(val->nodesetval);
2400 break;
2401 case XPATH_STRING:
2402 return(val->stringval);
2403 case XPATH_BOOLEAN:
2404 ret = xmlXPathCastBooleanToString(val->boolval);
2405 break;
2406 case XPATH_NUMBER: {
2407 ret = xmlXPathCastNumberToString(val->floatval);
2408 break;
2409 }
2410 case XPATH_USERS:
2411 case XPATH_POINT:
2412 case XPATH_RANGE:
2413 case XPATH_LOCATIONSET:
2414 TODO
2415 ret = xmlStrdup((const xmlChar *) "");
2416 break;
2417 }
2418 return(ret);
2419}
2420
2421/**
2422 * xmlXPathConvertString:
2423 * @val: an XPath object
2424 *
2425 * Converts an existing object to its string() equivalent
2426 *
2427 * Returns the new object, the old one is freed (or the operation
2428 * is done directly on @val)
2429 */
2430xmlXPathObjectPtr
2431xmlXPathConvertString(xmlXPathObjectPtr val) {
2432 xmlChar *res = NULL;
2433
2434 if (val == NULL)
2435 return(xmlXPathNewCString(""));
2436
2437 switch (val->type) {
2438 case XPATH_UNDEFINED:
2439#ifdef DEBUG_EXPR
2440 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2441#endif
2442 break;
2443 case XPATH_XSLT_TREE:
2444 case XPATH_NODESET:
2445 res = xmlXPathCastNodeSetToString(val->nodesetval);
2446 break;
2447 case XPATH_STRING:
2448 return(val);
2449 case XPATH_BOOLEAN:
2450 res = xmlXPathCastBooleanToString(val->boolval);
2451 break;
2452 case XPATH_NUMBER:
2453 res = xmlXPathCastNumberToString(val->floatval);
2454 break;
2455 case XPATH_USERS:
2456 case XPATH_POINT:
2457 case XPATH_RANGE:
2458 case XPATH_LOCATIONSET:
2459 TODO;
2460 break;
2461 }
2462 xmlXPathFreeObject(val);
2463 if (res == NULL)
2464 return(xmlXPathNewCString(""));
2465 return(xmlXPathWrapString(res));
2466}
2467
2468/**
2469 * xmlXPathCastBooleanToNumber:
2470 * @val: a boolean
2471 *
2472 * Converts a boolean to its number value
2473 *
2474 * Returns the number value
2475 */
2476double
2477xmlXPathCastBooleanToNumber(int val) {
2478 if (val)
2479 return(1.0);
2480 return(0.0);
2481}
2482
2483/**
2484 * xmlXPathCastStringToNumber:
2485 * @val: a string
2486 *
2487 * Converts a string to its number value
2488 *
2489 * Returns the number value
2490 */
2491double
2492xmlXPathCastStringToNumber(const xmlChar * val) {
2493 return(xmlXPathStringEvalNumber(val));
2494}
2495
2496/**
2497 * xmlXPathCastNodeToNumber:
2498 * @node: a node
2499 *
2500 * Converts a node to its number value
2501 *
2502 * Returns the number value
2503 */
2504double
2505xmlXPathCastNodeToNumber (xmlNodePtr node) {
2506 xmlChar *strval;
2507 double ret;
2508
2509 if (node == NULL)
2510 return(xmlXPathNAN);
2511 strval = xmlXPathCastNodeToString(node);
2512 if (strval == NULL)
2513 return(xmlXPathNAN);
2514 ret = xmlXPathCastStringToNumber(strval);
2515 xmlFree(strval);
2516
2517 return(ret);
2518}
2519
2520/**
2521 * xmlXPathCastNodeSetToNumber:
2522 * @ns: a node-set
2523 *
2524 * Converts a node-set to its number value
2525 *
2526 * Returns the number value
2527 */
2528double
2529xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
2530 xmlChar *str;
2531 double ret;
2532
2533 if (ns == NULL)
2534 return(xmlXPathNAN);
2535 str = xmlXPathCastNodeSetToString(ns);
2536 ret = xmlXPathCastStringToNumber(str);
2537 xmlFree(str);
2538 return(ret);
2539}
2540
2541/**
2542 * xmlXPathCastToNumber:
2543 * @val: an XPath object
2544 *
2545 * Converts an XPath object to its number value
2546 *
2547 * Returns the number value
2548 */
2549double
2550xmlXPathCastToNumber(xmlXPathObjectPtr val) {
2551 double ret = 0.0;
2552
2553 if (val == NULL)
2554 return(xmlXPathNAN);
2555 switch (val->type) {
2556 case XPATH_UNDEFINED:
2557#ifdef DEGUB_EXPR
2558 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
2559#endif
2560 ret = xmlXPathNAN;
2561 break;
2562 case XPATH_XSLT_TREE:
2563 case XPATH_NODESET:
2564 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
2565 break;
2566 case XPATH_STRING:
2567 ret = xmlXPathCastStringToNumber(val->stringval);
2568 break;
2569 case XPATH_NUMBER:
2570 ret = val->floatval;
2571 break;
2572 case XPATH_BOOLEAN:
2573 ret = xmlXPathCastBooleanToNumber(val->boolval);
2574 break;
2575 case XPATH_USERS:
2576 case XPATH_POINT:
2577 case XPATH_RANGE:
2578 case XPATH_LOCATIONSET:
2579 TODO;
2580 ret = xmlXPathNAN;
2581 break;
2582 }
2583 return(ret);
2584}
2585
2586/**
2587 * xmlXPathConvertNumber:
2588 * @val: an XPath object
2589 *
2590 * Converts an existing object to its number() equivalent
2591 *
2592 * Returns the new object, the old one is freed (or the operation
2593 * is done directly on @val)
2594 */
2595xmlXPathObjectPtr
2596xmlXPathConvertNumber(xmlXPathObjectPtr val) {
2597 xmlXPathObjectPtr ret;
2598
2599 if (val == NULL)
2600 return(xmlXPathNewFloat(0.0));
2601 if (val->type == XPATH_NUMBER)
2602 return(val);
2603 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
2604 xmlXPathFreeObject(val);
2605 return(ret);
2606}
2607
2608/**
2609 * xmlXPathCastNumberToBoolean:
2610 * @val: a number
2611 *
2612 * Converts a number to its boolean value
2613 *
2614 * Returns the boolean value
2615 */
2616int
2617xmlXPathCastNumberToBoolean (double val) {
2618 if (isnan(val) || (val == 0.0))
2619 return(0);
2620 return(1);
2621}
2622
2623/**
2624 * xmlXPathCastStringToBoolean:
2625 * @val: a string
2626 *
2627 * Converts a string to its boolean value
2628 *
2629 * Returns the boolean value
2630 */
2631int
2632xmlXPathCastStringToBoolean (const xmlChar *val) {
2633 if ((val == NULL) || (xmlStrlen(val) == 0))
2634 return(0);
2635 return(1);
2636}
2637
2638/**
2639 * xmlXPathCastNodeSetToBoolean:
2640 * @ns: a node-set
2641 *
2642 * Converts a node-set to its boolean value
2643 *
2644 * Returns the boolean value
2645 */
2646int
2647xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
2648 if ((ns == NULL) || (ns->nodeNr == 0))
2649 return(0);
2650 return(1);
2651}
2652
2653/**
2654 * xmlXpathCastToBoolean:
2655 * @val: an XPath object
2656 *
2657 * Converts an XPath object to its boolean value
2658 *
2659 * Returns the boolean value
2660 */
2661int
2662xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
2663 int ret = 0;
2664
2665 if (val == NULL)
2666 return(0);
2667 switch (val->type) {
2668 case XPATH_UNDEFINED:
2669#ifdef DEBUG_EXPR
2670 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
2671#endif
2672 ret = 0;
2673 break;
2674 case XPATH_XSLT_TREE:
2675 case XPATH_NODESET:
2676 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
2677 break;
2678 case XPATH_STRING:
2679 ret = xmlXPathCastStringToBoolean(val->stringval);
2680 break;
2681 case XPATH_NUMBER:
2682 ret = xmlXPathCastNumberToBoolean(val->floatval);
2683 break;
2684 case XPATH_BOOLEAN:
2685 ret = val->boolval;
2686 break;
2687 case XPATH_USERS:
2688 case XPATH_POINT:
2689 case XPATH_RANGE:
2690 case XPATH_LOCATIONSET:
2691 TODO;
2692 ret = 0;
2693 break;
2694 }
2695 return(ret);
2696}
2697
2698
2699/**
2700 * xmlXPathConvertBoolean:
2701 * @val: an XPath object
2702 *
2703 * Converts an existing object to its boolean() equivalent
2704 *
2705 * Returns the new object, the old one is freed (or the operation
2706 * is done directly on @val)
2707 */
2708xmlXPathObjectPtr
2709xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
2710 xmlXPathObjectPtr ret;
2711
2712 if (val == NULL)
2713 return(xmlXPathNewBoolean(0));
2714 if (val->type == XPATH_BOOLEAN)
2715 return(val);
2716 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
2717 xmlXPathFreeObject(val);
2718 return(ret);
2719}
2720
Owen Taylor3473f882001-02-23 17:55:21 +00002721/************************************************************************
2722 * *
2723 * Routines to handle XPath contexts *
2724 * *
2725 ************************************************************************/
2726
2727/**
2728 * xmlXPathNewContext:
2729 * @doc: the XML document
2730 *
2731 * Create a new xmlXPathContext
2732 *
2733 * Returns the xmlXPathContext just allocated.
2734 */
2735xmlXPathContextPtr
2736xmlXPathNewContext(xmlDocPtr doc) {
2737 xmlXPathContextPtr ret;
2738
2739 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
2740 if (ret == NULL) {
2741 xmlGenericError(xmlGenericErrorContext,
2742 "xmlXPathNewContext: out of memory\n");
2743 return(NULL);
2744 }
2745 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
2746 ret->doc = doc;
2747 ret->node = NULL;
2748
2749 ret->varHash = NULL;
2750
2751 ret->nb_types = 0;
2752 ret->max_types = 0;
2753 ret->types = NULL;
2754
2755 ret->funcHash = xmlHashCreate(0);
2756
2757 ret->nb_axis = 0;
2758 ret->max_axis = 0;
2759 ret->axis = NULL;
2760
2761 ret->nsHash = NULL;
2762 ret->user = NULL;
2763
2764 ret->contextSize = -1;
2765 ret->proximityPosition = -1;
2766
2767 xmlXPathRegisterAllFunctions(ret);
2768
2769 return(ret);
2770}
2771
2772/**
2773 * xmlXPathFreeContext:
2774 * @ctxt: the context to free
2775 *
2776 * Free up an xmlXPathContext
2777 */
2778void
2779xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
2780 xmlXPathRegisteredNsCleanup(ctxt);
2781 xmlXPathRegisteredFuncsCleanup(ctxt);
2782 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00002783 xmlFree(ctxt);
2784}
2785
2786/************************************************************************
2787 * *
2788 * Routines to handle XPath parser contexts *
2789 * *
2790 ************************************************************************/
2791
2792#define CHECK_CTXT(ctxt) \
2793 if (ctxt == NULL) { \
2794 xmlGenericError(xmlGenericErrorContext, \
2795 "%s:%d Internal error: ctxt == NULL\n", \
2796 __FILE__, __LINE__); \
2797 } \
2798
2799
2800#define CHECK_CONTEXT(ctxt) \
2801 if (ctxt == NULL) { \
2802 xmlGenericError(xmlGenericErrorContext, \
2803 "%s:%d Internal error: no context\n", \
2804 __FILE__, __LINE__); \
2805 } \
2806 else if (ctxt->doc == NULL) { \
2807 xmlGenericError(xmlGenericErrorContext, \
2808 "%s:%d Internal error: no document\n", \
2809 __FILE__, __LINE__); \
2810 } \
2811 else if (ctxt->doc->children == NULL) { \
2812 xmlGenericError(xmlGenericErrorContext, \
2813 "%s:%d Internal error: document without root\n", \
2814 __FILE__, __LINE__); \
2815 } \
2816
2817
2818/**
2819 * xmlXPathNewParserContext:
2820 * @str: the XPath expression
2821 * @ctxt: the XPath context
2822 *
2823 * Create a new xmlXPathParserContext
2824 *
2825 * Returns the xmlXPathParserContext just allocated.
2826 */
2827xmlXPathParserContextPtr
2828xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
2829 xmlXPathParserContextPtr ret;
2830
2831 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
2832 if (ret == NULL) {
2833 xmlGenericError(xmlGenericErrorContext,
2834 "xmlXPathNewParserContext: out of memory\n");
2835 return(NULL);
2836 }
2837 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
2838 ret->cur = ret->base = str;
2839 ret->context = ctxt;
2840
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002841 ret->comp = xmlXPathNewCompExpr();
2842 if (ret->comp == NULL) {
2843 xmlFree(ret->valueTab);
2844 xmlFree(ret);
2845 return(NULL);
2846 }
2847
2848 return(ret);
2849}
2850
2851/**
2852 * xmlXPathCompParserContext:
2853 * @comp: the XPath compiled expression
2854 * @ctxt: the XPath context
2855 *
2856 * Create a new xmlXPathParserContext when processing a compiled expression
2857 *
2858 * Returns the xmlXPathParserContext just allocated.
2859 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002860static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002861xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
2862 xmlXPathParserContextPtr ret;
2863
2864 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
2865 if (ret == NULL) {
2866 xmlGenericError(xmlGenericErrorContext,
2867 "xmlXPathNewParserContext: out of memory\n");
2868 return(NULL);
2869 }
2870 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
2871
Owen Taylor3473f882001-02-23 17:55:21 +00002872 /* Allocate the value stack */
2873 ret->valueTab = (xmlXPathObjectPtr *)
2874 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002875 if (ret->valueTab == NULL) {
2876 xmlFree(ret);
2877 xmlGenericError(xmlGenericErrorContext,
2878 "xmlXPathNewParserContext: out of memory\n");
2879 return(NULL);
2880 }
Owen Taylor3473f882001-02-23 17:55:21 +00002881 ret->valueNr = 0;
2882 ret->valueMax = 10;
2883 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002884
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00002885 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002886 ret->comp = comp;
2887
Owen Taylor3473f882001-02-23 17:55:21 +00002888 return(ret);
2889}
2890
2891/**
2892 * xmlXPathFreeParserContext:
2893 * @ctxt: the context to free
2894 *
2895 * Free up an xmlXPathParserContext
2896 */
2897void
2898xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
2899 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002900 xmlFree(ctxt->valueTab);
2901 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002902 if (ctxt->comp)
2903 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00002904 xmlFree(ctxt);
2905}
2906
2907/************************************************************************
2908 * *
2909 * The implicit core function library *
2910 * *
2911 ************************************************************************/
2912
Owen Taylor3473f882001-02-23 17:55:21 +00002913/**
Daniel Veillardf06307e2001-07-03 10:35:50 +00002914 * xmlXPathNodeStringHash:
2915 * @node: a node pointer
2916 *
2917 * Function computing the beginning of the string value of the node,
2918 * used to speed up comparisons
2919 *
2920 * Returns an int usable as a hash
2921 */
2922static unsigned int
2923xmlXPathNodeValHash(xmlNodePtr node) {
2924 int len = 2;
2925 const xmlChar * string = NULL;
2926 xmlNodePtr tmp = NULL;
2927 unsigned int ret = 0;
2928
2929 if (node == NULL)
2930 return(0);
2931
2932
2933 switch (node->type) {
2934 case XML_COMMENT_NODE:
2935 case XML_PI_NODE:
2936 case XML_CDATA_SECTION_NODE:
2937 case XML_TEXT_NODE:
2938 string = node->content;
2939 if (string == NULL)
2940 return(0);
2941 if (string[0] == 0)
2942 return(0);
2943 return(((unsigned int) string[0]) +
2944 (((unsigned int) string[1]) << 8));
2945 case XML_NAMESPACE_DECL:
2946 string = ((xmlNsPtr)node)->href;
2947 if (string == NULL)
2948 return(0);
2949 if (string[0] == 0)
2950 return(0);
2951 return(((unsigned int) string[0]) +
2952 (((unsigned int) string[1]) << 8));
2953 case XML_ATTRIBUTE_NODE:
2954 tmp = ((xmlAttrPtr) node)->children;
2955 break;
2956 case XML_ELEMENT_NODE:
2957 tmp = node->children;
2958 break;
2959 default:
2960 return(0);
2961 }
2962 while (tmp != NULL) {
2963 switch (tmp->type) {
2964 case XML_COMMENT_NODE:
2965 case XML_PI_NODE:
2966 case XML_CDATA_SECTION_NODE:
2967 case XML_TEXT_NODE:
2968 string = tmp->content;
2969 break;
2970 case XML_NAMESPACE_DECL:
2971 string = ((xmlNsPtr)tmp)->href;
2972 break;
2973 default:
2974 break;
2975 }
2976 if ((string != NULL) && (string[0] != 0)) {
2977 if (string[0] == 0)
2978 return(0);
2979 if (len == 1) {
2980 return(ret + (((unsigned int) string[0]) << 8));
2981 }
2982 if (string[1] == 0) {
2983 len = 1;
2984 ret = (unsigned int) string[0];
2985 } else {
2986 return(((unsigned int) string[0]) +
2987 (((unsigned int) string[1]) << 8));
2988 }
2989 }
2990 /*
2991 * Skip to next node
2992 */
2993 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
2994 if (tmp->children->type != XML_ENTITY_DECL) {
2995 tmp = tmp->children;
2996 continue;
2997 }
2998 }
2999 if (tmp == node)
3000 break;
3001
3002 if (tmp->next != NULL) {
3003 tmp = tmp->next;
3004 continue;
3005 }
3006
3007 do {
3008 tmp = tmp->parent;
3009 if (tmp == NULL)
3010 break;
3011 if (tmp == node) {
3012 tmp = NULL;
3013 break;
3014 }
3015 if (tmp->next != NULL) {
3016 tmp = tmp->next;
3017 break;
3018 }
3019 } while (tmp != NULL);
3020 }
3021 return(ret);
3022}
3023
3024/**
3025 * xmlXPathStringHash:
3026 * @string: a string
3027 *
3028 * Function computing the beginning of the string value of the node,
3029 * used to speed up comparisons
3030 *
3031 * Returns an int usable as a hash
3032 */
3033static unsigned int
3034xmlXPathStringHash(const xmlChar * string) {
3035 if (string == NULL)
3036 return((unsigned int) 0);
3037 if (string[0] == 0)
3038 return(0);
3039 return(((unsigned int) string[0]) +
3040 (((unsigned int) string[1]) << 8));
3041}
3042
3043/**
Owen Taylor3473f882001-02-23 17:55:21 +00003044 * xmlXPathCompareNodeSetFloat:
3045 * @ctxt: the XPath Parser context
3046 * @inf: less than (1) or greater than (0)
3047 * @strict: is the comparison strict
3048 * @arg: the node set
3049 * @f: the value
3050 *
3051 * Implement the compare operation between a nodeset and a number
3052 * @ns < @val (1, 1, ...
3053 * @ns <= @val (1, 0, ...
3054 * @ns > @val (0, 1, ...
3055 * @ns >= @val (0, 0, ...
3056 *
3057 * If one object to be compared is a node-set and the other is a number,
3058 * then the comparison will be true if and only if there is a node in the
3059 * node-set such that the result of performing the comparison on the number
3060 * to be compared and on the result of converting the string-value of that
3061 * node to a number using the number function is true.
3062 *
3063 * Returns 0 or 1 depending on the results of the test.
3064 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003065static int
Owen Taylor3473f882001-02-23 17:55:21 +00003066xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
3067 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
3068 int i, ret = 0;
3069 xmlNodeSetPtr ns;
3070 xmlChar *str2;
3071
3072 if ((f == NULL) || (arg == NULL) ||
3073 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3074 xmlXPathFreeObject(arg);
3075 xmlXPathFreeObject(f);
3076 return(0);
3077 }
3078 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003079 if (ns != NULL) {
3080 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003081 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003082 if (str2 != NULL) {
3083 valuePush(ctxt,
3084 xmlXPathNewString(str2));
3085 xmlFree(str2);
3086 xmlXPathNumberFunction(ctxt, 1);
3087 valuePush(ctxt, xmlXPathObjectCopy(f));
3088 ret = xmlXPathCompareValues(ctxt, inf, strict);
3089 if (ret)
3090 break;
3091 }
3092 }
Owen Taylor3473f882001-02-23 17:55:21 +00003093 }
3094 xmlXPathFreeObject(arg);
3095 xmlXPathFreeObject(f);
3096 return(ret);
3097}
3098
3099/**
3100 * xmlXPathCompareNodeSetString:
3101 * @ctxt: the XPath Parser context
3102 * @inf: less than (1) or greater than (0)
3103 * @strict: is the comparison strict
3104 * @arg: the node set
3105 * @s: the value
3106 *
3107 * Implement the compare operation between a nodeset and a string
3108 * @ns < @val (1, 1, ...
3109 * @ns <= @val (1, 0, ...
3110 * @ns > @val (0, 1, ...
3111 * @ns >= @val (0, 0, ...
3112 *
3113 * If one object to be compared is a node-set and the other is a string,
3114 * then the comparison will be true if and only if there is a node in
3115 * the node-set such that the result of performing the comparison on the
3116 * string-value of the node and the other string is true.
3117 *
3118 * Returns 0 or 1 depending on the results of the test.
3119 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003120static int
Owen Taylor3473f882001-02-23 17:55:21 +00003121xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
3122 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
3123 int i, ret = 0;
3124 xmlNodeSetPtr ns;
3125 xmlChar *str2;
3126
3127 if ((s == NULL) || (arg == NULL) ||
3128 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3129 xmlXPathFreeObject(arg);
3130 xmlXPathFreeObject(s);
3131 return(0);
3132 }
3133 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003134 if (ns != NULL) {
3135 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003136 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003137 if (str2 != NULL) {
3138 valuePush(ctxt,
3139 xmlXPathNewString(str2));
3140 xmlFree(str2);
3141 valuePush(ctxt, xmlXPathObjectCopy(s));
3142 ret = xmlXPathCompareValues(ctxt, inf, strict);
3143 if (ret)
3144 break;
3145 }
3146 }
Owen Taylor3473f882001-02-23 17:55:21 +00003147 }
3148 xmlXPathFreeObject(arg);
3149 xmlXPathFreeObject(s);
3150 return(ret);
3151}
3152
3153/**
3154 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003155 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00003156 * @strict: is the comparison strict
3157 * @arg1: the fist node set object
3158 * @arg2: the second node set object
3159 *
3160 * Implement the compare operation on nodesets:
3161 *
3162 * If both objects to be compared are node-sets, then the comparison
3163 * will be true if and only if there is a node in the first node-set
3164 * and a node in the second node-set such that the result of performing
3165 * the comparison on the string-values of the two nodes is true.
3166 * ....
3167 * When neither object to be compared is a node-set and the operator
3168 * is <=, <, >= or >, then the objects are compared by converting both
3169 * objects to numbers and comparing the numbers according to IEEE 754.
3170 * ....
3171 * The number function converts its argument to a number as follows:
3172 * - a string that consists of optional whitespace followed by an
3173 * optional minus sign followed by a Number followed by whitespace
3174 * is converted to the IEEE 754 number that is nearest (according
3175 * to the IEEE 754 round-to-nearest rule) to the mathematical value
3176 * represented by the string; any other string is converted to NaN
3177 *
3178 * Conclusion all nodes need to be converted first to their string value
3179 * and then the comparison must be done when possible
3180 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003181static int
3182xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00003183 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3184 int i, j, init = 0;
3185 double val1;
3186 double *values2;
3187 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003188 xmlNodeSetPtr ns1;
3189 xmlNodeSetPtr ns2;
3190
3191 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003192 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
3193 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003194 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003195 }
Owen Taylor3473f882001-02-23 17:55:21 +00003196 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003197 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
3198 xmlXPathFreeObject(arg1);
3199 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003200 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003201 }
Owen Taylor3473f882001-02-23 17:55:21 +00003202
3203 ns1 = arg1->nodesetval;
3204 ns2 = arg2->nodesetval;
3205
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003206 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003207 xmlXPathFreeObject(arg1);
3208 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003209 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003210 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003211 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003212 xmlXPathFreeObject(arg1);
3213 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003214 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003215 }
Owen Taylor3473f882001-02-23 17:55:21 +00003216
3217 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
3218 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003219 xmlXPathFreeObject(arg1);
3220 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003221 return(0);
3222 }
3223 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003224 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00003225 if (isnan(val1))
3226 continue;
3227 for (j = 0;j < ns2->nodeNr;j++) {
3228 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003229 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00003230 }
3231 if (isnan(values2[j]))
3232 continue;
3233 if (inf && strict)
3234 ret = (val1 < values2[j]);
3235 else if (inf && !strict)
3236 ret = (val1 <= values2[j]);
3237 else if (!inf && strict)
3238 ret = (val1 > values2[j]);
3239 else if (!inf && !strict)
3240 ret = (val1 >= values2[j]);
3241 if (ret)
3242 break;
3243 }
3244 if (ret)
3245 break;
3246 init = 1;
3247 }
3248 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003249 xmlXPathFreeObject(arg1);
3250 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003251 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003252}
3253
3254/**
3255 * xmlXPathCompareNodeSetValue:
3256 * @ctxt: the XPath Parser context
3257 * @inf: less than (1) or greater than (0)
3258 * @strict: is the comparison strict
3259 * @arg: the node set
3260 * @val: the value
3261 *
3262 * Implement the compare operation between a nodeset and a value
3263 * @ns < @val (1, 1, ...
3264 * @ns <= @val (1, 0, ...
3265 * @ns > @val (0, 1, ...
3266 * @ns >= @val (0, 0, ...
3267 *
3268 * If one object to be compared is a node-set and the other is a boolean,
3269 * then the comparison will be true if and only if the result of performing
3270 * the comparison on the boolean and on the result of converting
3271 * the node-set to a boolean using the boolean function is true.
3272 *
3273 * Returns 0 or 1 depending on the results of the test.
3274 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003275static int
Owen Taylor3473f882001-02-23 17:55:21 +00003276xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
3277 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
3278 if ((val == NULL) || (arg == NULL) ||
3279 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3280 return(0);
3281
3282 switch(val->type) {
3283 case XPATH_NUMBER:
3284 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
3285 case XPATH_NODESET:
3286 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003287 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00003288 case XPATH_STRING:
3289 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
3290 case XPATH_BOOLEAN:
3291 valuePush(ctxt, arg);
3292 xmlXPathBooleanFunction(ctxt, 1);
3293 valuePush(ctxt, val);
3294 return(xmlXPathCompareValues(ctxt, inf, strict));
3295 default:
3296 TODO
3297 return(0);
3298 }
3299 return(0);
3300}
3301
3302/**
3303 * xmlXPathEqualNodeSetString
3304 * @arg: the nodeset object argument
3305 * @str: the string to compare to.
3306 *
3307 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3308 * If one object to be compared is a node-set and the other is a string,
3309 * then the comparison will be true if and only if there is a node in
3310 * the node-set such that the result of performing the comparison on the
3311 * string-value of the node and the other string is true.
3312 *
3313 * Returns 0 or 1 depending on the results of the test.
3314 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003315static int
Daniel Veillardf06307e2001-07-03 10:35:50 +00003316xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str)
3317{
Owen Taylor3473f882001-02-23 17:55:21 +00003318 int i;
3319 xmlNodeSetPtr ns;
3320 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003321 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00003322
3323 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00003324 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3325 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00003326 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003327 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003328 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00003329 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00003330 if (ns->nodeNr <= 0) {
3331 if (hash == 0)
3332 return(1);
3333 return(0);
3334 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003335 for (i = 0; i < ns->nodeNr; i++) {
3336 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
3337 str2 = xmlNodeGetContent(ns->nodeTab[i]);
3338 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
3339 xmlFree(str2);
3340 return (1);
3341 }
3342 if (str2 != NULL)
3343 xmlFree(str2);
3344 }
Owen Taylor3473f882001-02-23 17:55:21 +00003345 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003346 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00003347}
3348
3349/**
3350 * xmlXPathEqualNodeSetFloat
3351 * @arg: the nodeset object argument
3352 * @f: the float to compare to
3353 *
3354 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3355 * If one object to be compared is a node-set and the other is a number,
3356 * then the comparison will be true if and only if there is a node in
3357 * the node-set such that the result of performing the comparison on the
3358 * number to be compared and on the result of converting the string-value
3359 * of that node to a number using the number function is true.
3360 *
3361 * Returns 0 or 1 depending on the results of the test.
3362 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003363static int
Owen Taylor3473f882001-02-23 17:55:21 +00003364xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) {
3365 char buf[100] = "";
3366
3367 if ((arg == NULL) ||
3368 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3369 return(0);
3370
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003371 xmlXPathFormatNumber(f, buf, sizeof(buf));
Owen Taylor3473f882001-02-23 17:55:21 +00003372 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
3373}
3374
3375
3376/**
3377 * xmlXPathEqualNodeSets
3378 * @arg1: first nodeset object argument
3379 * @arg2: second nodeset object argument
3380 *
3381 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
3382 * If both objects to be compared are node-sets, then the comparison
3383 * will be true if and only if there is a node in the first node-set and
3384 * a node in the second node-set such that the result of performing the
3385 * comparison on the string-values of the two nodes is true.
3386 *
3387 * (needless to say, this is a costly operation)
3388 *
3389 * Returns 0 or 1 depending on the results of the test.
3390 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003391static int
Owen Taylor3473f882001-02-23 17:55:21 +00003392xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3393 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003394 unsigned int *hashs1;
3395 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00003396 xmlChar **values1;
3397 xmlChar **values2;
3398 int ret = 0;
3399 xmlNodeSetPtr ns1;
3400 xmlNodeSetPtr ns2;
3401
3402 if ((arg1 == NULL) ||
3403 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
3404 return(0);
3405 if ((arg2 == NULL) ||
3406 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
3407 return(0);
3408
3409 ns1 = arg1->nodesetval;
3410 ns2 = arg2->nodesetval;
3411
Daniel Veillard911f49a2001-04-07 15:39:35 +00003412 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00003413 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003414 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00003415 return(0);
3416
3417 /*
3418 * check if there is a node pertaining to both sets
3419 */
3420 for (i = 0;i < ns1->nodeNr;i++)
3421 for (j = 0;j < ns2->nodeNr;j++)
3422 if (ns1->nodeTab[i] == ns2->nodeTab[j])
3423 return(1);
3424
3425 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
3426 if (values1 == NULL)
3427 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00003428 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
3429 if (hashs1 == NULL) {
3430 xmlFree(values1);
3431 return(0);
3432 }
Owen Taylor3473f882001-02-23 17:55:21 +00003433 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
3434 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
3435 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00003436 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00003437 xmlFree(values1);
3438 return(0);
3439 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003440 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
3441 if (hashs2 == NULL) {
3442 xmlFree(hashs1);
3443 xmlFree(values1);
3444 xmlFree(values2);
3445 return(0);
3446 }
Owen Taylor3473f882001-02-23 17:55:21 +00003447 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
3448 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00003449 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00003450 for (j = 0;j < ns2->nodeNr;j++) {
3451 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00003452 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
3453 if (hashs1[i] == hashs2[j]) {
3454 if (values1[i] == NULL)
3455 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
3456 if (values2[j] == NULL)
3457 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
3458 ret = xmlStrEqual(values1[i], values2[j]);
3459 if (ret)
3460 break;
3461 }
Owen Taylor3473f882001-02-23 17:55:21 +00003462 }
3463 if (ret)
3464 break;
3465 }
3466 for (i = 0;i < ns1->nodeNr;i++)
3467 if (values1[i] != NULL)
3468 xmlFree(values1[i]);
3469 for (j = 0;j < ns2->nodeNr;j++)
3470 if (values2[j] != NULL)
3471 xmlFree(values2[j]);
3472 xmlFree(values1);
3473 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00003474 xmlFree(hashs1);
3475 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00003476 return(ret);
3477}
3478
3479/**
3480 * xmlXPathEqualValues:
3481 * @ctxt: the XPath Parser context
3482 *
3483 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3484 *
3485 * Returns 0 or 1 depending on the results of the test.
3486 */
3487int
3488xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
3489 xmlXPathObjectPtr arg1, arg2;
3490 int ret = 0;
3491
3492 arg1 = valuePop(ctxt);
3493 if (arg1 == NULL)
3494 XP_ERROR0(XPATH_INVALID_OPERAND);
3495
3496 arg2 = valuePop(ctxt);
3497 if (arg2 == NULL) {
3498 xmlXPathFreeObject(arg1);
3499 XP_ERROR0(XPATH_INVALID_OPERAND);
3500 }
3501
3502 if (arg1 == arg2) {
3503#ifdef DEBUG_EXPR
3504 xmlGenericError(xmlGenericErrorContext,
3505 "Equal: by pointer\n");
3506#endif
3507 return(1);
3508 }
3509
3510 switch (arg1->type) {
3511 case XPATH_UNDEFINED:
3512#ifdef DEBUG_EXPR
3513 xmlGenericError(xmlGenericErrorContext,
3514 "Equal: undefined\n");
3515#endif
3516 break;
3517 case XPATH_XSLT_TREE:
3518 case XPATH_NODESET:
3519 switch (arg2->type) {
3520 case XPATH_UNDEFINED:
3521#ifdef DEBUG_EXPR
3522 xmlGenericError(xmlGenericErrorContext,
3523 "Equal: undefined\n");
3524#endif
3525 break;
3526 case XPATH_XSLT_TREE:
3527 case XPATH_NODESET:
3528 ret = xmlXPathEqualNodeSets(arg1, arg2);
3529 break;
3530 case XPATH_BOOLEAN:
3531 if ((arg1->nodesetval == NULL) ||
3532 (arg1->nodesetval->nodeNr == 0)) ret = 0;
3533 else
3534 ret = 1;
3535 ret = (ret == arg2->boolval);
3536 break;
3537 case XPATH_NUMBER:
3538 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
3539 break;
3540 case XPATH_STRING:
3541 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
3542 break;
3543 case XPATH_USERS:
3544 case XPATH_POINT:
3545 case XPATH_RANGE:
3546 case XPATH_LOCATIONSET:
3547 TODO
3548 break;
3549 }
3550 break;
3551 case XPATH_BOOLEAN:
3552 switch (arg2->type) {
3553 case XPATH_UNDEFINED:
3554#ifdef DEBUG_EXPR
3555 xmlGenericError(xmlGenericErrorContext,
3556 "Equal: undefined\n");
3557#endif
3558 break;
3559 case XPATH_NODESET:
3560 case XPATH_XSLT_TREE:
3561 if ((arg2->nodesetval == NULL) ||
3562 (arg2->nodesetval->nodeNr == 0)) ret = 0;
3563 else
3564 ret = 1;
3565 break;
3566 case XPATH_BOOLEAN:
3567#ifdef DEBUG_EXPR
3568 xmlGenericError(xmlGenericErrorContext,
3569 "Equal: %d boolean %d \n",
3570 arg1->boolval, arg2->boolval);
3571#endif
3572 ret = (arg1->boolval == arg2->boolval);
3573 break;
3574 case XPATH_NUMBER:
3575 if (arg2->floatval) ret = 1;
3576 else ret = 0;
3577 ret = (arg1->boolval == ret);
3578 break;
3579 case XPATH_STRING:
3580 if ((arg2->stringval == NULL) ||
3581 (arg2->stringval[0] == 0)) ret = 0;
3582 else
3583 ret = 1;
3584 ret = (arg1->boolval == ret);
3585 break;
3586 case XPATH_USERS:
3587 case XPATH_POINT:
3588 case XPATH_RANGE:
3589 case XPATH_LOCATIONSET:
3590 TODO
3591 break;
3592 }
3593 break;
3594 case XPATH_NUMBER:
3595 switch (arg2->type) {
3596 case XPATH_UNDEFINED:
3597#ifdef DEBUG_EXPR
3598 xmlGenericError(xmlGenericErrorContext,
3599 "Equal: undefined\n");
3600#endif
3601 break;
3602 case XPATH_NODESET:
3603 case XPATH_XSLT_TREE:
3604 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
3605 break;
3606 case XPATH_BOOLEAN:
3607 if (arg1->floatval) ret = 1;
3608 else ret = 0;
3609 ret = (arg2->boolval == ret);
3610 break;
3611 case XPATH_STRING:
3612 valuePush(ctxt, arg2);
3613 xmlXPathNumberFunction(ctxt, 1);
3614 arg2 = valuePop(ctxt);
3615 /* no break on purpose */
3616 case XPATH_NUMBER:
3617 ret = (arg1->floatval == arg2->floatval);
3618 break;
3619 case XPATH_USERS:
3620 case XPATH_POINT:
3621 case XPATH_RANGE:
3622 case XPATH_LOCATIONSET:
3623 TODO
3624 break;
3625 }
3626 break;
3627 case XPATH_STRING:
3628 switch (arg2->type) {
3629 case XPATH_UNDEFINED:
3630#ifdef DEBUG_EXPR
3631 xmlGenericError(xmlGenericErrorContext,
3632 "Equal: undefined\n");
3633#endif
3634 break;
3635 case XPATH_NODESET:
3636 case XPATH_XSLT_TREE:
3637 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
3638 break;
3639 case XPATH_BOOLEAN:
3640 if ((arg1->stringval == NULL) ||
3641 (arg1->stringval[0] == 0)) ret = 0;
3642 else
3643 ret = 1;
3644 ret = (arg2->boolval == ret);
3645 break;
3646 case XPATH_STRING:
3647 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
3648 break;
3649 case XPATH_NUMBER:
3650 valuePush(ctxt, arg1);
3651 xmlXPathNumberFunction(ctxt, 1);
3652 arg1 = valuePop(ctxt);
3653 ret = (arg1->floatval == arg2->floatval);
3654 break;
3655 case XPATH_USERS:
3656 case XPATH_POINT:
3657 case XPATH_RANGE:
3658 case XPATH_LOCATIONSET:
3659 TODO
3660 break;
3661 }
3662 break;
3663 case XPATH_USERS:
3664 case XPATH_POINT:
3665 case XPATH_RANGE:
3666 case XPATH_LOCATIONSET:
3667 TODO
3668 break;
3669 }
3670 xmlXPathFreeObject(arg1);
3671 xmlXPathFreeObject(arg2);
3672 return(ret);
3673}
3674
3675
3676/**
3677 * xmlXPathCompareValues:
3678 * @ctxt: the XPath Parser context
3679 * @inf: less than (1) or greater than (0)
3680 * @strict: is the comparison strict
3681 *
3682 * Implement the compare operation on XPath objects:
3683 * @arg1 < @arg2 (1, 1, ...
3684 * @arg1 <= @arg2 (1, 0, ...
3685 * @arg1 > @arg2 (0, 1, ...
3686 * @arg1 >= @arg2 (0, 0, ...
3687 *
3688 * When neither object to be compared is a node-set and the operator is
3689 * <=, <, >=, >, then the objects are compared by converted both objects
3690 * to numbers and comparing the numbers according to IEEE 754. The <
3691 * comparison will be true if and only if the first number is less than the
3692 * second number. The <= comparison will be true if and only if the first
3693 * number is less than or equal to the second number. The > comparison
3694 * will be true if and only if the first number is greater than the second
3695 * number. The >= comparison will be true if and only if the first number
3696 * is greater than or equal to the second number.
3697 *
3698 * Returns 1 if the comparaison succeeded, 0 if it failed
3699 */
3700int
3701xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
3702 int ret = 0;
3703 xmlXPathObjectPtr arg1, arg2;
3704
3705 arg2 = valuePop(ctxt);
3706 if (arg2 == NULL) {
3707 XP_ERROR0(XPATH_INVALID_OPERAND);
3708 }
3709
3710 arg1 = valuePop(ctxt);
3711 if (arg1 == NULL) {
3712 xmlXPathFreeObject(arg2);
3713 XP_ERROR0(XPATH_INVALID_OPERAND);
3714 }
3715
3716 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
3717 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003718 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003719 } else {
3720 if (arg1->type == XPATH_NODESET) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00003721 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
3722 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003723 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00003724 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
3725 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00003726 }
3727 }
3728 return(ret);
3729 }
3730
3731 if (arg1->type != XPATH_NUMBER) {
3732 valuePush(ctxt, arg1);
3733 xmlXPathNumberFunction(ctxt, 1);
3734 arg1 = valuePop(ctxt);
3735 }
3736 if (arg1->type != XPATH_NUMBER) {
3737 xmlXPathFreeObject(arg1);
3738 xmlXPathFreeObject(arg2);
3739 XP_ERROR0(XPATH_INVALID_OPERAND);
3740 }
3741 if (arg2->type != XPATH_NUMBER) {
3742 valuePush(ctxt, arg2);
3743 xmlXPathNumberFunction(ctxt, 1);
3744 arg2 = valuePop(ctxt);
3745 }
3746 if (arg2->type != XPATH_NUMBER) {
3747 xmlXPathFreeObject(arg1);
3748 xmlXPathFreeObject(arg2);
3749 XP_ERROR0(XPATH_INVALID_OPERAND);
3750 }
3751 /*
3752 * Add tests for infinity and nan
3753 * => feedback on 3.4 for Inf and NaN
3754 */
3755 if (inf && strict)
3756 ret = (arg1->floatval < arg2->floatval);
3757 else if (inf && !strict)
3758 ret = (arg1->floatval <= arg2->floatval);
3759 else if (!inf && strict)
3760 ret = (arg1->floatval > arg2->floatval);
3761 else if (!inf && !strict)
3762 ret = (arg1->floatval >= arg2->floatval);
3763 xmlXPathFreeObject(arg1);
3764 xmlXPathFreeObject(arg2);
3765 return(ret);
3766}
3767
3768/**
3769 * xmlXPathValueFlipSign:
3770 * @ctxt: the XPath Parser context
3771 *
3772 * Implement the unary - operation on an XPath object
3773 * The numeric operators convert their operands to numbers as if
3774 * by calling the number function.
3775 */
3776void
3777xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003778 CAST_TO_NUMBER;
3779 CHECK_TYPE(XPATH_NUMBER);
3780 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00003781}
3782
3783/**
3784 * xmlXPathAddValues:
3785 * @ctxt: the XPath Parser context
3786 *
3787 * Implement the add operation on XPath objects:
3788 * The numeric operators convert their operands to numbers as if
3789 * by calling the number function.
3790 */
3791void
3792xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
3793 xmlXPathObjectPtr arg;
3794 double val;
3795
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003796 arg = valuePop(ctxt);
3797 if (arg == NULL)
3798 XP_ERROR(XPATH_INVALID_OPERAND);
3799 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00003800 xmlXPathFreeObject(arg);
3801
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003802 CAST_TO_NUMBER;
3803 CHECK_TYPE(XPATH_NUMBER);
3804 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00003805}
3806
3807/**
3808 * xmlXPathSubValues:
3809 * @ctxt: the XPath Parser context
3810 *
3811 * Implement the substraction operation on XPath objects:
3812 * The numeric operators convert their operands to numbers as if
3813 * by calling the number function.
3814 */
3815void
3816xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
3817 xmlXPathObjectPtr arg;
3818 double val;
3819
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003820 arg = valuePop(ctxt);
3821 if (arg == NULL)
3822 XP_ERROR(XPATH_INVALID_OPERAND);
3823 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00003824 xmlXPathFreeObject(arg);
3825
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003826 CAST_TO_NUMBER;
3827 CHECK_TYPE(XPATH_NUMBER);
3828 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00003829}
3830
3831/**
3832 * xmlXPathMultValues:
3833 * @ctxt: the XPath Parser context
3834 *
3835 * Implement the multiply operation on XPath objects:
3836 * The numeric operators convert their operands to numbers as if
3837 * by calling the number function.
3838 */
3839void
3840xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
3841 xmlXPathObjectPtr arg;
3842 double val;
3843
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003844 arg = valuePop(ctxt);
3845 if (arg == NULL)
3846 XP_ERROR(XPATH_INVALID_OPERAND);
3847 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00003848 xmlXPathFreeObject(arg);
3849
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003850 CAST_TO_NUMBER;
3851 CHECK_TYPE(XPATH_NUMBER);
3852 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00003853}
3854
3855/**
3856 * xmlXPathDivValues:
3857 * @ctxt: the XPath Parser context
3858 *
3859 * Implement the div operation on XPath objects @arg1 / @arg2:
3860 * The numeric operators convert their operands to numbers as if
3861 * by calling the number function.
3862 */
3863void
3864xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
3865 xmlXPathObjectPtr arg;
3866 double val;
3867
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003868 arg = valuePop(ctxt);
3869 if (arg == NULL)
3870 XP_ERROR(XPATH_INVALID_OPERAND);
3871 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00003872 xmlXPathFreeObject(arg);
3873
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003874 CAST_TO_NUMBER;
3875 CHECK_TYPE(XPATH_NUMBER);
3876 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00003877}
3878
3879/**
3880 * xmlXPathModValues:
3881 * @ctxt: the XPath Parser context
3882 *
3883 * Implement the mod operation on XPath objects: @arg1 / @arg2
3884 * The numeric operators convert their operands to numbers as if
3885 * by calling the number function.
3886 */
3887void
3888xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
3889 xmlXPathObjectPtr arg;
3890 int arg1, arg2;
3891
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003892 arg = valuePop(ctxt);
3893 if (arg == NULL)
3894 XP_ERROR(XPATH_INVALID_OPERAND);
3895 arg2 = (int) xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00003896 xmlXPathFreeObject(arg);
3897
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003898 CAST_TO_NUMBER;
3899 CHECK_TYPE(XPATH_NUMBER);
3900 arg1 = (int) ctxt->value->floatval;
3901 ctxt->value->floatval = arg1 % arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00003902}
3903
3904/************************************************************************
3905 * *
3906 * The traversal functions *
3907 * *
3908 ************************************************************************/
3909
Owen Taylor3473f882001-02-23 17:55:21 +00003910/*
3911 * A traversal function enumerates nodes along an axis.
3912 * Initially it must be called with NULL, and it indicates
3913 * termination on the axis by returning NULL.
3914 */
3915typedef xmlNodePtr (*xmlXPathTraversalFunction)
3916 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
3917
3918/**
3919 * xmlXPathNextSelf:
3920 * @ctxt: the XPath Parser context
3921 * @cur: the current node in the traversal
3922 *
3923 * Traversal function for the "self" direction
3924 * The self axis contains just the context node itself
3925 *
3926 * Returns the next element following that axis
3927 */
3928xmlNodePtr
3929xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3930 if (cur == NULL)
3931 return(ctxt->context->node);
3932 return(NULL);
3933}
3934
3935/**
3936 * xmlXPathNextChild:
3937 * @ctxt: the XPath Parser context
3938 * @cur: the current node in the traversal
3939 *
3940 * Traversal function for the "child" direction
3941 * The child axis contains the children of the context node in document order.
3942 *
3943 * Returns the next element following that axis
3944 */
3945xmlNodePtr
3946xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3947 if (cur == NULL) {
3948 if (ctxt->context->node == NULL) return(NULL);
3949 switch (ctxt->context->node->type) {
3950 case XML_ELEMENT_NODE:
3951 case XML_TEXT_NODE:
3952 case XML_CDATA_SECTION_NODE:
3953 case XML_ENTITY_REF_NODE:
3954 case XML_ENTITY_NODE:
3955 case XML_PI_NODE:
3956 case XML_COMMENT_NODE:
3957 case XML_NOTATION_NODE:
3958 case XML_DTD_NODE:
3959 return(ctxt->context->node->children);
3960 case XML_DOCUMENT_NODE:
3961 case XML_DOCUMENT_TYPE_NODE:
3962 case XML_DOCUMENT_FRAG_NODE:
3963 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003964#ifdef LIBXML_DOCB_ENABLED
3965 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003966#endif
3967 return(((xmlDocPtr) ctxt->context->node)->children);
3968 case XML_ELEMENT_DECL:
3969 case XML_ATTRIBUTE_DECL:
3970 case XML_ENTITY_DECL:
3971 case XML_ATTRIBUTE_NODE:
3972 case XML_NAMESPACE_DECL:
3973 case XML_XINCLUDE_START:
3974 case XML_XINCLUDE_END:
3975 return(NULL);
3976 }
3977 return(NULL);
3978 }
3979 if ((cur->type == XML_DOCUMENT_NODE) ||
3980 (cur->type == XML_HTML_DOCUMENT_NODE))
3981 return(NULL);
3982 return(cur->next);
3983}
3984
3985/**
3986 * xmlXPathNextDescendant:
3987 * @ctxt: the XPath Parser context
3988 * @cur: the current node in the traversal
3989 *
3990 * Traversal function for the "descendant" direction
3991 * the descendant axis contains the descendants of the context node in document
3992 * order; a descendant is a child or a child of a child and so on.
3993 *
3994 * Returns the next element following that axis
3995 */
3996xmlNodePtr
3997xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3998 if (cur == NULL) {
3999 if (ctxt->context->node == NULL)
4000 return(NULL);
4001 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4002 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4003 return(NULL);
4004
4005 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
4006 return(ctxt->context->doc->children);
4007 return(ctxt->context->node->children);
4008 }
4009
4010 if (cur->children != NULL)
4011 {
4012 if (cur->children->type != XML_ENTITY_DECL)
4013 return(cur->children);
4014 }
4015 if (cur->next != NULL) return(cur->next);
4016
4017 do {
4018 cur = cur->parent;
4019 if (cur == NULL) return(NULL);
4020 if (cur == ctxt->context->node) return(NULL);
4021 if (cur->next != NULL) {
4022 cur = cur->next;
4023 return(cur);
4024 }
4025 } while (cur != NULL);
4026 return(cur);
4027}
4028
4029/**
4030 * xmlXPathNextDescendantOrSelf:
4031 * @ctxt: the XPath Parser context
4032 * @cur: the current node in the traversal
4033 *
4034 * Traversal function for the "descendant-or-self" direction
4035 * the descendant-or-self axis contains the context node and the descendants
4036 * of the context node in document order; thus the context node is the first
4037 * node on the axis, and the first child of the context node is the second node
4038 * on the axis
4039 *
4040 * Returns the next element following that axis
4041 */
4042xmlNodePtr
4043xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4044 if (cur == NULL) {
4045 if (ctxt->context->node == NULL)
4046 return(NULL);
4047 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4048 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4049 return(NULL);
4050 return(ctxt->context->node);
4051 }
4052
4053 return(xmlXPathNextDescendant(ctxt, cur));
4054}
4055
4056/**
4057 * xmlXPathNextParent:
4058 * @ctxt: the XPath Parser context
4059 * @cur: the current node in the traversal
4060 *
4061 * Traversal function for the "parent" direction
4062 * The parent axis contains the parent of the context node, if there is one.
4063 *
4064 * Returns the next element following that axis
4065 */
4066xmlNodePtr
4067xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4068 /*
4069 * the parent of an attribute or namespace node is the element
4070 * to which the attribute or namespace node is attached
4071 * Namespace handling !!!
4072 */
4073 if (cur == NULL) {
4074 if (ctxt->context->node == NULL) return(NULL);
4075 switch (ctxt->context->node->type) {
4076 case XML_ELEMENT_NODE:
4077 case XML_TEXT_NODE:
4078 case XML_CDATA_SECTION_NODE:
4079 case XML_ENTITY_REF_NODE:
4080 case XML_ENTITY_NODE:
4081 case XML_PI_NODE:
4082 case XML_COMMENT_NODE:
4083 case XML_NOTATION_NODE:
4084 case XML_DTD_NODE:
4085 case XML_ELEMENT_DECL:
4086 case XML_ATTRIBUTE_DECL:
4087 case XML_XINCLUDE_START:
4088 case XML_XINCLUDE_END:
4089 case XML_ENTITY_DECL:
4090 if (ctxt->context->node->parent == NULL)
4091 return((xmlNodePtr) ctxt->context->doc);
4092 return(ctxt->context->node->parent);
4093 case XML_ATTRIBUTE_NODE: {
4094 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4095
4096 return(att->parent);
4097 }
4098 case XML_DOCUMENT_NODE:
4099 case XML_DOCUMENT_TYPE_NODE:
4100 case XML_DOCUMENT_FRAG_NODE:
4101 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004102#ifdef LIBXML_DOCB_ENABLED
4103 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004104#endif
4105 return(NULL);
4106 case XML_NAMESPACE_DECL:
4107 /*
4108 * TODO !!! may require extending struct _xmlNs with
4109 * parent field
4110 * C.f. Infoset case...
4111 */
4112 return(NULL);
4113 }
4114 }
4115 return(NULL);
4116}
4117
4118/**
4119 * xmlXPathNextAncestor:
4120 * @ctxt: the XPath Parser context
4121 * @cur: the current node in the traversal
4122 *
4123 * Traversal function for the "ancestor" direction
4124 * the ancestor axis contains the ancestors of the context node; the ancestors
4125 * of the context node consist of the parent of context node and the parent's
4126 * parent and so on; the nodes are ordered in reverse document order; thus the
4127 * parent is the first node on the axis, and the parent's parent is the second
4128 * node on the axis
4129 *
4130 * Returns the next element following that axis
4131 */
4132xmlNodePtr
4133xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4134 /*
4135 * the parent of an attribute or namespace node is the element
4136 * to which the attribute or namespace node is attached
4137 * !!!!!!!!!!!!!
4138 */
4139 if (cur == NULL) {
4140 if (ctxt->context->node == NULL) return(NULL);
4141 switch (ctxt->context->node->type) {
4142 case XML_ELEMENT_NODE:
4143 case XML_TEXT_NODE:
4144 case XML_CDATA_SECTION_NODE:
4145 case XML_ENTITY_REF_NODE:
4146 case XML_ENTITY_NODE:
4147 case XML_PI_NODE:
4148 case XML_COMMENT_NODE:
4149 case XML_DTD_NODE:
4150 case XML_ELEMENT_DECL:
4151 case XML_ATTRIBUTE_DECL:
4152 case XML_ENTITY_DECL:
4153 case XML_NOTATION_NODE:
4154 case XML_XINCLUDE_START:
4155 case XML_XINCLUDE_END:
4156 if (ctxt->context->node->parent == NULL)
4157 return((xmlNodePtr) ctxt->context->doc);
4158 return(ctxt->context->node->parent);
4159 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004160 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00004161
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004162 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00004163 }
4164 case XML_DOCUMENT_NODE:
4165 case XML_DOCUMENT_TYPE_NODE:
4166 case XML_DOCUMENT_FRAG_NODE:
4167 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004168#ifdef LIBXML_DOCB_ENABLED
4169 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004170#endif
4171 return(NULL);
4172 case XML_NAMESPACE_DECL:
4173 /*
4174 * TODO !!! may require extending struct _xmlNs with
4175 * parent field
4176 * C.f. Infoset case...
4177 */
4178 return(NULL);
4179 }
4180 return(NULL);
4181 }
4182 if (cur == ctxt->context->doc->children)
4183 return((xmlNodePtr) ctxt->context->doc);
4184 if (cur == (xmlNodePtr) ctxt->context->doc)
4185 return(NULL);
4186 switch (cur->type) {
4187 case XML_ELEMENT_NODE:
4188 case XML_TEXT_NODE:
4189 case XML_CDATA_SECTION_NODE:
4190 case XML_ENTITY_REF_NODE:
4191 case XML_ENTITY_NODE:
4192 case XML_PI_NODE:
4193 case XML_COMMENT_NODE:
4194 case XML_NOTATION_NODE:
4195 case XML_DTD_NODE:
4196 case XML_ELEMENT_DECL:
4197 case XML_ATTRIBUTE_DECL:
4198 case XML_ENTITY_DECL:
4199 case XML_XINCLUDE_START:
4200 case XML_XINCLUDE_END:
4201 return(cur->parent);
4202 case XML_ATTRIBUTE_NODE: {
4203 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4204
4205 return(att->parent);
4206 }
4207 case XML_DOCUMENT_NODE:
4208 case XML_DOCUMENT_TYPE_NODE:
4209 case XML_DOCUMENT_FRAG_NODE:
4210 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004211#ifdef LIBXML_DOCB_ENABLED
4212 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004213#endif
4214 return(NULL);
4215 case XML_NAMESPACE_DECL:
4216 /*
4217 * TODO !!! may require extending struct _xmlNs with
4218 * parent field
4219 * C.f. Infoset case...
4220 */
4221 return(NULL);
4222 }
4223 return(NULL);
4224}
4225
4226/**
4227 * xmlXPathNextAncestorOrSelf:
4228 * @ctxt: the XPath Parser context
4229 * @cur: the current node in the traversal
4230 *
4231 * Traversal function for the "ancestor-or-self" direction
4232 * he ancestor-or-self axis contains the context node and ancestors of
4233 * the context node in reverse document order; thus the context node is
4234 * the first node on the axis, and the context node's parent the second;
4235 * parent here is defined the same as with the parent axis.
4236 *
4237 * Returns the next element following that axis
4238 */
4239xmlNodePtr
4240xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4241 if (cur == NULL)
4242 return(ctxt->context->node);
4243 return(xmlXPathNextAncestor(ctxt, cur));
4244}
4245
4246/**
4247 * xmlXPathNextFollowingSibling:
4248 * @ctxt: the XPath Parser context
4249 * @cur: the current node in the traversal
4250 *
4251 * Traversal function for the "following-sibling" direction
4252 * The following-sibling axis contains the following siblings of the context
4253 * node in document order.
4254 *
4255 * Returns the next element following that axis
4256 */
4257xmlNodePtr
4258xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4259 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4260 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4261 return(NULL);
4262 if (cur == (xmlNodePtr) ctxt->context->doc)
4263 return(NULL);
4264 if (cur == NULL)
4265 return(ctxt->context->node->next);
4266 return(cur->next);
4267}
4268
4269/**
4270 * xmlXPathNextPrecedingSibling:
4271 * @ctxt: the XPath Parser context
4272 * @cur: the current node in the traversal
4273 *
4274 * Traversal function for the "preceding-sibling" direction
4275 * The preceding-sibling axis contains the preceding siblings of the context
4276 * node in reverse document order; the first preceding sibling is first on the
4277 * axis; the sibling preceding that node is the second on the axis and so on.
4278 *
4279 * Returns the next element following that axis
4280 */
4281xmlNodePtr
4282xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4283 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4284 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4285 return(NULL);
4286 if (cur == (xmlNodePtr) ctxt->context->doc)
4287 return(NULL);
4288 if (cur == NULL)
4289 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004290 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
4291 cur = cur->prev;
4292 if (cur == NULL)
4293 return(ctxt->context->node->prev);
4294 }
Owen Taylor3473f882001-02-23 17:55:21 +00004295 return(cur->prev);
4296}
4297
4298/**
4299 * xmlXPathNextFollowing:
4300 * @ctxt: the XPath Parser context
4301 * @cur: the current node in the traversal
4302 *
4303 * Traversal function for the "following" direction
4304 * The following axis contains all nodes in the same document as the context
4305 * node that are after the context node in document order, excluding any
4306 * descendants and excluding attribute nodes and namespace nodes; the nodes
4307 * are ordered in document order
4308 *
4309 * Returns the next element following that axis
4310 */
4311xmlNodePtr
4312xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4313 if (cur != NULL && cur->children != NULL)
4314 return cur->children ;
4315 if (cur == NULL) cur = ctxt->context->node;
4316 if (cur == NULL) return(NULL) ; /* ERROR */
4317 if (cur->next != NULL) return(cur->next) ;
4318 do {
4319 cur = cur->parent;
4320 if (cur == NULL) return(NULL);
4321 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
4322 if (cur->next != NULL) return(cur->next);
4323 } while (cur != NULL);
4324 return(cur);
4325}
4326
4327/*
4328 * xmlXPathIsAncestor:
4329 * @ancestor: the ancestor node
4330 * @node: the current node
4331 *
4332 * Check that @ancestor is a @node's ancestor
4333 *
4334 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
4335 */
4336static int
4337xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
4338 if ((ancestor == NULL) || (node == NULL)) return(0);
4339 /* nodes need to be in the same document */
4340 if (ancestor->doc != node->doc) return(0);
4341 /* avoid searching if ancestor or node is the root node */
4342 if (ancestor == (xmlNodePtr) node->doc) return(1);
4343 if (node == (xmlNodePtr) ancestor->doc) return(0);
4344 while (node->parent != NULL) {
4345 if (node->parent == ancestor)
4346 return(1);
4347 node = node->parent;
4348 }
4349 return(0);
4350}
4351
4352/**
4353 * xmlXPathNextPreceding:
4354 * @ctxt: the XPath Parser context
4355 * @cur: the current node in the traversal
4356 *
4357 * Traversal function for the "preceding" direction
4358 * the preceding axis contains all nodes in the same document as the context
4359 * node that are before the context node in document order, excluding any
4360 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4361 * ordered in reverse document order
4362 *
4363 * Returns the next element following that axis
4364 */
4365xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00004366xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
4367{
Owen Taylor3473f882001-02-23 17:55:21 +00004368 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004369 cur = ctxt->context->node;
4370 if (cur == NULL)
4371 return (NULL);
4372 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
4373 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00004374 do {
4375 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004376 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
4377 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004378 }
4379
4380 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004381 if (cur == NULL)
4382 return (NULL);
4383 if (cur == ctxt->context->doc->children)
4384 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004385 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00004386 return (cur);
4387}
4388
4389/**
4390 * xmlXPathNextPrecedingInternal:
4391 * @ctxt: the XPath Parser context
4392 * @cur: the current node in the traversal
4393 *
4394 * Traversal function for the "preceding" direction
4395 * the preceding axis contains all nodes in the same document as the context
4396 * node that are before the context node in document order, excluding any
4397 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4398 * ordered in reverse document order
4399 * This is a faster implementation but internal only since it requires a
4400 * state kept in the parser context: ctxt->ancestor.
4401 *
4402 * Returns the next element following that axis
4403 */
4404static xmlNodePtr
4405xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
4406 xmlNodePtr cur)
4407{
4408 if (cur == NULL) {
4409 cur = ctxt->context->node;
4410 if (cur == NULL)
4411 return (NULL);
4412 ctxt->ancestor = cur->parent;
4413 }
4414 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
4415 cur = cur->prev;
4416 while (cur->prev == NULL) {
4417 cur = cur->parent;
4418 if (cur == NULL)
4419 return (NULL);
4420 if (cur == ctxt->context->doc->children)
4421 return (NULL);
4422 if (cur != ctxt->ancestor)
4423 return (cur);
4424 ctxt->ancestor = cur->parent;
4425 }
4426 cur = cur->prev;
4427 while (cur->last != NULL)
4428 cur = cur->last;
4429 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004430}
4431
4432/**
4433 * xmlXPathNextNamespace:
4434 * @ctxt: the XPath Parser context
4435 * @cur: the current attribute in the traversal
4436 *
4437 * Traversal function for the "namespace" direction
4438 * the namespace axis contains the namespace nodes of the context node;
4439 * the order of nodes on this axis is implementation-defined; the axis will
4440 * be empty unless the context node is an element
4441 *
4442 * Returns the next element following that axis
4443 */
4444xmlNodePtr
4445xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4446 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
4447 if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
4448 if (ctxt->context->namespaces != NULL)
4449 xmlFree(ctxt->context->namespaces);
4450 ctxt->context->namespaces =
4451 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
4452 if (ctxt->context->namespaces == NULL) return(NULL);
4453 ctxt->context->nsNr = 0;
4454 }
4455 return((xmlNodePtr)ctxt->context->namespaces[ctxt->context->nsNr++]);
4456}
4457
4458/**
4459 * xmlXPathNextAttribute:
4460 * @ctxt: the XPath Parser context
4461 * @cur: the current attribute in the traversal
4462 *
4463 * Traversal function for the "attribute" direction
4464 * TODO: support DTD inherited default attributes
4465 *
4466 * Returns the next element following that axis
4467 */
4468xmlNodePtr
4469xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00004470 if (ctxt->context->node == NULL)
4471 return(NULL);
4472 if (ctxt->context->node->type != XML_ELEMENT_NODE)
4473 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004474 if (cur == NULL) {
4475 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
4476 return(NULL);
4477 return((xmlNodePtr)ctxt->context->node->properties);
4478 }
4479 return((xmlNodePtr)cur->next);
4480}
4481
4482/************************************************************************
4483 * *
4484 * NodeTest Functions *
4485 * *
4486 ************************************************************************/
4487
Owen Taylor3473f882001-02-23 17:55:21 +00004488#define IS_FUNCTION 200
4489
Owen Taylor3473f882001-02-23 17:55:21 +00004490
4491/************************************************************************
4492 * *
4493 * Implicit tree core function library *
4494 * *
4495 ************************************************************************/
4496
4497/**
4498 * xmlXPathRoot:
4499 * @ctxt: the XPath Parser context
4500 *
4501 * Initialize the context to the root of the document
4502 */
4503void
4504xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
4505 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
4506 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4507}
4508
4509/************************************************************************
4510 * *
4511 * The explicit core function library *
4512 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
4513 * *
4514 ************************************************************************/
4515
4516
4517/**
4518 * xmlXPathLastFunction:
4519 * @ctxt: the XPath Parser context
4520 * @nargs: the number of arguments
4521 *
4522 * Implement the last() XPath function
4523 * number last()
4524 * The last function returns the number of nodes in the context node list.
4525 */
4526void
4527xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4528 CHECK_ARITY(0);
4529 if (ctxt->context->contextSize >= 0) {
4530 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
4531#ifdef DEBUG_EXPR
4532 xmlGenericError(xmlGenericErrorContext,
4533 "last() : %d\n", ctxt->context->contextSize);
4534#endif
4535 } else {
4536 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
4537 }
4538}
4539
4540/**
4541 * xmlXPathPositionFunction:
4542 * @ctxt: the XPath Parser context
4543 * @nargs: the number of arguments
4544 *
4545 * Implement the position() XPath function
4546 * number position()
4547 * The position function returns the position of the context node in the
4548 * context node list. The first position is 1, and so the last positionr
4549 * will be equal to last().
4550 */
4551void
4552xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4553 CHECK_ARITY(0);
4554 if (ctxt->context->proximityPosition >= 0) {
4555 valuePush(ctxt,
4556 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
4557#ifdef DEBUG_EXPR
4558 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
4559 ctxt->context->proximityPosition);
4560#endif
4561 } else {
4562 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
4563 }
4564}
4565
4566/**
4567 * xmlXPathCountFunction:
4568 * @ctxt: the XPath Parser context
4569 * @nargs: the number of arguments
4570 *
4571 * Implement the count() XPath function
4572 * number count(node-set)
4573 */
4574void
4575xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4576 xmlXPathObjectPtr cur;
4577
4578 CHECK_ARITY(1);
4579 if ((ctxt->value == NULL) ||
4580 ((ctxt->value->type != XPATH_NODESET) &&
4581 (ctxt->value->type != XPATH_XSLT_TREE)))
4582 XP_ERROR(XPATH_INVALID_TYPE);
4583 cur = valuePop(ctxt);
4584
Daniel Veillard911f49a2001-04-07 15:39:35 +00004585 if ((cur == NULL) || (cur->nodesetval == NULL))
4586 valuePush(ctxt, xmlXPathNewFloat((double) 0));
4587 else
4588 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Owen Taylor3473f882001-02-23 17:55:21 +00004589 xmlXPathFreeObject(cur);
4590}
4591
4592/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004593 * xmlXPathGetElementsByIds:
4594 * @doc: the document
4595 * @ids: a whitespace separated list of IDs
4596 *
4597 * Selects elements by their unique ID.
4598 *
4599 * Returns a node-set of selected elements.
4600 */
4601static xmlNodeSetPtr
4602xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
4603 xmlNodeSetPtr ret;
4604 const xmlChar *cur = ids;
4605 xmlChar *ID;
4606 xmlAttrPtr attr;
4607 xmlNodePtr elem = NULL;
4608
4609 ret = xmlXPathNodeSetCreate(NULL);
4610
4611 while (IS_BLANK(*cur)) cur++;
4612 while (*cur != 0) {
4613 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
4614 (*cur == '.') || (*cur == '-') ||
4615 (*cur == '_') || (*cur == ':') ||
4616 (IS_COMBINING(*cur)) ||
4617 (IS_EXTENDER(*cur)))
4618 cur++;
4619
4620 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
4621
4622 ID = xmlStrndup(ids, cur - ids);
4623 attr = xmlGetID(doc, ID);
4624 if (attr != NULL) {
4625 elem = attr->parent;
4626 xmlXPathNodeSetAdd(ret, elem);
4627 }
4628 if (ID != NULL)
4629 xmlFree(ID);
4630
4631 while (IS_BLANK(*cur)) cur++;
4632 ids = cur;
4633 }
4634 return(ret);
4635}
4636
4637/**
Owen Taylor3473f882001-02-23 17:55:21 +00004638 * xmlXPathIdFunction:
4639 * @ctxt: the XPath Parser context
4640 * @nargs: the number of arguments
4641 *
4642 * Implement the id() XPath function
4643 * node-set id(object)
4644 * The id function selects elements by their unique ID
4645 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
4646 * then the result is the union of the result of applying id to the
4647 * string value of each of the nodes in the argument node-set. When the
4648 * argument to id is of any other type, the argument is converted to a
4649 * string as if by a call to the string function; the string is split
4650 * into a whitespace-separated list of tokens (whitespace is any sequence
4651 * of characters matching the production S); the result is a node-set
4652 * containing the elements in the same document as the context node that
4653 * have a unique ID equal to any of the tokens in the list.
4654 */
4655void
4656xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004657 xmlChar *tokens;
4658 xmlNodeSetPtr ret;
4659 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00004660
4661 CHECK_ARITY(1);
4662 obj = valuePop(ctxt);
4663 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
4664 if (obj->type == XPATH_NODESET) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004665 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00004666 int i;
4667
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004668 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004669
Daniel Veillard911f49a2001-04-07 15:39:35 +00004670 if (obj->nodesetval != NULL) {
4671 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004672 tokens =
4673 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
4674 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
4675 ret = xmlXPathNodeSetMerge(ret, ns);
4676 xmlXPathFreeNodeSet(ns);
4677 if (tokens != NULL)
4678 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004679 }
Owen Taylor3473f882001-02-23 17:55:21 +00004680 }
4681
4682 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004683 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00004684 return;
4685 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004686 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00004687
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004688 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
4689 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00004690
Owen Taylor3473f882001-02-23 17:55:21 +00004691 xmlXPathFreeObject(obj);
4692 return;
4693}
4694
4695/**
4696 * xmlXPathLocalNameFunction:
4697 * @ctxt: the XPath Parser context
4698 * @nargs: the number of arguments
4699 *
4700 * Implement the local-name() XPath function
4701 * string local-name(node-set?)
4702 * The local-name function returns a string containing the local part
4703 * of the name of the node in the argument node-set that is first in
4704 * document order. If the node-set is empty or the first node has no
4705 * name, an empty string is returned. If the argument is omitted it
4706 * defaults to the context node.
4707 */
4708void
4709xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4710 xmlXPathObjectPtr cur;
4711
4712 if (nargs == 0) {
4713 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4714 nargs = 1;
4715 }
4716
4717 CHECK_ARITY(1);
4718 if ((ctxt->value == NULL) ||
4719 ((ctxt->value->type != XPATH_NODESET) &&
4720 (ctxt->value->type != XPATH_XSLT_TREE)))
4721 XP_ERROR(XPATH_INVALID_TYPE);
4722 cur = valuePop(ctxt);
4723
Daniel Veillard911f49a2001-04-07 15:39:35 +00004724 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004725 valuePush(ctxt, xmlXPathNewCString(""));
4726 } else {
4727 int i = 0; /* Should be first in document order !!!!! */
4728 switch (cur->nodesetval->nodeTab[i]->type) {
4729 case XML_ELEMENT_NODE:
4730 case XML_ATTRIBUTE_NODE:
4731 case XML_PI_NODE:
4732 valuePush(ctxt,
4733 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
4734 break;
4735 case XML_NAMESPACE_DECL:
4736 valuePush(ctxt, xmlXPathNewString(
4737 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
4738 break;
4739 default:
4740 valuePush(ctxt, xmlXPathNewCString(""));
4741 }
4742 }
4743 xmlXPathFreeObject(cur);
4744}
4745
4746/**
4747 * xmlXPathNamespaceURIFunction:
4748 * @ctxt: the XPath Parser context
4749 * @nargs: the number of arguments
4750 *
4751 * Implement the namespace-uri() XPath function
4752 * string namespace-uri(node-set?)
4753 * The namespace-uri function returns a string containing the
4754 * namespace URI of the expanded name of the node in the argument
4755 * node-set that is first in document order. If the node-set is empty,
4756 * the first node has no name, or the expanded name has no namespace
4757 * URI, an empty string is returned. If the argument is omitted it
4758 * defaults to the context node.
4759 */
4760void
4761xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4762 xmlXPathObjectPtr cur;
4763
4764 if (nargs == 0) {
4765 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4766 nargs = 1;
4767 }
4768 CHECK_ARITY(1);
4769 if ((ctxt->value == NULL) ||
4770 ((ctxt->value->type != XPATH_NODESET) &&
4771 (ctxt->value->type != XPATH_XSLT_TREE)))
4772 XP_ERROR(XPATH_INVALID_TYPE);
4773 cur = valuePop(ctxt);
4774
Daniel Veillard911f49a2001-04-07 15:39:35 +00004775 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004776 valuePush(ctxt, xmlXPathNewCString(""));
4777 } else {
4778 int i = 0; /* Should be first in document order !!!!! */
4779 switch (cur->nodesetval->nodeTab[i]->type) {
4780 case XML_ELEMENT_NODE:
4781 case XML_ATTRIBUTE_NODE:
4782 if (cur->nodesetval->nodeTab[i]->ns == NULL)
4783 valuePush(ctxt, xmlXPathNewCString(""));
4784 else
4785 valuePush(ctxt, xmlXPathNewString(
4786 cur->nodesetval->nodeTab[i]->ns->href));
4787 break;
4788 default:
4789 valuePush(ctxt, xmlXPathNewCString(""));
4790 }
4791 }
4792 xmlXPathFreeObject(cur);
4793}
4794
4795/**
4796 * xmlXPathNameFunction:
4797 * @ctxt: the XPath Parser context
4798 * @nargs: the number of arguments
4799 *
4800 * Implement the name() XPath function
4801 * string name(node-set?)
4802 * The name function returns a string containing a QName representing
4803 * the name of the node in the argument node-set that is first in documenti
4804 * order. The QName must represent the name with respect to the namespace
4805 * declarations in effect on the node whose name is being represented.
4806 * Typically, this will be the form in which the name occurred in the XML
4807 * source. This need not be the case if there are namespace declarations
4808 * in effect on the node that associate multiple prefixes with the same
4809 * namespace. However, an implementation may include information about
4810 * the original prefix in its representation of nodes; in this case, an
4811 * implementation can ensure that the returned string is always the same
4812 * as the QName used in the XML source. If the argument it omitted it
4813 * defaults to the context node.
4814 * Libxml keep the original prefix so the "real qualified name" used is
4815 * returned.
4816 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004817static void
Daniel Veillard04383752001-07-08 14:27:15 +00004818xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
4819{
Owen Taylor3473f882001-02-23 17:55:21 +00004820 xmlXPathObjectPtr cur;
4821
4822 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00004823 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4824 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00004825 }
4826
4827 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00004828 if ((ctxt->value == NULL) ||
4829 ((ctxt->value->type != XPATH_NODESET) &&
4830 (ctxt->value->type != XPATH_XSLT_TREE)))
4831 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00004832 cur = valuePop(ctxt);
4833
Daniel Veillard911f49a2001-04-07 15:39:35 +00004834 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00004835 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00004836 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00004837 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00004838
Daniel Veillard04383752001-07-08 14:27:15 +00004839 switch (cur->nodesetval->nodeTab[i]->type) {
4840 case XML_ELEMENT_NODE:
4841 case XML_ATTRIBUTE_NODE:
4842 if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
4843 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL))
4844 valuePush(ctxt,
4845 xmlXPathNewString(cur->nodesetval->
4846 nodeTab[i]->name));
4847
4848 else {
4849 char name[2000];
4850
4851 snprintf(name, sizeof(name), "%s:%s",
4852 (char *) cur->nodesetval->nodeTab[i]->ns->
4853 prefix,
4854 (char *) cur->nodesetval->nodeTab[i]->name);
4855 name[sizeof(name) - 1] = 0;
4856 valuePush(ctxt, xmlXPathNewCString(name));
4857 }
4858 break;
4859 default:
4860 valuePush(ctxt,
4861 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
4862 xmlXPathLocalNameFunction(ctxt, 1);
4863 }
Owen Taylor3473f882001-02-23 17:55:21 +00004864 }
4865 xmlXPathFreeObject(cur);
4866}
4867
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004868
4869/**
Owen Taylor3473f882001-02-23 17:55:21 +00004870 * xmlXPathStringFunction:
4871 * @ctxt: the XPath Parser context
4872 * @nargs: the number of arguments
4873 *
4874 * Implement the string() XPath function
4875 * string string(object?)
4876 * he string function converts an object to a string as follows:
4877 * - A node-set is converted to a string by returning the value of
4878 * the node in the node-set that is first in document order.
4879 * If the node-set is empty, an empty string is returned.
4880 * - A number is converted to a string as follows
4881 * + NaN is converted to the string NaN
4882 * + positive zero is converted to the string 0
4883 * + negative zero is converted to the string 0
4884 * + positive infinity is converted to the string Infinity
4885 * + negative infinity is converted to the string -Infinity
4886 * + if the number is an integer, the number is represented in
4887 * decimal form as a Number with no decimal point and no leading
4888 * zeros, preceded by a minus sign (-) if the number is negative
4889 * + otherwise, the number is represented in decimal form as a
4890 * Number including a decimal point with at least one digit
4891 * before the decimal point and at least one digit after the
4892 * decimal point, preceded by a minus sign (-) if the number
4893 * is negative; there must be no leading zeros before the decimal
4894 * point apart possibly from the one required digit immediatelyi
4895 * before the decimal point; beyond the one required digit
4896 * after the decimal point there must be as many, but only as
4897 * many, more digits as are needed to uniquely distinguish the
4898 * number from all other IEEE 754 numeric values.
4899 * - The boolean false value is converted to the string false.
4900 * The boolean true value is converted to the string true.
4901 *
4902 * If the argument is omitted, it defaults to a node-set with the
4903 * context node as its only member.
4904 */
4905void
4906xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4907 xmlXPathObjectPtr cur;
4908
4909 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004910 valuePush(ctxt,
4911 xmlXPathWrapString(
4912 xmlXPathCastNodeToString(ctxt->context->node)));
4913 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004914 }
4915
4916 CHECK_ARITY(1);
4917 cur = valuePop(ctxt);
4918 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004919 cur = xmlXPathConvertString(cur);
4920 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004921}
4922
4923/**
4924 * xmlXPathStringLengthFunction:
4925 * @ctxt: the XPath Parser context
4926 * @nargs: the number of arguments
4927 *
4928 * Implement the string-length() XPath function
4929 * number string-length(string?)
4930 * The string-length returns the number of characters in the string
4931 * (see [3.6 Strings]). If the argument is omitted, it defaults to
4932 * the context node converted to a string, in other words the value
4933 * of the context node.
4934 */
4935void
4936xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4937 xmlXPathObjectPtr cur;
4938
4939 if (nargs == 0) {
4940 if (ctxt->context->node == NULL) {
4941 valuePush(ctxt, xmlXPathNewFloat(0));
4942 } else {
4943 xmlChar *content;
4944
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004945 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00004946 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00004947 xmlFree(content);
4948 }
4949 return;
4950 }
4951 CHECK_ARITY(1);
4952 CAST_TO_STRING;
4953 CHECK_TYPE(XPATH_STRING);
4954 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00004955 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00004956 xmlXPathFreeObject(cur);
4957}
4958
4959/**
4960 * xmlXPathConcatFunction:
4961 * @ctxt: the XPath Parser context
4962 * @nargs: the number of arguments
4963 *
4964 * Implement the concat() XPath function
4965 * string concat(string, string, string*)
4966 * The concat function returns the concatenation of its arguments.
4967 */
4968void
4969xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4970 xmlXPathObjectPtr cur, newobj;
4971 xmlChar *tmp;
4972
4973 if (nargs < 2) {
4974 CHECK_ARITY(2);
4975 }
4976
4977 CAST_TO_STRING;
4978 cur = valuePop(ctxt);
4979 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
4980 xmlXPathFreeObject(cur);
4981 return;
4982 }
4983 nargs--;
4984
4985 while (nargs > 0) {
4986 CAST_TO_STRING;
4987 newobj = valuePop(ctxt);
4988 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
4989 xmlXPathFreeObject(newobj);
4990 xmlXPathFreeObject(cur);
4991 XP_ERROR(XPATH_INVALID_TYPE);
4992 }
4993 tmp = xmlStrcat(newobj->stringval, cur->stringval);
4994 newobj->stringval = cur->stringval;
4995 cur->stringval = tmp;
4996
4997 xmlXPathFreeObject(newobj);
4998 nargs--;
4999 }
5000 valuePush(ctxt, cur);
5001}
5002
5003/**
5004 * xmlXPathContainsFunction:
5005 * @ctxt: the XPath Parser context
5006 * @nargs: the number of arguments
5007 *
5008 * Implement the contains() XPath function
5009 * boolean contains(string, string)
5010 * The contains function returns true if the first argument string
5011 * contains the second argument string, and otherwise returns false.
5012 */
5013void
5014xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5015 xmlXPathObjectPtr hay, needle;
5016
5017 CHECK_ARITY(2);
5018 CAST_TO_STRING;
5019 CHECK_TYPE(XPATH_STRING);
5020 needle = valuePop(ctxt);
5021 CAST_TO_STRING;
5022 hay = valuePop(ctxt);
5023 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5024 xmlXPathFreeObject(hay);
5025 xmlXPathFreeObject(needle);
5026 XP_ERROR(XPATH_INVALID_TYPE);
5027 }
5028 if (xmlStrstr(hay->stringval, needle->stringval))
5029 valuePush(ctxt, xmlXPathNewBoolean(1));
5030 else
5031 valuePush(ctxt, xmlXPathNewBoolean(0));
5032 xmlXPathFreeObject(hay);
5033 xmlXPathFreeObject(needle);
5034}
5035
5036/**
5037 * xmlXPathStartsWithFunction:
5038 * @ctxt: the XPath Parser context
5039 * @nargs: the number of arguments
5040 *
5041 * Implement the starts-with() XPath function
5042 * boolean starts-with(string, string)
5043 * The starts-with function returns true if the first argument string
5044 * starts with the second argument string, and otherwise returns false.
5045 */
5046void
5047xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5048 xmlXPathObjectPtr hay, needle;
5049 int n;
5050
5051 CHECK_ARITY(2);
5052 CAST_TO_STRING;
5053 CHECK_TYPE(XPATH_STRING);
5054 needle = valuePop(ctxt);
5055 CAST_TO_STRING;
5056 hay = valuePop(ctxt);
5057 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5058 xmlXPathFreeObject(hay);
5059 xmlXPathFreeObject(needle);
5060 XP_ERROR(XPATH_INVALID_TYPE);
5061 }
5062 n = xmlStrlen(needle->stringval);
5063 if (xmlStrncmp(hay->stringval, needle->stringval, n))
5064 valuePush(ctxt, xmlXPathNewBoolean(0));
5065 else
5066 valuePush(ctxt, xmlXPathNewBoolean(1));
5067 xmlXPathFreeObject(hay);
5068 xmlXPathFreeObject(needle);
5069}
5070
5071/**
5072 * xmlXPathSubstringFunction:
5073 * @ctxt: the XPath Parser context
5074 * @nargs: the number of arguments
5075 *
5076 * Implement the substring() XPath function
5077 * string substring(string, number, number?)
5078 * The substring function returns the substring of the first argument
5079 * starting at the position specified in the second argument with
5080 * length specified in the third argument. For example,
5081 * substring("12345",2,3) returns "234". If the third argument is not
5082 * specified, it returns the substring starting at the position specified
5083 * in the second argument and continuing to the end of the string. For
5084 * example, substring("12345",2) returns "2345". More precisely, each
5085 * character in the string (see [3.6 Strings]) is considered to have a
5086 * numeric position: the position of the first character is 1, the position
5087 * of the second character is 2 and so on. The returned substring contains
5088 * those characters for which the position of the character is greater than
5089 * or equal to the second argument and, if the third argument is specified,
5090 * less than the sum of the second and third arguments; the comparisons
5091 * and addition used for the above follow the standard IEEE 754 rules. Thus:
5092 * - substring("12345", 1.5, 2.6) returns "234"
5093 * - substring("12345", 0, 3) returns "12"
5094 * - substring("12345", 0 div 0, 3) returns ""
5095 * - substring("12345", 1, 0 div 0) returns ""
5096 * - substring("12345", -42, 1 div 0) returns "12345"
5097 * - substring("12345", -1 div 0, 1 div 0) returns ""
5098 */
5099void
5100xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5101 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005102 double le=0, in;
5103 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00005104 xmlChar *ret;
5105
Owen Taylor3473f882001-02-23 17:55:21 +00005106 if (nargs < 2) {
5107 CHECK_ARITY(2);
5108 }
5109 if (nargs > 3) {
5110 CHECK_ARITY(3);
5111 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005112 /*
5113 * take care of possible last (position) argument
5114 */
Owen Taylor3473f882001-02-23 17:55:21 +00005115 if (nargs == 3) {
5116 CAST_TO_NUMBER;
5117 CHECK_TYPE(XPATH_NUMBER);
5118 len = valuePop(ctxt);
5119 le = len->floatval;
5120 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00005121 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005122
Owen Taylor3473f882001-02-23 17:55:21 +00005123 CAST_TO_NUMBER;
5124 CHECK_TYPE(XPATH_NUMBER);
5125 start = valuePop(ctxt);
5126 in = start->floatval;
5127 xmlXPathFreeObject(start);
5128 CAST_TO_STRING;
5129 CHECK_TYPE(XPATH_STRING);
5130 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00005131 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005132
Daniel Veillard97ac1312001-05-30 19:14:17 +00005133 /*
5134 * If last pos not present, calculate last position
5135 */
5136 if (nargs != 3)
5137 le = m;
5138
5139 /*
5140 * To meet our requirements, initial index calculations
5141 * must be done before we convert to integer format
5142 *
5143 * First we normalize indices
5144 */
5145 in -= 1.0;
5146 le += in;
5147 if (in < 0.0)
5148 in = 0.0;
5149 if (le > (double)m)
5150 le = (double)m;
5151
5152 /*
5153 * Now we go to integer form, rounding up
5154 */
Owen Taylor3473f882001-02-23 17:55:21 +00005155 i = (int) in;
5156 if (((double)i) != in) i++;
5157
Owen Taylor3473f882001-02-23 17:55:21 +00005158 l = (int) le;
5159 if (((double)l) != le) l++;
5160
Daniel Veillard97ac1312001-05-30 19:14:17 +00005161 if (l > m) l=m;
Owen Taylor3473f882001-02-23 17:55:21 +00005162
5163 /* number of chars to copy */
5164 l -= i;
5165
Daniel Veillard97ac1312001-05-30 19:14:17 +00005166 ret = xmlUTF8Strsub(str->stringval, i, l);
Owen Taylor3473f882001-02-23 17:55:21 +00005167 if (ret == NULL)
5168 valuePush(ctxt, xmlXPathNewCString(""));
5169 else {
5170 valuePush(ctxt, xmlXPathNewString(ret));
5171 xmlFree(ret);
5172 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005173
Owen Taylor3473f882001-02-23 17:55:21 +00005174 xmlXPathFreeObject(str);
5175}
5176
5177/**
5178 * xmlXPathSubstringBeforeFunction:
5179 * @ctxt: the XPath Parser context
5180 * @nargs: the number of arguments
5181 *
5182 * Implement the substring-before() XPath function
5183 * string substring-before(string, string)
5184 * The substring-before function returns the substring of the first
5185 * argument string that precedes the first occurrence of the second
5186 * argument string in the first argument string, or the empty string
5187 * if the first argument string does not contain the second argument
5188 * string. For example, substring-before("1999/04/01","/") returns 1999.
5189 */
5190void
5191xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5192 xmlXPathObjectPtr str;
5193 xmlXPathObjectPtr find;
5194 xmlBufferPtr target;
5195 const xmlChar *point;
5196 int offset;
5197
5198 CHECK_ARITY(2);
5199 CAST_TO_STRING;
5200 find = valuePop(ctxt);
5201 CAST_TO_STRING;
5202 str = valuePop(ctxt);
5203
5204 target = xmlBufferCreate();
5205 if (target) {
5206 point = xmlStrstr(str->stringval, find->stringval);
5207 if (point) {
5208 offset = (int)(point - str->stringval);
5209 xmlBufferAdd(target, str->stringval, offset);
5210 }
5211 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5212 xmlBufferFree(target);
5213 }
5214
5215 xmlXPathFreeObject(str);
5216 xmlXPathFreeObject(find);
5217}
5218
5219/**
5220 * xmlXPathSubstringAfterFunction:
5221 * @ctxt: the XPath Parser context
5222 * @nargs: the number of arguments
5223 *
5224 * Implement the substring-after() XPath function
5225 * string substring-after(string, string)
5226 * The substring-after function returns the substring of the first
5227 * argument string that follows the first occurrence of the second
5228 * argument string in the first argument string, or the empty stringi
5229 * if the first argument string does not contain the second argument
5230 * string. For example, substring-after("1999/04/01","/") returns 04/01,
5231 * and substring-after("1999/04/01","19") returns 99/04/01.
5232 */
5233void
5234xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5235 xmlXPathObjectPtr str;
5236 xmlXPathObjectPtr find;
5237 xmlBufferPtr target;
5238 const xmlChar *point;
5239 int offset;
5240
5241 CHECK_ARITY(2);
5242 CAST_TO_STRING;
5243 find = valuePop(ctxt);
5244 CAST_TO_STRING;
5245 str = valuePop(ctxt);
5246
5247 target = xmlBufferCreate();
5248 if (target) {
5249 point = xmlStrstr(str->stringval, find->stringval);
5250 if (point) {
5251 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
5252 xmlBufferAdd(target, &str->stringval[offset],
5253 xmlStrlen(str->stringval) - offset);
5254 }
5255 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5256 xmlBufferFree(target);
5257 }
5258
5259 xmlXPathFreeObject(str);
5260 xmlXPathFreeObject(find);
5261}
5262
5263/**
5264 * xmlXPathNormalizeFunction:
5265 * @ctxt: the XPath Parser context
5266 * @nargs: the number of arguments
5267 *
5268 * Implement the normalize-space() XPath function
5269 * string normalize-space(string?)
5270 * The normalize-space function returns the argument string with white
5271 * space normalized by stripping leading and trailing whitespace
5272 * and replacing sequences of whitespace characters by a single
5273 * space. Whitespace characters are the same allowed by the S production
5274 * in XML. If the argument is omitted, it defaults to the context
5275 * node converted to a string, in other words the value of the context node.
5276 */
5277void
5278xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5279 xmlXPathObjectPtr obj = NULL;
5280 xmlChar *source = NULL;
5281 xmlBufferPtr target;
5282 xmlChar blank;
5283
5284 if (nargs == 0) {
5285 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005286 valuePush(ctxt,
5287 xmlXPathWrapString(
5288 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00005289 nargs = 1;
5290 }
5291
5292 CHECK_ARITY(1);
5293 CAST_TO_STRING;
5294 CHECK_TYPE(XPATH_STRING);
5295 obj = valuePop(ctxt);
5296 source = obj->stringval;
5297
5298 target = xmlBufferCreate();
5299 if (target && source) {
5300
5301 /* Skip leading whitespaces */
5302 while (IS_BLANK(*source))
5303 source++;
5304
5305 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
5306 blank = 0;
5307 while (*source) {
5308 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005309 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00005310 } else {
5311 if (blank) {
5312 xmlBufferAdd(target, &blank, 1);
5313 blank = 0;
5314 }
5315 xmlBufferAdd(target, source, 1);
5316 }
5317 source++;
5318 }
5319
5320 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5321 xmlBufferFree(target);
5322 }
5323 xmlXPathFreeObject(obj);
5324}
5325
5326/**
5327 * xmlXPathTranslateFunction:
5328 * @ctxt: the XPath Parser context
5329 * @nargs: the number of arguments
5330 *
5331 * Implement the translate() XPath function
5332 * string translate(string, string, string)
5333 * The translate function returns the first argument string with
5334 * occurrences of characters in the second argument string replaced
5335 * by the character at the corresponding position in the third argument
5336 * string. For example, translate("bar","abc","ABC") returns the string
5337 * BAr. If there is a character in the second argument string with no
5338 * character at a corresponding position in the third argument string
5339 * (because the second argument string is longer than the third argument
5340 * string), then occurrences of that character in the first argument
5341 * string are removed. For example, translate("--aaa--","abc-","ABC")
5342 * returns "AAA". If a character occurs more than once in second
5343 * argument string, then the first occurrence determines the replacement
5344 * character. If the third argument string is longer than the second
5345 * argument string, then excess characters are ignored.
5346 */
5347void
5348xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00005349 xmlXPathObjectPtr str;
5350 xmlXPathObjectPtr from;
5351 xmlXPathObjectPtr to;
5352 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005353 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00005354 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005355 xmlChar *point;
5356 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00005357
Daniel Veillarde043ee12001-04-16 14:08:07 +00005358 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00005359
Daniel Veillarde043ee12001-04-16 14:08:07 +00005360 CAST_TO_STRING;
5361 to = valuePop(ctxt);
5362 CAST_TO_STRING;
5363 from = valuePop(ctxt);
5364 CAST_TO_STRING;
5365 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005366
Daniel Veillarde043ee12001-04-16 14:08:07 +00005367 target = xmlBufferCreate();
5368 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005369 max = xmlUTF8Strlen(to->stringval);
5370 for (cptr = str->stringval; (ch=*cptr); ) {
5371 offset = xmlUTF8Strloc(from->stringval, cptr);
5372 if (offset >= 0) {
5373 if (offset < max) {
5374 point = xmlUTF8Strpos(to->stringval, offset);
5375 if (point)
5376 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
5377 }
5378 } else
5379 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
5380
5381 /* Step to next character in input */
5382 cptr++;
5383 if ( ch & 0x80 ) {
5384 /* if not simple ascii, verify proper format */
5385 if ( (ch & 0xc0) != 0xc0 ) {
5386 xmlGenericError(xmlGenericErrorContext,
5387 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5388 break;
5389 }
5390 /* then skip over remaining bytes for this char */
5391 while ( (ch <<= 1) & 0x80 )
5392 if ( (*cptr++ & 0xc0) != 0x80 ) {
5393 xmlGenericError(xmlGenericErrorContext,
5394 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5395 break;
5396 }
5397 if (ch & 0x80) /* must have had error encountered */
5398 break;
5399 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005400 }
Owen Taylor3473f882001-02-23 17:55:21 +00005401 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005402 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5403 xmlBufferFree(target);
5404 xmlXPathFreeObject(str);
5405 xmlXPathFreeObject(from);
5406 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00005407}
5408
5409/**
5410 * xmlXPathBooleanFunction:
5411 * @ctxt: the XPath Parser context
5412 * @nargs: the number of arguments
5413 *
5414 * Implement the boolean() XPath function
5415 * boolean boolean(object)
5416 * he boolean function converts its argument to a boolean as follows:
5417 * - a number is true if and only if it is neither positive or
5418 * negative zero nor NaN
5419 * - a node-set is true if and only if it is non-empty
5420 * - a string is true if and only if its length is non-zero
5421 */
5422void
5423xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5424 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00005425
5426 CHECK_ARITY(1);
5427 cur = valuePop(ctxt);
5428 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005429 cur = xmlXPathConvertBoolean(cur);
5430 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005431}
5432
5433/**
5434 * xmlXPathNotFunction:
5435 * @ctxt: the XPath Parser context
5436 * @nargs: the number of arguments
5437 *
5438 * Implement the not() XPath function
5439 * boolean not(boolean)
5440 * The not function returns true if its argument is false,
5441 * and false otherwise.
5442 */
5443void
5444xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5445 CHECK_ARITY(1);
5446 CAST_TO_BOOLEAN;
5447 CHECK_TYPE(XPATH_BOOLEAN);
5448 ctxt->value->boolval = ! ctxt->value->boolval;
5449}
5450
5451/**
5452 * xmlXPathTrueFunction:
5453 * @ctxt: the XPath Parser context
5454 * @nargs: the number of arguments
5455 *
5456 * Implement the true() XPath function
5457 * boolean true()
5458 */
5459void
5460xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5461 CHECK_ARITY(0);
5462 valuePush(ctxt, xmlXPathNewBoolean(1));
5463}
5464
5465/**
5466 * xmlXPathFalseFunction:
5467 * @ctxt: the XPath Parser context
5468 * @nargs: the number of arguments
5469 *
5470 * Implement the false() XPath function
5471 * boolean false()
5472 */
5473void
5474xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5475 CHECK_ARITY(0);
5476 valuePush(ctxt, xmlXPathNewBoolean(0));
5477}
5478
5479/**
5480 * xmlXPathLangFunction:
5481 * @ctxt: the XPath Parser context
5482 * @nargs: the number of arguments
5483 *
5484 * Implement the lang() XPath function
5485 * boolean lang(string)
5486 * The lang function returns true or false depending on whether the
5487 * language of the context node as specified by xml:lang attributes
5488 * is the same as or is a sublanguage of the language specified by
5489 * the argument string. The language of the context node is determined
5490 * by the value of the xml:lang attribute on the context node, or, if
5491 * the context node has no xml:lang attribute, by the value of the
5492 * xml:lang attribute on the nearest ancestor of the context node that
5493 * has an xml:lang attribute. If there is no such attribute, then lang
5494 * returns false. If there is such an attribute, then lang returns
5495 * true if the attribute value is equal to the argument ignoring case,
5496 * or if there is some suffix starting with - such that the attribute
5497 * value is equal to the argument ignoring that suffix of the attribute
5498 * value and ignoring case.
5499 */
5500void
5501xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5502 xmlXPathObjectPtr val;
5503 const xmlChar *theLang;
5504 const xmlChar *lang;
5505 int ret = 0;
5506 int i;
5507
5508 CHECK_ARITY(1);
5509 CAST_TO_STRING;
5510 CHECK_TYPE(XPATH_STRING);
5511 val = valuePop(ctxt);
5512 lang = val->stringval;
5513 theLang = xmlNodeGetLang(ctxt->context->node);
5514 if ((theLang != NULL) && (lang != NULL)) {
5515 for (i = 0;lang[i] != 0;i++)
5516 if (toupper(lang[i]) != toupper(theLang[i]))
5517 goto not_equal;
5518 ret = 1;
5519 }
5520not_equal:
5521 xmlXPathFreeObject(val);
5522 valuePush(ctxt, xmlXPathNewBoolean(ret));
5523}
5524
5525/**
5526 * xmlXPathNumberFunction:
5527 * @ctxt: the XPath Parser context
5528 * @nargs: the number of arguments
5529 *
5530 * Implement the number() XPath function
5531 * number number(object?)
5532 */
5533void
5534xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5535 xmlXPathObjectPtr cur;
5536 double res;
5537
5538 if (nargs == 0) {
5539 if (ctxt->context->node == NULL) {
5540 valuePush(ctxt, xmlXPathNewFloat(0.0));
5541 } else {
5542 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
5543
5544 res = xmlXPathStringEvalNumber(content);
5545 valuePush(ctxt, xmlXPathNewFloat(res));
5546 xmlFree(content);
5547 }
5548 return;
5549 }
5550
5551 CHECK_ARITY(1);
5552 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005553 cur = xmlXPathConvertNumber(cur);
5554 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005555}
5556
5557/**
5558 * xmlXPathSumFunction:
5559 * @ctxt: the XPath Parser context
5560 * @nargs: the number of arguments
5561 *
5562 * Implement the sum() XPath function
5563 * number sum(node-set)
5564 * The sum function returns the sum of the values of the nodes in
5565 * the argument node-set.
5566 */
5567void
5568xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5569 xmlXPathObjectPtr cur;
5570 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005571 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00005572
5573 CHECK_ARITY(1);
5574 if ((ctxt->value == NULL) ||
5575 ((ctxt->value->type != XPATH_NODESET) &&
5576 (ctxt->value->type != XPATH_XSLT_TREE)))
5577 XP_ERROR(XPATH_INVALID_TYPE);
5578 cur = valuePop(ctxt);
5579
Daniel Veillardd8df6c02001-04-05 16:54:14 +00005580 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005581 valuePush(ctxt, xmlXPathNewFloat(0.0));
5582 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005583 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
5584 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00005585 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005586 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00005587 }
5588 xmlXPathFreeObject(cur);
5589}
5590
5591/**
5592 * xmlXPathFloorFunction:
5593 * @ctxt: the XPath Parser context
5594 * @nargs: the number of arguments
5595 *
5596 * Implement the floor() XPath function
5597 * number floor(number)
5598 * The floor function returns the largest (closest to positive infinity)
5599 * number that is not greater than the argument and that is an integer.
5600 */
5601void
5602xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5603 CHECK_ARITY(1);
5604 CAST_TO_NUMBER;
5605 CHECK_TYPE(XPATH_NUMBER);
5606#if 0
5607 ctxt->value->floatval = floor(ctxt->value->floatval);
5608#else
5609 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
5610 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
5611#endif
5612}
5613
5614/**
5615 * xmlXPathCeilingFunction:
5616 * @ctxt: the XPath Parser context
5617 * @nargs: the number of arguments
5618 *
5619 * Implement the ceiling() XPath function
5620 * number ceiling(number)
5621 * The ceiling function returns the smallest (closest to negative infinity)
5622 * number that is not less than the argument and that is an integer.
5623 */
5624void
5625xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5626 double f;
5627
5628 CHECK_ARITY(1);
5629 CAST_TO_NUMBER;
5630 CHECK_TYPE(XPATH_NUMBER);
5631
5632#if 0
5633 ctxt->value->floatval = ceil(ctxt->value->floatval);
5634#else
5635 f = (double)((int) ctxt->value->floatval);
5636 if (f != ctxt->value->floatval)
5637 ctxt->value->floatval = f + 1;
5638#endif
5639}
5640
5641/**
5642 * xmlXPathRoundFunction:
5643 * @ctxt: the XPath Parser context
5644 * @nargs: the number of arguments
5645 *
5646 * Implement the round() XPath function
5647 * number round(number)
5648 * The round function returns the number that is closest to the
5649 * argument and that is an integer. If there are two such numbers,
5650 * then the one that is even is returned.
5651 */
5652void
5653xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5654 double f;
5655
5656 CHECK_ARITY(1);
5657 CAST_TO_NUMBER;
5658 CHECK_TYPE(XPATH_NUMBER);
5659
5660 if ((ctxt->value->floatval == xmlXPathNAN) ||
5661 (ctxt->value->floatval == xmlXPathPINF) ||
5662 (ctxt->value->floatval == xmlXPathNINF) ||
5663 (ctxt->value->floatval == 0.0))
5664 return;
5665
5666#if 0
5667 f = floor(ctxt->value->floatval);
5668#else
5669 f = (double)((int) ctxt->value->floatval);
5670#endif
5671 if (ctxt->value->floatval < f + 0.5)
5672 ctxt->value->floatval = f;
5673 else
5674 ctxt->value->floatval = f + 1;
5675}
5676
5677/************************************************************************
5678 * *
5679 * The Parser *
5680 * *
5681 ************************************************************************/
5682
5683/*
5684 * a couple of forward declarations since we use a recursive call based
5685 * implementation.
5686 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005687static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00005688static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005689static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005690#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005691static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
5692#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00005693#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005694static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005695#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00005696static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
5697 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00005698
5699/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00005700 * xmlXPathCurrentChar:
5701 * @ctxt: the XPath parser context
5702 * @cur: pointer to the beginning of the char
5703 * @len: pointer to the length of the char read
5704 *
5705 * The current char value, if using UTF-8 this may actaully span multiple
5706 * bytes in the input buffer.
5707 *
5708 * Returns the current char value and its lenght
5709 */
5710
5711static int
5712xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
5713 unsigned char c;
5714 unsigned int val;
5715 const xmlChar *cur;
5716
5717 if (ctxt == NULL)
5718 return(0);
5719 cur = ctxt->cur;
5720
5721 /*
5722 * We are supposed to handle UTF8, check it's valid
5723 * From rfc2044: encoding of the Unicode values on UTF-8:
5724 *
5725 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
5726 * 0000 0000-0000 007F 0xxxxxxx
5727 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
5728 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
5729 *
5730 * Check for the 0x110000 limit too
5731 */
5732 c = *cur;
5733 if (c & 0x80) {
5734 if ((cur[1] & 0xc0) != 0x80)
5735 goto encoding_error;
5736 if ((c & 0xe0) == 0xe0) {
5737
5738 if ((cur[2] & 0xc0) != 0x80)
5739 goto encoding_error;
5740 if ((c & 0xf0) == 0xf0) {
5741 if (((c & 0xf8) != 0xf0) ||
5742 ((cur[3] & 0xc0) != 0x80))
5743 goto encoding_error;
5744 /* 4-byte code */
5745 *len = 4;
5746 val = (cur[0] & 0x7) << 18;
5747 val |= (cur[1] & 0x3f) << 12;
5748 val |= (cur[2] & 0x3f) << 6;
5749 val |= cur[3] & 0x3f;
5750 } else {
5751 /* 3-byte code */
5752 *len = 3;
5753 val = (cur[0] & 0xf) << 12;
5754 val |= (cur[1] & 0x3f) << 6;
5755 val |= cur[2] & 0x3f;
5756 }
5757 } else {
5758 /* 2-byte code */
5759 *len = 2;
5760 val = (cur[0] & 0x1f) << 6;
5761 val |= cur[1] & 0x3f;
5762 }
5763 if (!IS_CHAR(val)) {
5764 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
5765 }
5766 return(val);
5767 } else {
5768 /* 1-byte code */
5769 *len = 1;
5770 return((int) *cur);
5771 }
5772encoding_error:
5773 /*
5774 * If we detect an UTF8 error that probably mean that the
5775 * input encoding didn't get properly advertized in the
5776 * declaration header. Report the error and switch the encoding
5777 * to ISO-Latin-1 (if you don't like this policy, just declare the
5778 * encoding !)
5779 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00005780 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00005781 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00005782}
5783
5784/**
Owen Taylor3473f882001-02-23 17:55:21 +00005785 * xmlXPathParseNCName:
5786 * @ctxt: the XPath Parser context
5787 *
5788 * parse an XML namespace non qualified name.
5789 *
5790 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
5791 *
5792 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
5793 * CombiningChar | Extender
5794 *
5795 * Returns the namespace name or NULL
5796 */
5797
5798xmlChar *
5799xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00005800 const xmlChar *in;
5801 xmlChar *ret;
5802 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005803
Daniel Veillard2156a562001-04-28 12:24:34 +00005804 /*
5805 * Accelerator for simple ASCII names
5806 */
5807 in = ctxt->cur;
5808 if (((*in >= 0x61) && (*in <= 0x7A)) ||
5809 ((*in >= 0x41) && (*in <= 0x5A)) ||
5810 (*in == '_')) {
5811 in++;
5812 while (((*in >= 0x61) && (*in <= 0x7A)) ||
5813 ((*in >= 0x41) && (*in <= 0x5A)) ||
5814 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00005815 (*in == '_') || (*in == '.') ||
5816 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00005817 in++;
5818 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
5819 (*in == '[') || (*in == ']') || (*in == ':') ||
5820 (*in == '@') || (*in == '*')) {
5821 count = in - ctxt->cur;
5822 if (count == 0)
5823 return(NULL);
5824 ret = xmlStrndup(ctxt->cur, count);
5825 ctxt->cur = in;
5826 return(ret);
5827 }
5828 }
5829 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00005830}
5831
Daniel Veillard2156a562001-04-28 12:24:34 +00005832
Owen Taylor3473f882001-02-23 17:55:21 +00005833/**
5834 * xmlXPathParseQName:
5835 * @ctxt: the XPath Parser context
5836 * @prefix: a xmlChar **
5837 *
5838 * parse an XML qualified name
5839 *
5840 * [NS 5] QName ::= (Prefix ':')? LocalPart
5841 *
5842 * [NS 6] Prefix ::= NCName
5843 *
5844 * [NS 7] LocalPart ::= NCName
5845 *
5846 * Returns the function returns the local part, and prefix is updated
5847 * to get the Prefix if any.
5848 */
5849
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005850static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005851xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
5852 xmlChar *ret = NULL;
5853
5854 *prefix = NULL;
5855 ret = xmlXPathParseNCName(ctxt);
5856 if (CUR == ':') {
5857 *prefix = ret;
5858 NEXT;
5859 ret = xmlXPathParseNCName(ctxt);
5860 }
5861 return(ret);
5862}
5863
5864/**
5865 * xmlXPathParseName:
5866 * @ctxt: the XPath Parser context
5867 *
5868 * parse an XML name
5869 *
5870 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
5871 * CombiningChar | Extender
5872 *
5873 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
5874 *
5875 * Returns the namespace name or NULL
5876 */
5877
5878xmlChar *
5879xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005880 const xmlChar *in;
5881 xmlChar *ret;
5882 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005883
Daniel Veillard61d80a22001-04-27 17:13:01 +00005884 /*
5885 * Accelerator for simple ASCII names
5886 */
5887 in = ctxt->cur;
5888 if (((*in >= 0x61) && (*in <= 0x7A)) ||
5889 ((*in >= 0x41) && (*in <= 0x5A)) ||
5890 (*in == '_') || (*in == ':')) {
5891 in++;
5892 while (((*in >= 0x61) && (*in <= 0x7A)) ||
5893 ((*in >= 0x41) && (*in <= 0x5A)) ||
5894 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00005895 (*in == '_') || (*in == '-') ||
5896 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00005897 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00005898 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005899 count = in - ctxt->cur;
5900 ret = xmlStrndup(ctxt->cur, count);
5901 ctxt->cur = in;
5902 return(ret);
5903 }
5904 }
Daniel Veillard2156a562001-04-28 12:24:34 +00005905 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00005906}
5907
Daniel Veillard61d80a22001-04-27 17:13:01 +00005908static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00005909xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005910 xmlChar buf[XML_MAX_NAMELEN + 5];
5911 int len = 0, l;
5912 int c;
5913
5914 /*
5915 * Handler for more complex cases
5916 */
5917 c = CUR_CHAR(l);
5918 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00005919 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
5920 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00005921 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00005922 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005923 return(NULL);
5924 }
5925
5926 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
5927 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
5928 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00005929 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00005930 (IS_COMBINING(c)) ||
5931 (IS_EXTENDER(c)))) {
5932 COPY_BUF(l,buf,len,c);
5933 NEXTL(l);
5934 c = CUR_CHAR(l);
5935 if (len >= XML_MAX_NAMELEN) {
5936 /*
5937 * Okay someone managed to make a huge name, so he's ready to pay
5938 * for the processing speed.
5939 */
5940 xmlChar *buffer;
5941 int max = len * 2;
5942
5943 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
5944 if (buffer == NULL) {
5945 XP_ERROR0(XPATH_MEMORY_ERROR);
5946 }
5947 memcpy(buffer, buf, len);
5948 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
5949 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00005950 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00005951 (IS_COMBINING(c)) ||
5952 (IS_EXTENDER(c))) {
5953 if (len + 10 > max) {
5954 max *= 2;
5955 buffer = (xmlChar *) xmlRealloc(buffer,
5956 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00005957 if (buffer == NULL) {
5958 XP_ERROR0(XPATH_MEMORY_ERROR);
5959 }
5960 }
5961 COPY_BUF(l,buffer,len,c);
5962 NEXTL(l);
5963 c = CUR_CHAR(l);
5964 }
5965 buffer[len] = 0;
5966 return(buffer);
5967 }
5968 }
Daniel Veillard2156a562001-04-28 12:24:34 +00005969 if (len == 0)
5970 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00005971 return(xmlStrndup(buf, len));
5972}
Owen Taylor3473f882001-02-23 17:55:21 +00005973/**
5974 * xmlXPathStringEvalNumber:
5975 * @str: A string to scan
5976 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00005977 * [30a] Float ::= Number ('e' Digits?)?
5978 *
Owen Taylor3473f882001-02-23 17:55:21 +00005979 * [30] Number ::= Digits ('.' Digits?)?
5980 * | '.' Digits
5981 * [31] Digits ::= [0-9]+
5982 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005983 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00005984 * In complement of the Number expression, this function also handles
5985 * negative values : '-' Number.
5986 *
5987 * Returns the double value.
5988 */
5989double
5990xmlXPathStringEvalNumber(const xmlChar *str) {
5991 const xmlChar *cur = str;
5992 double ret = 0.0;
5993 double mult = 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00005994 int ok = 0, tmp = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005995 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005996 int exponent = 0;
5997 int is_exponent_negative = 0;
5998
Owen Taylor3473f882001-02-23 17:55:21 +00005999 while (IS_BLANK(*cur)) cur++;
6000 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
6001 return(xmlXPathNAN);
6002 }
6003 if (*cur == '-') {
6004 isneg = 1;
6005 cur++;
6006 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006007 /*
6008 * tmp is a workaroudn against a gcc compiler bug
6009 */
Owen Taylor3473f882001-02-23 17:55:21 +00006010 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006011 tmp = tmp * 10 + (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00006012 ok = 1;
6013 cur++;
6014 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006015 ret = (double) tmp;
6016
Owen Taylor3473f882001-02-23 17:55:21 +00006017 if (*cur == '.') {
6018 cur++;
6019 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
6020 return(xmlXPathNAN);
6021 }
6022 while ((*cur >= '0') && (*cur <= '9')) {
6023 mult /= 10;
6024 ret = ret + (*cur - '0') * mult;
6025 cur++;
6026 }
6027 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006028 if ((*cur == 'e') || (*cur == 'E')) {
6029 cur++;
6030 if (*cur == '-') {
6031 is_exponent_negative = 1;
6032 cur++;
6033 }
6034 while ((*cur >= '0') && (*cur <= '9')) {
6035 exponent = exponent * 10 + (*cur - '0');
6036 cur++;
6037 }
6038 }
Owen Taylor3473f882001-02-23 17:55:21 +00006039 while (IS_BLANK(*cur)) cur++;
6040 if (*cur != 0) return(xmlXPathNAN);
6041 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006042 if (is_exponent_negative) exponent = -exponent;
6043 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00006044 return(ret);
6045}
6046
6047/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006048 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00006049 * @ctxt: the XPath Parser context
6050 *
6051 * [30] Number ::= Digits ('.' Digits?)?
6052 * | '.' Digits
6053 * [31] Digits ::= [0-9]+
6054 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006055 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00006056 *
6057 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006058static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006059xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
6060{
Owen Taylor3473f882001-02-23 17:55:21 +00006061 double ret = 0.0;
6062 double mult = 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006063 int ok = 0, tmp = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006064 int exponent = 0;
6065 int is_exponent_negative = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006066
6067 CHECK_ERROR;
6068 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
6069 XP_ERROR(XPATH_NUMBER_ERROR);
6070 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006071 /*
6072 * Try to work around a gcc optimizer bug
6073 */
Owen Taylor3473f882001-02-23 17:55:21 +00006074 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006075 tmp = tmp * 10 + (CUR - '0');
6076 ok = 1;
6077 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +00006078 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006079 ret = (double) tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00006080 if (CUR == '.') {
6081 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006082 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
6083 XP_ERROR(XPATH_NUMBER_ERROR);
6084 }
6085 while ((CUR >= '0') && (CUR <= '9')) {
6086 mult /= 10;
6087 ret = ret + (CUR - '0') * mult;
6088 NEXT;
6089 }
Owen Taylor3473f882001-02-23 17:55:21 +00006090 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006091 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006092 NEXT;
6093 if (CUR == '-') {
6094 is_exponent_negative = 1;
6095 NEXT;
6096 }
6097 while ((CUR >= '0') && (CUR <= '9')) {
6098 exponent = exponent * 10 + (CUR - '0');
6099 NEXT;
6100 }
6101 if (is_exponent_negative)
6102 exponent = -exponent;
6103 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006104 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006105 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006106 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006107}
6108
6109/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006110 * xmlXPathParseLiteral:
6111 * @ctxt: the XPath Parser context
6112 *
6113 * Parse a Literal
6114 *
6115 * [29] Literal ::= '"' [^"]* '"'
6116 * | "'" [^']* "'"
6117 *
6118 * Returns the value found or NULL in case of error
6119 */
6120static xmlChar *
6121xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
6122 const xmlChar *q;
6123 xmlChar *ret = NULL;
6124
6125 if (CUR == '"') {
6126 NEXT;
6127 q = CUR_PTR;
6128 while ((IS_CHAR(CUR)) && (CUR != '"'))
6129 NEXT;
6130 if (!IS_CHAR(CUR)) {
6131 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6132 } else {
6133 ret = xmlStrndup(q, CUR_PTR - q);
6134 NEXT;
6135 }
6136 } else if (CUR == '\'') {
6137 NEXT;
6138 q = CUR_PTR;
6139 while ((IS_CHAR(CUR)) && (CUR != '\''))
6140 NEXT;
6141 if (!IS_CHAR(CUR)) {
6142 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6143 } else {
6144 ret = xmlStrndup(q, CUR_PTR - q);
6145 NEXT;
6146 }
6147 } else {
6148 XP_ERROR0(XPATH_START_LITERAL_ERROR);
6149 }
6150 return(ret);
6151}
6152
6153/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006154 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00006155 * @ctxt: the XPath Parser context
6156 *
6157 * Parse a Literal and push it on the stack.
6158 *
6159 * [29] Literal ::= '"' [^"]* '"'
6160 * | "'" [^']* "'"
6161 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006162 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00006163 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006164static void
6165xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006166 const xmlChar *q;
6167 xmlChar *ret = NULL;
6168
6169 if (CUR == '"') {
6170 NEXT;
6171 q = CUR_PTR;
6172 while ((IS_CHAR(CUR)) && (CUR != '"'))
6173 NEXT;
6174 if (!IS_CHAR(CUR)) {
6175 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
6176 } else {
6177 ret = xmlStrndup(q, CUR_PTR - q);
6178 NEXT;
6179 }
6180 } else if (CUR == '\'') {
6181 NEXT;
6182 q = CUR_PTR;
6183 while ((IS_CHAR(CUR)) && (CUR != '\''))
6184 NEXT;
6185 if (!IS_CHAR(CUR)) {
6186 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
6187 } else {
6188 ret = xmlStrndup(q, CUR_PTR - q);
6189 NEXT;
6190 }
6191 } else {
6192 XP_ERROR(XPATH_START_LITERAL_ERROR);
6193 }
6194 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006195 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
6196 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006197 xmlFree(ret);
6198}
6199
6200/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006201 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00006202 * @ctxt: the XPath Parser context
6203 *
6204 * Parse a VariableReference, evaluate it and push it on the stack.
6205 *
6206 * The variable bindings consist of a mapping from variable names
6207 * to variable values. The value of a variable is an object, which
6208 * of any of the types that are possible for the value of an expression,
6209 * and may also be of additional types not specified here.
6210 *
6211 * Early evaluation is possible since:
6212 * The variable bindings [...] used to evaluate a subexpression are
6213 * always the same as those used to evaluate the containing expression.
6214 *
6215 * [36] VariableReference ::= '$' QName
6216 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006217static void
6218xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006219 xmlChar *name;
6220 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006221
6222 SKIP_BLANKS;
6223 if (CUR != '$') {
6224 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
6225 }
6226 NEXT;
6227 name = xmlXPathParseQName(ctxt, &prefix);
6228 if (name == NULL) {
6229 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
6230 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006231 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006232 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
6233 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006234 SKIP_BLANKS;
6235}
6236
6237/**
6238 * xmlXPathIsNodeType:
6239 * @ctxt: the XPath Parser context
6240 * @name: a name string
6241 *
6242 * Is the name given a NodeType one.
6243 *
6244 * [38] NodeType ::= 'comment'
6245 * | 'text'
6246 * | 'processing-instruction'
6247 * | 'node'
6248 *
6249 * Returns 1 if true 0 otherwise
6250 */
6251int
6252xmlXPathIsNodeType(const xmlChar *name) {
6253 if (name == NULL)
6254 return(0);
6255
6256 if (xmlStrEqual(name, BAD_CAST "comment"))
6257 return(1);
6258 if (xmlStrEqual(name, BAD_CAST "text"))
6259 return(1);
6260 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
6261 return(1);
6262 if (xmlStrEqual(name, BAD_CAST "node"))
6263 return(1);
6264 return(0);
6265}
6266
6267/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006268 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00006269 * @ctxt: the XPath Parser context
6270 *
6271 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
6272 * [17] Argument ::= Expr
6273 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006274 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00006275 * pushed on the stack
6276 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006277static void
6278xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006279 xmlChar *name;
6280 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006281 int nbargs = 0;
6282
6283 name = xmlXPathParseQName(ctxt, &prefix);
6284 if (name == NULL) {
6285 XP_ERROR(XPATH_EXPR_ERROR);
6286 }
6287 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006288#ifdef DEBUG_EXPR
6289 if (prefix == NULL)
6290 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
6291 name);
6292 else
6293 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
6294 prefix, name);
6295#endif
6296
Owen Taylor3473f882001-02-23 17:55:21 +00006297 if (CUR != '(') {
6298 XP_ERROR(XPATH_EXPR_ERROR);
6299 }
6300 NEXT;
6301 SKIP_BLANKS;
6302
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006303 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006304 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006305 int op1 = ctxt->comp->last;
6306 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006307 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006308 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006309 nbargs++;
6310 if (CUR == ')') break;
6311 if (CUR != ',') {
6312 XP_ERROR(XPATH_EXPR_ERROR);
6313 }
6314 NEXT;
6315 SKIP_BLANKS;
6316 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006317 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
6318 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006319 NEXT;
6320 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006321}
6322
6323/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006324 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006325 * @ctxt: the XPath Parser context
6326 *
6327 * [15] PrimaryExpr ::= VariableReference
6328 * | '(' Expr ')'
6329 * | Literal
6330 * | Number
6331 * | FunctionCall
6332 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006333 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006334 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006335static void
6336xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006337 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006338 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006339 else if (CUR == '(') {
6340 NEXT;
6341 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006342 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006343 if (CUR != ')') {
6344 XP_ERROR(XPATH_EXPR_ERROR);
6345 }
6346 NEXT;
6347 SKIP_BLANKS;
6348 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006349 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006350 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006351 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006352 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006353 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006354 }
6355 SKIP_BLANKS;
6356}
6357
6358/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006359 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006360 * @ctxt: the XPath Parser context
6361 *
6362 * [20] FilterExpr ::= PrimaryExpr
6363 * | FilterExpr Predicate
6364 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006365 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006366 * Square brackets are used to filter expressions in the same way that
6367 * they are used in location paths. It is an error if the expression to
6368 * be filtered does not evaluate to a node-set. The context node list
6369 * used for evaluating the expression in square brackets is the node-set
6370 * to be filtered listed in document order.
6371 */
6372
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006373static void
6374xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
6375 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006376 CHECK_ERROR;
6377 SKIP_BLANKS;
6378
6379 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006380 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00006381 SKIP_BLANKS;
6382 }
6383
6384
6385}
6386
6387/**
6388 * xmlXPathScanName:
6389 * @ctxt: the XPath Parser context
6390 *
6391 * Trickery: parse an XML name but without consuming the input flow
6392 * Needed to avoid insanity in the parser state.
6393 *
6394 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6395 * CombiningChar | Extender
6396 *
6397 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6398 *
6399 * [6] Names ::= Name (S Name)*
6400 *
6401 * Returns the Name parsed or NULL
6402 */
6403
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006404static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006405xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
6406 xmlChar buf[XML_MAX_NAMELEN];
6407 int len = 0;
6408
6409 SKIP_BLANKS;
6410 if (!IS_LETTER(CUR) && (CUR != '_') &&
6411 (CUR != ':')) {
6412 return(NULL);
6413 }
6414
6415 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
6416 (NXT(len) == '.') || (NXT(len) == '-') ||
6417 (NXT(len) == '_') || (NXT(len) == ':') ||
6418 (IS_COMBINING(NXT(len))) ||
6419 (IS_EXTENDER(NXT(len)))) {
6420 buf[len] = NXT(len);
6421 len++;
6422 if (len >= XML_MAX_NAMELEN) {
6423 xmlGenericError(xmlGenericErrorContext,
6424 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
6425 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
6426 (NXT(len) == '.') || (NXT(len) == '-') ||
6427 (NXT(len) == '_') || (NXT(len) == ':') ||
6428 (IS_COMBINING(NXT(len))) ||
6429 (IS_EXTENDER(NXT(len))))
6430 len++;
6431 break;
6432 }
6433 }
6434 return(xmlStrndup(buf, len));
6435}
6436
6437/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006438 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006439 * @ctxt: the XPath Parser context
6440 *
6441 * [19] PathExpr ::= LocationPath
6442 * | FilterExpr
6443 * | FilterExpr '/' RelativeLocationPath
6444 * | FilterExpr '//' RelativeLocationPath
6445 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006446 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006447 * The / operator and // operators combine an arbitrary expression
6448 * and a relative location path. It is an error if the expression
6449 * does not evaluate to a node-set.
6450 * The / operator does composition in the same way as when / is
6451 * used in a location path. As in location paths, // is short for
6452 * /descendant-or-self::node()/.
6453 */
6454
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006455static void
6456xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006457 int lc = 1; /* Should we branch to LocationPath ? */
6458 xmlChar *name = NULL; /* we may have to preparse a name to find out */
6459
6460 SKIP_BLANKS;
6461 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
6462 (CUR == '\'') || (CUR == '"')) {
6463 lc = 0;
6464 } else if (CUR == '*') {
6465 /* relative or absolute location path */
6466 lc = 1;
6467 } else if (CUR == '/') {
6468 /* relative or absolute location path */
6469 lc = 1;
6470 } else if (CUR == '@') {
6471 /* relative abbreviated attribute location path */
6472 lc = 1;
6473 } else if (CUR == '.') {
6474 /* relative abbreviated attribute location path */
6475 lc = 1;
6476 } else {
6477 /*
6478 * Problem is finding if we have a name here whether it's:
6479 * - a nodetype
6480 * - a function call in which case it's followed by '('
6481 * - an axis in which case it's followed by ':'
6482 * - a element name
6483 * We do an a priori analysis here rather than having to
6484 * maintain parsed token content through the recursive function
6485 * calls. This looks uglier but makes the code quite easier to
6486 * read/write/debug.
6487 */
6488 SKIP_BLANKS;
6489 name = xmlXPathScanName(ctxt);
6490 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
6491#ifdef DEBUG_STEP
6492 xmlGenericError(xmlGenericErrorContext,
6493 "PathExpr: Axis\n");
6494#endif
6495 lc = 1;
6496 xmlFree(name);
6497 } else if (name != NULL) {
6498 int len =xmlStrlen(name);
6499 int blank = 0;
6500
6501
6502 while (NXT(len) != 0) {
6503 if (NXT(len) == '/') {
6504 /* element name */
6505#ifdef DEBUG_STEP
6506 xmlGenericError(xmlGenericErrorContext,
6507 "PathExpr: AbbrRelLocation\n");
6508#endif
6509 lc = 1;
6510 break;
6511 } else if (IS_BLANK(NXT(len))) {
6512 /* skip to next */
6513 blank = 1;
6514 } else if (NXT(len) == ':') {
6515#ifdef DEBUG_STEP
6516 xmlGenericError(xmlGenericErrorContext,
6517 "PathExpr: AbbrRelLocation\n");
6518#endif
6519 lc = 1;
6520 break;
6521 } else if ((NXT(len) == '(')) {
6522 /* Note Type or Function */
6523 if (xmlXPathIsNodeType(name)) {
6524#ifdef DEBUG_STEP
6525 xmlGenericError(xmlGenericErrorContext,
6526 "PathExpr: Type search\n");
6527#endif
6528 lc = 1;
6529 } else {
6530#ifdef DEBUG_STEP
6531 xmlGenericError(xmlGenericErrorContext,
6532 "PathExpr: function call\n");
6533#endif
6534 lc = 0;
6535 }
6536 break;
6537 } else if ((NXT(len) == '[')) {
6538 /* element name */
6539#ifdef DEBUG_STEP
6540 xmlGenericError(xmlGenericErrorContext,
6541 "PathExpr: AbbrRelLocation\n");
6542#endif
6543 lc = 1;
6544 break;
6545 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
6546 (NXT(len) == '=')) {
6547 lc = 1;
6548 break;
6549 } else {
6550 lc = 1;
6551 break;
6552 }
6553 len++;
6554 }
6555 if (NXT(len) == 0) {
6556#ifdef DEBUG_STEP
6557 xmlGenericError(xmlGenericErrorContext,
6558 "PathExpr: AbbrRelLocation\n");
6559#endif
6560 /* element name */
6561 lc = 1;
6562 }
6563 xmlFree(name);
6564 } else {
6565 /* make sure all cases are covered explicitely */
6566 XP_ERROR(XPATH_EXPR_ERROR);
6567 }
6568 }
6569
6570 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006571 if (CUR == '/') {
6572 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
6573 } else {
6574 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006575 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006576 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006577 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006578 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006579 CHECK_ERROR;
6580 if ((CUR == '/') && (NXT(1) == '/')) {
6581 SKIP(2);
6582 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006583
6584 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
6585 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
6586 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
6587
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006588 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006589 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006590 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006591 }
6592 }
6593 SKIP_BLANKS;
6594}
6595
6596/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006597 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006598 * @ctxt: the XPath Parser context
6599 *
6600 * [18] UnionExpr ::= PathExpr
6601 * | UnionExpr '|' PathExpr
6602 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006603 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006604 */
6605
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006606static void
6607xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
6608 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006609 CHECK_ERROR;
6610 SKIP_BLANKS;
6611 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006612 int op1 = ctxt->comp->last;
6613 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006614
6615 NEXT;
6616 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006617 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006618
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006619 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
6620
Owen Taylor3473f882001-02-23 17:55:21 +00006621 SKIP_BLANKS;
6622 }
Owen Taylor3473f882001-02-23 17:55:21 +00006623}
6624
6625/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006626 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006627 * @ctxt: the XPath Parser context
6628 *
6629 * [27] UnaryExpr ::= UnionExpr
6630 * | '-' UnaryExpr
6631 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006632 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006633 */
6634
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006635static void
6636xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006637 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006638 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006639
6640 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00006641 while (CUR == '-') {
6642 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006643 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006644 NEXT;
6645 SKIP_BLANKS;
6646 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006647
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006648 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006649 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006650 if (found) {
6651 if (minus)
6652 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
6653 else
6654 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006655 }
6656}
6657
6658/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006659 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006660 * @ctxt: the XPath Parser context
6661 *
6662 * [26] MultiplicativeExpr ::= UnaryExpr
6663 * | MultiplicativeExpr MultiplyOperator UnaryExpr
6664 * | MultiplicativeExpr 'div' UnaryExpr
6665 * | MultiplicativeExpr 'mod' UnaryExpr
6666 * [34] MultiplyOperator ::= '*'
6667 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006668 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006669 */
6670
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006671static void
6672xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
6673 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006674 CHECK_ERROR;
6675 SKIP_BLANKS;
6676 while ((CUR == '*') ||
6677 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
6678 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
6679 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006680 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006681
6682 if (CUR == '*') {
6683 op = 0;
6684 NEXT;
6685 } else if (CUR == 'd') {
6686 op = 1;
6687 SKIP(3);
6688 } else if (CUR == 'm') {
6689 op = 2;
6690 SKIP(3);
6691 }
6692 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006693 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006694 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006695 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006696 SKIP_BLANKS;
6697 }
6698}
6699
6700/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006701 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006702 * @ctxt: the XPath Parser context
6703 *
6704 * [25] AdditiveExpr ::= MultiplicativeExpr
6705 * | AdditiveExpr '+' MultiplicativeExpr
6706 * | AdditiveExpr '-' MultiplicativeExpr
6707 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006708 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006709 */
6710
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006711static void
6712xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006713
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006714 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006715 CHECK_ERROR;
6716 SKIP_BLANKS;
6717 while ((CUR == '+') || (CUR == '-')) {
6718 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006719 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006720
6721 if (CUR == '+') plus = 1;
6722 else plus = 0;
6723 NEXT;
6724 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006725 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006726 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006727 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006728 SKIP_BLANKS;
6729 }
6730}
6731
6732/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006733 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006734 * @ctxt: the XPath Parser context
6735 *
6736 * [24] RelationalExpr ::= AdditiveExpr
6737 * | RelationalExpr '<' AdditiveExpr
6738 * | RelationalExpr '>' AdditiveExpr
6739 * | RelationalExpr '<=' AdditiveExpr
6740 * | RelationalExpr '>=' AdditiveExpr
6741 *
6742 * A <= B > C is allowed ? Answer from James, yes with
6743 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
6744 * which is basically what got implemented.
6745 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006746 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00006747 * on the stack
6748 */
6749
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006750static void
6751xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
6752 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006753 CHECK_ERROR;
6754 SKIP_BLANKS;
6755 while ((CUR == '<') ||
6756 (CUR == '>') ||
6757 ((CUR == '<') && (NXT(1) == '=')) ||
6758 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006759 int inf, strict;
6760 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006761
6762 if (CUR == '<') inf = 1;
6763 else inf = 0;
6764 if (NXT(1) == '=') strict = 0;
6765 else strict = 1;
6766 NEXT;
6767 if (!strict) NEXT;
6768 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006769 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006770 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006771 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00006772 SKIP_BLANKS;
6773 }
6774}
6775
6776/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006777 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006778 * @ctxt: the XPath Parser context
6779 *
6780 * [23] EqualityExpr ::= RelationalExpr
6781 * | EqualityExpr '=' RelationalExpr
6782 * | EqualityExpr '!=' RelationalExpr
6783 *
6784 * A != B != C is allowed ? Answer from James, yes with
6785 * (RelationalExpr = RelationalExpr) = RelationalExpr
6786 * (RelationalExpr != RelationalExpr) != RelationalExpr
6787 * which is basically what got implemented.
6788 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006789 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006790 *
6791 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006792static void
6793xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
6794 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006795 CHECK_ERROR;
6796 SKIP_BLANKS;
6797 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006798 int eq;
6799 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006800
6801 if (CUR == '=') eq = 1;
6802 else eq = 0;
6803 NEXT;
6804 if (!eq) NEXT;
6805 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006806 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006807 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006808 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006809 SKIP_BLANKS;
6810 }
6811}
6812
6813/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006814 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006815 * @ctxt: the XPath Parser context
6816 *
6817 * [22] AndExpr ::= EqualityExpr
6818 * | AndExpr 'and' EqualityExpr
6819 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006820 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006821 *
6822 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006823static void
6824xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
6825 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006826 CHECK_ERROR;
6827 SKIP_BLANKS;
6828 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006829 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006830 SKIP(3);
6831 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006832 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006833 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006834 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006835 SKIP_BLANKS;
6836 }
6837}
6838
6839/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006840 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006841 * @ctxt: the XPath Parser context
6842 *
6843 * [14] Expr ::= OrExpr
6844 * [21] OrExpr ::= AndExpr
6845 * | OrExpr 'or' AndExpr
6846 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006847 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00006848 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006849static void
6850xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
6851 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006852 CHECK_ERROR;
6853 SKIP_BLANKS;
6854 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006855 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006856 SKIP(2);
6857 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006858 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006859 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006860 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
6861 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00006862 SKIP_BLANKS;
6863 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006864 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
6865 /* more ops could be optimized too */
6866 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
6867 }
Owen Taylor3473f882001-02-23 17:55:21 +00006868}
6869
6870/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006871 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00006872 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006873 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00006874 *
6875 * [8] Predicate ::= '[' PredicateExpr ']'
6876 * [9] PredicateExpr ::= Expr
6877 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006878 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00006879 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006880static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006881xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006882 int op1 = ctxt->comp->last;
6883
6884 SKIP_BLANKS;
6885 if (CUR != '[') {
6886 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
6887 }
6888 NEXT;
6889 SKIP_BLANKS;
6890
6891 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006892 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006893 CHECK_ERROR;
6894
6895 if (CUR != ']') {
6896 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
6897 }
6898
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006899 if (filter)
6900 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
6901 else
6902 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006903
6904 NEXT;
6905 SKIP_BLANKS;
6906}
6907
6908/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006909 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00006910 * @ctxt: the XPath Parser context
6911 * @test: pointer to a xmlXPathTestVal
6912 * @type: pointer to a xmlXPathTypeVal
6913 * @prefix: placeholder for a possible name prefix
6914 *
6915 * [7] NodeTest ::= NameTest
6916 * | NodeType '(' ')'
6917 * | 'processing-instruction' '(' Literal ')'
6918 *
6919 * [37] NameTest ::= '*'
6920 * | NCName ':' '*'
6921 * | QName
6922 * [38] NodeType ::= 'comment'
6923 * | 'text'
6924 * | 'processing-instruction'
6925 * | 'node'
6926 *
6927 * Returns the name found and update @test, @type and @prefix appropriately
6928 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006929static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006930xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
6931 xmlXPathTypeVal *type, const xmlChar **prefix,
6932 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00006933 int blanks;
6934
6935 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
6936 STRANGE;
6937 return(NULL);
6938 }
6939 *type = 0;
6940 *test = 0;
6941 *prefix = NULL;
6942 SKIP_BLANKS;
6943
6944 if ((name == NULL) && (CUR == '*')) {
6945 /*
6946 * All elements
6947 */
6948 NEXT;
6949 *test = NODE_TEST_ALL;
6950 return(NULL);
6951 }
6952
6953 if (name == NULL)
6954 name = xmlXPathParseNCName(ctxt);
6955 if (name == NULL) {
6956 XP_ERROR0(XPATH_EXPR_ERROR);
6957 }
6958
6959 blanks = IS_BLANK(CUR);
6960 SKIP_BLANKS;
6961 if (CUR == '(') {
6962 NEXT;
6963 /*
6964 * NodeType or PI search
6965 */
6966 if (xmlStrEqual(name, BAD_CAST "comment"))
6967 *type = NODE_TYPE_COMMENT;
6968 else if (xmlStrEqual(name, BAD_CAST "node"))
6969 *type = NODE_TYPE_NODE;
6970 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
6971 *type = NODE_TYPE_PI;
6972 else if (xmlStrEqual(name, BAD_CAST "text"))
6973 *type = NODE_TYPE_TEXT;
6974 else {
6975 if (name != NULL)
6976 xmlFree(name);
6977 XP_ERROR0(XPATH_EXPR_ERROR);
6978 }
6979
6980 *test = NODE_TEST_TYPE;
6981
6982 SKIP_BLANKS;
6983 if (*type == NODE_TYPE_PI) {
6984 /*
6985 * Specific case: search a PI by name.
6986 */
Owen Taylor3473f882001-02-23 17:55:21 +00006987 if (name != NULL)
6988 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00006989 name = NULL;
6990 if (CUR != ')') {
6991 name = xmlXPathParseLiteral(ctxt);
6992 CHECK_ERROR 0;
6993 SKIP_BLANKS;
6994 }
Owen Taylor3473f882001-02-23 17:55:21 +00006995 }
6996 if (CUR != ')') {
6997 if (name != NULL)
6998 xmlFree(name);
6999 XP_ERROR0(XPATH_UNCLOSED_ERROR);
7000 }
7001 NEXT;
7002 return(name);
7003 }
7004 *test = NODE_TEST_NAME;
7005 if ((!blanks) && (CUR == ':')) {
7006 NEXT;
7007
7008 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007009 * Since currently the parser context don't have a
7010 * namespace list associated:
7011 * The namespace name for this prefix can be computed
7012 * only at evaluation time. The compilation is done
7013 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00007014 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007015#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00007016 *prefix = xmlXPathNsLookup(ctxt->context, name);
7017 if (name != NULL)
7018 xmlFree(name);
7019 if (*prefix == NULL) {
7020 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
7021 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007022#else
7023 *prefix = name;
7024#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007025
7026 if (CUR == '*') {
7027 /*
7028 * All elements
7029 */
7030 NEXT;
7031 *test = NODE_TEST_ALL;
7032 return(NULL);
7033 }
7034
7035 name = xmlXPathParseNCName(ctxt);
7036 if (name == NULL) {
7037 XP_ERROR0(XPATH_EXPR_ERROR);
7038 }
7039 }
7040 return(name);
7041}
7042
7043/**
7044 * xmlXPathIsAxisName:
7045 * @name: a preparsed name token
7046 *
7047 * [6] AxisName ::= 'ancestor'
7048 * | 'ancestor-or-self'
7049 * | 'attribute'
7050 * | 'child'
7051 * | 'descendant'
7052 * | 'descendant-or-self'
7053 * | 'following'
7054 * | 'following-sibling'
7055 * | 'namespace'
7056 * | 'parent'
7057 * | 'preceding'
7058 * | 'preceding-sibling'
7059 * | 'self'
7060 *
7061 * Returns the axis or 0
7062 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007063static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00007064xmlXPathIsAxisName(const xmlChar *name) {
7065 xmlXPathAxisVal ret = 0;
7066 switch (name[0]) {
7067 case 'a':
7068 if (xmlStrEqual(name, BAD_CAST "ancestor"))
7069 ret = AXIS_ANCESTOR;
7070 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
7071 ret = AXIS_ANCESTOR_OR_SELF;
7072 if (xmlStrEqual(name, BAD_CAST "attribute"))
7073 ret = AXIS_ATTRIBUTE;
7074 break;
7075 case 'c':
7076 if (xmlStrEqual(name, BAD_CAST "child"))
7077 ret = AXIS_CHILD;
7078 break;
7079 case 'd':
7080 if (xmlStrEqual(name, BAD_CAST "descendant"))
7081 ret = AXIS_DESCENDANT;
7082 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
7083 ret = AXIS_DESCENDANT_OR_SELF;
7084 break;
7085 case 'f':
7086 if (xmlStrEqual(name, BAD_CAST "following"))
7087 ret = AXIS_FOLLOWING;
7088 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
7089 ret = AXIS_FOLLOWING_SIBLING;
7090 break;
7091 case 'n':
7092 if (xmlStrEqual(name, BAD_CAST "namespace"))
7093 ret = AXIS_NAMESPACE;
7094 break;
7095 case 'p':
7096 if (xmlStrEqual(name, BAD_CAST "parent"))
7097 ret = AXIS_PARENT;
7098 if (xmlStrEqual(name, BAD_CAST "preceding"))
7099 ret = AXIS_PRECEDING;
7100 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
7101 ret = AXIS_PRECEDING_SIBLING;
7102 break;
7103 case 's':
7104 if (xmlStrEqual(name, BAD_CAST "self"))
7105 ret = AXIS_SELF;
7106 break;
7107 }
7108 return(ret);
7109}
7110
7111/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007112 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00007113 * @ctxt: the XPath Parser context
7114 *
7115 * [4] Step ::= AxisSpecifier NodeTest Predicate*
7116 * | AbbreviatedStep
7117 *
7118 * [12] AbbreviatedStep ::= '.' | '..'
7119 *
7120 * [5] AxisSpecifier ::= AxisName '::'
7121 * | AbbreviatedAxisSpecifier
7122 *
7123 * [13] AbbreviatedAxisSpecifier ::= '@'?
7124 *
7125 * Modified for XPtr range support as:
7126 *
7127 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
7128 * | AbbreviatedStep
7129 * | 'range-to' '(' Expr ')' Predicate*
7130 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007131 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00007132 * A location step of . is short for self::node(). This is
7133 * particularly useful in conjunction with //. For example, the
7134 * location path .//para is short for
7135 * self::node()/descendant-or-self::node()/child::para
7136 * and so will select all para descendant elements of the context
7137 * node.
7138 * Similarly, a location step of .. is short for parent::node().
7139 * For example, ../title is short for parent::node()/child::title
7140 * and so will select the title children of the parent of the context
7141 * node.
7142 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007143static void
7144xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007145#ifdef LIBXML_XPTR_ENABLED
7146 int rangeto = 0;
7147 int op2 = -1;
7148#endif
7149
Owen Taylor3473f882001-02-23 17:55:21 +00007150 SKIP_BLANKS;
7151 if ((CUR == '.') && (NXT(1) == '.')) {
7152 SKIP(2);
7153 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007154 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
7155 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007156 } else if (CUR == '.') {
7157 NEXT;
7158 SKIP_BLANKS;
7159 } else {
7160 xmlChar *name = NULL;
7161 const xmlChar *prefix = NULL;
7162 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007163 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007164 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007165 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00007166
7167 /*
7168 * The modification needed for XPointer change to the production
7169 */
7170#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007171 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00007172 name = xmlXPathParseNCName(ctxt);
7173 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007174 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007175 xmlFree(name);
7176 SKIP_BLANKS;
7177 if (CUR != '(') {
7178 XP_ERROR(XPATH_EXPR_ERROR);
7179 }
7180 NEXT;
7181 SKIP_BLANKS;
7182
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007183 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007184 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00007185 CHECK_ERROR;
7186
7187 SKIP_BLANKS;
7188 if (CUR != ')') {
7189 XP_ERROR(XPATH_EXPR_ERROR);
7190 }
7191 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007192 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007193 goto eval_predicates;
7194 }
7195 }
7196#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00007197 if (CUR == '*') {
7198 axis = AXIS_CHILD;
7199 } else {
7200 if (name == NULL)
7201 name = xmlXPathParseNCName(ctxt);
7202 if (name != NULL) {
7203 axis = xmlXPathIsAxisName(name);
7204 if (axis != 0) {
7205 SKIP_BLANKS;
7206 if ((CUR == ':') && (NXT(1) == ':')) {
7207 SKIP(2);
7208 xmlFree(name);
7209 name = NULL;
7210 } else {
7211 /* an element name can conflict with an axis one :-\ */
7212 axis = AXIS_CHILD;
7213 }
Owen Taylor3473f882001-02-23 17:55:21 +00007214 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00007215 axis = AXIS_CHILD;
7216 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007217 } else if (CUR == '@') {
7218 NEXT;
7219 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00007220 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00007221 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00007222 }
Owen Taylor3473f882001-02-23 17:55:21 +00007223 }
7224
7225 CHECK_ERROR;
7226
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007227 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00007228 if (test == 0)
7229 return;
7230
7231#ifdef DEBUG_STEP
7232 xmlGenericError(xmlGenericErrorContext,
7233 "Basis : computing new set\n");
7234#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007235
Owen Taylor3473f882001-02-23 17:55:21 +00007236#ifdef DEBUG_STEP
7237 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007238 if (ctxt->value == NULL)
7239 xmlGenericError(xmlGenericErrorContext, "no value\n");
7240 else if (ctxt->value->nodesetval == NULL)
7241 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7242 else
7243 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007244#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007245
7246eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007247 op1 = ctxt->comp->last;
7248 ctxt->comp->last = -1;
7249
Owen Taylor3473f882001-02-23 17:55:21 +00007250 SKIP_BLANKS;
7251 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007252 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007253 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007254
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007255#ifdef LIBXML_XPTR_ENABLED
7256 if (rangeto) {
7257 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
7258 } else
7259#endif
7260 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
7261 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007262
Owen Taylor3473f882001-02-23 17:55:21 +00007263 }
7264#ifdef DEBUG_STEP
7265 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007266 if (ctxt->value == NULL)
7267 xmlGenericError(xmlGenericErrorContext, "no value\n");
7268 else if (ctxt->value->nodesetval == NULL)
7269 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7270 else
7271 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
7272 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007273#endif
7274}
7275
7276/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007277 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007278 * @ctxt: the XPath Parser context
7279 *
7280 * [3] RelativeLocationPath ::= Step
7281 * | RelativeLocationPath '/' Step
7282 * | AbbreviatedRelativeLocationPath
7283 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
7284 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007285 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00007286 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007287static void
Owen Taylor3473f882001-02-23 17:55:21 +00007288#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007289xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007290#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007291xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007292#endif
7293(xmlXPathParserContextPtr ctxt) {
7294 SKIP_BLANKS;
7295 if ((CUR == '/') && (NXT(1) == '/')) {
7296 SKIP(2);
7297 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007298 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7299 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007300 } else if (CUR == '/') {
7301 NEXT;
7302 SKIP_BLANKS;
7303 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007304 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007305 SKIP_BLANKS;
7306 while (CUR == '/') {
7307 if ((CUR == '/') && (NXT(1) == '/')) {
7308 SKIP(2);
7309 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007310 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00007311 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007312 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007313 } else if (CUR == '/') {
7314 NEXT;
7315 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007316 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007317 }
7318 SKIP_BLANKS;
7319 }
7320}
7321
7322/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007323 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007324 * @ctxt: the XPath Parser context
7325 *
7326 * [1] LocationPath ::= RelativeLocationPath
7327 * | AbsoluteLocationPath
7328 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
7329 * | AbbreviatedAbsoluteLocationPath
7330 * [10] AbbreviatedAbsoluteLocationPath ::=
7331 * '//' RelativeLocationPath
7332 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007333 * Compile a location path
7334 *
Owen Taylor3473f882001-02-23 17:55:21 +00007335 * // is short for /descendant-or-self::node()/. For example,
7336 * //para is short for /descendant-or-self::node()/child::para and
7337 * so will select any para element in the document (even a para element
7338 * that is a document element will be selected by //para since the
7339 * document element node is a child of the root node); div//para is
7340 * short for div/descendant-or-self::node()/child::para and so will
7341 * select all para descendants of div children.
7342 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007343static void
7344xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007345 SKIP_BLANKS;
7346 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007347 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007348 } else {
7349 while (CUR == '/') {
7350 if ((CUR == '/') && (NXT(1) == '/')) {
7351 SKIP(2);
7352 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007353 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7354 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007355 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007356 } else if (CUR == '/') {
7357 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00007358 SKIP_BLANKS;
7359 if ((CUR != 0 ) &&
7360 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
7361 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007362 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007363 }
7364 }
7365 }
7366}
7367
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007368/************************************************************************
7369 * *
7370 * XPath precompiled expression evaluation *
7371 * *
7372 ************************************************************************/
7373
Daniel Veillardf06307e2001-07-03 10:35:50 +00007374static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007375xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
7376
7377/**
7378 * xmlXPathNodeCollectAndTest:
7379 * @ctxt: the XPath Parser context
7380 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00007381 * @first: pointer to the first element in document order
7382 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007383 *
7384 * This is the function implementing a step: based on the current list
7385 * of nodes, it builds up a new list, looking at all nodes under that
7386 * axis and selecting them it also do the predicate filtering
7387 *
7388 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00007389 *
7390 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007391 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00007392static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007393xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00007394 xmlXPathStepOpPtr op,
7395 xmlNodePtr * first, xmlNodePtr * last)
7396{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007397 xmlXPathAxisVal axis = op->value;
7398 xmlXPathTestVal test = op->value2;
7399 xmlXPathTypeVal type = op->value3;
7400 const xmlChar *prefix = op->value4;
7401 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00007402 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007403
7404#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007405 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007406#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007407 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007408 xmlNodeSetPtr ret, list;
7409 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00007410 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007411 xmlNodePtr cur = NULL;
7412 xmlXPathObjectPtr obj;
7413 xmlNodeSetPtr nodelist;
7414 xmlNodePtr tmp;
7415
Daniel Veillardf06307e2001-07-03 10:35:50 +00007416 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007417 obj = valuePop(ctxt);
7418 addNode = xmlXPathNodeSetAdd;
Daniel Veillarde043ee12001-04-16 14:08:07 +00007419 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00007420 URI = xmlXPathNsLookup(ctxt->context, prefix);
7421 if (URI == NULL)
7422 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00007423 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007424#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007425 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007426#endif
7427 switch (axis) {
7428 case AXIS_ANCESTOR:
7429#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007430 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007431#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007432 first = NULL;
7433 next = xmlXPathNextAncestor;
7434 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007435 case AXIS_ANCESTOR_OR_SELF:
7436#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007437 xmlGenericError(xmlGenericErrorContext,
7438 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007439#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007440 first = NULL;
7441 next = xmlXPathNextAncestorOrSelf;
7442 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007443 case AXIS_ATTRIBUTE:
7444#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007445 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007446#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007447 first = NULL;
7448 last = NULL;
7449 next = xmlXPathNextAttribute;
7450 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007451 case AXIS_CHILD:
7452#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007453 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007454#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007455 last = NULL;
7456 next = xmlXPathNextChild;
7457 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007458 case AXIS_DESCENDANT:
7459#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007460 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007461#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007462 last = NULL;
7463 next = xmlXPathNextDescendant;
7464 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007465 case AXIS_DESCENDANT_OR_SELF:
7466#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007467 xmlGenericError(xmlGenericErrorContext,
7468 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007469#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007470 last = NULL;
7471 next = xmlXPathNextDescendantOrSelf;
7472 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007473 case AXIS_FOLLOWING:
7474#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007475 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007476#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007477 last = NULL;
7478 next = xmlXPathNextFollowing;
7479 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007480 case AXIS_FOLLOWING_SIBLING:
7481#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007482 xmlGenericError(xmlGenericErrorContext,
7483 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007484#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007485 last = NULL;
7486 next = xmlXPathNextFollowingSibling;
7487 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007488 case AXIS_NAMESPACE:
7489#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007490 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007491#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007492 first = NULL;
7493 last = NULL;
7494 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
7495 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007496 case AXIS_PARENT:
7497#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007498 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007499#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007500 first = NULL;
7501 next = xmlXPathNextParent;
7502 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007503 case AXIS_PRECEDING:
7504#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007505 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007506#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007507 first = NULL;
7508 next = xmlXPathNextPrecedingInternal;
7509 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007510 case AXIS_PRECEDING_SIBLING:
7511#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007512 xmlGenericError(xmlGenericErrorContext,
7513 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007514#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007515 first = NULL;
7516 next = xmlXPathNextPrecedingSibling;
7517 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007518 case AXIS_SELF:
7519#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007520 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007521#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007522 first = NULL;
7523 last = NULL;
7524 next = xmlXPathNextSelf;
7525 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007526 }
7527 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00007528 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007529
7530 nodelist = obj->nodesetval;
7531 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00007532 xmlXPathFreeObject(obj);
7533 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
7534 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007535 }
7536 addNode = xmlXPathNodeSetAddUnique;
7537 ret = NULL;
7538#ifdef DEBUG_STEP
7539 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00007540 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007541 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00007542 case NODE_TEST_NONE:
7543 xmlGenericError(xmlGenericErrorContext,
7544 " searching for none !!!\n");
7545 break;
7546 case NODE_TEST_TYPE:
7547 xmlGenericError(xmlGenericErrorContext,
7548 " searching for type %d\n", type);
7549 break;
7550 case NODE_TEST_PI:
7551 xmlGenericError(xmlGenericErrorContext,
7552 " searching for PI !!!\n");
7553 break;
7554 case NODE_TEST_ALL:
7555 xmlGenericError(xmlGenericErrorContext,
7556 " searching for *\n");
7557 break;
7558 case NODE_TEST_NS:
7559 xmlGenericError(xmlGenericErrorContext,
7560 " searching for namespace %s\n",
7561 prefix);
7562 break;
7563 case NODE_TEST_NAME:
7564 xmlGenericError(xmlGenericErrorContext,
7565 " searching for name %s\n", name);
7566 if (prefix != NULL)
7567 xmlGenericError(xmlGenericErrorContext,
7568 " with namespace %s\n", prefix);
7569 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007570 }
7571 xmlGenericError(xmlGenericErrorContext, "Testing : ");
7572#endif
7573 /*
7574 * 2.3 Node Tests
7575 * - For the attribute axis, the principal node type is attribute.
7576 * - For the namespace axis, the principal node type is namespace.
7577 * - For other axes, the principal node type is element.
7578 *
7579 * A node test * is true for any node of the
7580 * principal node type. For example, child::* willi
7581 * select all element children of the context node
7582 */
7583 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00007584 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007585 ctxt->context->node = nodelist->nodeTab[i];
7586
Daniel Veillardf06307e2001-07-03 10:35:50 +00007587 cur = NULL;
7588 list = xmlXPathNodeSetCreate(NULL);
7589 do {
7590 cur = next(ctxt, cur);
7591 if (cur == NULL)
7592 break;
7593 if ((first != NULL) && (*first == cur))
7594 break;
7595 if (((t % 256) == 0) &&
7596 (first != NULL) && (*first != NULL) &&
7597 (xmlXPathCmpNodes(*first, cur) >= 0))
7598 break;
7599 if ((last != NULL) && (*last == cur))
7600 break;
7601 if (((t % 256) == 0) &&
7602 (last != NULL) && (*last != NULL) &&
7603 (xmlXPathCmpNodes(cur, *last) >= 0))
7604 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007605 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00007606#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007607 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
7608#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007609 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007610 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00007611 ctxt->context->node = tmp;
7612 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007613 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00007614 if ((cur->type == type) ||
7615 ((type == NODE_TYPE_NODE) &&
7616 ((cur->type == XML_DOCUMENT_NODE) ||
7617 (cur->type == XML_HTML_DOCUMENT_NODE) ||
7618 (cur->type == XML_ELEMENT_NODE) ||
7619 (cur->type == XML_PI_NODE) ||
7620 (cur->type == XML_COMMENT_NODE) ||
7621 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00007622 (cur->type == XML_TEXT_NODE))) ||
7623 ((type == NODE_TYPE_TEXT) &&
7624 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007625#ifdef DEBUG_STEP
7626 n++;
7627#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007628 addNode(list, cur);
7629 }
7630 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007631 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00007632 if (cur->type == XML_PI_NODE) {
7633 if ((name != NULL) &&
7634 (!xmlStrEqual(name, cur->name)))
7635 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007636#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007637 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007638#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007639 addNode(list, cur);
7640 }
7641 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007642 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00007643 if (axis == AXIS_ATTRIBUTE) {
7644 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007645#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007646 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007647#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007648 addNode(list, cur);
7649 }
7650 } else if (axis == AXIS_NAMESPACE) {
7651 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007652#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007653 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007654#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007655 addNode(list, cur);
7656 }
7657 } else {
7658 if (cur->type == XML_ELEMENT_NODE) {
7659 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007660#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007661 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007662#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007663 addNode(list, cur);
7664 } else if ((cur->ns != NULL) &&
7665 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007666#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007667 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007668#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007669 addNode(list, cur);
7670 }
7671 }
7672 }
7673 break;
7674 case NODE_TEST_NS:{
7675 TODO;
7676 break;
7677 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007678 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00007679 switch (cur->type) {
7680 case XML_ELEMENT_NODE:
7681 if (xmlStrEqual(name, cur->name)) {
7682 if (prefix == NULL) {
7683 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007684#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007685 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007686#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007687 addNode(list, cur);
7688 }
7689 } else {
7690 if ((cur->ns != NULL) &&
7691 (xmlStrEqual(URI,
7692 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007693#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007694 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007695#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007696 addNode(list, cur);
7697 }
7698 }
7699 }
7700 break;
7701 case XML_ATTRIBUTE_NODE:{
7702 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007703
Daniel Veillardf06307e2001-07-03 10:35:50 +00007704 if (xmlStrEqual(name, attr->name)) {
7705 if (prefix == NULL) {
7706 if ((attr->ns == NULL) ||
7707 (attr->ns->prefix == NULL)) {
7708#ifdef DEBUG_STEP
7709 n++;
7710#endif
7711 addNode(list,
7712 (xmlNodePtr) attr);
7713 }
7714 } else {
7715 if ((attr->ns != NULL) &&
7716 (xmlStrEqual(URI,
7717 attr->ns->
7718 href))) {
7719#ifdef DEBUG_STEP
7720 n++;
7721#endif
7722 addNode(list,
7723 (xmlNodePtr) attr);
7724 }
7725 }
7726 }
7727 break;
7728 }
7729 case XML_NAMESPACE_DECL:
7730 if (cur->type == XML_NAMESPACE_DECL) {
7731 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007732
Daniel Veillardf06307e2001-07-03 10:35:50 +00007733 if ((ns->prefix != NULL) && (name != NULL)
7734 && (xmlStrEqual(ns->prefix, name))) {
7735#ifdef DEBUG_STEP
7736 n++;
7737#endif
7738 addNode(list, cur);
7739 }
7740 }
7741 break;
7742 default:
7743 break;
7744 }
7745 break;
7746 break;
7747 }
7748 } while (cur != NULL);
7749
7750 /*
7751 * If there is some predicate filtering do it now
7752 */
7753 if (op->ch2 != -1) {
7754 xmlXPathObjectPtr obj2;
7755
7756 valuePush(ctxt, xmlXPathWrapNodeSet(list));
7757 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
7758 CHECK_TYPE0(XPATH_NODESET);
7759 obj2 = valuePop(ctxt);
7760 list = obj2->nodesetval;
7761 obj2->nodesetval = NULL;
7762 xmlXPathFreeObject(obj2);
7763 }
7764 if (ret == NULL) {
7765 ret = list;
7766 } else {
7767 ret = xmlXPathNodeSetMerge(ret, list);
7768 xmlXPathFreeNodeSet(list);
7769 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007770 }
7771 ctxt->context->node = tmp;
7772#ifdef DEBUG_STEP
7773 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00007774 "\nExamined %d nodes, found %d nodes at that step\n",
7775 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007776#endif
7777 xmlXPathFreeObject(obj);
7778 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillardf06307e2001-07-03 10:35:50 +00007779 return(t);
7780}
7781
7782/**
7783 * xmlXPathNodeCollectAndTestNth:
7784 * @ctxt: the XPath Parser context
7785 * @op: the XPath precompiled step operation
7786 * @indx: the index to collect
7787 * @first: pointer to the first element in document order
7788 * @last: pointer to the last element in document order
7789 *
7790 * This is the function implementing a step: based on the current list
7791 * of nodes, it builds up a new list, looking at all nodes under that
7792 * axis and selecting them it also do the predicate filtering
7793 *
7794 * Pushes the new NodeSet resulting from the search.
7795 * Returns the number of node traversed
7796 */
7797static int
7798xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
7799 xmlXPathStepOpPtr op, int indx,
7800 xmlNodePtr * first, xmlNodePtr * last)
7801{
7802 xmlXPathAxisVal axis = op->value;
7803 xmlXPathTestVal test = op->value2;
7804 xmlXPathTypeVal type = op->value3;
7805 const xmlChar *prefix = op->value4;
7806 const xmlChar *name = op->value5;
7807 const xmlChar *URI = NULL;
7808 int n = 0, t = 0;
7809
7810 int i;
7811 xmlNodeSetPtr list;
7812 xmlXPathTraversalFunction next = NULL;
7813 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
7814 xmlNodePtr cur = NULL;
7815 xmlXPathObjectPtr obj;
7816 xmlNodeSetPtr nodelist;
7817 xmlNodePtr tmp;
7818
7819 CHECK_TYPE0(XPATH_NODESET);
7820 obj = valuePop(ctxt);
7821 addNode = xmlXPathNodeSetAdd;
7822 if (prefix != NULL) {
7823 URI = xmlXPathNsLookup(ctxt->context, prefix);
7824 if (URI == NULL)
7825 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
7826 }
7827#ifdef DEBUG_STEP_NTH
7828 xmlGenericError(xmlGenericErrorContext, "new step : ");
7829 if (first != NULL) {
7830 if (*first != NULL)
7831 xmlGenericError(xmlGenericErrorContext, "first = %s ",
7832 (*first)->name);
7833 else
7834 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
7835 }
7836 if (last != NULL) {
7837 if (*last != NULL)
7838 xmlGenericError(xmlGenericErrorContext, "last = %s ",
7839 (*last)->name);
7840 else
7841 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
7842 }
7843#endif
7844 switch (axis) {
7845 case AXIS_ANCESTOR:
7846#ifdef DEBUG_STEP_NTH
7847 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
7848#endif
7849 first = NULL;
7850 next = xmlXPathNextAncestor;
7851 break;
7852 case AXIS_ANCESTOR_OR_SELF:
7853#ifdef DEBUG_STEP_NTH
7854 xmlGenericError(xmlGenericErrorContext,
7855 "axis 'ancestors-or-self' ");
7856#endif
7857 first = NULL;
7858 next = xmlXPathNextAncestorOrSelf;
7859 break;
7860 case AXIS_ATTRIBUTE:
7861#ifdef DEBUG_STEP_NTH
7862 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
7863#endif
7864 first = NULL;
7865 last = NULL;
7866 next = xmlXPathNextAttribute;
7867 break;
7868 case AXIS_CHILD:
7869#ifdef DEBUG_STEP_NTH
7870 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
7871#endif
7872 last = NULL;
7873 next = xmlXPathNextChild;
7874 break;
7875 case AXIS_DESCENDANT:
7876#ifdef DEBUG_STEP_NTH
7877 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
7878#endif
7879 last = NULL;
7880 next = xmlXPathNextDescendant;
7881 break;
7882 case AXIS_DESCENDANT_OR_SELF:
7883#ifdef DEBUG_STEP_NTH
7884 xmlGenericError(xmlGenericErrorContext,
7885 "axis 'descendant-or-self' ");
7886#endif
7887 last = NULL;
7888 next = xmlXPathNextDescendantOrSelf;
7889 break;
7890 case AXIS_FOLLOWING:
7891#ifdef DEBUG_STEP_NTH
7892 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
7893#endif
7894 last = NULL;
7895 next = xmlXPathNextFollowing;
7896 break;
7897 case AXIS_FOLLOWING_SIBLING:
7898#ifdef DEBUG_STEP_NTH
7899 xmlGenericError(xmlGenericErrorContext,
7900 "axis 'following-siblings' ");
7901#endif
7902 last = NULL;
7903 next = xmlXPathNextFollowingSibling;
7904 break;
7905 case AXIS_NAMESPACE:
7906#ifdef DEBUG_STEP_NTH
7907 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
7908#endif
7909 last = NULL;
7910 first = NULL;
7911 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
7912 break;
7913 case AXIS_PARENT:
7914#ifdef DEBUG_STEP_NTH
7915 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
7916#endif
7917 first = NULL;
7918 next = xmlXPathNextParent;
7919 break;
7920 case AXIS_PRECEDING:
7921#ifdef DEBUG_STEP_NTH
7922 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
7923#endif
7924 first = NULL;
7925 next = xmlXPathNextPrecedingInternal;
7926 break;
7927 case AXIS_PRECEDING_SIBLING:
7928#ifdef DEBUG_STEP_NTH
7929 xmlGenericError(xmlGenericErrorContext,
7930 "axis 'preceding-sibling' ");
7931#endif
7932 first = NULL;
7933 next = xmlXPathNextPrecedingSibling;
7934 break;
7935 case AXIS_SELF:
7936#ifdef DEBUG_STEP_NTH
7937 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
7938#endif
7939 first = NULL;
7940 last = NULL;
7941 next = xmlXPathNextSelf;
7942 break;
7943 }
7944 if (next == NULL)
7945 return(0);
7946
7947 nodelist = obj->nodesetval;
7948 if (nodelist == NULL) {
7949 xmlXPathFreeObject(obj);
7950 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
7951 return(0);
7952 }
7953 addNode = xmlXPathNodeSetAddUnique;
7954#ifdef DEBUG_STEP_NTH
7955 xmlGenericError(xmlGenericErrorContext,
7956 " context contains %d nodes\n", nodelist->nodeNr);
7957 switch (test) {
7958 case NODE_TEST_NONE:
7959 xmlGenericError(xmlGenericErrorContext,
7960 " searching for none !!!\n");
7961 break;
7962 case NODE_TEST_TYPE:
7963 xmlGenericError(xmlGenericErrorContext,
7964 " searching for type %d\n", type);
7965 break;
7966 case NODE_TEST_PI:
7967 xmlGenericError(xmlGenericErrorContext,
7968 " searching for PI !!!\n");
7969 break;
7970 case NODE_TEST_ALL:
7971 xmlGenericError(xmlGenericErrorContext,
7972 " searching for *\n");
7973 break;
7974 case NODE_TEST_NS:
7975 xmlGenericError(xmlGenericErrorContext,
7976 " searching for namespace %s\n",
7977 prefix);
7978 break;
7979 case NODE_TEST_NAME:
7980 xmlGenericError(xmlGenericErrorContext,
7981 " searching for name %s\n", name);
7982 if (prefix != NULL)
7983 xmlGenericError(xmlGenericErrorContext,
7984 " with namespace %s\n", prefix);
7985 break;
7986 }
7987 xmlGenericError(xmlGenericErrorContext, "Testing : ");
7988#endif
7989 /*
7990 * 2.3 Node Tests
7991 * - For the attribute axis, the principal node type is attribute.
7992 * - For the namespace axis, the principal node type is namespace.
7993 * - For other axes, the principal node type is element.
7994 *
7995 * A node test * is true for any node of the
7996 * principal node type. For example, child::* willi
7997 * select all element children of the context node
7998 */
7999 tmp = ctxt->context->node;
8000 list = xmlXPathNodeSetCreate(NULL);
8001 for (i = 0; i < nodelist->nodeNr; i++) {
8002 ctxt->context->node = nodelist->nodeTab[i];
8003
8004 cur = NULL;
8005 n = 0;
8006 do {
8007 cur = next(ctxt, cur);
8008 if (cur == NULL)
8009 break;
8010 if ((first != NULL) && (*first == cur))
8011 break;
8012 if (((t % 256) == 0) &&
8013 (first != NULL) && (*first != NULL) &&
8014 (xmlXPathCmpNodes(*first, cur) >= 0))
8015 break;
8016 if ((last != NULL) && (*last == cur))
8017 break;
8018 if (((t % 256) == 0) &&
8019 (last != NULL) && (*last != NULL) &&
8020 (xmlXPathCmpNodes(cur, *last) >= 0))
8021 break;
8022 t++;
8023 switch (test) {
8024 case NODE_TEST_NONE:
8025 ctxt->context->node = tmp;
8026 STRANGE return(0);
8027 case NODE_TEST_TYPE:
8028 if ((cur->type == type) ||
8029 ((type == NODE_TYPE_NODE) &&
8030 ((cur->type == XML_DOCUMENT_NODE) ||
8031 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8032 (cur->type == XML_ELEMENT_NODE) ||
8033 (cur->type == XML_PI_NODE) ||
8034 (cur->type == XML_COMMENT_NODE) ||
8035 (cur->type == XML_CDATA_SECTION_NODE) ||
8036 (cur->type == XML_TEXT_NODE)))) {
8037 n++;
8038 if (n == indx)
8039 addNode(list, cur);
8040 }
8041 break;
8042 case NODE_TEST_PI:
8043 if (cur->type == XML_PI_NODE) {
8044 if ((name != NULL) &&
8045 (!xmlStrEqual(name, cur->name)))
8046 break;
8047 n++;
8048 if (n == indx)
8049 addNode(list, cur);
8050 }
8051 break;
8052 case NODE_TEST_ALL:
8053 if (axis == AXIS_ATTRIBUTE) {
8054 if (cur->type == XML_ATTRIBUTE_NODE) {
8055 n++;
8056 if (n == indx)
8057 addNode(list, cur);
8058 }
8059 } else if (axis == AXIS_NAMESPACE) {
8060 if (cur->type == XML_NAMESPACE_DECL) {
8061 n++;
8062 if (n == indx)
8063 addNode(list, cur);
8064 }
8065 } else {
8066 if (cur->type == XML_ELEMENT_NODE) {
8067 if (prefix == NULL) {
8068 n++;
8069 if (n == indx)
8070 addNode(list, cur);
8071 } else if ((cur->ns != NULL) &&
8072 (xmlStrEqual(URI, cur->ns->href))) {
8073 n++;
8074 if (n == indx)
8075 addNode(list, cur);
8076 }
8077 }
8078 }
8079 break;
8080 case NODE_TEST_NS:{
8081 TODO;
8082 break;
8083 }
8084 case NODE_TEST_NAME:
8085 switch (cur->type) {
8086 case XML_ELEMENT_NODE:
8087 if (xmlStrEqual(name, cur->name)) {
8088 if (prefix == NULL) {
8089 if (cur->ns == NULL) {
8090 n++;
8091 if (n == indx)
8092 addNode(list, cur);
8093 }
8094 } else {
8095 if ((cur->ns != NULL) &&
8096 (xmlStrEqual(URI,
8097 cur->ns->href))) {
8098 n++;
8099 if (n == indx)
8100 addNode(list, cur);
8101 }
8102 }
8103 }
8104 break;
8105 case XML_ATTRIBUTE_NODE:{
8106 xmlAttrPtr attr = (xmlAttrPtr) cur;
8107
8108 if (xmlStrEqual(name, attr->name)) {
8109 if (prefix == NULL) {
8110 if ((attr->ns == NULL) ||
8111 (attr->ns->prefix == NULL)) {
8112 n++;
8113 if (n == indx)
8114 addNode(list, cur);
8115 }
8116 } else {
8117 if ((attr->ns != NULL) &&
8118 (xmlStrEqual(URI,
8119 attr->ns->
8120 href))) {
8121 n++;
8122 if (n == indx)
8123 addNode(list, cur);
8124 }
8125 }
8126 }
8127 break;
8128 }
8129 case XML_NAMESPACE_DECL:
8130 if (cur->type == XML_NAMESPACE_DECL) {
8131 xmlNsPtr ns = (xmlNsPtr) cur;
8132
8133 if ((ns->prefix != NULL) && (name != NULL)
8134 && (xmlStrEqual(ns->prefix, name))) {
8135 n++;
8136 if (n == indx)
8137 addNode(list, cur);
8138 }
8139 }
8140 break;
8141 default:
8142 break;
8143 }
8144 break;
8145 break;
8146 }
8147 } while (n < indx);
8148 }
8149 ctxt->context->node = tmp;
8150#ifdef DEBUG_STEP_NTH
8151 xmlGenericError(xmlGenericErrorContext,
8152 "\nExamined %d nodes, found %d nodes at that step\n",
8153 t, list->nodeNr);
8154#endif
8155 xmlXPathFreeObject(obj);
8156 valuePush(ctxt, xmlXPathWrapNodeSet(list));
8157 return(t);
8158}
8159
8160/**
8161 * xmlXPathCompOpEvalFirst:
8162 * @ctxt: the XPath parser context with the compiled expression
8163 * @op: an XPath compiled operation
8164 * @first: the first elem found so far
8165 *
8166 * Evaluate the Precompiled XPath operation searching only the first
8167 * element in document order
8168 *
8169 * Returns the number of examined objects.
8170 */
8171static int
8172xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
8173 xmlXPathStepOpPtr op, xmlNodePtr * first)
8174{
8175 int total = 0, cur;
8176 xmlXPathCompExprPtr comp;
8177 xmlXPathObjectPtr arg1, arg2;
8178
8179 comp = ctxt->comp;
8180 switch (op->op) {
8181 case XPATH_OP_END:
8182 return (0);
8183 case XPATH_OP_UNION:
8184 total =
8185 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
8186 first);
8187 if ((ctxt->value != NULL)
8188 && (ctxt->value->type == XPATH_NODESET)
8189 && (ctxt->value->nodesetval != NULL)
8190 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8191 /*
8192 * limit tree traversing to first node in the result
8193 */
8194 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8195 *first = ctxt->value->nodesetval->nodeTab[0];
8196 }
8197 cur =
8198 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
8199 first);
8200 CHECK_TYPE0(XPATH_NODESET);
8201 arg2 = valuePop(ctxt);
8202
8203 CHECK_TYPE0(XPATH_NODESET);
8204 arg1 = valuePop(ctxt);
8205
8206 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8207 arg2->nodesetval);
8208 valuePush(ctxt, arg1);
8209 xmlXPathFreeObject(arg2);
8210 /* optimizer */
8211 if (total > cur)
8212 xmlXPathCompSwap(op);
8213 return (total + cur);
8214 case XPATH_OP_ROOT:
8215 xmlXPathRoot(ctxt);
8216 return (0);
8217 case XPATH_OP_NODE:
8218 if (op->ch1 != -1)
8219 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8220 if (op->ch2 != -1)
8221 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8222 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8223 return (total);
8224 case XPATH_OP_RESET:
8225 if (op->ch1 != -1)
8226 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8227 if (op->ch2 != -1)
8228 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8229 ctxt->context->node = NULL;
8230 return (total);
8231 case XPATH_OP_COLLECT:{
8232 if (op->ch1 == -1)
8233 return (total);
8234
8235 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8236
8237 /*
8238 * Optimization for [n] selection where n is a number
8239 */
8240 if ((op->ch2 != -1) &&
8241 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8242 (comp->steps[op->ch2].ch1 == -1) &&
8243 (comp->steps[op->ch2].ch2 != -1) &&
8244 (comp->steps[comp->steps[op->ch2].ch2].op ==
8245 XPATH_OP_VALUE)) {
8246 xmlXPathObjectPtr val;
8247
8248 val = comp->steps[comp->steps[op->ch2].ch2].value4;
8249 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
8250 int indx = (int) val->floatval;
8251
8252 if (val->floatval == (float) indx) {
8253 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
8254 first, NULL);
8255 return (total);
8256 }
8257 }
8258 }
8259 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
8260 return (total);
8261 }
8262 case XPATH_OP_VALUE:
8263 valuePush(ctxt,
8264 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
8265 return (0);
8266 case XPATH_OP_SORT:
8267 if (op->ch1 != -1)
8268 total +=
8269 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
8270 first);
8271 if ((ctxt->value != NULL)
8272 && (ctxt->value->type == XPATH_NODESET)
8273 && (ctxt->value->nodesetval != NULL))
8274 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8275 return (total);
8276 default:
8277 return (xmlXPathCompOpEval(ctxt, op));
8278 }
8279}
8280
8281/**
8282 * xmlXPathCompOpEvalLast:
8283 * @ctxt: the XPath parser context with the compiled expression
8284 * @op: an XPath compiled operation
8285 * @last: the last elem found so far
8286 *
8287 * Evaluate the Precompiled XPath operation searching only the last
8288 * element in document order
8289 *
8290 * Returns the number of node traversed
8291 */
8292static int
8293xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
8294 xmlNodePtr * last)
8295{
8296 int total = 0, cur;
8297 xmlXPathCompExprPtr comp;
8298 xmlXPathObjectPtr arg1, arg2;
8299
8300 comp = ctxt->comp;
8301 switch (op->op) {
8302 case XPATH_OP_END:
8303 return (0);
8304 case XPATH_OP_UNION:
8305 total =
8306 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
8307 if ((ctxt->value != NULL)
8308 && (ctxt->value->type == XPATH_NODESET)
8309 && (ctxt->value->nodesetval != NULL)
8310 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8311 /*
8312 * limit tree traversing to first node in the result
8313 */
8314 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8315 *last =
8316 ctxt->value->nodesetval->nodeTab[ctxt->value->
8317 nodesetval->nodeNr -
8318 1];
8319 }
8320 cur =
8321 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
8322 if ((ctxt->value != NULL)
8323 && (ctxt->value->type == XPATH_NODESET)
8324 && (ctxt->value->nodesetval != NULL)
8325 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8326 }
8327 CHECK_TYPE0(XPATH_NODESET);
8328 arg2 = valuePop(ctxt);
8329
8330 CHECK_TYPE0(XPATH_NODESET);
8331 arg1 = valuePop(ctxt);
8332
8333 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8334 arg2->nodesetval);
8335 valuePush(ctxt, arg1);
8336 xmlXPathFreeObject(arg2);
8337 /* optimizer */
8338 if (total > cur)
8339 xmlXPathCompSwap(op);
8340 return (total + cur);
8341 case XPATH_OP_ROOT:
8342 xmlXPathRoot(ctxt);
8343 return (0);
8344 case XPATH_OP_NODE:
8345 if (op->ch1 != -1)
8346 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8347 if (op->ch2 != -1)
8348 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8349 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8350 return (total);
8351 case XPATH_OP_RESET:
8352 if (op->ch1 != -1)
8353 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8354 if (op->ch2 != -1)
8355 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8356 ctxt->context->node = NULL;
8357 return (total);
8358 case XPATH_OP_COLLECT:{
8359 if (op->ch1 == -1)
8360 return (0);
8361
8362 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8363
8364 /*
8365 * Optimization for [n] selection where n is a number
8366 */
8367 if ((op->ch2 != -1) &&
8368 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8369 (comp->steps[op->ch2].ch1 == -1) &&
8370 (comp->steps[op->ch2].ch2 != -1) &&
8371 (comp->steps[comp->steps[op->ch2].ch2].op ==
8372 XPATH_OP_VALUE)) {
8373 xmlXPathObjectPtr val;
8374
8375 val = comp->steps[comp->steps[op->ch2].ch2].value4;
8376 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
8377 int indx = (int) val->floatval;
8378
8379 if (val->floatval == (float) indx) {
8380 total +=
8381 xmlXPathNodeCollectAndTestNth(ctxt, op,
8382 indx, NULL,
8383 last);
8384 return (total);
8385 }
8386 }
8387 }
8388 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
8389 return (total);
8390 }
8391 case XPATH_OP_VALUE:
8392 valuePush(ctxt,
8393 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
8394 return (0);
8395 case XPATH_OP_SORT:
8396 if (op->ch1 != -1)
8397 total +=
8398 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
8399 last);
8400 if ((ctxt->value != NULL)
8401 && (ctxt->value->type == XPATH_NODESET)
8402 && (ctxt->value->nodesetval != NULL))
8403 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8404 return (total);
8405 default:
8406 return (xmlXPathCompOpEval(ctxt, op));
8407 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008408}
8409
Owen Taylor3473f882001-02-23 17:55:21 +00008410/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008411 * xmlXPathCompOpEval:
8412 * @ctxt: the XPath parser context with the compiled expression
8413 * @op: an XPath compiled operation
8414 *
8415 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008416 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008417 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008418static int
8419xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
8420{
8421 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008422 int equal, ret;
8423 xmlXPathCompExprPtr comp;
8424 xmlXPathObjectPtr arg1, arg2;
8425
8426 comp = ctxt->comp;
8427 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008428 case XPATH_OP_END:
8429 return (0);
8430 case XPATH_OP_AND:
8431 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8432 xmlXPathBooleanFunction(ctxt, 1);
8433 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
8434 return (total);
8435 arg2 = valuePop(ctxt);
8436 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8437 xmlXPathBooleanFunction(ctxt, 1);
8438 arg1 = valuePop(ctxt);
8439 arg1->boolval &= arg2->boolval;
8440 valuePush(ctxt, arg1);
8441 xmlXPathFreeObject(arg2);
8442 return (total);
8443 case XPATH_OP_OR:
8444 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8445 xmlXPathBooleanFunction(ctxt, 1);
8446 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
8447 return (total);
8448 arg2 = valuePop(ctxt);
8449 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8450 xmlXPathBooleanFunction(ctxt, 1);
8451 arg1 = valuePop(ctxt);
8452 arg1->boolval |= arg2->boolval;
8453 valuePush(ctxt, arg1);
8454 xmlXPathFreeObject(arg2);
8455 return (total);
8456 case XPATH_OP_EQUAL:
8457 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8458 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8459 equal = xmlXPathEqualValues(ctxt);
8460 if (op->value)
8461 valuePush(ctxt, xmlXPathNewBoolean(equal));
8462 else
8463 valuePush(ctxt, xmlXPathNewBoolean(!equal));
8464 return (total);
8465 case XPATH_OP_CMP:
8466 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8467 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8468 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
8469 valuePush(ctxt, xmlXPathNewBoolean(ret));
8470 return (total);
8471 case XPATH_OP_PLUS:
8472 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8473 if (op->ch2 != -1)
8474 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8475 if (op->value == 0)
8476 xmlXPathSubValues(ctxt);
8477 else if (op->value == 1)
8478 xmlXPathAddValues(ctxt);
8479 else if (op->value == 2)
8480 xmlXPathValueFlipSign(ctxt);
8481 else if (op->value == 3) {
8482 CAST_TO_NUMBER;
8483 CHECK_TYPE0(XPATH_NUMBER);
8484 }
8485 return (total);
8486 case XPATH_OP_MULT:
8487 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8488 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8489 if (op->value == 0)
8490 xmlXPathMultValues(ctxt);
8491 else if (op->value == 1)
8492 xmlXPathDivValues(ctxt);
8493 else if (op->value == 2)
8494 xmlXPathModValues(ctxt);
8495 return (total);
8496 case XPATH_OP_UNION:
8497 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8498 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8499 CHECK_TYPE0(XPATH_NODESET);
8500 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008501
Daniel Veillardf06307e2001-07-03 10:35:50 +00008502 CHECK_TYPE0(XPATH_NODESET);
8503 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008504
Daniel Veillardf06307e2001-07-03 10:35:50 +00008505 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8506 arg2->nodesetval);
8507 valuePush(ctxt, arg1);
8508 xmlXPathFreeObject(arg2);
8509 return (total);
8510 case XPATH_OP_ROOT:
8511 xmlXPathRoot(ctxt);
8512 return (total);
8513 case XPATH_OP_NODE:
8514 if (op->ch1 != -1)
8515 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8516 if (op->ch2 != -1)
8517 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8518 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8519 return (total);
8520 case XPATH_OP_RESET:
8521 if (op->ch1 != -1)
8522 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8523 if (op->ch2 != -1)
8524 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8525 ctxt->context->node = NULL;
8526 return (total);
8527 case XPATH_OP_COLLECT:{
8528 if (op->ch1 == -1)
8529 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008530
Daniel Veillardf06307e2001-07-03 10:35:50 +00008531 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008532
Daniel Veillardf06307e2001-07-03 10:35:50 +00008533 /*
8534 * Optimization for [n] selection where n is a number
8535 */
8536 if ((op->ch2 != -1) &&
8537 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8538 (comp->steps[op->ch2].ch1 == -1) &&
8539 (comp->steps[op->ch2].ch2 != -1) &&
8540 (comp->steps[comp->steps[op->ch2].ch2].op ==
8541 XPATH_OP_VALUE)) {
8542 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00008543
Daniel Veillardf06307e2001-07-03 10:35:50 +00008544 val = comp->steps[comp->steps[op->ch2].ch2].value4;
8545 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
8546 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008547
Daniel Veillardf06307e2001-07-03 10:35:50 +00008548 if (val->floatval == (float) indx) {
8549 total +=
8550 xmlXPathNodeCollectAndTestNth(ctxt, op,
8551 indx, NULL,
8552 NULL);
8553 return (total);
8554 }
8555 }
8556 }
8557 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
8558 return (total);
8559 }
8560 case XPATH_OP_VALUE:
8561 valuePush(ctxt,
8562 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
8563 return (total);
8564 case XPATH_OP_VARIABLE:{
8565 if (op->ch1 != -1)
8566 total +=
8567 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8568 if (op->value5 == NULL)
8569 valuePush(ctxt,
8570 xmlXPathVariableLookup(ctxt->context,
8571 op->value4));
8572 else {
8573 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008574
Daniel Veillardf06307e2001-07-03 10:35:50 +00008575 URI = xmlXPathNsLookup(ctxt->context, op->value5);
8576 if (URI == NULL) {
8577 xmlGenericError(xmlGenericErrorContext,
8578 "xmlXPathRunEval: variable %s bound to undefined prefix %s\n",
8579 op->value4, op->value5);
8580 return (total);
8581 }
8582 valuePush(ctxt,
8583 xmlXPathVariableLookupNS(ctxt->context,
8584 op->value4, URI));
8585 }
8586 return (total);
8587 }
8588 case XPATH_OP_FUNCTION:{
8589 xmlXPathFunction func;
8590 const xmlChar *oldFunc, *oldFuncURI;
8591
8592 if (op->ch1 != -1)
8593 total +=
8594 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8595 if (op->cache != NULL)
8596 func = (xmlXPathFunction) op->cache;
8597 else {
8598 const xmlChar *URI = NULL;
8599
8600 if (op->value5 == NULL)
8601 func =
8602 xmlXPathFunctionLookup(ctxt->context,
8603 op->value4);
8604 else {
8605 URI = xmlXPathNsLookup(ctxt->context, op->value5);
8606 if (URI == NULL) {
8607 xmlGenericError(xmlGenericErrorContext,
8608 "xmlXPathRunEval: function %s bound to undefined prefix %s\n",
8609 op->value4, op->value5);
8610 return (total);
8611 }
8612 func = xmlXPathFunctionLookupNS(ctxt->context,
8613 op->value4, URI);
8614 }
8615 if (func == NULL) {
8616 xmlGenericError(xmlGenericErrorContext,
8617 "xmlXPathRunEval: function %s not found\n",
8618 op->value4);
8619 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
8620 return (total);
8621 }
8622 op->cache = (void *) func;
8623 op->cacheURI = (void *) URI;
8624 }
8625 oldFunc = ctxt->context->function;
8626 oldFuncURI = ctxt->context->functionURI;
8627 ctxt->context->function = op->value4;
8628 ctxt->context->functionURI = op->cacheURI;
8629 func(ctxt, op->value);
8630 ctxt->context->function = oldFunc;
8631 ctxt->context->functionURI = oldFuncURI;
8632 return (total);
8633 }
8634 case XPATH_OP_ARG:
8635 if (op->ch1 != -1)
8636 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8637 if (op->ch2 != -1)
8638 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8639 return (total);
8640 case XPATH_OP_PREDICATE:
8641 case XPATH_OP_FILTER:{
8642 xmlXPathObjectPtr res;
8643 xmlXPathObjectPtr obj, tmp;
8644 xmlNodeSetPtr newset = NULL;
8645 xmlNodeSetPtr oldset;
8646 xmlNodePtr oldnode;
8647 int i;
8648
8649 /*
8650 * Optimization for ()[1] selection i.e. the first elem
8651 */
8652 if ((op->ch1 != -1) && (op->ch2 != -1) &&
8653 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
8654 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
8655 xmlXPathObjectPtr val;
8656
8657 val = comp->steps[op->ch2].value4;
8658 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
8659 (val->floatval == 1.0)) {
8660 xmlNodePtr first = NULL;
8661
8662 total +=
8663 xmlXPathCompOpEvalFirst(ctxt,
8664 &comp->steps[op->ch1],
8665 &first);
8666 /*
8667 * The nodeset should be in document order,
8668 * Keep only the first value
8669 */
8670 if ((ctxt->value != NULL) &&
8671 (ctxt->value->type == XPATH_NODESET) &&
8672 (ctxt->value->nodesetval != NULL) &&
8673 (ctxt->value->nodesetval->nodeNr > 1))
8674 ctxt->value->nodesetval->nodeNr = 1;
8675 return (total);
8676 }
8677 }
8678 /*
8679 * Optimization for ()[last()] selection i.e. the last elem
8680 */
8681 if ((op->ch1 != -1) && (op->ch2 != -1) &&
8682 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
8683 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
8684 int f = comp->steps[op->ch2].ch1;
8685
8686 if ((f != -1) &&
8687 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
8688 (comp->steps[f].value5 == NULL) &&
8689 (comp->steps[f].value == 0) &&
8690 (comp->steps[f].value4 != NULL) &&
8691 (xmlStrEqual
8692 (comp->steps[f].value4, BAD_CAST "last"))) {
8693 xmlNodePtr last = NULL;
8694
8695 total +=
8696 xmlXPathCompOpEvalLast(ctxt,
8697 &comp->steps[op->ch1],
8698 &last);
8699 /*
8700 * The nodeset should be in document order,
8701 * Keep only the last value
8702 */
8703 if ((ctxt->value != NULL) &&
8704 (ctxt->value->type == XPATH_NODESET) &&
8705 (ctxt->value->nodesetval != NULL) &&
8706 (ctxt->value->nodesetval->nodeTab != NULL) &&
8707 (ctxt->value->nodesetval->nodeNr > 1)) {
8708 ctxt->value->nodesetval->nodeTab[0] =
8709 ctxt->value->nodesetval->nodeTab[ctxt->
8710 value->
8711 nodesetval->
8712 nodeNr -
8713 1];
8714 ctxt->value->nodesetval->nodeNr = 1;
8715 }
8716 return (total);
8717 }
8718 }
8719
8720 if (op->ch1 != -1)
8721 total +=
8722 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8723 if (op->ch2 == -1)
8724 return (total);
8725 if (ctxt->value == NULL)
8726 return (total);
8727
8728 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008729
8730#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00008731 /*
8732 * Hum are we filtering the result of an XPointer expression
8733 */
8734 if (ctxt->value->type == XPATH_LOCATIONSET) {
8735 xmlLocationSetPtr newlocset = NULL;
8736 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008737
Daniel Veillardf06307e2001-07-03 10:35:50 +00008738 /*
8739 * Extract the old locset, and then evaluate the result of the
8740 * expression for all the element in the locset. use it to grow
8741 * up a new locset.
8742 */
8743 CHECK_TYPE0(XPATH_LOCATIONSET);
8744 obj = valuePop(ctxt);
8745 oldlocset = obj->user;
8746 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008747
Daniel Veillardf06307e2001-07-03 10:35:50 +00008748 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
8749 ctxt->context->contextSize = 0;
8750 ctxt->context->proximityPosition = 0;
8751 if (op->ch2 != -1)
8752 total +=
8753 xmlXPathCompOpEval(ctxt,
8754 &comp->steps[op->ch2]);
8755 res = valuePop(ctxt);
8756 if (res != NULL)
8757 xmlXPathFreeObject(res);
8758 valuePush(ctxt, obj);
8759 CHECK_ERROR0;
8760 return (total);
8761 }
8762 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008763
Daniel Veillardf06307e2001-07-03 10:35:50 +00008764 for (i = 0; i < oldlocset->locNr; i++) {
8765 /*
8766 * Run the evaluation with a node list made of a
8767 * single item in the nodelocset.
8768 */
8769 ctxt->context->node = oldlocset->locTab[i]->user;
8770 tmp = xmlXPathNewNodeSet(ctxt->context->node);
8771 valuePush(ctxt, tmp);
8772 ctxt->context->contextSize = oldlocset->locNr;
8773 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008774
Daniel Veillardf06307e2001-07-03 10:35:50 +00008775 if (op->ch2 != -1)
8776 total +=
8777 xmlXPathCompOpEval(ctxt,
8778 &comp->steps[op->ch2]);
8779 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008780
Daniel Veillardf06307e2001-07-03 10:35:50 +00008781 /*
8782 * The result of the evaluation need to be tested to
8783 * decided whether the filter succeeded or not
8784 */
8785 res = valuePop(ctxt);
8786 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
8787 xmlXPtrLocationSetAdd(newlocset,
8788 xmlXPathObjectCopy
8789 (oldlocset->locTab[i]));
8790 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008791
Daniel Veillardf06307e2001-07-03 10:35:50 +00008792 /*
8793 * Cleanup
8794 */
8795 if (res != NULL)
8796 xmlXPathFreeObject(res);
8797 if (ctxt->value == tmp) {
8798 res = valuePop(ctxt);
8799 xmlXPathFreeObject(res);
8800 }
8801
8802 ctxt->context->node = NULL;
8803 }
8804
8805 /*
8806 * The result is used as the new evaluation locset.
8807 */
8808 xmlXPathFreeObject(obj);
8809 ctxt->context->node = NULL;
8810 ctxt->context->contextSize = -1;
8811 ctxt->context->proximityPosition = -1;
8812 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
8813 ctxt->context->node = oldnode;
8814 return (total);
8815 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008816#endif /* LIBXML_XPTR_ENABLED */
8817
Daniel Veillardf06307e2001-07-03 10:35:50 +00008818 /*
8819 * Extract the old set, and then evaluate the result of the
8820 * expression for all the element in the set. use it to grow
8821 * up a new set.
8822 */
8823 CHECK_TYPE0(XPATH_NODESET);
8824 obj = valuePop(ctxt);
8825 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00008826
Daniel Veillardf06307e2001-07-03 10:35:50 +00008827 oldnode = ctxt->context->node;
8828 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008829
Daniel Veillardf06307e2001-07-03 10:35:50 +00008830 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
8831 ctxt->context->contextSize = 0;
8832 ctxt->context->proximityPosition = 0;
8833 if (op->ch2 != -1)
8834 total +=
8835 xmlXPathCompOpEval(ctxt,
8836 &comp->steps[op->ch2]);
8837 res = valuePop(ctxt);
8838 if (res != NULL)
8839 xmlXPathFreeObject(res);
8840 valuePush(ctxt, obj);
8841 ctxt->context->node = oldnode;
8842 CHECK_ERROR0;
8843 } else {
8844 /*
8845 * Initialize the new set.
8846 */
8847 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008848
Daniel Veillardf06307e2001-07-03 10:35:50 +00008849 for (i = 0; i < oldset->nodeNr; i++) {
8850 /*
8851 * Run the evaluation with a node list made of
8852 * a single item in the nodeset.
8853 */
8854 ctxt->context->node = oldset->nodeTab[i];
8855 tmp = xmlXPathNewNodeSet(ctxt->context->node);
8856 valuePush(ctxt, tmp);
8857 ctxt->context->contextSize = oldset->nodeNr;
8858 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008859
Daniel Veillardf06307e2001-07-03 10:35:50 +00008860 if (op->ch2 != -1)
8861 total +=
8862 xmlXPathCompOpEval(ctxt,
8863 &comp->steps[op->ch2]);
8864 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008865
Daniel Veillardf06307e2001-07-03 10:35:50 +00008866 /*
8867 * The result of the evaluation need to be tested to
8868 * decided whether the filter succeeded or not
8869 */
8870 res = valuePop(ctxt);
8871 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
8872 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
8873 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008874
Daniel Veillardf06307e2001-07-03 10:35:50 +00008875 /*
8876 * Cleanup
8877 */
8878 if (res != NULL)
8879 xmlXPathFreeObject(res);
8880 if (ctxt->value == tmp) {
8881 res = valuePop(ctxt);
8882 xmlXPathFreeObject(res);
8883 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008884
Daniel Veillardf06307e2001-07-03 10:35:50 +00008885 ctxt->context->node = NULL;
8886 }
8887
8888 /*
8889 * The result is used as the new evaluation set.
8890 */
8891 xmlXPathFreeObject(obj);
8892 ctxt->context->node = NULL;
8893 ctxt->context->contextSize = -1;
8894 ctxt->context->proximityPosition = -1;
8895 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
8896 }
8897 ctxt->context->node = oldnode;
8898 return (total);
8899 }
8900 case XPATH_OP_SORT:
8901 if (op->ch1 != -1)
8902 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8903 if ((ctxt->value != NULL) &&
8904 (ctxt->value->type == XPATH_NODESET) &&
8905 (ctxt->value->nodesetval != NULL))
8906 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8907 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008908#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00008909 case XPATH_OP_RANGETO:{
8910 xmlXPathObjectPtr range;
8911 xmlXPathObjectPtr res, obj;
8912 xmlXPathObjectPtr tmp;
8913 xmlLocationSetPtr newset = NULL;
8914 xmlNodeSetPtr oldset;
8915 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008916
Daniel Veillardf06307e2001-07-03 10:35:50 +00008917 if (op->ch1 != -1)
8918 total +=
8919 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8920 if (op->ch2 == -1)
8921 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008922
Daniel Veillardf06307e2001-07-03 10:35:50 +00008923 CHECK_TYPE0(XPATH_NODESET);
8924 obj = valuePop(ctxt);
8925 oldset = obj->nodesetval;
8926 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008927
Daniel Veillardf06307e2001-07-03 10:35:50 +00008928 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008929
Daniel Veillardf06307e2001-07-03 10:35:50 +00008930 if (oldset != NULL) {
8931 for (i = 0; i < oldset->nodeNr; i++) {
8932 /*
8933 * Run the evaluation with a node list made of a single item
8934 * in the nodeset.
8935 */
8936 ctxt->context->node = oldset->nodeTab[i];
8937 tmp = xmlXPathNewNodeSet(ctxt->context->node);
8938 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008939
Daniel Veillardf06307e2001-07-03 10:35:50 +00008940 if (op->ch2 != -1)
8941 total +=
8942 xmlXPathCompOpEval(ctxt,
8943 &comp->steps[op->ch2]);
8944 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008945
Daniel Veillardf06307e2001-07-03 10:35:50 +00008946 /*
8947 * The result of the evaluation need to be tested to
8948 * decided whether the filter succeeded or not
8949 */
8950 res = valuePop(ctxt);
8951 range =
8952 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
8953 res);
8954 if (range != NULL) {
8955 xmlXPtrLocationSetAdd(newset, range);
8956 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008957
Daniel Veillardf06307e2001-07-03 10:35:50 +00008958 /*
8959 * Cleanup
8960 */
8961 if (res != NULL)
8962 xmlXPathFreeObject(res);
8963 if (ctxt->value == tmp) {
8964 res = valuePop(ctxt);
8965 xmlXPathFreeObject(res);
8966 }
8967
8968 ctxt->context->node = NULL;
8969 }
8970 }
8971
8972 /*
8973 * The result is used as the new evaluation set.
8974 */
8975 xmlXPathFreeObject(obj);
8976 ctxt->context->node = NULL;
8977 ctxt->context->contextSize = -1;
8978 ctxt->context->proximityPosition = -1;
8979 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
8980 return (total);
8981 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008982#endif /* LIBXML_XPTR_ENABLED */
8983 }
8984 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008985 "XPath: unknown precompiled operation %d\n", op->op);
8986 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008987}
8988
8989/**
8990 * xmlXPathRunEval:
8991 * @ctxt: the XPath parser context with the compiled expression
8992 *
8993 * Evaluate the Precompiled XPath expression in the given context.
8994 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008995static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008996xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
8997 xmlXPathCompExprPtr comp;
8998
8999 if ((ctxt == NULL) || (ctxt->comp == NULL))
9000 return;
9001
9002 if (ctxt->valueTab == NULL) {
9003 /* Allocate the value stack */
9004 ctxt->valueTab = (xmlXPathObjectPtr *)
9005 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
9006 if (ctxt->valueTab == NULL) {
9007 xmlFree(ctxt);
9008 xmlGenericError(xmlGenericErrorContext,
9009 "xmlXPathRunEval: out of memory\n");
9010 return;
9011 }
9012 ctxt->valueNr = 0;
9013 ctxt->valueMax = 10;
9014 ctxt->value = NULL;
9015 }
9016 comp = ctxt->comp;
9017 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
9018}
9019
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009020/************************************************************************
9021 * *
9022 * Public interfaces *
9023 * *
9024 ************************************************************************/
9025
9026/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009027 * xmlXPathEvalPredicate:
9028 * @ctxt: the XPath context
9029 * @res: the Predicate Expression evaluation result
9030 *
9031 * Evaluate a predicate result for the current node.
9032 * A PredicateExpr is evaluated by evaluating the Expr and converting
9033 * the result to a boolean. If the result is a number, the result will
9034 * be converted to true if the number is equal to the position of the
9035 * context node in the context node list (as returned by the position
9036 * function) and will be converted to false otherwise; if the result
9037 * is not a number, then the result will be converted as if by a call
9038 * to the boolean function.
9039 *
9040 * Return 1 if predicate is true, 0 otherwise
9041 */
9042int
9043xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
9044 if (res == NULL) return(0);
9045 switch (res->type) {
9046 case XPATH_BOOLEAN:
9047 return(res->boolval);
9048 case XPATH_NUMBER:
9049 return(res->floatval == ctxt->proximityPosition);
9050 case XPATH_NODESET:
9051 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009052 if (res->nodesetval == NULL)
9053 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009054 return(res->nodesetval->nodeNr != 0);
9055 case XPATH_STRING:
9056 return((res->stringval != NULL) &&
9057 (xmlStrlen(res->stringval) != 0));
9058 default:
9059 STRANGE
9060 }
9061 return(0);
9062}
9063
9064/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009065 * xmlXPathEvaluatePredicateResult:
9066 * @ctxt: the XPath Parser context
9067 * @res: the Predicate Expression evaluation result
9068 *
9069 * Evaluate a predicate result for the current node.
9070 * A PredicateExpr is evaluated by evaluating the Expr and converting
9071 * the result to a boolean. If the result is a number, the result will
9072 * be converted to true if the number is equal to the position of the
9073 * context node in the context node list (as returned by the position
9074 * function) and will be converted to false otherwise; if the result
9075 * is not a number, then the result will be converted as if by a call
9076 * to the boolean function.
9077 *
9078 * Return 1 if predicate is true, 0 otherwise
9079 */
9080int
9081xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
9082 xmlXPathObjectPtr res) {
9083 if (res == NULL) return(0);
9084 switch (res->type) {
9085 case XPATH_BOOLEAN:
9086 return(res->boolval);
9087 case XPATH_NUMBER:
9088 return(res->floatval == ctxt->context->proximityPosition);
9089 case XPATH_NODESET:
9090 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +00009091 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +00009092 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009093 return(res->nodesetval->nodeNr != 0);
9094 case XPATH_STRING:
9095 return((res->stringval != NULL) &&
9096 (xmlStrlen(res->stringval) != 0));
9097 default:
9098 STRANGE
9099 }
9100 return(0);
9101}
9102
9103/**
9104 * xmlXPathCompile:
9105 * @str: the XPath expression
9106 *
9107 * Compile an XPath expression
9108 *
9109 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9110 * the caller has to free the object.
9111 */
9112xmlXPathCompExprPtr
9113xmlXPathCompile(const xmlChar *str) {
9114 xmlXPathParserContextPtr ctxt;
9115 xmlXPathCompExprPtr comp;
9116
9117 xmlXPathInit();
9118
9119 ctxt = xmlXPathNewParserContext(str, NULL);
9120 xmlXPathCompileExpr(ctxt);
9121
Daniel Veillard40af6492001-04-22 08:50:55 +00009122 if (*ctxt->cur != 0) {
9123 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9124 comp = NULL;
9125 } else {
9126 comp = ctxt->comp;
9127 ctxt->comp = NULL;
9128 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009129 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009130#ifdef DEBUG_EVAL_COUNTS
9131 if (comp != NULL) {
9132 comp->string = xmlStrdup(str);
9133 comp->nb = 0;
9134 }
9135#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009136 return(comp);
9137}
9138
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009139/**
9140 * xmlXPathCompiledEval:
9141 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +00009142 * @ctx: the XPath context
9143 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009144 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +00009145 *
9146 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9147 * the caller has to free the object.
9148 */
9149xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009150xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +00009151 xmlXPathParserContextPtr ctxt;
9152 xmlXPathObjectPtr res, tmp, init = NULL;
9153 int stack = 0;
9154
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009155 if ((comp == NULL) || (ctx == NULL))
9156 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00009157 xmlXPathInit();
9158
9159 CHECK_CONTEXT(ctx)
9160
Daniel Veillardf06307e2001-07-03 10:35:50 +00009161#ifdef DEBUG_EVAL_COUNTS
9162 comp->nb++;
9163 if ((comp->string != NULL) && (comp->nb > 100)) {
9164 fprintf(stderr, "100 x %s\n", comp->string);
9165 comp->nb = 0;
9166 }
9167#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009168 ctxt = xmlXPathCompParserContext(comp, ctx);
9169 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009170
9171 if (ctxt->value == NULL) {
9172 xmlGenericError(xmlGenericErrorContext,
9173 "xmlXPathEval: evaluation failed\n");
9174 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009175 } else {
9176 res = valuePop(ctxt);
9177 }
9178
Daniel Veillardf06307e2001-07-03 10:35:50 +00009179
Owen Taylor3473f882001-02-23 17:55:21 +00009180 do {
9181 tmp = valuePop(ctxt);
9182 if (tmp != NULL) {
9183 if (tmp != init)
9184 stack++;
9185 xmlXPathFreeObject(tmp);
9186 }
9187 } while (tmp != NULL);
9188 if ((stack != 0) && (res != NULL)) {
9189 xmlGenericError(xmlGenericErrorContext,
9190 "xmlXPathEval: %d object left on the stack\n",
9191 stack);
9192 }
9193 if (ctxt->error != XPATH_EXPRESSION_OK) {
9194 xmlXPathFreeObject(res);
9195 res = NULL;
9196 }
9197
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009198
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009199 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009200 xmlXPathFreeParserContext(ctxt);
9201 return(res);
9202}
9203
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009204/**
9205 * xmlXPathEvalExpr:
9206 * @ctxt: the XPath Parser context
9207 *
9208 * Parse and evaluate an XPath expression in the given context,
9209 * then push the result on the context stack
9210 */
9211void
9212xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
9213 xmlXPathCompileExpr(ctxt);
9214 xmlXPathRunEval(ctxt);
9215}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009216
9217/**
9218 * xmlXPathEval:
9219 * @str: the XPath expression
9220 * @ctx: the XPath context
9221 *
9222 * Evaluate the XPath Location Path in the given context.
9223 *
9224 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9225 * the caller has to free the object.
9226 */
9227xmlXPathObjectPtr
9228xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
9229 xmlXPathParserContextPtr ctxt;
9230 xmlXPathObjectPtr res, tmp, init = NULL;
9231 int stack = 0;
9232
9233 xmlXPathInit();
9234
9235 CHECK_CONTEXT(ctx)
9236
9237 ctxt = xmlXPathNewParserContext(str, ctx);
9238 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009239
9240 if (ctxt->value == NULL) {
9241 xmlGenericError(xmlGenericErrorContext,
9242 "xmlXPathEval: evaluation failed\n");
9243 res = NULL;
9244 } else if (*ctxt->cur != 0) {
9245 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9246 res = NULL;
9247 } else {
9248 res = valuePop(ctxt);
9249 }
9250
9251 do {
9252 tmp = valuePop(ctxt);
9253 if (tmp != NULL) {
9254 if (tmp != init)
9255 stack++;
9256 xmlXPathFreeObject(tmp);
9257 }
9258 } while (tmp != NULL);
9259 if ((stack != 0) && (res != NULL)) {
9260 xmlGenericError(xmlGenericErrorContext,
9261 "xmlXPathEval: %d object left on the stack\n",
9262 stack);
9263 }
9264 if (ctxt->error != XPATH_EXPRESSION_OK) {
9265 xmlXPathFreeObject(res);
9266 res = NULL;
9267 }
9268
Owen Taylor3473f882001-02-23 17:55:21 +00009269 xmlXPathFreeParserContext(ctxt);
9270 return(res);
9271}
9272
9273/**
9274 * xmlXPathEvalExpression:
9275 * @str: the XPath expression
9276 * @ctxt: the XPath context
9277 *
9278 * Evaluate the XPath expression in the given context.
9279 *
9280 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
9281 * the caller has to free the object.
9282 */
9283xmlXPathObjectPtr
9284xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
9285 xmlXPathParserContextPtr pctxt;
9286 xmlXPathObjectPtr res, tmp;
9287 int stack = 0;
9288
9289 xmlXPathInit();
9290
9291 CHECK_CONTEXT(ctxt)
9292
9293 pctxt = xmlXPathNewParserContext(str, ctxt);
9294 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009295
9296 if (*pctxt->cur != 0) {
9297 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9298 res = NULL;
9299 } else {
9300 res = valuePop(pctxt);
9301 }
9302 do {
9303 tmp = valuePop(pctxt);
9304 if (tmp != NULL) {
9305 xmlXPathFreeObject(tmp);
9306 stack++;
9307 }
9308 } while (tmp != NULL);
9309 if ((stack != 0) && (res != NULL)) {
9310 xmlGenericError(xmlGenericErrorContext,
9311 "xmlXPathEvalExpression: %d object left on the stack\n",
9312 stack);
9313 }
9314 xmlXPathFreeParserContext(pctxt);
9315 return(res);
9316}
9317
9318/**
9319 * xmlXPathRegisterAllFunctions:
9320 * @ctxt: the XPath context
9321 *
9322 * Registers all default XPath functions in this context
9323 */
9324void
9325xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
9326{
9327 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
9328 xmlXPathBooleanFunction);
9329 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
9330 xmlXPathCeilingFunction);
9331 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
9332 xmlXPathCountFunction);
9333 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
9334 xmlXPathConcatFunction);
9335 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
9336 xmlXPathContainsFunction);
9337 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
9338 xmlXPathIdFunction);
9339 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
9340 xmlXPathFalseFunction);
9341 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
9342 xmlXPathFloorFunction);
9343 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
9344 xmlXPathLastFunction);
9345 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
9346 xmlXPathLangFunction);
9347 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
9348 xmlXPathLocalNameFunction);
9349 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
9350 xmlXPathNotFunction);
9351 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
9352 xmlXPathNameFunction);
9353 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
9354 xmlXPathNamespaceURIFunction);
9355 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
9356 xmlXPathNormalizeFunction);
9357 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
9358 xmlXPathNumberFunction);
9359 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
9360 xmlXPathPositionFunction);
9361 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
9362 xmlXPathRoundFunction);
9363 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
9364 xmlXPathStringFunction);
9365 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
9366 xmlXPathStringLengthFunction);
9367 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
9368 xmlXPathStartsWithFunction);
9369 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
9370 xmlXPathSubstringFunction);
9371 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
9372 xmlXPathSubstringBeforeFunction);
9373 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
9374 xmlXPathSubstringAfterFunction);
9375 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
9376 xmlXPathSumFunction);
9377 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
9378 xmlXPathTrueFunction);
9379 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
9380 xmlXPathTranslateFunction);
9381}
9382
9383#endif /* LIBXML_XPATH_ENABLED */