blob: 7f6dd6f903f97c6d0fa090d2b9490e16bd596737 [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 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011 * See Copyright for the status of this software
Owen Taylor3473f882001-02-23 17:55:21 +000012 *
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
Daniel Veillard34ce8be2002-03-18 19:37:11 +000019#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000020#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000021#ifdef LIBXML_XPATH_ENABLED
22
Owen Taylor3473f882001-02-23 17:55:21 +000023#include <string.h>
24
25#ifdef HAVE_SYS_TYPES_H
26#include <sys/types.h>
27#endif
28#ifdef HAVE_MATH_H
29#include <math.h>
30#endif
31#ifdef HAVE_FLOAT_H
32#include <float.h>
33#endif
Owen Taylor3473f882001-02-23 17:55:21 +000034#ifdef HAVE_CTYPE_H
35#include <ctype.h>
36#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000037#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000038#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000039#endif
Owen Taylor3473f882001-02-23 17:55:21 +000040
41#include <libxml/xmlmemory.h>
42#include <libxml/tree.h>
43#include <libxml/valid.h>
44#include <libxml/xpath.h>
45#include <libxml/xpathInternals.h>
46#include <libxml/parserInternals.h>
47#include <libxml/hash.h>
48#ifdef LIBXML_XPTR_ENABLED
49#include <libxml/xpointer.h>
50#endif
51#ifdef LIBXML_DEBUG_ENABLED
52#include <libxml/debugXML.h>
53#endif
54#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000055#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000056#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000057
58/* #define DEBUG */
59/* #define DEBUG_STEP */
Daniel Veillardf06307e2001-07-03 10:35:50 +000060/* #define DEBUG_STEP_NTH */
Owen Taylor3473f882001-02-23 17:55:21 +000061/* #define DEBUG_EXPR */
Daniel Veillardf06307e2001-07-03 10:35:50 +000062/* #define DEBUG_EVAL_COUNTS */
Owen Taylor3473f882001-02-23 17:55:21 +000063
Daniel Veillard5792e162001-04-30 17:44:45 +000064double xmlXPathDivideBy(double f, double fzero);
Owen Taylor3473f882001-02-23 17:55:21 +000065
Daniel Veillard20ee8c02001-10-05 09:18:14 +000066static xmlNs xmlXPathXMLNamespaceStruct = {
67 NULL,
68 XML_NAMESPACE_DECL,
69 XML_XML_NAMESPACE,
70 BAD_CAST "xml"
71};
72static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
Daniel Veillard81463942001-10-16 12:34:39 +000073#ifndef LIBXML_THREADS_ENABLED
74/*
75 * Optimizer is disabled only when threaded apps are detected while
76 * the library ain't compiled for thread safety.
77 */
78static int xmlXPathDisableOptimizer = 0;
79#endif
Daniel Veillard20ee8c02001-10-05 09:18:14 +000080
Daniel Veillard9e7160d2001-03-18 23:17:47 +000081/************************************************************************
82 * *
83 * Floating point stuff *
84 * *
85 ************************************************************************/
86
Daniel Veillardc0631a62001-09-20 13:56:06 +000087#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +000088#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +000089#endif
Daniel Veillardcda96922001-08-21 10:56:31 +000090#include "trionan.c"
91
Owen Taylor3473f882001-02-23 17:55:21 +000092/*
Owen Taylor3473f882001-02-23 17:55:21 +000093 * The lack of portability of this section of the libc is annoying !
94 */
95double xmlXPathNAN = 0;
96double xmlXPathPINF = 1;
97double xmlXPathNINF = -1;
Daniel Veillard20ee8c02001-10-05 09:18:14 +000098static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000099
Owen Taylor3473f882001-02-23 17:55:21 +0000100/**
101 * xmlXPathInit:
102 *
103 * Initialize the XPath environment
104 */
105void
106xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000107 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +0000108
Bjorn Reese45029602001-08-21 09:23:53 +0000109 xmlXPathPINF = trio_pinf();
110 xmlXPathNINF = trio_ninf();
111 xmlXPathNAN = trio_nan();
Owen Taylor3473f882001-02-23 17:55:21 +0000112
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000113 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000114}
115
Daniel Veillardcda96922001-08-21 10:56:31 +0000116/**
117 * xmlXPathIsNaN:
118 * @val: a double value
119 *
120 * Provides a portable isnan() function to detect whether a double
121 * is a NotaNumber. Based on trio code
122 * http://sourceforge.net/projects/ctrio/
123 *
124 * Returns 1 if the value is a NaN, 0 otherwise
125 */
126int
127xmlXPathIsNaN(double val) {
128 return(trio_isnan(val));
129}
130
131/**
132 * xmlXPathIsInf:
133 * @val: a double value
134 *
135 * Provides a portable isinf() function to detect whether a double
136 * is a +Infinite or -Infinite. Based on trio code
137 * http://sourceforge.net/projects/ctrio/
138 *
139 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
140 */
141int
142xmlXPathIsInf(double val) {
143 return(trio_isinf(val));
144}
145
Owen Taylor3473f882001-02-23 17:55:21 +0000146/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000147 * *
148 * Parser Types *
149 * *
150 ************************************************************************/
151
152/*
153 * Types are private:
154 */
155
156typedef enum {
157 XPATH_OP_END=0,
158 XPATH_OP_AND,
159 XPATH_OP_OR,
160 XPATH_OP_EQUAL,
161 XPATH_OP_CMP,
162 XPATH_OP_PLUS,
163 XPATH_OP_MULT,
164 XPATH_OP_UNION,
165 XPATH_OP_ROOT,
166 XPATH_OP_NODE,
167 XPATH_OP_RESET,
168 XPATH_OP_COLLECT,
169 XPATH_OP_VALUE,
170 XPATH_OP_VARIABLE,
171 XPATH_OP_FUNCTION,
172 XPATH_OP_ARG,
173 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000174 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000175 XPATH_OP_SORT
176#ifdef LIBXML_XPTR_ENABLED
177 ,XPATH_OP_RANGETO
178#endif
179} xmlXPathOp;
180
181typedef enum {
182 AXIS_ANCESTOR = 1,
183 AXIS_ANCESTOR_OR_SELF,
184 AXIS_ATTRIBUTE,
185 AXIS_CHILD,
186 AXIS_DESCENDANT,
187 AXIS_DESCENDANT_OR_SELF,
188 AXIS_FOLLOWING,
189 AXIS_FOLLOWING_SIBLING,
190 AXIS_NAMESPACE,
191 AXIS_PARENT,
192 AXIS_PRECEDING,
193 AXIS_PRECEDING_SIBLING,
194 AXIS_SELF
195} xmlXPathAxisVal;
196
197typedef enum {
198 NODE_TEST_NONE = 0,
199 NODE_TEST_TYPE = 1,
200 NODE_TEST_PI = 2,
201 NODE_TEST_ALL = 3,
202 NODE_TEST_NS = 4,
203 NODE_TEST_NAME = 5
204} xmlXPathTestVal;
205
206typedef enum {
207 NODE_TYPE_NODE = 0,
208 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
209 NODE_TYPE_TEXT = XML_TEXT_NODE,
210 NODE_TYPE_PI = XML_PI_NODE
211} xmlXPathTypeVal;
212
213
214typedef struct _xmlXPathStepOp xmlXPathStepOp;
215typedef xmlXPathStepOp *xmlXPathStepOpPtr;
216struct _xmlXPathStepOp {
217 xmlXPathOp op;
218 int ch1;
219 int ch2;
220 int value;
221 int value2;
222 int value3;
223 void *value4;
224 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000225 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000226 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000227};
228
229struct _xmlXPathCompExpr {
230 int nbStep;
231 int maxStep;
232 xmlXPathStepOp *steps; /* ops for computation */
233 int last;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000234#ifdef DEBUG_EVAL_COUNTS
235 int nb;
236 xmlChar *string;
237#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000238};
239
240/************************************************************************
241 * *
242 * Parser Type functions *
243 * *
244 ************************************************************************/
245
246/**
247 * xmlXPathNewCompExpr:
248 *
249 * Create a new Xpath component
250 *
251 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
252 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000253static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000254xmlXPathNewCompExpr(void) {
255 xmlXPathCompExprPtr cur;
256
257 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
258 if (cur == NULL) {
259 xmlGenericError(xmlGenericErrorContext,
260 "xmlXPathNewCompExpr : malloc failed\n");
261 return(NULL);
262 }
263 memset(cur, 0, sizeof(xmlXPathCompExpr));
264 cur->maxStep = 10;
265 cur->nbStep = 0;
266 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
267 sizeof(xmlXPathStepOp));
268 if (cur->steps == NULL) {
269 xmlGenericError(xmlGenericErrorContext,
270 "xmlXPathNewCompExpr : malloc failed\n");
271 xmlFree(cur);
272 return(NULL);
273 }
274 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
275 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000276#ifdef DEBUG_EVAL_COUNTS
277 cur->nb = 0;
278#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000279 return(cur);
280}
281
282/**
283 * xmlXPathFreeCompExpr:
284 * @comp: an XPATH comp
285 *
286 * Free up the memory allocated by @comp
287 */
288void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000289xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
290{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000291 xmlXPathStepOpPtr op;
292 int i;
293
294 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000295 return;
296 for (i = 0; i < comp->nbStep; i++) {
297 op = &comp->steps[i];
298 if (op->value4 != NULL) {
299 if (op->op == XPATH_OP_VALUE)
300 xmlXPathFreeObject(op->value4);
301 else
302 xmlFree(op->value4);
303 }
304 if (op->value5 != NULL)
305 xmlFree(op->value5);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000306 }
307 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000308 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000309 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000310#ifdef DEBUG_EVAL_COUNTS
311 if (comp->string != NULL) {
312 xmlFree(comp->string);
313 }
314#endif
315
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000316 xmlFree(comp);
317}
318
319/**
320 * xmlXPathCompExprAdd:
321 * @comp: the compiled expression
322 * @ch1: first child index
323 * @ch2: second child index
324 * @op: an op
325 * @value: the first int value
326 * @value2: the second int value
327 * @value3: the third int value
328 * @value4: the first string value
329 * @value5: the second string value
330 *
331 * Add an step to an XPath Compiled Expression
332 *
333 * Returns -1 in case of failure, the index otherwise
334 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000335static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000336xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
337 xmlXPathOp op, int value,
338 int value2, int value3, void *value4, void *value5) {
339 if (comp->nbStep >= comp->maxStep) {
340 xmlXPathStepOp *real;
341
342 comp->maxStep *= 2;
343 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
344 comp->maxStep * sizeof(xmlXPathStepOp));
345 if (real == NULL) {
346 comp->maxStep /= 2;
347 xmlGenericError(xmlGenericErrorContext,
348 "xmlXPathCompExprAdd : realloc failed\n");
349 return(-1);
350 }
351 comp->steps = real;
352 }
353 comp->last = comp->nbStep;
354 comp->steps[comp->nbStep].ch1 = ch1;
355 comp->steps[comp->nbStep].ch2 = ch2;
356 comp->steps[comp->nbStep].op = op;
357 comp->steps[comp->nbStep].value = value;
358 comp->steps[comp->nbStep].value2 = value2;
359 comp->steps[comp->nbStep].value3 = value3;
360 comp->steps[comp->nbStep].value4 = value4;
361 comp->steps[comp->nbStep].value5 = value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000362 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000363 return(comp->nbStep++);
364}
365
Daniel Veillardf06307e2001-07-03 10:35:50 +0000366/**
367 * xmlXPathCompSwap:
368 * @comp: the compiled expression
369 * @op: operation index
370 *
371 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000372 */
373static void
374xmlXPathCompSwap(xmlXPathStepOpPtr op) {
375 int tmp;
376
Daniel Veillard81463942001-10-16 12:34:39 +0000377#ifdef LIBXML_THREADS_ENABLED
378 /*
379 * Since this manipulates possibly shared variables, this is
380 * disable if one detects that the library is used in a multithreaded
381 * application
382 */
383 if (xmlXPathDisableOptimizer)
384 return;
385#endif
386
Daniel Veillardf06307e2001-07-03 10:35:50 +0000387 tmp = op->ch1;
388 op->ch1 = op->ch2;
389 op->ch2 = tmp;
390}
391
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000392#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
393 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
394 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000395#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
396 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
397 (op), (val), (val2), (val3), (val4), (val5))
398
399#define PUSH_LEAVE_EXPR(op, val, val2) \
400xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
401
402#define PUSH_UNARY_EXPR(op, ch, val, val2) \
403xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
404
405#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
406xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
407
408/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000409 * *
410 * Debugging related functions *
411 * *
412 ************************************************************************/
413
414#define TODO \
415 xmlGenericError(xmlGenericErrorContext, \
416 "Unimplemented block at %s:%d\n", \
417 __FILE__, __LINE__);
418
419#define STRANGE \
420 xmlGenericError(xmlGenericErrorContext, \
421 "Internal error at %s:%d\n", \
422 __FILE__, __LINE__);
423
424#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000425static void
426xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000427 int i;
428 char shift[100];
429
430 for (i = 0;((i < depth) && (i < 25));i++)
431 shift[2 * i] = shift[2 * i + 1] = ' ';
432 shift[2 * i] = shift[2 * i + 1] = 0;
433 if (cur == NULL) {
434 fprintf(output, shift);
435 fprintf(output, "Node is NULL !\n");
436 return;
437
438 }
439
440 if ((cur->type == XML_DOCUMENT_NODE) ||
441 (cur->type == XML_HTML_DOCUMENT_NODE)) {
442 fprintf(output, shift);
443 fprintf(output, " /\n");
444 } else if (cur->type == XML_ATTRIBUTE_NODE)
445 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
446 else
447 xmlDebugDumpOneNode(output, cur, depth);
448}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000449static void
450xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000451 xmlNodePtr tmp;
452 int i;
453 char shift[100];
454
455 for (i = 0;((i < depth) && (i < 25));i++)
456 shift[2 * i] = shift[2 * i + 1] = ' ';
457 shift[2 * i] = shift[2 * i + 1] = 0;
458 if (cur == NULL) {
459 fprintf(output, shift);
460 fprintf(output, "Node is NULL !\n");
461 return;
462
463 }
464
465 while (cur != NULL) {
466 tmp = cur;
467 cur = cur->next;
468 xmlDebugDumpOneNode(output, tmp, depth);
469 }
470}
Owen Taylor3473f882001-02-23 17:55:21 +0000471
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000472static void
473xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000474 int i;
475 char shift[100];
476
477 for (i = 0;((i < depth) && (i < 25));i++)
478 shift[2 * i] = shift[2 * i + 1] = ' ';
479 shift[2 * i] = shift[2 * i + 1] = 0;
480
481 if (cur == NULL) {
482 fprintf(output, shift);
483 fprintf(output, "NodeSet is NULL !\n");
484 return;
485
486 }
487
Daniel Veillard911f49a2001-04-07 15:39:35 +0000488 if (cur != NULL) {
489 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
490 for (i = 0;i < cur->nodeNr;i++) {
491 fprintf(output, shift);
492 fprintf(output, "%d", i + 1);
493 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
494 }
Owen Taylor3473f882001-02-23 17:55:21 +0000495 }
496}
497
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000498static void
499xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000500 int i;
501 char shift[100];
502
503 for (i = 0;((i < depth) && (i < 25));i++)
504 shift[2 * i] = shift[2 * i + 1] = ' ';
505 shift[2 * i] = shift[2 * i + 1] = 0;
506
507 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
508 fprintf(output, shift);
509 fprintf(output, "Value Tree is NULL !\n");
510 return;
511
512 }
513
514 fprintf(output, shift);
515 fprintf(output, "%d", i + 1);
516 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
517}
Owen Taylor3473f882001-02-23 17:55:21 +0000518#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000519static void
520xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000521 int i;
522 char shift[100];
523
524 for (i = 0;((i < depth) && (i < 25));i++)
525 shift[2 * i] = shift[2 * i + 1] = ' ';
526 shift[2 * i] = shift[2 * i + 1] = 0;
527
528 if (cur == NULL) {
529 fprintf(output, shift);
530 fprintf(output, "LocationSet is NULL !\n");
531 return;
532
533 }
534
535 for (i = 0;i < cur->locNr;i++) {
536 fprintf(output, shift);
537 fprintf(output, "%d : ", i + 1);
538 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
539 }
540}
Daniel Veillard017b1082001-06-21 11:20:21 +0000541#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000542
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000543/**
544 * xmlXPathDebugDumpObject:
545 * @output: the FILE * to dump the output
546 * @cur: the object to inspect
547 * @depth: indentation level
548 *
549 * Dump the content of the object for debugging purposes
550 */
551void
552xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000553 int i;
554 char shift[100];
555
556 for (i = 0;((i < depth) && (i < 25));i++)
557 shift[2 * i] = shift[2 * i + 1] = ' ';
558 shift[2 * i] = shift[2 * i + 1] = 0;
559
560 fprintf(output, shift);
561
562 if (cur == NULL) {
563 fprintf(output, "Object is empty (NULL)\n");
564 return;
565 }
566 switch(cur->type) {
567 case XPATH_UNDEFINED:
568 fprintf(output, "Object is uninitialized\n");
569 break;
570 case XPATH_NODESET:
571 fprintf(output, "Object is a Node Set :\n");
572 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
573 break;
574 case XPATH_XSLT_TREE:
575 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000576 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000577 break;
578 case XPATH_BOOLEAN:
579 fprintf(output, "Object is a Boolean : ");
580 if (cur->boolval) fprintf(output, "true\n");
581 else fprintf(output, "false\n");
582 break;
583 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000584 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000585 case 1:
586 fprintf(output, "Object is a number : +Infinity\n");
587 break;
588 case -1:
589 fprintf(output, "Object is a number : -Infinity\n");
590 break;
591 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000592 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000593 fprintf(output, "Object is a number : NaN\n");
594 } else {
595 fprintf(output, "Object is a number : %0g\n", cur->floatval);
596 }
597 }
Owen Taylor3473f882001-02-23 17:55:21 +0000598 break;
599 case XPATH_STRING:
600 fprintf(output, "Object is a string : ");
601 xmlDebugDumpString(output, cur->stringval);
602 fprintf(output, "\n");
603 break;
604 case XPATH_POINT:
605 fprintf(output, "Object is a point : index %d in node", cur->index);
606 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
607 fprintf(output, "\n");
608 break;
609 case XPATH_RANGE:
610 if ((cur->user2 == NULL) ||
611 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
612 fprintf(output, "Object is a collapsed range :\n");
613 fprintf(output, shift);
614 if (cur->index >= 0)
615 fprintf(output, "index %d in ", cur->index);
616 fprintf(output, "node\n");
617 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
618 depth + 1);
619 } else {
620 fprintf(output, "Object is a range :\n");
621 fprintf(output, shift);
622 fprintf(output, "From ");
623 if (cur->index >= 0)
624 fprintf(output, "index %d in ", cur->index);
625 fprintf(output, "node\n");
626 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
627 depth + 1);
628 fprintf(output, shift);
629 fprintf(output, "To ");
630 if (cur->index2 >= 0)
631 fprintf(output, "index %d in ", cur->index2);
632 fprintf(output, "node\n");
633 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
634 depth + 1);
635 fprintf(output, "\n");
636 }
637 break;
638 case XPATH_LOCATIONSET:
639#if defined(LIBXML_XPTR_ENABLED)
640 fprintf(output, "Object is a Location Set:\n");
641 xmlXPathDebugDumpLocationSet(output,
642 (xmlLocationSetPtr) cur->user, depth);
643#endif
644 break;
645 case XPATH_USERS:
646 fprintf(output, "Object is user defined\n");
647 break;
648 }
649}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000650
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000651static void
652xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000653 xmlXPathStepOpPtr op, int depth) {
654 int i;
655 char shift[100];
656
657 for (i = 0;((i < depth) && (i < 25));i++)
658 shift[2 * i] = shift[2 * i + 1] = ' ';
659 shift[2 * i] = shift[2 * i + 1] = 0;
660
661 fprintf(output, shift);
662 if (op == NULL) {
663 fprintf(output, "Step is NULL\n");
664 return;
665 }
666 switch (op->op) {
667 case XPATH_OP_END:
668 fprintf(output, "END"); break;
669 case XPATH_OP_AND:
670 fprintf(output, "AND"); break;
671 case XPATH_OP_OR:
672 fprintf(output, "OR"); break;
673 case XPATH_OP_EQUAL:
674 if (op->value)
675 fprintf(output, "EQUAL =");
676 else
677 fprintf(output, "EQUAL !=");
678 break;
679 case XPATH_OP_CMP:
680 if (op->value)
681 fprintf(output, "CMP <");
682 else
683 fprintf(output, "CMP >");
684 if (!op->value2)
685 fprintf(output, "=");
686 break;
687 case XPATH_OP_PLUS:
688 if (op->value == 0)
689 fprintf(output, "PLUS -");
690 else if (op->value == 1)
691 fprintf(output, "PLUS +");
692 else if (op->value == 2)
693 fprintf(output, "PLUS unary -");
694 else if (op->value == 3)
695 fprintf(output, "PLUS unary - -");
696 break;
697 case XPATH_OP_MULT:
698 if (op->value == 0)
699 fprintf(output, "MULT *");
700 else if (op->value == 1)
701 fprintf(output, "MULT div");
702 else
703 fprintf(output, "MULT mod");
704 break;
705 case XPATH_OP_UNION:
706 fprintf(output, "UNION"); break;
707 case XPATH_OP_ROOT:
708 fprintf(output, "ROOT"); break;
709 case XPATH_OP_NODE:
710 fprintf(output, "NODE"); break;
711 case XPATH_OP_RESET:
712 fprintf(output, "RESET"); break;
713 case XPATH_OP_SORT:
714 fprintf(output, "SORT"); break;
715 case XPATH_OP_COLLECT: {
716 xmlXPathAxisVal axis = op->value;
717 xmlXPathTestVal test = op->value2;
718 xmlXPathTypeVal type = op->value3;
719 const xmlChar *prefix = op->value4;
720 const xmlChar *name = op->value5;
721
722 fprintf(output, "COLLECT ");
723 switch (axis) {
724 case AXIS_ANCESTOR:
725 fprintf(output, " 'ancestors' "); break;
726 case AXIS_ANCESTOR_OR_SELF:
727 fprintf(output, " 'ancestors-or-self' "); break;
728 case AXIS_ATTRIBUTE:
729 fprintf(output, " 'attributes' "); break;
730 case AXIS_CHILD:
731 fprintf(output, " 'child' "); break;
732 case AXIS_DESCENDANT:
733 fprintf(output, " 'descendant' "); break;
734 case AXIS_DESCENDANT_OR_SELF:
735 fprintf(output, " 'descendant-or-self' "); break;
736 case AXIS_FOLLOWING:
737 fprintf(output, " 'following' "); break;
738 case AXIS_FOLLOWING_SIBLING:
739 fprintf(output, " 'following-siblings' "); break;
740 case AXIS_NAMESPACE:
741 fprintf(output, " 'namespace' "); break;
742 case AXIS_PARENT:
743 fprintf(output, " 'parent' "); break;
744 case AXIS_PRECEDING:
745 fprintf(output, " 'preceding' "); break;
746 case AXIS_PRECEDING_SIBLING:
747 fprintf(output, " 'preceding-sibling' "); break;
748 case AXIS_SELF:
749 fprintf(output, " 'self' "); break;
750 }
751 switch (test) {
752 case NODE_TEST_NONE:
753 fprintf(output, "'none' "); break;
754 case NODE_TEST_TYPE:
755 fprintf(output, "'type' "); break;
756 case NODE_TEST_PI:
757 fprintf(output, "'PI' "); break;
758 case NODE_TEST_ALL:
759 fprintf(output, "'all' "); break;
760 case NODE_TEST_NS:
761 fprintf(output, "'namespace' "); break;
762 case NODE_TEST_NAME:
763 fprintf(output, "'name' "); break;
764 }
765 switch (type) {
766 case NODE_TYPE_NODE:
767 fprintf(output, "'node' "); break;
768 case NODE_TYPE_COMMENT:
769 fprintf(output, "'comment' "); break;
770 case NODE_TYPE_TEXT:
771 fprintf(output, "'text' "); break;
772 case NODE_TYPE_PI:
773 fprintf(output, "'PI' "); break;
774 }
775 if (prefix != NULL)
776 fprintf(output, "%s:", prefix);
777 if (name != NULL)
778 fprintf(output, "%s", name);
779 break;
780
781 }
782 case XPATH_OP_VALUE: {
783 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
784
785 fprintf(output, "ELEM ");
786 xmlXPathDebugDumpObject(output, object, 0);
787 goto finish;
788 }
789 case XPATH_OP_VARIABLE: {
790 const xmlChar *prefix = op->value5;
791 const xmlChar *name = op->value4;
792
793 if (prefix != NULL)
794 fprintf(output, "VARIABLE %s:%s", prefix, name);
795 else
796 fprintf(output, "VARIABLE %s", name);
797 break;
798 }
799 case XPATH_OP_FUNCTION: {
800 int nbargs = op->value;
801 const xmlChar *prefix = op->value5;
802 const xmlChar *name = op->value4;
803
804 if (prefix != NULL)
805 fprintf(output, "FUNCTION %s:%s(%d args)",
806 prefix, name, nbargs);
807 else
808 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
809 break;
810 }
811 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
812 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000813 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +0000814#ifdef LIBXML_XPTR_ENABLED
815 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
816#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000817 default:
818 fprintf(output, "UNKNOWN %d\n", op->op); return;
819 }
820 fprintf(output, "\n");
821finish:
822 if (op->ch1 >= 0)
823 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
824 if (op->ch2 >= 0)
825 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
826}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000827
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000828/**
829 * xmlXPathDebugDumpCompExpr:
830 * @output: the FILE * for the output
831 * @comp: the precompiled XPath expression
832 * @depth: the indentation level.
833 *
834 * Dumps the tree of the compiled XPath expression.
835 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000836void
837xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
838 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000839 int i;
840 char shift[100];
841
842 for (i = 0;((i < depth) && (i < 25));i++)
843 shift[2 * i] = shift[2 * i + 1] = ' ';
844 shift[2 * i] = shift[2 * i + 1] = 0;
845
846 fprintf(output, shift);
847
848 if (comp == NULL) {
849 fprintf(output, "Compiled Expression is NULL\n");
850 return;
851 }
852 fprintf(output, "Compiled Expression : %d elements\n",
853 comp->nbStep);
854 i = comp->last;
855 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
856}
Daniel Veillard017b1082001-06-21 11:20:21 +0000857#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000858
859/************************************************************************
860 * *
861 * Parser stacks related functions and macros *
862 * *
863 ************************************************************************/
864
865/*
866 * Generic function for accessing stacks in the Parser Context
867 */
868
869#define PUSH_AND_POP(type, name) \
870extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
871 if (ctxt->name##Nr >= ctxt->name##Max) { \
872 ctxt->name##Max *= 2; \
873 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
874 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
875 if (ctxt->name##Tab == NULL) { \
876 xmlGenericError(xmlGenericErrorContext, \
877 "realloc failed !\n"); \
878 return(0); \
879 } \
880 } \
881 ctxt->name##Tab[ctxt->name##Nr] = value; \
882 ctxt->name = value; \
883 return(ctxt->name##Nr++); \
884} \
885extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
886 type ret; \
887 if (ctxt->name##Nr <= 0) return(0); \
888 ctxt->name##Nr--; \
889 if (ctxt->name##Nr > 0) \
890 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
891 else \
892 ctxt->name = NULL; \
893 ret = ctxt->name##Tab[ctxt->name##Nr]; \
894 ctxt->name##Tab[ctxt->name##Nr] = 0; \
895 return(ret); \
896} \
897
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000898/**
899 * valuePop:
900 * @ctxt: an XPath evaluation context
901 *
902 * Pops the top XPath object from the value stack
903 *
904 * Returns the XPath object just removed
905 */
906/**
907 * valuePush:
908 * @ctxt: an XPath evaluation context
909 * @value: the XPath object
910 *
911 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000912 *
913 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000914 */
Owen Taylor3473f882001-02-23 17:55:21 +0000915PUSH_AND_POP(xmlXPathObjectPtr, value)
916
Thomas Broyerf06a3d82001-07-16 04:52:57 +0000917/**
918 * xmlXPathPopBoolean:
919 * @ctxt: an XPath parser context
920 *
921 * Pops a boolean from the stack, handling conversion if needed.
922 * Check error with #xmlXPathCheckError.
923 *
924 * Returns the boolean
925 */
926int
927xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
928 xmlXPathObjectPtr obj;
929 int ret;
930
931 obj = valuePop(ctxt);
932 if (obj == NULL) {
933 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
934 return(0);
935 }
936 ret = xmlXPathCastToBoolean(obj);
937 xmlXPathFreeObject(obj);
938 return(ret);
939}
940
941/**
942 * xmlXPathPopNumber:
943 * @ctxt: an XPath parser context
944 *
945 * Pops a number from the stack, handling conversion if needed.
946 * Check error with #xmlXPathCheckError.
947 *
948 * Returns the number
949 */
950double
951xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
952 xmlXPathObjectPtr obj;
953 double ret;
954
955 obj = valuePop(ctxt);
956 if (obj == NULL) {
957 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
958 return(0);
959 }
960 ret = xmlXPathCastToNumber(obj);
961 xmlXPathFreeObject(obj);
962 return(ret);
963}
964
965/**
966 * xmlXPathPopString:
967 * @ctxt: an XPath parser context
968 *
969 * Pops a string from the stack, handling conversion if needed.
970 * Check error with #xmlXPathCheckError.
971 *
972 * Returns the string
973 */
974xmlChar *
975xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
976 xmlXPathObjectPtr obj;
977 xmlChar * ret;
978
979 obj = valuePop(ctxt);
980 if (obj == NULL) {
981 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
982 return(NULL);
983 }
984 ret = xmlXPathCastToString(obj);
985 /* TODO: needs refactoring somewhere else */
986 if (obj->stringval == ret)
987 obj->stringval = NULL;
988 xmlXPathFreeObject(obj);
989 return(ret);
990}
991
992/**
993 * xmlXPathPopNodeSet:
994 * @ctxt: an XPath parser context
995 *
996 * Pops a node-set from the stack, handling conversion if needed.
997 * Check error with #xmlXPathCheckError.
998 *
999 * Returns the node-set
1000 */
1001xmlNodeSetPtr
1002xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1003 xmlXPathObjectPtr obj;
1004 xmlNodeSetPtr ret;
1005
1006 if (ctxt->value == NULL) {
1007 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1008 return(NULL);
1009 }
1010 if (!xmlXPathStackIsNodeSet(ctxt)) {
1011 xmlXPathSetTypeError(ctxt);
1012 return(NULL);
1013 }
1014 obj = valuePop(ctxt);
1015 ret = obj->nodesetval;
1016 xmlXPathFreeNodeSetList(obj);
1017 return(ret);
1018}
1019
1020/**
1021 * xmlXPathPopExternal:
1022 * @ctxt: an XPath parser context
1023 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001024 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001025 * Check error with #xmlXPathCheckError.
1026 *
1027 * Returns the object
1028 */
1029void *
1030xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1031 xmlXPathObjectPtr obj;
1032 void * ret;
1033
1034 if (ctxt->value == NULL) {
1035 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1036 return(NULL);
1037 }
1038 if (ctxt->value->type != XPATH_USERS) {
1039 xmlXPathSetTypeError(ctxt);
1040 return(NULL);
1041 }
1042 obj = valuePop(ctxt);
1043 ret = obj->user;
1044 xmlXPathFreeObject(obj);
1045 return(ret);
1046}
1047
Owen Taylor3473f882001-02-23 17:55:21 +00001048/*
1049 * Macros for accessing the content. Those should be used only by the parser,
1050 * and not exported.
1051 *
1052 * Dirty macros, i.e. one need to make assumption on the context to use them
1053 *
1054 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1055 * CUR returns the current xmlChar value, i.e. a 8 bit value
1056 * in ISO-Latin or UTF-8.
1057 * This should be used internally by the parser
1058 * only to compare to ASCII values otherwise it would break when
1059 * running with UTF-8 encoding.
1060 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1061 * to compare on ASCII based substring.
1062 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1063 * strings within the parser.
1064 * CURRENT Returns the current char value, with the full decoding of
1065 * UTF-8 if we are using this mode. It returns an int.
1066 * NEXT Skip to the next character, this does the proper decoding
1067 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1068 * It returns the pointer to the current xmlChar.
1069 */
1070
1071#define CUR (*ctxt->cur)
1072#define SKIP(val) ctxt->cur += (val)
1073#define NXT(val) ctxt->cur[(val)]
1074#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001075#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1076
1077#define COPY_BUF(l,b,i,v) \
1078 if (l == 1) b[i++] = (xmlChar) v; \
1079 else i += xmlCopyChar(l,&b[i],v)
1080
1081#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001082
1083#define SKIP_BLANKS \
1084 while (IS_BLANK(*(ctxt->cur))) NEXT
1085
1086#define CURRENT (*ctxt->cur)
1087#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1088
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001089
1090#ifndef DBL_DIG
1091#define DBL_DIG 16
1092#endif
1093#ifndef DBL_EPSILON
1094#define DBL_EPSILON 1E-9
1095#endif
1096
1097#define UPPER_DOUBLE 1E9
1098#define LOWER_DOUBLE 1E-5
1099
1100#define INTEGER_DIGITS DBL_DIG
1101#define FRACTION_DIGITS (DBL_DIG + 1)
1102#define EXPONENT_DIGITS (3 + 2)
1103
1104/**
1105 * xmlXPathFormatNumber:
1106 * @number: number to format
1107 * @buffer: output buffer
1108 * @buffersize: size of output buffer
1109 *
1110 * Convert the number into a string representation.
1111 */
1112static void
1113xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1114{
Daniel Veillardcda96922001-08-21 10:56:31 +00001115 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001116 case 1:
1117 if (buffersize > (int)sizeof("+Infinity"))
1118 sprintf(buffer, "+Infinity");
1119 break;
1120 case -1:
1121 if (buffersize > (int)sizeof("-Infinity"))
1122 sprintf(buffer, "-Infinity");
1123 break;
1124 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001125 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001126 if (buffersize > (int)sizeof("NaN"))
1127 sprintf(buffer, "NaN");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001128 } else if (number == ((int) number)) {
1129 char work[30];
1130 char *ptr, *cur;
1131 int res, value = (int) number;
1132
1133 ptr = &buffer[0];
1134 if (value < 0) {
1135 *ptr++ = '-';
1136 value = -value;
1137 }
1138 if (value == 0) {
1139 *ptr++ = '0';
1140 } else {
1141 cur = &work[0];
1142 while (value != 0) {
1143 res = value % 10;
1144 value = value / 10;
1145 *cur++ = '0' + res;
1146 }
1147 cur--;
1148 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) {
1149 *ptr++ = *cur--;
1150 }
1151 }
1152 if (ptr - buffer < buffersize) {
1153 *ptr = 0;
1154 } else if (buffersize > 0) {
1155 ptr--;
1156 *ptr = 0;
1157 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001158 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001159 /* 3 is sign, decimal point, and terminating zero */
1160 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1161 int integer_place, fraction_place;
1162 char *ptr;
1163 char *after_fraction;
1164 double absolute_value;
1165 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001166
Bjorn Reese70a9da52001-04-21 16:57:29 +00001167 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001168
Bjorn Reese70a9da52001-04-21 16:57:29 +00001169 /*
1170 * First choose format - scientific or regular floating point.
1171 * In either case, result is in work, and after_fraction points
1172 * just past the fractional part.
1173 */
1174 if ( ((absolute_value > UPPER_DOUBLE) ||
1175 (absolute_value < LOWER_DOUBLE)) &&
1176 (absolute_value != 0.0) ) {
1177 /* Use scientific notation */
1178 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1179 fraction_place = DBL_DIG - 1;
1180 snprintf(work, sizeof(work),"%*.*e",
1181 integer_place, fraction_place, number);
1182 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001183 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001184 else {
1185 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001186 if (absolute_value > 0.0)
1187 integer_place = 1 + (int)log10(absolute_value);
1188 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001189 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001190 fraction_place = (integer_place > 0)
1191 ? DBL_DIG - integer_place
1192 : DBL_DIG;
1193 size = snprintf(work, sizeof(work), "%0.*f",
1194 fraction_place, number);
1195 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001196 }
1197
Bjorn Reese70a9da52001-04-21 16:57:29 +00001198 /* Remove fractional trailing zeroes */
1199 ptr = after_fraction;
1200 while (*(--ptr) == '0')
1201 ;
1202 if (*ptr != '.')
1203 ptr++;
1204 strcpy(ptr, after_fraction);
1205
1206 /* Finally copy result back to caller */
1207 size = strlen(work) + 1;
1208 if (size > buffersize) {
1209 work[buffersize - 1] = 0;
1210 size = buffersize;
1211 }
1212 memcpy(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001213 }
1214 break;
1215 }
1216}
1217
Owen Taylor3473f882001-02-23 17:55:21 +00001218/************************************************************************
1219 * *
1220 * Error handling routines *
1221 * *
1222 ************************************************************************/
1223
1224
Daniel Veillardb44025c2001-10-11 22:55:55 +00001225static const char *xmlXPathErrorMessages[] = {
Owen Taylor3473f882001-02-23 17:55:21 +00001226 "Ok",
1227 "Number encoding",
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001228 "Unfinished literal",
1229 "Start of literal",
Owen Taylor3473f882001-02-23 17:55:21 +00001230 "Expected $ for variable reference",
1231 "Undefined variable",
1232 "Invalid predicate",
1233 "Invalid expression",
1234 "Missing closing curly brace",
1235 "Unregistered function",
1236 "Invalid operand",
1237 "Invalid type",
1238 "Invalid number of arguments",
1239 "Invalid context size",
1240 "Invalid context position",
1241 "Memory allocation error",
1242 "Syntax error",
1243 "Resource error",
1244 "Sub resource error",
Daniel Veillard61d80a22001-04-27 17:13:01 +00001245 "Undefined namespace prefix",
1246 "Encoding error",
1247 "Char out of XML range"
Owen Taylor3473f882001-02-23 17:55:21 +00001248};
1249
1250/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001251 * xmlXPatherror:
Owen Taylor3473f882001-02-23 17:55:21 +00001252 * @ctxt: the XPath Parser context
1253 * @file: the file name
1254 * @line: the line number
1255 * @no: the error number
1256 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001257 * Formats an error message.
Owen Taylor3473f882001-02-23 17:55:21 +00001258 */
1259void
1260xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
1261 int line, int no) {
1262 int n;
1263 const xmlChar *cur;
1264 const xmlChar *base;
1265
1266 xmlGenericError(xmlGenericErrorContext,
1267 "Error %s:%d: %s\n", file, line,
1268 xmlXPathErrorMessages[no]);
1269
1270 cur = ctxt->cur;
1271 base = ctxt->base;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001272 if ((cur == NULL) || (base == NULL))
1273 return;
1274
Owen Taylor3473f882001-02-23 17:55:21 +00001275 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
1276 cur--;
1277 }
1278 n = 0;
1279 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
1280 cur--;
1281 if ((*cur == '\n') || (*cur == '\r')) cur++;
1282 base = cur;
1283 n = 0;
1284 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1285 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
1286 n++;
1287 }
1288 xmlGenericError(xmlGenericErrorContext, "\n");
1289 cur = ctxt->cur;
1290 while ((*cur == '\n') || (*cur == '\r'))
1291 cur--;
1292 n = 0;
1293 while ((cur != base) && (n++ < 80)) {
1294 xmlGenericError(xmlGenericErrorContext, " ");
1295 base++;
1296 }
1297 xmlGenericError(xmlGenericErrorContext,"^\n");
1298}
1299
1300
1301/************************************************************************
1302 * *
1303 * Routines to handle NodeSets *
1304 * *
1305 ************************************************************************/
1306
1307/**
1308 * xmlXPathCmpNodes:
1309 * @node1: the first node
1310 * @node2: the second node
1311 *
1312 * Compare two nodes w.r.t document order
1313 *
1314 * Returns -2 in case of error 1 if first point < second point, 0 if
1315 * that's the same node, -1 otherwise
1316 */
1317int
1318xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1319 int depth1, depth2;
1320 xmlNodePtr cur, root;
1321
1322 if ((node1 == NULL) || (node2 == NULL))
1323 return(-2);
1324 /*
1325 * a couple of optimizations which will avoid computations in most cases
1326 */
1327 if (node1 == node2)
1328 return(0);
Daniel Veillardb33c2012001-04-25 12:59:04 +00001329 if ((node1->type == XML_NAMESPACE_DECL) ||
1330 (node2->type == XML_NAMESPACE_DECL))
1331 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001332 if (node1 == node2->prev)
1333 return(1);
1334 if (node1 == node2->next)
1335 return(-1);
1336
1337 /*
1338 * compute depth to root
1339 */
1340 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1341 if (cur == node1)
1342 return(1);
1343 depth2++;
1344 }
1345 root = cur;
1346 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1347 if (cur == node2)
1348 return(-1);
1349 depth1++;
1350 }
1351 /*
1352 * Distinct document (or distinct entities :-( ) case.
1353 */
1354 if (root != cur) {
1355 return(-2);
1356 }
1357 /*
1358 * get the nearest common ancestor.
1359 */
1360 while (depth1 > depth2) {
1361 depth1--;
1362 node1 = node1->parent;
1363 }
1364 while (depth2 > depth1) {
1365 depth2--;
1366 node2 = node2->parent;
1367 }
1368 while (node1->parent != node2->parent) {
1369 node1 = node1->parent;
1370 node2 = node2->parent;
1371 /* should not happen but just in case ... */
1372 if ((node1 == NULL) || (node2 == NULL))
1373 return(-2);
1374 }
1375 /*
1376 * Find who's first.
1377 */
1378 if (node1 == node2->next)
1379 return(-1);
1380 for (cur = node1->next;cur != NULL;cur = cur->next)
1381 if (cur == node2)
1382 return(1);
1383 return(-1); /* assume there is no sibling list corruption */
1384}
1385
1386/**
1387 * xmlXPathNodeSetSort:
1388 * @set: the node set
1389 *
1390 * Sort the node set in document order
1391 */
1392void
1393xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001394 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001395 xmlNodePtr tmp;
1396
1397 if (set == NULL)
1398 return;
1399
1400 /* Use Shell's sort to sort the node-set */
1401 len = set->nodeNr;
1402 for (incr = len / 2; incr > 0; incr /= 2) {
1403 for (i = incr; i < len; i++) {
1404 j = i - incr;
1405 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001406 if (xmlXPathCmpNodes(set->nodeTab[j],
1407 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001408 tmp = set->nodeTab[j];
1409 set->nodeTab[j] = set->nodeTab[j + incr];
1410 set->nodeTab[j + incr] = tmp;
1411 j -= incr;
1412 } else
1413 break;
1414 }
1415 }
1416 }
1417}
1418
1419#define XML_NODESET_DEFAULT 10
1420/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001421 * xmlXPathNodeSetDupNs:
1422 * @node: the parent node of the namespace XPath node
1423 * @ns: the libxml namespace declaration node.
1424 *
1425 * Namespace node in libxml don't match the XPath semantic. In a node set
1426 * the namespace nodes are duplicated and the next pointer is set to the
1427 * parent node in the XPath semantic.
1428 *
1429 * Returns the newly created object.
1430 */
1431static xmlNodePtr
1432xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1433 xmlNsPtr cur;
1434
1435 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1436 return(NULL);
1437 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1438 return((xmlNodePtr) ns);
1439
1440 /*
1441 * Allocate a new Namespace and fill the fields.
1442 */
1443 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1444 if (cur == NULL) {
1445 xmlGenericError(xmlGenericErrorContext,
1446 "xmlXPathNodeSetDupNs : malloc failed\n");
1447 return(NULL);
1448 }
1449 memset(cur, 0, sizeof(xmlNs));
1450 cur->type = XML_NAMESPACE_DECL;
1451 if (ns->href != NULL)
1452 cur->href = xmlStrdup(ns->href);
1453 if (ns->prefix != NULL)
1454 cur->prefix = xmlStrdup(ns->prefix);
1455 cur->next = (xmlNsPtr) node;
1456 return((xmlNodePtr) cur);
1457}
1458
1459/**
1460 * xmlXPathNodeSetFreeNs:
1461 * @ns: the XPath namespace node found in a nodeset.
1462 *
1463 * Namespace node in libxml don't match the XPath semantic. In a node set
1464 * the namespace nodes are duplicated and the next pointer is set to the
1465 * parent node in the XPath semantic. Check if such a node need to be freed
1466 */
1467static void
1468xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1469 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1470 return;
1471
1472 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1473 if (ns->href != NULL)
1474 xmlFree((xmlChar *)ns->href);
1475 if (ns->prefix != NULL)
1476 xmlFree((xmlChar *)ns->prefix);
1477 xmlFree(ns);
1478 }
1479}
1480
1481/**
Owen Taylor3473f882001-02-23 17:55:21 +00001482 * xmlXPathNodeSetCreate:
1483 * @val: an initial xmlNodePtr, or NULL
1484 *
1485 * Create a new xmlNodeSetPtr of type double and of value @val
1486 *
1487 * Returns the newly created object.
1488 */
1489xmlNodeSetPtr
1490xmlXPathNodeSetCreate(xmlNodePtr val) {
1491 xmlNodeSetPtr ret;
1492
1493 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1494 if (ret == NULL) {
1495 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001496 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001497 return(NULL);
1498 }
1499 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1500 if (val != NULL) {
1501 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1502 sizeof(xmlNodePtr));
1503 if (ret->nodeTab == NULL) {
1504 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001505 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001506 return(NULL);
1507 }
1508 memset(ret->nodeTab, 0 ,
1509 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1510 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001511 if (val->type == XML_NAMESPACE_DECL) {
1512 xmlNsPtr ns = (xmlNsPtr) val;
1513
1514 ret->nodeTab[ret->nodeNr++] =
1515 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1516 } else
1517 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001518 }
1519 return(ret);
1520}
1521
1522/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001523 * xmlXPathNodeSetContains:
1524 * @cur: the node-set
1525 * @val: the node
1526 *
1527 * checks whether @cur contains @val
1528 *
1529 * Returns true (1) if @cur contains @val, false (0) otherwise
1530 */
1531int
1532xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1533 int i;
1534
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001535 if (val->type == XML_NAMESPACE_DECL) {
1536 for (i = 0; i < cur->nodeNr; i++) {
1537 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1538 xmlNsPtr ns1, ns2;
1539
1540 ns1 = (xmlNsPtr) val;
1541 ns2 = (xmlNsPtr) cur->nodeTab[i];
1542 if (ns1 == ns2)
1543 return(1);
1544 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1545 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1546 return(1);
1547 }
1548 }
1549 } else {
1550 for (i = 0; i < cur->nodeNr; i++) {
1551 if (cur->nodeTab[i] == val)
1552 return(1);
1553 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001554 }
1555 return(0);
1556}
1557
1558/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001559 * xmlXPathNodeSetAddNs:
1560 * @cur: the initial node set
1561 * @node: the hosting node
1562 * @ns: a the namespace node
1563 *
1564 * add a new namespace node to an existing NodeSet
1565 */
1566static void
1567xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1568 int i;
1569
1570 if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) ||
1571 (node->type != XML_ELEMENT_NODE))
1572 return;
1573
1574 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1575 /*
1576 * check against doublons
1577 */
1578 for (i = 0;i < cur->nodeNr;i++) {
1579 if ((cur->nodeTab[i] != NULL) &&
1580 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001581 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001582 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1583 return;
1584 }
1585
1586 /*
1587 * grow the nodeTab if needed
1588 */
1589 if (cur->nodeMax == 0) {
1590 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1591 sizeof(xmlNodePtr));
1592 if (cur->nodeTab == NULL) {
1593 xmlGenericError(xmlGenericErrorContext,
1594 "xmlXPathNodeSetAdd: out of memory\n");
1595 return;
1596 }
1597 memset(cur->nodeTab, 0 ,
1598 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1599 cur->nodeMax = XML_NODESET_DEFAULT;
1600 } else if (cur->nodeNr == cur->nodeMax) {
1601 xmlNodePtr *temp;
1602
1603 cur->nodeMax *= 2;
1604 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1605 sizeof(xmlNodePtr));
1606 if (temp == NULL) {
1607 xmlGenericError(xmlGenericErrorContext,
1608 "xmlXPathNodeSetAdd: out of memory\n");
1609 return;
1610 }
1611 cur->nodeTab = temp;
1612 }
1613 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1614}
1615
1616/**
Owen Taylor3473f882001-02-23 17:55:21 +00001617 * xmlXPathNodeSetAdd:
1618 * @cur: the initial node set
1619 * @val: a new xmlNodePtr
1620 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001621 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001622 */
1623void
1624xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1625 int i;
1626
1627 if (val == NULL) return;
1628
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001629 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001630 /*
1631 * check against doublons
1632 */
1633 for (i = 0;i < cur->nodeNr;i++)
1634 if (cur->nodeTab[i] == val) return;
1635
1636 /*
1637 * grow the nodeTab if needed
1638 */
1639 if (cur->nodeMax == 0) {
1640 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1641 sizeof(xmlNodePtr));
1642 if (cur->nodeTab == NULL) {
1643 xmlGenericError(xmlGenericErrorContext,
1644 "xmlXPathNodeSetAdd: out of memory\n");
1645 return;
1646 }
1647 memset(cur->nodeTab, 0 ,
1648 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1649 cur->nodeMax = XML_NODESET_DEFAULT;
1650 } else if (cur->nodeNr == cur->nodeMax) {
1651 xmlNodePtr *temp;
1652
1653 cur->nodeMax *= 2;
1654 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1655 sizeof(xmlNodePtr));
1656 if (temp == NULL) {
1657 xmlGenericError(xmlGenericErrorContext,
1658 "xmlXPathNodeSetAdd: out of memory\n");
1659 return;
1660 }
1661 cur->nodeTab = temp;
1662 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001663 if (val->type == XML_NAMESPACE_DECL) {
1664 xmlNsPtr ns = (xmlNsPtr) val;
1665
1666 cur->nodeTab[cur->nodeNr++] =
1667 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1668 } else
1669 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001670}
1671
1672/**
1673 * xmlXPathNodeSetAddUnique:
1674 * @cur: the initial node set
1675 * @val: a new xmlNodePtr
1676 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001677 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001678 * when we are sure the node is not already in the set.
1679 */
1680void
1681xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1682 if (val == NULL) return;
1683
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001684 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001685 /*
1686 * grow the nodeTab if needed
1687 */
1688 if (cur->nodeMax == 0) {
1689 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1690 sizeof(xmlNodePtr));
1691 if (cur->nodeTab == NULL) {
1692 xmlGenericError(xmlGenericErrorContext,
1693 "xmlXPathNodeSetAddUnique: out of memory\n");
1694 return;
1695 }
1696 memset(cur->nodeTab, 0 ,
1697 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1698 cur->nodeMax = XML_NODESET_DEFAULT;
1699 } else if (cur->nodeNr == cur->nodeMax) {
1700 xmlNodePtr *temp;
1701
1702 cur->nodeMax *= 2;
1703 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1704 sizeof(xmlNodePtr));
1705 if (temp == NULL) {
1706 xmlGenericError(xmlGenericErrorContext,
1707 "xmlXPathNodeSetAddUnique: out of memory\n");
1708 return;
1709 }
1710 cur->nodeTab = temp;
1711 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001712 if (val->type == XML_NAMESPACE_DECL) {
1713 xmlNsPtr ns = (xmlNsPtr) val;
1714
1715 cur->nodeTab[cur->nodeNr++] =
1716 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1717 } else
1718 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001719}
1720
1721/**
1722 * xmlXPathNodeSetMerge:
1723 * @val1: the first NodeSet or NULL
1724 * @val2: the second NodeSet
1725 *
1726 * Merges two nodesets, all nodes from @val2 are added to @val1
1727 * if @val1 is NULL, a new set is created and copied from @val2
1728 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001729 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001730 */
1731xmlNodeSetPtr
1732xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001733 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001734
1735 if (val2 == NULL) return(val1);
1736 if (val1 == NULL) {
1737 val1 = xmlXPathNodeSetCreate(NULL);
1738 }
1739
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001740 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001741 initNr = val1->nodeNr;
1742
1743 for (i = 0;i < val2->nodeNr;i++) {
1744 /*
1745 * check against doublons
1746 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001747 skip = 0;
1748 for (j = 0; j < initNr; j++) {
1749 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1750 skip = 1;
1751 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001752 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
1753 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
1754 xmlNsPtr ns1, ns2;
1755 ns1 = (xmlNsPtr) val1->nodeTab[j];
1756 ns2 = (xmlNsPtr) val2->nodeTab[i];
1757 if ((ns1->next == ns2->next) &&
1758 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
1759 skip = 1;
1760 break;
1761 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001762 }
1763 }
1764 if (skip)
1765 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001766
1767 /*
1768 * grow the nodeTab if needed
1769 */
1770 if (val1->nodeMax == 0) {
1771 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1772 sizeof(xmlNodePtr));
1773 if (val1->nodeTab == NULL) {
1774 xmlGenericError(xmlGenericErrorContext,
1775 "xmlXPathNodeSetMerge: out of memory\n");
1776 return(NULL);
1777 }
1778 memset(val1->nodeTab, 0 ,
1779 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1780 val1->nodeMax = XML_NODESET_DEFAULT;
1781 } else if (val1->nodeNr == val1->nodeMax) {
1782 xmlNodePtr *temp;
1783
1784 val1->nodeMax *= 2;
1785 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1786 sizeof(xmlNodePtr));
1787 if (temp == NULL) {
1788 xmlGenericError(xmlGenericErrorContext,
1789 "xmlXPathNodeSetMerge: out of memory\n");
1790 return(NULL);
1791 }
1792 val1->nodeTab = temp;
1793 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001794 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1795 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1796
1797 val1->nodeTab[val1->nodeNr++] =
1798 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1799 } else
1800 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00001801 }
1802
1803 return(val1);
1804}
1805
1806/**
Daniel Veillard75be0132002-03-13 10:03:35 +00001807 * xmlXPathNodeSetMergeUnique:
1808 * @val1: the first NodeSet or NULL
1809 * @val2: the second NodeSet
1810 *
1811 * Merges two nodesets, all nodes from @val2 are added to @val1
1812 * if @val1 is NULL, a new set is created and copied from @val2
1813 *
1814 * Returns @val1 once extended or NULL in case of error.
1815 */
1816static xmlNodeSetPtr
1817xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
1818 int i, initNr;
1819
1820 if (val2 == NULL) return(val1);
1821 if (val1 == NULL) {
1822 val1 = xmlXPathNodeSetCreate(NULL);
1823 }
1824
1825 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1826 initNr = val1->nodeNr;
1827
1828 for (i = 0;i < val2->nodeNr;i++) {
1829 /*
1830 * grow the nodeTab if needed
1831 */
1832 if (val1->nodeMax == 0) {
1833 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1834 sizeof(xmlNodePtr));
1835 if (val1->nodeTab == NULL) {
1836 xmlGenericError(xmlGenericErrorContext,
1837 "xmlXPathNodeSetMerge: out of memory\n");
1838 return(NULL);
1839 }
1840 memset(val1->nodeTab, 0 ,
1841 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1842 val1->nodeMax = XML_NODESET_DEFAULT;
1843 } else if (val1->nodeNr == val1->nodeMax) {
1844 xmlNodePtr *temp;
1845
1846 val1->nodeMax *= 2;
1847 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1848 sizeof(xmlNodePtr));
1849 if (temp == NULL) {
1850 xmlGenericError(xmlGenericErrorContext,
1851 "xmlXPathNodeSetMerge: out of memory\n");
1852 return(NULL);
1853 }
1854 val1->nodeTab = temp;
1855 }
1856 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1857 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1858
1859 val1->nodeTab[val1->nodeNr++] =
1860 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1861 } else
1862 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1863 }
1864
1865 return(val1);
1866}
1867
1868/**
Owen Taylor3473f882001-02-23 17:55:21 +00001869 * xmlXPathNodeSetDel:
1870 * @cur: the initial node set
1871 * @val: an xmlNodePtr
1872 *
1873 * Removes an xmlNodePtr from an existing NodeSet
1874 */
1875void
1876xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
1877 int i;
1878
1879 if (cur == NULL) return;
1880 if (val == NULL) return;
1881
1882 /*
1883 * check against doublons
1884 */
1885 for (i = 0;i < cur->nodeNr;i++)
1886 if (cur->nodeTab[i] == val) break;
1887
1888 if (i >= cur->nodeNr) {
1889#ifdef DEBUG
1890 xmlGenericError(xmlGenericErrorContext,
1891 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
1892 val->name);
1893#endif
1894 return;
1895 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001896 if ((cur->nodeTab[i] != NULL) &&
1897 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
1898 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001899 cur->nodeNr--;
1900 for (;i < cur->nodeNr;i++)
1901 cur->nodeTab[i] = cur->nodeTab[i + 1];
1902 cur->nodeTab[cur->nodeNr] = NULL;
1903}
1904
1905/**
1906 * xmlXPathNodeSetRemove:
1907 * @cur: the initial node set
1908 * @val: the index to remove
1909 *
1910 * Removes an entry from an existing NodeSet list.
1911 */
1912void
1913xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
1914 if (cur == NULL) return;
1915 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001916 if ((cur->nodeTab[val] != NULL) &&
1917 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
1918 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00001919 cur->nodeNr--;
1920 for (;val < cur->nodeNr;val++)
1921 cur->nodeTab[val] = cur->nodeTab[val + 1];
1922 cur->nodeTab[cur->nodeNr] = NULL;
1923}
1924
1925/**
1926 * xmlXPathFreeNodeSet:
1927 * @obj: the xmlNodeSetPtr to free
1928 *
1929 * Free the NodeSet compound (not the actual nodes !).
1930 */
1931void
1932xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
1933 if (obj == NULL) return;
1934 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001935 int i;
1936
1937 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1938 for (i = 0;i < obj->nodeNr;i++)
1939 if ((obj->nodeTab[i] != NULL) &&
1940 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
1941 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001942 xmlFree(obj->nodeTab);
1943 }
Owen Taylor3473f882001-02-23 17:55:21 +00001944 xmlFree(obj);
1945}
1946
1947/**
1948 * xmlXPathFreeValueTree:
1949 * @obj: the xmlNodeSetPtr to free
1950 *
1951 * Free the NodeSet compound and the actual tree, this is different
1952 * from xmlXPathFreeNodeSet()
1953 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001954static void
Owen Taylor3473f882001-02-23 17:55:21 +00001955xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
1956 int i;
1957
1958 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001959
1960 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001961 for (i = 0;i < obj->nodeNr;i++) {
1962 if (obj->nodeTab[i] != NULL) {
1963 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1964 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
1965 } else {
1966 xmlFreeNodeList(obj->nodeTab[i]);
1967 }
1968 }
1969 }
Owen Taylor3473f882001-02-23 17:55:21 +00001970 xmlFree(obj->nodeTab);
1971 }
Owen Taylor3473f882001-02-23 17:55:21 +00001972 xmlFree(obj);
1973}
1974
1975#if defined(DEBUG) || defined(DEBUG_STEP)
1976/**
1977 * xmlGenericErrorContextNodeSet:
1978 * @output: a FILE * for the output
1979 * @obj: the xmlNodeSetPtr to free
1980 *
1981 * Quick display of a NodeSet
1982 */
1983void
1984xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
1985 int i;
1986
1987 if (output == NULL) output = xmlGenericErrorContext;
1988 if (obj == NULL) {
1989 fprintf(output, "NodeSet == NULL !\n");
1990 return;
1991 }
1992 if (obj->nodeNr == 0) {
1993 fprintf(output, "NodeSet is empty\n");
1994 return;
1995 }
1996 if (obj->nodeTab == NULL) {
1997 fprintf(output, " nodeTab == NULL !\n");
1998 return;
1999 }
2000 for (i = 0; i < obj->nodeNr; i++) {
2001 if (obj->nodeTab[i] == NULL) {
2002 fprintf(output, " NULL !\n");
2003 return;
2004 }
2005 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2006 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2007 fprintf(output, " /");
2008 else if (obj->nodeTab[i]->name == NULL)
2009 fprintf(output, " noname!");
2010 else fprintf(output, " %s", obj->nodeTab[i]->name);
2011 }
2012 fprintf(output, "\n");
2013}
2014#endif
2015
2016/**
2017 * xmlXPathNewNodeSet:
2018 * @val: the NodePtr value
2019 *
2020 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2021 * it with the single Node @val
2022 *
2023 * Returns the newly created object.
2024 */
2025xmlXPathObjectPtr
2026xmlXPathNewNodeSet(xmlNodePtr val) {
2027 xmlXPathObjectPtr ret;
2028
2029 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2030 if (ret == NULL) {
2031 xmlGenericError(xmlGenericErrorContext,
2032 "xmlXPathNewNodeSet: out of memory\n");
2033 return(NULL);
2034 }
2035 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2036 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002037 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002038 ret->nodesetval = xmlXPathNodeSetCreate(val);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002039 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002040 return(ret);
2041}
2042
2043/**
2044 * xmlXPathNewValueTree:
2045 * @val: the NodePtr value
2046 *
2047 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2048 * it with the tree root @val
2049 *
2050 * Returns the newly created object.
2051 */
2052xmlXPathObjectPtr
2053xmlXPathNewValueTree(xmlNodePtr val) {
2054 xmlXPathObjectPtr ret;
2055
2056 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2057 if (ret == NULL) {
2058 xmlGenericError(xmlGenericErrorContext,
2059 "xmlXPathNewNodeSet: out of memory\n");
2060 return(NULL);
2061 }
2062 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2063 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002064 ret->boolval = 1;
2065 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002066 ret->nodesetval = xmlXPathNodeSetCreate(val);
2067 return(ret);
2068}
2069
2070/**
2071 * xmlXPathNewNodeSetList:
2072 * @val: an existing NodeSet
2073 *
2074 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2075 * it with the Nodeset @val
2076 *
2077 * Returns the newly created object.
2078 */
2079xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002080xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2081{
Owen Taylor3473f882001-02-23 17:55:21 +00002082 xmlXPathObjectPtr ret;
2083 int i;
2084
2085 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002086 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002087 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002088 ret = xmlXPathNewNodeSet(NULL);
2089 else {
2090 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2091 for (i = 1; i < val->nodeNr; ++i)
2092 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2093 }
Owen Taylor3473f882001-02-23 17:55:21 +00002094
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002095 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002096}
2097
2098/**
2099 * xmlXPathWrapNodeSet:
2100 * @val: the NodePtr value
2101 *
2102 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2103 *
2104 * Returns the newly created object.
2105 */
2106xmlXPathObjectPtr
2107xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2108 xmlXPathObjectPtr ret;
2109
2110 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2111 if (ret == NULL) {
2112 xmlGenericError(xmlGenericErrorContext,
2113 "xmlXPathWrapNodeSet: out of memory\n");
2114 return(NULL);
2115 }
2116 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2117 ret->type = XPATH_NODESET;
2118 ret->nodesetval = val;
2119 return(ret);
2120}
2121
2122/**
2123 * xmlXPathFreeNodeSetList:
2124 * @obj: an existing NodeSetList object
2125 *
2126 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2127 * the list contrary to xmlXPathFreeObject().
2128 */
2129void
2130xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2131 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002132 xmlFree(obj);
2133}
2134
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002135/**
2136 * xmlXPathDifference:
2137 * @nodes1: a node-set
2138 * @nodes2: a node-set
2139 *
2140 * Implements the EXSLT - Sets difference() function:
2141 * node-set set:difference (node-set, node-set)
2142 *
2143 * Returns the difference between the two node sets, or nodes1 if
2144 * nodes2 is empty
2145 */
2146xmlNodeSetPtr
2147xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2148 xmlNodeSetPtr ret;
2149 int i, l1;
2150 xmlNodePtr cur;
2151
2152 if (xmlXPathNodeSetIsEmpty(nodes2))
2153 return(nodes1);
2154
2155 ret = xmlXPathNodeSetCreate(NULL);
2156 if (xmlXPathNodeSetIsEmpty(nodes1))
2157 return(ret);
2158
2159 l1 = xmlXPathNodeSetGetLength(nodes1);
2160
2161 for (i = 0; i < l1; i++) {
2162 cur = xmlXPathNodeSetItem(nodes1, i);
2163 if (!xmlXPathNodeSetContains(nodes2, cur))
2164 xmlXPathNodeSetAddUnique(ret, cur);
2165 }
2166 return(ret);
2167}
2168
2169/**
2170 * xmlXPathIntersection:
2171 * @nodes1: a node-set
2172 * @nodes2: a node-set
2173 *
2174 * Implements the EXSLT - Sets intersection() function:
2175 * node-set set:intersection (node-set, node-set)
2176 *
2177 * Returns a node set comprising the nodes that are within both the
2178 * node sets passed as arguments
2179 */
2180xmlNodeSetPtr
2181xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2182 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2183 int i, l1;
2184 xmlNodePtr cur;
2185
2186 if (xmlXPathNodeSetIsEmpty(nodes1))
2187 return(ret);
2188 if (xmlXPathNodeSetIsEmpty(nodes2))
2189 return(ret);
2190
2191 l1 = xmlXPathNodeSetGetLength(nodes1);
2192
2193 for (i = 0; i < l1; i++) {
2194 cur = xmlXPathNodeSetItem(nodes1, i);
2195 if (xmlXPathNodeSetContains(nodes2, cur))
2196 xmlXPathNodeSetAddUnique(ret, cur);
2197 }
2198 return(ret);
2199}
2200
2201/**
2202 * xmlXPathDistinctSorted:
2203 * @nodes: a node-set, sorted by document order
2204 *
2205 * Implements the EXSLT - Sets distinct() function:
2206 * node-set set:distinct (node-set)
2207 *
2208 * Returns a subset of the nodes contained in @nodes, or @nodes if
2209 * it is empty
2210 */
2211xmlNodeSetPtr
2212xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2213 xmlNodeSetPtr ret;
2214 xmlHashTablePtr hash;
2215 int i, l;
2216 xmlChar * strval;
2217 xmlNodePtr cur;
2218
2219 if (xmlXPathNodeSetIsEmpty(nodes))
2220 return(nodes);
2221
2222 ret = xmlXPathNodeSetCreate(NULL);
2223 l = xmlXPathNodeSetGetLength(nodes);
2224 hash = xmlHashCreate (l);
2225 for (i = 0; i < l; i++) {
2226 cur = xmlXPathNodeSetItem(nodes, i);
2227 strval = xmlXPathCastNodeToString(cur);
2228 if (xmlHashLookup(hash, strval) == NULL) {
2229 xmlHashAddEntry(hash, strval, strval);
2230 xmlXPathNodeSetAddUnique(ret, cur);
2231 } else {
2232 xmlFree(strval);
2233 }
2234 }
2235 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2236 return(ret);
2237}
2238
2239/**
2240 * xmlXPathDistinct:
2241 * @nodes: a node-set
2242 *
2243 * Implements the EXSLT - Sets distinct() function:
2244 * node-set set:distinct (node-set)
2245 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2246 * is called with the sorted node-set
2247 *
2248 * Returns a subset of the nodes contained in @nodes, or @nodes if
2249 * it is empty
2250 */
2251xmlNodeSetPtr
2252xmlXPathDistinct (xmlNodeSetPtr nodes) {
2253 if (xmlXPathNodeSetIsEmpty(nodes))
2254 return(nodes);
2255
2256 xmlXPathNodeSetSort(nodes);
2257 return(xmlXPathDistinctSorted(nodes));
2258}
2259
2260/**
2261 * xmlXPathHasSameNodes:
2262 * @nodes1: a node-set
2263 * @nodes2: a node-set
2264 *
2265 * Implements the EXSLT - Sets has-same-nodes function:
2266 * boolean set:has-same-node(node-set, node-set)
2267 *
2268 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2269 * otherwise
2270 */
2271int
2272xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2273 int i, l;
2274 xmlNodePtr cur;
2275
2276 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2277 xmlXPathNodeSetIsEmpty(nodes2))
2278 return(0);
2279
2280 l = xmlXPathNodeSetGetLength(nodes1);
2281 for (i = 0; i < l; i++) {
2282 cur = xmlXPathNodeSetItem(nodes1, i);
2283 if (xmlXPathNodeSetContains(nodes2, cur))
2284 return(1);
2285 }
2286 return(0);
2287}
2288
2289/**
2290 * xmlXPathNodeLeadingSorted:
2291 * @nodes: a node-set, sorted by document order
2292 * @node: a node
2293 *
2294 * Implements the EXSLT - Sets leading() function:
2295 * node-set set:leading (node-set, node-set)
2296 *
2297 * Returns the nodes in @nodes that precede @node in document order,
2298 * @nodes if @node is NULL or an empty node-set if @nodes
2299 * doesn't contain @node
2300 */
2301xmlNodeSetPtr
2302xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2303 int i, l;
2304 xmlNodePtr cur;
2305 xmlNodeSetPtr ret;
2306
2307 if (node == NULL)
2308 return(nodes);
2309
2310 ret = xmlXPathNodeSetCreate(NULL);
2311 if (xmlXPathNodeSetIsEmpty(nodes) ||
2312 (!xmlXPathNodeSetContains(nodes, node)))
2313 return(ret);
2314
2315 l = xmlXPathNodeSetGetLength(nodes);
2316 for (i = 0; i < l; i++) {
2317 cur = xmlXPathNodeSetItem(nodes, i);
2318 if (cur == node)
2319 break;
2320 xmlXPathNodeSetAddUnique(ret, cur);
2321 }
2322 return(ret);
2323}
2324
2325/**
2326 * xmlXPathNodeLeading:
2327 * @nodes: a node-set
2328 * @node: a node
2329 *
2330 * Implements the EXSLT - Sets leading() function:
2331 * node-set set:leading (node-set, node-set)
2332 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2333 * is called.
2334 *
2335 * Returns the nodes in @nodes that precede @node in document order,
2336 * @nodes if @node is NULL or an empty node-set if @nodes
2337 * doesn't contain @node
2338 */
2339xmlNodeSetPtr
2340xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2341 xmlXPathNodeSetSort(nodes);
2342 return(xmlXPathNodeLeadingSorted(nodes, node));
2343}
2344
2345/**
2346 * xmlXPathLeadingSorted:
2347 * @nodes1: a node-set, sorted by document order
2348 * @nodes2: a node-set, sorted by document order
2349 *
2350 * Implements the EXSLT - Sets leading() function:
2351 * node-set set:leading (node-set, node-set)
2352 *
2353 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2354 * in document order, @nodes1 if @nodes2 is NULL or empty or
2355 * an empty node-set if @nodes1 doesn't contain @nodes2
2356 */
2357xmlNodeSetPtr
2358xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2359 if (xmlXPathNodeSetIsEmpty(nodes2))
2360 return(nodes1);
2361 return(xmlXPathNodeLeadingSorted(nodes1,
2362 xmlXPathNodeSetItem(nodes2, 1)));
2363}
2364
2365/**
2366 * xmlXPathLeading:
2367 * @nodes1: a node-set
2368 * @nodes2: a node-set
2369 *
2370 * Implements the EXSLT - Sets leading() function:
2371 * node-set set:leading (node-set, node-set)
2372 * @nodes1 and @nodes2 are sorted by document order, then
2373 * #exslSetsLeadingSorted is called.
2374 *
2375 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2376 * in document order, @nodes1 if @nodes2 is NULL or empty or
2377 * an empty node-set if @nodes1 doesn't contain @nodes2
2378 */
2379xmlNodeSetPtr
2380xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2381 if (xmlXPathNodeSetIsEmpty(nodes2))
2382 return(nodes1);
2383 if (xmlXPathNodeSetIsEmpty(nodes1))
2384 return(xmlXPathNodeSetCreate(NULL));
2385 xmlXPathNodeSetSort(nodes1);
2386 xmlXPathNodeSetSort(nodes2);
2387 return(xmlXPathNodeLeadingSorted(nodes1,
2388 xmlXPathNodeSetItem(nodes2, 1)));
2389}
2390
2391/**
2392 * xmlXPathNodeTrailingSorted:
2393 * @nodes: a node-set, sorted by document order
2394 * @node: a node
2395 *
2396 * Implements the EXSLT - Sets trailing() function:
2397 * node-set set:trailing (node-set, node-set)
2398 *
2399 * Returns the nodes in @nodes that follow @node in document order,
2400 * @nodes if @node is NULL or an empty node-set if @nodes
2401 * doesn't contain @node
2402 */
2403xmlNodeSetPtr
2404xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2405 int i, l;
2406 xmlNodePtr cur;
2407 xmlNodeSetPtr ret;
2408
2409 if (node == NULL)
2410 return(nodes);
2411
2412 ret = xmlXPathNodeSetCreate(NULL);
2413 if (xmlXPathNodeSetIsEmpty(nodes) ||
2414 (!xmlXPathNodeSetContains(nodes, node)))
2415 return(ret);
2416
2417 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002418 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002419 cur = xmlXPathNodeSetItem(nodes, i);
2420 if (cur == node)
2421 break;
2422 xmlXPathNodeSetAddUnique(ret, cur);
2423 }
2424 return(ret);
2425}
2426
2427/**
2428 * xmlXPathNodeTrailing:
2429 * @nodes: a node-set
2430 * @node: a node
2431 *
2432 * Implements the EXSLT - Sets trailing() function:
2433 * node-set set:trailing (node-set, node-set)
2434 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2435 * is called.
2436 *
2437 * Returns the nodes in @nodes that follow @node in document order,
2438 * @nodes if @node is NULL or an empty node-set if @nodes
2439 * doesn't contain @node
2440 */
2441xmlNodeSetPtr
2442xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2443 xmlXPathNodeSetSort(nodes);
2444 return(xmlXPathNodeTrailingSorted(nodes, node));
2445}
2446
2447/**
2448 * xmlXPathTrailingSorted:
2449 * @nodes1: a node-set, sorted by document order
2450 * @nodes2: a node-set, sorted by document order
2451 *
2452 * Implements the EXSLT - Sets trailing() function:
2453 * node-set set:trailing (node-set, node-set)
2454 *
2455 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2456 * in document order, @nodes1 if @nodes2 is NULL or empty or
2457 * an empty node-set if @nodes1 doesn't contain @nodes2
2458 */
2459xmlNodeSetPtr
2460xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2461 if (xmlXPathNodeSetIsEmpty(nodes2))
2462 return(nodes1);
2463 return(xmlXPathNodeTrailingSorted(nodes1,
2464 xmlXPathNodeSetItem(nodes2, 0)));
2465}
2466
2467/**
2468 * xmlXPathTrailing:
2469 * @nodes1: a node-set
2470 * @nodes2: a node-set
2471 *
2472 * Implements the EXSLT - Sets trailing() function:
2473 * node-set set:trailing (node-set, node-set)
2474 * @nodes1 and @nodes2 are sorted by document order, then
2475 * #xmlXPathTrailingSorted is called.
2476 *
2477 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2478 * in document order, @nodes1 if @nodes2 is NULL or empty or
2479 * an empty node-set if @nodes1 doesn't contain @nodes2
2480 */
2481xmlNodeSetPtr
2482xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2483 if (xmlXPathNodeSetIsEmpty(nodes2))
2484 return(nodes1);
2485 if (xmlXPathNodeSetIsEmpty(nodes1))
2486 return(xmlXPathNodeSetCreate(NULL));
2487 xmlXPathNodeSetSort(nodes1);
2488 xmlXPathNodeSetSort(nodes2);
2489 return(xmlXPathNodeTrailingSorted(nodes1,
2490 xmlXPathNodeSetItem(nodes2, 0)));
2491}
2492
Owen Taylor3473f882001-02-23 17:55:21 +00002493/************************************************************************
2494 * *
2495 * Routines to handle extra functions *
2496 * *
2497 ************************************************************************/
2498
2499/**
2500 * xmlXPathRegisterFunc:
2501 * @ctxt: the XPath context
2502 * @name: the function name
2503 * @f: the function implementation or NULL
2504 *
2505 * Register a new function. If @f is NULL it unregisters the function
2506 *
2507 * Returns 0 in case of success, -1 in case of error
2508 */
2509int
2510xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2511 xmlXPathFunction f) {
2512 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2513}
2514
2515/**
2516 * xmlXPathRegisterFuncNS:
2517 * @ctxt: the XPath context
2518 * @name: the function name
2519 * @ns_uri: the function namespace URI
2520 * @f: the function implementation or NULL
2521 *
2522 * Register a new function. If @f is NULL it unregisters the function
2523 *
2524 * Returns 0 in case of success, -1 in case of error
2525 */
2526int
2527xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2528 const xmlChar *ns_uri, xmlXPathFunction f) {
2529 if (ctxt == NULL)
2530 return(-1);
2531 if (name == NULL)
2532 return(-1);
2533
2534 if (ctxt->funcHash == NULL)
2535 ctxt->funcHash = xmlHashCreate(0);
2536 if (ctxt->funcHash == NULL)
2537 return(-1);
2538 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2539}
2540
2541/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002542 * xmlXPathRegisterFuncLookup:
2543 * @ctxt: the XPath context
2544 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002545 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002546 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002547 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002548 */
2549void
2550xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2551 xmlXPathFuncLookupFunc f,
2552 void *funcCtxt) {
2553 if (ctxt == NULL)
2554 return;
2555 ctxt->funcLookupFunc = (void *) f;
2556 ctxt->funcLookupData = funcCtxt;
2557}
2558
2559/**
Owen Taylor3473f882001-02-23 17:55:21 +00002560 * xmlXPathFunctionLookup:
2561 * @ctxt: the XPath context
2562 * @name: the function name
2563 *
2564 * Search in the Function array of the context for the given
2565 * function.
2566 *
2567 * Returns the xmlXPathFunction or NULL if not found
2568 */
2569xmlXPathFunction
2570xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002571 if (ctxt == NULL)
2572 return (NULL);
2573
2574 if (ctxt->funcLookupFunc != NULL) {
2575 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002576 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002577
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002578 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002579 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002580 if (ret != NULL)
2581 return(ret);
2582 }
Owen Taylor3473f882001-02-23 17:55:21 +00002583 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2584}
2585
2586/**
2587 * xmlXPathFunctionLookupNS:
2588 * @ctxt: the XPath context
2589 * @name: the function name
2590 * @ns_uri: the function namespace URI
2591 *
2592 * Search in the Function array of the context for the given
2593 * function.
2594 *
2595 * Returns the xmlXPathFunction or NULL if not found
2596 */
2597xmlXPathFunction
2598xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2599 const xmlChar *ns_uri) {
2600 if (ctxt == NULL)
2601 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002602 if (name == NULL)
2603 return(NULL);
2604
Thomas Broyerba4ad322001-07-26 16:55:21 +00002605 if (ctxt->funcLookupFunc != NULL) {
2606 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002607 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002608
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002609 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002610 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002611 if (ret != NULL)
2612 return(ret);
2613 }
2614
2615 if (ctxt->funcHash == NULL)
2616 return(NULL);
2617
Owen Taylor3473f882001-02-23 17:55:21 +00002618 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2619}
2620
2621/**
2622 * xmlXPathRegisteredFuncsCleanup:
2623 * @ctxt: the XPath context
2624 *
2625 * Cleanup the XPath context data associated to registered functions
2626 */
2627void
2628xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2629 if (ctxt == NULL)
2630 return;
2631
2632 xmlHashFree(ctxt->funcHash, NULL);
2633 ctxt->funcHash = NULL;
2634}
2635
2636/************************************************************************
2637 * *
2638 * Routines to handle Variable *
2639 * *
2640 ************************************************************************/
2641
2642/**
2643 * xmlXPathRegisterVariable:
2644 * @ctxt: the XPath context
2645 * @name: the variable name
2646 * @value: the variable value or NULL
2647 *
2648 * Register a new variable value. If @value is NULL it unregisters
2649 * the variable
2650 *
2651 * Returns 0 in case of success, -1 in case of error
2652 */
2653int
2654xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2655 xmlXPathObjectPtr value) {
2656 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2657}
2658
2659/**
2660 * xmlXPathRegisterVariableNS:
2661 * @ctxt: the XPath context
2662 * @name: the variable name
2663 * @ns_uri: the variable namespace URI
2664 * @value: the variable value or NULL
2665 *
2666 * Register a new variable value. If @value is NULL it unregisters
2667 * the variable
2668 *
2669 * Returns 0 in case of success, -1 in case of error
2670 */
2671int
2672xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2673 const xmlChar *ns_uri,
2674 xmlXPathObjectPtr value) {
2675 if (ctxt == NULL)
2676 return(-1);
2677 if (name == NULL)
2678 return(-1);
2679
2680 if (ctxt->varHash == NULL)
2681 ctxt->varHash = xmlHashCreate(0);
2682 if (ctxt->varHash == NULL)
2683 return(-1);
2684 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2685 (void *) value,
2686 (xmlHashDeallocator)xmlXPathFreeObject));
2687}
2688
2689/**
2690 * xmlXPathRegisterVariableLookup:
2691 * @ctxt: the XPath context
2692 * @f: the lookup function
2693 * @data: the lookup data
2694 *
2695 * register an external mechanism to do variable lookup
2696 */
2697void
2698xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2699 xmlXPathVariableLookupFunc f, void *data) {
2700 if (ctxt == NULL)
2701 return;
2702 ctxt->varLookupFunc = (void *) f;
2703 ctxt->varLookupData = data;
2704}
2705
2706/**
2707 * xmlXPathVariableLookup:
2708 * @ctxt: the XPath context
2709 * @name: the variable name
2710 *
2711 * Search in the Variable array of the context for the given
2712 * variable value.
2713 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002714 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002715 */
2716xmlXPathObjectPtr
2717xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2718 if (ctxt == NULL)
2719 return(NULL);
2720
2721 if (ctxt->varLookupFunc != NULL) {
2722 xmlXPathObjectPtr ret;
2723
2724 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2725 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002726 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002727 }
2728 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2729}
2730
2731/**
2732 * xmlXPathVariableLookupNS:
2733 * @ctxt: the XPath context
2734 * @name: the variable name
2735 * @ns_uri: the variable namespace URI
2736 *
2737 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002738 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002739 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002740 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002741 */
2742xmlXPathObjectPtr
2743xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2744 const xmlChar *ns_uri) {
2745 if (ctxt == NULL)
2746 return(NULL);
2747
2748 if (ctxt->varLookupFunc != NULL) {
2749 xmlXPathObjectPtr ret;
2750
2751 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2752 (ctxt->varLookupData, name, ns_uri);
2753 if (ret != NULL) return(ret);
2754 }
2755
2756 if (ctxt->varHash == NULL)
2757 return(NULL);
2758 if (name == NULL)
2759 return(NULL);
2760
Daniel Veillard8c357d52001-07-03 23:43:33 +00002761 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2762 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002763}
2764
2765/**
2766 * xmlXPathRegisteredVariablesCleanup:
2767 * @ctxt: the XPath context
2768 *
2769 * Cleanup the XPath context data associated to registered variables
2770 */
2771void
2772xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2773 if (ctxt == NULL)
2774 return;
2775
Daniel Veillard76d66f42001-05-16 21:05:17 +00002776 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002777 ctxt->varHash = NULL;
2778}
2779
2780/**
2781 * xmlXPathRegisterNs:
2782 * @ctxt: the XPath context
2783 * @prefix: the namespace prefix
2784 * @ns_uri: the namespace name
2785 *
2786 * Register a new namespace. If @ns_uri is NULL it unregisters
2787 * the namespace
2788 *
2789 * Returns 0 in case of success, -1 in case of error
2790 */
2791int
2792xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2793 const xmlChar *ns_uri) {
2794 if (ctxt == NULL)
2795 return(-1);
2796 if (prefix == NULL)
2797 return(-1);
2798
2799 if (ctxt->nsHash == NULL)
2800 ctxt->nsHash = xmlHashCreate(10);
2801 if (ctxt->nsHash == NULL)
2802 return(-1);
2803 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) ns_uri,
2804 (xmlHashDeallocator)xmlFree));
2805}
2806
2807/**
2808 * xmlXPathNsLookup:
2809 * @ctxt: the XPath context
2810 * @prefix: the namespace prefix value
2811 *
2812 * Search in the namespace declaration array of the context for the given
2813 * namespace name associated to the given prefix
2814 *
2815 * Returns the value or NULL if not found
2816 */
2817const xmlChar *
2818xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2819 if (ctxt == NULL)
2820 return(NULL);
2821 if (prefix == NULL)
2822 return(NULL);
2823
2824#ifdef XML_XML_NAMESPACE
2825 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
2826 return(XML_XML_NAMESPACE);
2827#endif
2828
Daniel Veillardc8f620b2001-04-30 20:31:33 +00002829 if (ctxt->namespaces != NULL) {
2830 int i;
2831
2832 for (i = 0;i < ctxt->nsNr;i++) {
2833 if ((ctxt->namespaces[i] != NULL) &&
2834 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
2835 return(ctxt->namespaces[i]->href);
2836 }
2837 }
Owen Taylor3473f882001-02-23 17:55:21 +00002838
2839 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
2840}
2841
2842/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002843 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00002844 * @ctxt: the XPath context
2845 *
2846 * Cleanup the XPath context data associated to registered variables
2847 */
2848void
2849xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2850 if (ctxt == NULL)
2851 return;
2852
2853 xmlHashFree(ctxt->nsHash, NULL);
2854 ctxt->nsHash = NULL;
2855}
2856
2857/************************************************************************
2858 * *
2859 * Routines to handle Values *
2860 * *
2861 ************************************************************************/
2862
2863/* Allocations are terrible, one need to optimize all this !!! */
2864
2865/**
2866 * xmlXPathNewFloat:
2867 * @val: the double value
2868 *
2869 * Create a new xmlXPathObjectPtr of type double and of value @val
2870 *
2871 * Returns the newly created object.
2872 */
2873xmlXPathObjectPtr
2874xmlXPathNewFloat(double val) {
2875 xmlXPathObjectPtr ret;
2876
2877 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2878 if (ret == NULL) {
2879 xmlGenericError(xmlGenericErrorContext,
2880 "xmlXPathNewFloat: out of memory\n");
2881 return(NULL);
2882 }
2883 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2884 ret->type = XPATH_NUMBER;
2885 ret->floatval = val;
2886 return(ret);
2887}
2888
2889/**
2890 * xmlXPathNewBoolean:
2891 * @val: the boolean value
2892 *
2893 * Create a new xmlXPathObjectPtr of type boolean and of value @val
2894 *
2895 * Returns the newly created object.
2896 */
2897xmlXPathObjectPtr
2898xmlXPathNewBoolean(int val) {
2899 xmlXPathObjectPtr ret;
2900
2901 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2902 if (ret == NULL) {
2903 xmlGenericError(xmlGenericErrorContext,
2904 "xmlXPathNewBoolean: out of memory\n");
2905 return(NULL);
2906 }
2907 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2908 ret->type = XPATH_BOOLEAN;
2909 ret->boolval = (val != 0);
2910 return(ret);
2911}
2912
2913/**
2914 * xmlXPathNewString:
2915 * @val: the xmlChar * value
2916 *
2917 * Create a new xmlXPathObjectPtr of type string and of value @val
2918 *
2919 * Returns the newly created object.
2920 */
2921xmlXPathObjectPtr
2922xmlXPathNewString(const xmlChar *val) {
2923 xmlXPathObjectPtr ret;
2924
2925 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2926 if (ret == NULL) {
2927 xmlGenericError(xmlGenericErrorContext,
2928 "xmlXPathNewString: out of memory\n");
2929 return(NULL);
2930 }
2931 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2932 ret->type = XPATH_STRING;
2933 if (val != NULL)
2934 ret->stringval = xmlStrdup(val);
2935 else
2936 ret->stringval = xmlStrdup((const xmlChar *)"");
2937 return(ret);
2938}
2939
2940/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002941 * xmlXPathWrapString:
2942 * @val: the xmlChar * value
2943 *
2944 * Wraps the @val string into an XPath object.
2945 *
2946 * Returns the newly created object.
2947 */
2948xmlXPathObjectPtr
2949xmlXPathWrapString (xmlChar *val) {
2950 xmlXPathObjectPtr ret;
2951
2952 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2953 if (ret == NULL) {
2954 xmlGenericError(xmlGenericErrorContext,
2955 "xmlXPathWrapString: out of memory\n");
2956 return(NULL);
2957 }
2958 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2959 ret->type = XPATH_STRING;
2960 ret->stringval = val;
2961 return(ret);
2962}
2963
2964/**
Owen Taylor3473f882001-02-23 17:55:21 +00002965 * xmlXPathNewCString:
2966 * @val: the char * value
2967 *
2968 * Create a new xmlXPathObjectPtr of type string and of value @val
2969 *
2970 * Returns the newly created object.
2971 */
2972xmlXPathObjectPtr
2973xmlXPathNewCString(const char *val) {
2974 xmlXPathObjectPtr ret;
2975
2976 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2977 if (ret == NULL) {
2978 xmlGenericError(xmlGenericErrorContext,
2979 "xmlXPathNewCString: out of memory\n");
2980 return(NULL);
2981 }
2982 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2983 ret->type = XPATH_STRING;
2984 ret->stringval = xmlStrdup(BAD_CAST val);
2985 return(ret);
2986}
2987
2988/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002989 * xmlXPathWrapCString:
2990 * @val: the char * value
2991 *
2992 * Wraps a string into an XPath object.
2993 *
2994 * Returns the newly created object.
2995 */
2996xmlXPathObjectPtr
2997xmlXPathWrapCString (char * val) {
2998 return(xmlXPathWrapString((xmlChar *)(val)));
2999}
3000
3001/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003002 * xmlXPathWrapExternal:
3003 * @val: the user data
3004 *
3005 * Wraps the @val data into an XPath object.
3006 *
3007 * Returns the newly created object.
3008 */
3009xmlXPathObjectPtr
3010xmlXPathWrapExternal (void *val) {
3011 xmlXPathObjectPtr ret;
3012
3013 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3014 if (ret == NULL) {
3015 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003016 "xmlXPathWrapExternal: out of memory\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003017 return(NULL);
3018 }
3019 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3020 ret->type = XPATH_USERS;
3021 ret->user = val;
3022 return(ret);
3023}
3024
3025/**
Owen Taylor3473f882001-02-23 17:55:21 +00003026 * xmlXPathObjectCopy:
3027 * @val: the original object
3028 *
3029 * allocate a new copy of a given object
3030 *
3031 * Returns the newly created object.
3032 */
3033xmlXPathObjectPtr
3034xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3035 xmlXPathObjectPtr ret;
3036
3037 if (val == NULL)
3038 return(NULL);
3039
3040 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3041 if (ret == NULL) {
3042 xmlGenericError(xmlGenericErrorContext,
3043 "xmlXPathObjectCopy: out of memory\n");
3044 return(NULL);
3045 }
3046 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3047 switch (val->type) {
3048 case XPATH_BOOLEAN:
3049 case XPATH_NUMBER:
3050 case XPATH_POINT:
3051 case XPATH_RANGE:
3052 break;
3053 case XPATH_STRING:
3054 ret->stringval = xmlStrdup(val->stringval);
3055 break;
3056 case XPATH_XSLT_TREE:
3057 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003058 (val->nodesetval->nodeTab != NULL)) {
3059 ret->boolval = 1;
Daniel Veillard6ab38382001-10-06 13:08:27 +00003060 ret->user = xmlDocCopyNode(val->nodesetval->nodeTab[0],
3061 val->nodesetval->nodeTab[0]->doc, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003062 ret->nodesetval = xmlXPathNodeSetCreate(
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003063 (xmlNodePtr) ret->user);
3064 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003065 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003066 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003067 break;
3068 case XPATH_NODESET:
3069 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003070 /* Do not deallocate the copied tree value */
3071 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003072 break;
3073 case XPATH_LOCATIONSET:
3074#ifdef LIBXML_XPTR_ENABLED
3075 {
3076 xmlLocationSetPtr loc = val->user;
3077 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3078 break;
3079 }
3080#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003081 case XPATH_USERS:
3082 ret->user = val->user;
3083 break;
3084 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003085 xmlGenericError(xmlGenericErrorContext,
3086 "xmlXPathObjectCopy: unsupported type %d\n",
3087 val->type);
3088 break;
3089 }
3090 return(ret);
3091}
3092
3093/**
3094 * xmlXPathFreeObject:
3095 * @obj: the object to free
3096 *
3097 * Free up an xmlXPathObjectPtr object.
3098 */
3099void
3100xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3101 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003102 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003103 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003104 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003105 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003106 xmlFreeNodeList((xmlNodePtr) obj->user);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003107 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003108 xmlXPathFreeValueTree(obj->nodesetval);
3109 } else {
3110 if (obj->nodesetval != NULL)
3111 xmlXPathFreeNodeSet(obj->nodesetval);
3112 }
Owen Taylor3473f882001-02-23 17:55:21 +00003113#ifdef LIBXML_XPTR_ENABLED
3114 } else if (obj->type == XPATH_LOCATIONSET) {
3115 if (obj->user != NULL)
3116 xmlXPtrFreeLocationSet(obj->user);
3117#endif
3118 } else if (obj->type == XPATH_STRING) {
3119 if (obj->stringval != NULL)
3120 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003121 }
3122
Owen Taylor3473f882001-02-23 17:55:21 +00003123 xmlFree(obj);
3124}
3125
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003126
3127/************************************************************************
3128 * *
3129 * Type Casting Routines *
3130 * *
3131 ************************************************************************/
3132
3133/**
3134 * xmlXPathCastBooleanToString:
3135 * @val: a boolean
3136 *
3137 * Converts a boolean to its string value.
3138 *
3139 * Returns a newly allocated string.
3140 */
3141xmlChar *
3142xmlXPathCastBooleanToString (int val) {
3143 xmlChar *ret;
3144 if (val)
3145 ret = xmlStrdup((const xmlChar *) "true");
3146 else
3147 ret = xmlStrdup((const xmlChar *) "false");
3148 return(ret);
3149}
3150
3151/**
3152 * xmlXPathCastNumberToString:
3153 * @val: a number
3154 *
3155 * Converts a number to its string value.
3156 *
3157 * Returns a newly allocated string.
3158 */
3159xmlChar *
3160xmlXPathCastNumberToString (double val) {
3161 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003162 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003163 case 1:
3164 ret = xmlStrdup((const xmlChar *) "+Infinity");
3165 break;
3166 case -1:
3167 ret = xmlStrdup((const xmlChar *) "-Infinity");
3168 break;
3169 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003170 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003171 ret = xmlStrdup((const xmlChar *) "NaN");
3172 } else {
3173 /* could be improved */
3174 char buf[100];
3175 xmlXPathFormatNumber(val, buf, 100);
3176 ret = xmlStrdup((const xmlChar *) buf);
3177 }
3178 }
3179 return(ret);
3180}
3181
3182/**
3183 * xmlXPathCastNodeToString:
3184 * @node: a node
3185 *
3186 * Converts a node to its string value.
3187 *
3188 * Returns a newly allocated string.
3189 */
3190xmlChar *
3191xmlXPathCastNodeToString (xmlNodePtr node) {
3192 return(xmlNodeGetContent(node));
3193}
3194
3195/**
3196 * xmlXPathCastNodeSetToString:
3197 * @ns: a node-set
3198 *
3199 * Converts a node-set to its string value.
3200 *
3201 * Returns a newly allocated string.
3202 */
3203xmlChar *
3204xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3205 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3206 return(xmlStrdup((const xmlChar *) ""));
3207
3208 xmlXPathNodeSetSort(ns);
3209 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3210}
3211
3212/**
3213 * xmlXPathCastToString:
3214 * @val: an XPath object
3215 *
3216 * Converts an existing object to its string() equivalent
3217 *
3218 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003219 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003220 * string object).
3221 */
3222xmlChar *
3223xmlXPathCastToString(xmlXPathObjectPtr val) {
3224 xmlChar *ret = NULL;
3225
3226 if (val == NULL)
3227 return(xmlStrdup((const xmlChar *) ""));
3228 switch (val->type) {
3229 case XPATH_UNDEFINED:
3230#ifdef DEBUG_EXPR
3231 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3232#endif
3233 ret = xmlStrdup((const xmlChar *) "");
3234 break;
3235 case XPATH_XSLT_TREE:
3236 case XPATH_NODESET:
3237 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3238 break;
3239 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003240 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003241 case XPATH_BOOLEAN:
3242 ret = xmlXPathCastBooleanToString(val->boolval);
3243 break;
3244 case XPATH_NUMBER: {
3245 ret = xmlXPathCastNumberToString(val->floatval);
3246 break;
3247 }
3248 case XPATH_USERS:
3249 case XPATH_POINT:
3250 case XPATH_RANGE:
3251 case XPATH_LOCATIONSET:
3252 TODO
3253 ret = xmlStrdup((const xmlChar *) "");
3254 break;
3255 }
3256 return(ret);
3257}
3258
3259/**
3260 * xmlXPathConvertString:
3261 * @val: an XPath object
3262 *
3263 * Converts an existing object to its string() equivalent
3264 *
3265 * Returns the new object, the old one is freed (or the operation
3266 * is done directly on @val)
3267 */
3268xmlXPathObjectPtr
3269xmlXPathConvertString(xmlXPathObjectPtr val) {
3270 xmlChar *res = NULL;
3271
3272 if (val == NULL)
3273 return(xmlXPathNewCString(""));
3274
3275 switch (val->type) {
3276 case XPATH_UNDEFINED:
3277#ifdef DEBUG_EXPR
3278 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3279#endif
3280 break;
3281 case XPATH_XSLT_TREE:
3282 case XPATH_NODESET:
3283 res = xmlXPathCastNodeSetToString(val->nodesetval);
3284 break;
3285 case XPATH_STRING:
3286 return(val);
3287 case XPATH_BOOLEAN:
3288 res = xmlXPathCastBooleanToString(val->boolval);
3289 break;
3290 case XPATH_NUMBER:
3291 res = xmlXPathCastNumberToString(val->floatval);
3292 break;
3293 case XPATH_USERS:
3294 case XPATH_POINT:
3295 case XPATH_RANGE:
3296 case XPATH_LOCATIONSET:
3297 TODO;
3298 break;
3299 }
3300 xmlXPathFreeObject(val);
3301 if (res == NULL)
3302 return(xmlXPathNewCString(""));
3303 return(xmlXPathWrapString(res));
3304}
3305
3306/**
3307 * xmlXPathCastBooleanToNumber:
3308 * @val: a boolean
3309 *
3310 * Converts a boolean to its number value
3311 *
3312 * Returns the number value
3313 */
3314double
3315xmlXPathCastBooleanToNumber(int val) {
3316 if (val)
3317 return(1.0);
3318 return(0.0);
3319}
3320
3321/**
3322 * xmlXPathCastStringToNumber:
3323 * @val: a string
3324 *
3325 * Converts a string to its number value
3326 *
3327 * Returns the number value
3328 */
3329double
3330xmlXPathCastStringToNumber(const xmlChar * val) {
3331 return(xmlXPathStringEvalNumber(val));
3332}
3333
3334/**
3335 * xmlXPathCastNodeToNumber:
3336 * @node: a node
3337 *
3338 * Converts a node to its number value
3339 *
3340 * Returns the number value
3341 */
3342double
3343xmlXPathCastNodeToNumber (xmlNodePtr node) {
3344 xmlChar *strval;
3345 double ret;
3346
3347 if (node == NULL)
3348 return(xmlXPathNAN);
3349 strval = xmlXPathCastNodeToString(node);
3350 if (strval == NULL)
3351 return(xmlXPathNAN);
3352 ret = xmlXPathCastStringToNumber(strval);
3353 xmlFree(strval);
3354
3355 return(ret);
3356}
3357
3358/**
3359 * xmlXPathCastNodeSetToNumber:
3360 * @ns: a node-set
3361 *
3362 * Converts a node-set to its number value
3363 *
3364 * Returns the number value
3365 */
3366double
3367xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3368 xmlChar *str;
3369 double ret;
3370
3371 if (ns == NULL)
3372 return(xmlXPathNAN);
3373 str = xmlXPathCastNodeSetToString(ns);
3374 ret = xmlXPathCastStringToNumber(str);
3375 xmlFree(str);
3376 return(ret);
3377}
3378
3379/**
3380 * xmlXPathCastToNumber:
3381 * @val: an XPath object
3382 *
3383 * Converts an XPath object to its number value
3384 *
3385 * Returns the number value
3386 */
3387double
3388xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3389 double ret = 0.0;
3390
3391 if (val == NULL)
3392 return(xmlXPathNAN);
3393 switch (val->type) {
3394 case XPATH_UNDEFINED:
3395#ifdef DEGUB_EXPR
3396 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3397#endif
3398 ret = xmlXPathNAN;
3399 break;
3400 case XPATH_XSLT_TREE:
3401 case XPATH_NODESET:
3402 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3403 break;
3404 case XPATH_STRING:
3405 ret = xmlXPathCastStringToNumber(val->stringval);
3406 break;
3407 case XPATH_NUMBER:
3408 ret = val->floatval;
3409 break;
3410 case XPATH_BOOLEAN:
3411 ret = xmlXPathCastBooleanToNumber(val->boolval);
3412 break;
3413 case XPATH_USERS:
3414 case XPATH_POINT:
3415 case XPATH_RANGE:
3416 case XPATH_LOCATIONSET:
3417 TODO;
3418 ret = xmlXPathNAN;
3419 break;
3420 }
3421 return(ret);
3422}
3423
3424/**
3425 * xmlXPathConvertNumber:
3426 * @val: an XPath object
3427 *
3428 * Converts an existing object to its number() equivalent
3429 *
3430 * Returns the new object, the old one is freed (or the operation
3431 * is done directly on @val)
3432 */
3433xmlXPathObjectPtr
3434xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3435 xmlXPathObjectPtr ret;
3436
3437 if (val == NULL)
3438 return(xmlXPathNewFloat(0.0));
3439 if (val->type == XPATH_NUMBER)
3440 return(val);
3441 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3442 xmlXPathFreeObject(val);
3443 return(ret);
3444}
3445
3446/**
3447 * xmlXPathCastNumberToBoolean:
3448 * @val: a number
3449 *
3450 * Converts a number to its boolean value
3451 *
3452 * Returns the boolean value
3453 */
3454int
3455xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003456 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003457 return(0);
3458 return(1);
3459}
3460
3461/**
3462 * xmlXPathCastStringToBoolean:
3463 * @val: a string
3464 *
3465 * Converts a string to its boolean value
3466 *
3467 * Returns the boolean value
3468 */
3469int
3470xmlXPathCastStringToBoolean (const xmlChar *val) {
3471 if ((val == NULL) || (xmlStrlen(val) == 0))
3472 return(0);
3473 return(1);
3474}
3475
3476/**
3477 * xmlXPathCastNodeSetToBoolean:
3478 * @ns: a node-set
3479 *
3480 * Converts a node-set to its boolean value
3481 *
3482 * Returns the boolean value
3483 */
3484int
3485xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3486 if ((ns == NULL) || (ns->nodeNr == 0))
3487 return(0);
3488 return(1);
3489}
3490
3491/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003492 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003493 * @val: an XPath object
3494 *
3495 * Converts an XPath object to its boolean value
3496 *
3497 * Returns the boolean value
3498 */
3499int
3500xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3501 int ret = 0;
3502
3503 if (val == NULL)
3504 return(0);
3505 switch (val->type) {
3506 case XPATH_UNDEFINED:
3507#ifdef DEBUG_EXPR
3508 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3509#endif
3510 ret = 0;
3511 break;
3512 case XPATH_XSLT_TREE:
3513 case XPATH_NODESET:
3514 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3515 break;
3516 case XPATH_STRING:
3517 ret = xmlXPathCastStringToBoolean(val->stringval);
3518 break;
3519 case XPATH_NUMBER:
3520 ret = xmlXPathCastNumberToBoolean(val->floatval);
3521 break;
3522 case XPATH_BOOLEAN:
3523 ret = val->boolval;
3524 break;
3525 case XPATH_USERS:
3526 case XPATH_POINT:
3527 case XPATH_RANGE:
3528 case XPATH_LOCATIONSET:
3529 TODO;
3530 ret = 0;
3531 break;
3532 }
3533 return(ret);
3534}
3535
3536
3537/**
3538 * xmlXPathConvertBoolean:
3539 * @val: an XPath object
3540 *
3541 * Converts an existing object to its boolean() equivalent
3542 *
3543 * Returns the new object, the old one is freed (or the operation
3544 * is done directly on @val)
3545 */
3546xmlXPathObjectPtr
3547xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3548 xmlXPathObjectPtr ret;
3549
3550 if (val == NULL)
3551 return(xmlXPathNewBoolean(0));
3552 if (val->type == XPATH_BOOLEAN)
3553 return(val);
3554 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3555 xmlXPathFreeObject(val);
3556 return(ret);
3557}
3558
Owen Taylor3473f882001-02-23 17:55:21 +00003559/************************************************************************
3560 * *
3561 * Routines to handle XPath contexts *
3562 * *
3563 ************************************************************************/
3564
3565/**
3566 * xmlXPathNewContext:
3567 * @doc: the XML document
3568 *
3569 * Create a new xmlXPathContext
3570 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003571 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003572 */
3573xmlXPathContextPtr
3574xmlXPathNewContext(xmlDocPtr doc) {
3575 xmlXPathContextPtr ret;
3576
3577 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3578 if (ret == NULL) {
3579 xmlGenericError(xmlGenericErrorContext,
3580 "xmlXPathNewContext: out of memory\n");
3581 return(NULL);
3582 }
3583 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3584 ret->doc = doc;
3585 ret->node = NULL;
3586
3587 ret->varHash = NULL;
3588
3589 ret->nb_types = 0;
3590 ret->max_types = 0;
3591 ret->types = NULL;
3592
3593 ret->funcHash = xmlHashCreate(0);
3594
3595 ret->nb_axis = 0;
3596 ret->max_axis = 0;
3597 ret->axis = NULL;
3598
3599 ret->nsHash = NULL;
3600 ret->user = NULL;
3601
3602 ret->contextSize = -1;
3603 ret->proximityPosition = -1;
3604
3605 xmlXPathRegisterAllFunctions(ret);
3606
3607 return(ret);
3608}
3609
3610/**
3611 * xmlXPathFreeContext:
3612 * @ctxt: the context to free
3613 *
3614 * Free up an xmlXPathContext
3615 */
3616void
3617xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3618 xmlXPathRegisteredNsCleanup(ctxt);
3619 xmlXPathRegisteredFuncsCleanup(ctxt);
3620 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003621 xmlFree(ctxt);
3622}
3623
3624/************************************************************************
3625 * *
3626 * Routines to handle XPath parser contexts *
3627 * *
3628 ************************************************************************/
3629
3630#define CHECK_CTXT(ctxt) \
3631 if (ctxt == NULL) { \
3632 xmlGenericError(xmlGenericErrorContext, \
3633 "%s:%d Internal error: ctxt == NULL\n", \
3634 __FILE__, __LINE__); \
3635 } \
3636
3637
3638#define CHECK_CONTEXT(ctxt) \
3639 if (ctxt == NULL) { \
3640 xmlGenericError(xmlGenericErrorContext, \
3641 "%s:%d Internal error: no context\n", \
3642 __FILE__, __LINE__); \
3643 } \
3644 else if (ctxt->doc == NULL) { \
3645 xmlGenericError(xmlGenericErrorContext, \
3646 "%s:%d Internal error: no document\n", \
3647 __FILE__, __LINE__); \
3648 } \
3649 else if (ctxt->doc->children == NULL) { \
3650 xmlGenericError(xmlGenericErrorContext, \
3651 "%s:%d Internal error: document without root\n", \
3652 __FILE__, __LINE__); \
3653 } \
3654
3655
3656/**
3657 * xmlXPathNewParserContext:
3658 * @str: the XPath expression
3659 * @ctxt: the XPath context
3660 *
3661 * Create a new xmlXPathParserContext
3662 *
3663 * Returns the xmlXPathParserContext just allocated.
3664 */
3665xmlXPathParserContextPtr
3666xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3667 xmlXPathParserContextPtr ret;
3668
3669 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3670 if (ret == NULL) {
3671 xmlGenericError(xmlGenericErrorContext,
3672 "xmlXPathNewParserContext: out of memory\n");
3673 return(NULL);
3674 }
3675 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3676 ret->cur = ret->base = str;
3677 ret->context = ctxt;
3678
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003679 ret->comp = xmlXPathNewCompExpr();
3680 if (ret->comp == NULL) {
3681 xmlFree(ret->valueTab);
3682 xmlFree(ret);
3683 return(NULL);
3684 }
3685
3686 return(ret);
3687}
3688
3689/**
3690 * xmlXPathCompParserContext:
3691 * @comp: the XPath compiled expression
3692 * @ctxt: the XPath context
3693 *
3694 * Create a new xmlXPathParserContext when processing a compiled expression
3695 *
3696 * Returns the xmlXPathParserContext just allocated.
3697 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003698static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003699xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3700 xmlXPathParserContextPtr ret;
3701
3702 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3703 if (ret == NULL) {
3704 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003705 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003706 return(NULL);
3707 }
3708 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3709
Owen Taylor3473f882001-02-23 17:55:21 +00003710 /* Allocate the value stack */
3711 ret->valueTab = (xmlXPathObjectPtr *)
3712 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003713 if (ret->valueTab == NULL) {
3714 xmlFree(ret);
3715 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003716 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003717 return(NULL);
3718 }
Owen Taylor3473f882001-02-23 17:55:21 +00003719 ret->valueNr = 0;
3720 ret->valueMax = 10;
3721 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003722
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003723 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003724 ret->comp = comp;
3725
Owen Taylor3473f882001-02-23 17:55:21 +00003726 return(ret);
3727}
3728
3729/**
3730 * xmlXPathFreeParserContext:
3731 * @ctxt: the context to free
3732 *
3733 * Free up an xmlXPathParserContext
3734 */
3735void
3736xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3737 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003738 xmlFree(ctxt->valueTab);
3739 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003740 if (ctxt->comp)
3741 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003742 xmlFree(ctxt);
3743}
3744
3745/************************************************************************
3746 * *
3747 * The implicit core function library *
3748 * *
3749 ************************************************************************/
3750
Owen Taylor3473f882001-02-23 17:55:21 +00003751/**
Daniel Veillardf06307e2001-07-03 10:35:50 +00003752 * xmlXPathNodeStringHash:
3753 * @node: a node pointer
3754 *
3755 * Function computing the beginning of the string value of the node,
3756 * used to speed up comparisons
3757 *
3758 * Returns an int usable as a hash
3759 */
3760static unsigned int
3761xmlXPathNodeValHash(xmlNodePtr node) {
3762 int len = 2;
3763 const xmlChar * string = NULL;
3764 xmlNodePtr tmp = NULL;
3765 unsigned int ret = 0;
3766
3767 if (node == NULL)
3768 return(0);
3769
3770
3771 switch (node->type) {
3772 case XML_COMMENT_NODE:
3773 case XML_PI_NODE:
3774 case XML_CDATA_SECTION_NODE:
3775 case XML_TEXT_NODE:
3776 string = node->content;
3777 if (string == NULL)
3778 return(0);
3779 if (string[0] == 0)
3780 return(0);
3781 return(((unsigned int) string[0]) +
3782 (((unsigned int) string[1]) << 8));
3783 case XML_NAMESPACE_DECL:
3784 string = ((xmlNsPtr)node)->href;
3785 if (string == NULL)
3786 return(0);
3787 if (string[0] == 0)
3788 return(0);
3789 return(((unsigned int) string[0]) +
3790 (((unsigned int) string[1]) << 8));
3791 case XML_ATTRIBUTE_NODE:
3792 tmp = ((xmlAttrPtr) node)->children;
3793 break;
3794 case XML_ELEMENT_NODE:
3795 tmp = node->children;
3796 break;
3797 default:
3798 return(0);
3799 }
3800 while (tmp != NULL) {
3801 switch (tmp->type) {
3802 case XML_COMMENT_NODE:
3803 case XML_PI_NODE:
3804 case XML_CDATA_SECTION_NODE:
3805 case XML_TEXT_NODE:
3806 string = tmp->content;
3807 break;
3808 case XML_NAMESPACE_DECL:
3809 string = ((xmlNsPtr)tmp)->href;
3810 break;
3811 default:
3812 break;
3813 }
3814 if ((string != NULL) && (string[0] != 0)) {
3815 if (string[0] == 0)
3816 return(0);
3817 if (len == 1) {
3818 return(ret + (((unsigned int) string[0]) << 8));
3819 }
3820 if (string[1] == 0) {
3821 len = 1;
3822 ret = (unsigned int) string[0];
3823 } else {
3824 return(((unsigned int) string[0]) +
3825 (((unsigned int) string[1]) << 8));
3826 }
3827 }
3828 /*
3829 * Skip to next node
3830 */
3831 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
3832 if (tmp->children->type != XML_ENTITY_DECL) {
3833 tmp = tmp->children;
3834 continue;
3835 }
3836 }
3837 if (tmp == node)
3838 break;
3839
3840 if (tmp->next != NULL) {
3841 tmp = tmp->next;
3842 continue;
3843 }
3844
3845 do {
3846 tmp = tmp->parent;
3847 if (tmp == NULL)
3848 break;
3849 if (tmp == node) {
3850 tmp = NULL;
3851 break;
3852 }
3853 if (tmp->next != NULL) {
3854 tmp = tmp->next;
3855 break;
3856 }
3857 } while (tmp != NULL);
3858 }
3859 return(ret);
3860}
3861
3862/**
3863 * xmlXPathStringHash:
3864 * @string: a string
3865 *
3866 * Function computing the beginning of the string value of the node,
3867 * used to speed up comparisons
3868 *
3869 * Returns an int usable as a hash
3870 */
3871static unsigned int
3872xmlXPathStringHash(const xmlChar * string) {
3873 if (string == NULL)
3874 return((unsigned int) 0);
3875 if (string[0] == 0)
3876 return(0);
3877 return(((unsigned int) string[0]) +
3878 (((unsigned int) string[1]) << 8));
3879}
3880
3881/**
Owen Taylor3473f882001-02-23 17:55:21 +00003882 * xmlXPathCompareNodeSetFloat:
3883 * @ctxt: the XPath Parser context
3884 * @inf: less than (1) or greater than (0)
3885 * @strict: is the comparison strict
3886 * @arg: the node set
3887 * @f: the value
3888 *
3889 * Implement the compare operation between a nodeset and a number
3890 * @ns < @val (1, 1, ...
3891 * @ns <= @val (1, 0, ...
3892 * @ns > @val (0, 1, ...
3893 * @ns >= @val (0, 0, ...
3894 *
3895 * If one object to be compared is a node-set and the other is a number,
3896 * then the comparison will be true if and only if there is a node in the
3897 * node-set such that the result of performing the comparison on the number
3898 * to be compared and on the result of converting the string-value of that
3899 * node to a number using the number function is true.
3900 *
3901 * Returns 0 or 1 depending on the results of the test.
3902 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003903static int
Owen Taylor3473f882001-02-23 17:55:21 +00003904xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
3905 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
3906 int i, ret = 0;
3907 xmlNodeSetPtr ns;
3908 xmlChar *str2;
3909
3910 if ((f == NULL) || (arg == NULL) ||
3911 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3912 xmlXPathFreeObject(arg);
3913 xmlXPathFreeObject(f);
3914 return(0);
3915 }
3916 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003917 if (ns != NULL) {
3918 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003919 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003920 if (str2 != NULL) {
3921 valuePush(ctxt,
3922 xmlXPathNewString(str2));
3923 xmlFree(str2);
3924 xmlXPathNumberFunction(ctxt, 1);
3925 valuePush(ctxt, xmlXPathObjectCopy(f));
3926 ret = xmlXPathCompareValues(ctxt, inf, strict);
3927 if (ret)
3928 break;
3929 }
3930 }
Owen Taylor3473f882001-02-23 17:55:21 +00003931 }
3932 xmlXPathFreeObject(arg);
3933 xmlXPathFreeObject(f);
3934 return(ret);
3935}
3936
3937/**
3938 * xmlXPathCompareNodeSetString:
3939 * @ctxt: the XPath Parser context
3940 * @inf: less than (1) or greater than (0)
3941 * @strict: is the comparison strict
3942 * @arg: the node set
3943 * @s: the value
3944 *
3945 * Implement the compare operation between a nodeset and a string
3946 * @ns < @val (1, 1, ...
3947 * @ns <= @val (1, 0, ...
3948 * @ns > @val (0, 1, ...
3949 * @ns >= @val (0, 0, ...
3950 *
3951 * If one object to be compared is a node-set and the other is a string,
3952 * then the comparison will be true if and only if there is a node in
3953 * the node-set such that the result of performing the comparison on the
3954 * string-value of the node and the other string is true.
3955 *
3956 * Returns 0 or 1 depending on the results of the test.
3957 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003958static int
Owen Taylor3473f882001-02-23 17:55:21 +00003959xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
3960 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
3961 int i, ret = 0;
3962 xmlNodeSetPtr ns;
3963 xmlChar *str2;
3964
3965 if ((s == NULL) || (arg == NULL) ||
3966 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3967 xmlXPathFreeObject(arg);
3968 xmlXPathFreeObject(s);
3969 return(0);
3970 }
3971 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003972 if (ns != NULL) {
3973 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003974 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003975 if (str2 != NULL) {
3976 valuePush(ctxt,
3977 xmlXPathNewString(str2));
3978 xmlFree(str2);
3979 valuePush(ctxt, xmlXPathObjectCopy(s));
3980 ret = xmlXPathCompareValues(ctxt, inf, strict);
3981 if (ret)
3982 break;
3983 }
3984 }
Owen Taylor3473f882001-02-23 17:55:21 +00003985 }
3986 xmlXPathFreeObject(arg);
3987 xmlXPathFreeObject(s);
3988 return(ret);
3989}
3990
3991/**
3992 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003993 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00003994 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003995 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00003996 * @arg2: the second node set object
3997 *
3998 * Implement the compare operation on nodesets:
3999 *
4000 * If both objects to be compared are node-sets, then the comparison
4001 * will be true if and only if there is a node in the first node-set
4002 * and a node in the second node-set such that the result of performing
4003 * the comparison on the string-values of the two nodes is true.
4004 * ....
4005 * When neither object to be compared is a node-set and the operator
4006 * is <=, <, >= or >, then the objects are compared by converting both
4007 * objects to numbers and comparing the numbers according to IEEE 754.
4008 * ....
4009 * The number function converts its argument to a number as follows:
4010 * - a string that consists of optional whitespace followed by an
4011 * optional minus sign followed by a Number followed by whitespace
4012 * is converted to the IEEE 754 number that is nearest (according
4013 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4014 * represented by the string; any other string is converted to NaN
4015 *
4016 * Conclusion all nodes need to be converted first to their string value
4017 * and then the comparison must be done when possible
4018 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004019static int
4020xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004021 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4022 int i, j, init = 0;
4023 double val1;
4024 double *values2;
4025 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004026 xmlNodeSetPtr ns1;
4027 xmlNodeSetPtr ns2;
4028
4029 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004030 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4031 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004032 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004033 }
Owen Taylor3473f882001-02-23 17:55:21 +00004034 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004035 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4036 xmlXPathFreeObject(arg1);
4037 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004038 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004039 }
Owen Taylor3473f882001-02-23 17:55:21 +00004040
4041 ns1 = arg1->nodesetval;
4042 ns2 = arg2->nodesetval;
4043
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004044 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004045 xmlXPathFreeObject(arg1);
4046 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004047 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004048 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004049 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004050 xmlXPathFreeObject(arg1);
4051 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004052 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004053 }
Owen Taylor3473f882001-02-23 17:55:21 +00004054
4055 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4056 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004057 xmlXPathFreeObject(arg1);
4058 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004059 return(0);
4060 }
4061 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004062 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004063 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004064 continue;
4065 for (j = 0;j < ns2->nodeNr;j++) {
4066 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004067 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004068 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004069 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004070 continue;
4071 if (inf && strict)
4072 ret = (val1 < values2[j]);
4073 else if (inf && !strict)
4074 ret = (val1 <= values2[j]);
4075 else if (!inf && strict)
4076 ret = (val1 > values2[j]);
4077 else if (!inf && !strict)
4078 ret = (val1 >= values2[j]);
4079 if (ret)
4080 break;
4081 }
4082 if (ret)
4083 break;
4084 init = 1;
4085 }
4086 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004087 xmlXPathFreeObject(arg1);
4088 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004089 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004090}
4091
4092/**
4093 * xmlXPathCompareNodeSetValue:
4094 * @ctxt: the XPath Parser context
4095 * @inf: less than (1) or greater than (0)
4096 * @strict: is the comparison strict
4097 * @arg: the node set
4098 * @val: the value
4099 *
4100 * Implement the compare operation between a nodeset and a value
4101 * @ns < @val (1, 1, ...
4102 * @ns <= @val (1, 0, ...
4103 * @ns > @val (0, 1, ...
4104 * @ns >= @val (0, 0, ...
4105 *
4106 * If one object to be compared is a node-set and the other is a boolean,
4107 * then the comparison will be true if and only if the result of performing
4108 * the comparison on the boolean and on the result of converting
4109 * the node-set to a boolean using the boolean function is true.
4110 *
4111 * Returns 0 or 1 depending on the results of the test.
4112 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004113static int
Owen Taylor3473f882001-02-23 17:55:21 +00004114xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4115 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4116 if ((val == NULL) || (arg == NULL) ||
4117 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4118 return(0);
4119
4120 switch(val->type) {
4121 case XPATH_NUMBER:
4122 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4123 case XPATH_NODESET:
4124 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004125 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004126 case XPATH_STRING:
4127 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4128 case XPATH_BOOLEAN:
4129 valuePush(ctxt, arg);
4130 xmlXPathBooleanFunction(ctxt, 1);
4131 valuePush(ctxt, val);
4132 return(xmlXPathCompareValues(ctxt, inf, strict));
4133 default:
4134 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004135 }
4136 return(0);
4137}
4138
4139/**
4140 * xmlXPathEqualNodeSetString
4141 * @arg: the nodeset object argument
4142 * @str: the string to compare to.
4143 *
4144 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4145 * If one object to be compared is a node-set and the other is a string,
4146 * then the comparison will be true if and only if there is a node in
4147 * the node-set such that the result of performing the comparison on the
4148 * string-value of the node and the other string is true.
4149 *
4150 * Returns 0 or 1 depending on the results of the test.
4151 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004152static int
Daniel Veillardf06307e2001-07-03 10:35:50 +00004153xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str)
4154{
Owen Taylor3473f882001-02-23 17:55:21 +00004155 int i;
4156 xmlNodeSetPtr ns;
4157 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004158 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004159
4160 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004161 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4162 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004163 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004164 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004165 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004166 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004167 if (ns->nodeNr <= 0) {
4168 if (hash == 0)
4169 return(1);
4170 return(0);
4171 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004172 for (i = 0; i < ns->nodeNr; i++) {
4173 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4174 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4175 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4176 xmlFree(str2);
4177 return (1);
4178 }
4179 if (str2 != NULL)
4180 xmlFree(str2);
4181 }
Owen Taylor3473f882001-02-23 17:55:21 +00004182 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004183 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004184}
4185
4186/**
4187 * xmlXPathEqualNodeSetFloat
4188 * @arg: the nodeset object argument
4189 * @f: the float to compare to
4190 *
4191 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4192 * If one object to be compared is a node-set and the other is a number,
4193 * then the comparison will be true if and only if there is a node in
4194 * the node-set such that the result of performing the comparison on the
4195 * number to be compared and on the result of converting the string-value
4196 * of that node to a number using the number function is true.
4197 *
4198 * Returns 0 or 1 depending on the results of the test.
4199 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004200static int
Owen Taylor3473f882001-02-23 17:55:21 +00004201xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) {
4202 char buf[100] = "";
4203
4204 if ((arg == NULL) ||
4205 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4206 return(0);
4207
Bjorn Reesee1dc0112001-03-03 12:09:03 +00004208 xmlXPathFormatNumber(f, buf, sizeof(buf));
Owen Taylor3473f882001-02-23 17:55:21 +00004209 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
4210}
4211
4212
4213/**
4214 * xmlXPathEqualNodeSets
4215 * @arg1: first nodeset object argument
4216 * @arg2: second nodeset object argument
4217 *
4218 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
4219 * If both objects to be compared are node-sets, then the comparison
4220 * will be true if and only if there is a node in the first node-set and
4221 * a node in the second node-set such that the result of performing the
4222 * comparison on the string-values of the two nodes is true.
4223 *
4224 * (needless to say, this is a costly operation)
4225 *
4226 * Returns 0 or 1 depending on the results of the test.
4227 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004228static int
Owen Taylor3473f882001-02-23 17:55:21 +00004229xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4230 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004231 unsigned int *hashs1;
4232 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004233 xmlChar **values1;
4234 xmlChar **values2;
4235 int ret = 0;
4236 xmlNodeSetPtr ns1;
4237 xmlNodeSetPtr ns2;
4238
4239 if ((arg1 == NULL) ||
4240 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4241 return(0);
4242 if ((arg2 == NULL) ||
4243 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4244 return(0);
4245
4246 ns1 = arg1->nodesetval;
4247 ns2 = arg2->nodesetval;
4248
Daniel Veillard911f49a2001-04-07 15:39:35 +00004249 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004250 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004251 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004252 return(0);
4253
4254 /*
4255 * check if there is a node pertaining to both sets
4256 */
4257 for (i = 0;i < ns1->nodeNr;i++)
4258 for (j = 0;j < ns2->nodeNr;j++)
4259 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4260 return(1);
4261
4262 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
4263 if (values1 == NULL)
4264 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004265 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4266 if (hashs1 == NULL) {
4267 xmlFree(values1);
4268 return(0);
4269 }
Owen Taylor3473f882001-02-23 17:55:21 +00004270 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4271 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4272 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004273 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004274 xmlFree(values1);
4275 return(0);
4276 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004277 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4278 if (hashs2 == NULL) {
4279 xmlFree(hashs1);
4280 xmlFree(values1);
4281 xmlFree(values2);
4282 return(0);
4283 }
Owen Taylor3473f882001-02-23 17:55:21 +00004284 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4285 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004286 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004287 for (j = 0;j < ns2->nodeNr;j++) {
4288 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004289 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
4290 if (hashs1[i] == hashs2[j]) {
4291 if (values1[i] == NULL)
4292 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4293 if (values2[j] == NULL)
4294 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
4295 ret = xmlStrEqual(values1[i], values2[j]);
4296 if (ret)
4297 break;
4298 }
Owen Taylor3473f882001-02-23 17:55:21 +00004299 }
4300 if (ret)
4301 break;
4302 }
4303 for (i = 0;i < ns1->nodeNr;i++)
4304 if (values1[i] != NULL)
4305 xmlFree(values1[i]);
4306 for (j = 0;j < ns2->nodeNr;j++)
4307 if (values2[j] != NULL)
4308 xmlFree(values2[j]);
4309 xmlFree(values1);
4310 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004311 xmlFree(hashs1);
4312 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004313 return(ret);
4314}
4315
4316/**
4317 * xmlXPathEqualValues:
4318 * @ctxt: the XPath Parser context
4319 *
4320 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4321 *
4322 * Returns 0 or 1 depending on the results of the test.
4323 */
4324int
4325xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4326 xmlXPathObjectPtr arg1, arg2;
4327 int ret = 0;
4328
4329 arg1 = valuePop(ctxt);
4330 if (arg1 == NULL)
4331 XP_ERROR0(XPATH_INVALID_OPERAND);
4332
4333 arg2 = valuePop(ctxt);
4334 if (arg2 == NULL) {
4335 xmlXPathFreeObject(arg1);
4336 XP_ERROR0(XPATH_INVALID_OPERAND);
4337 }
4338
4339 if (arg1 == arg2) {
4340#ifdef DEBUG_EXPR
4341 xmlGenericError(xmlGenericErrorContext,
4342 "Equal: by pointer\n");
4343#endif
4344 return(1);
4345 }
4346
4347 switch (arg1->type) {
4348 case XPATH_UNDEFINED:
4349#ifdef DEBUG_EXPR
4350 xmlGenericError(xmlGenericErrorContext,
4351 "Equal: undefined\n");
4352#endif
4353 break;
4354 case XPATH_XSLT_TREE:
4355 case XPATH_NODESET:
4356 switch (arg2->type) {
4357 case XPATH_UNDEFINED:
4358#ifdef DEBUG_EXPR
4359 xmlGenericError(xmlGenericErrorContext,
4360 "Equal: undefined\n");
4361#endif
4362 break;
4363 case XPATH_XSLT_TREE:
4364 case XPATH_NODESET:
4365 ret = xmlXPathEqualNodeSets(arg1, arg2);
4366 break;
4367 case XPATH_BOOLEAN:
4368 if ((arg1->nodesetval == NULL) ||
4369 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4370 else
4371 ret = 1;
4372 ret = (ret == arg2->boolval);
4373 break;
4374 case XPATH_NUMBER:
4375 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
4376 break;
4377 case XPATH_STRING:
4378 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
4379 break;
4380 case XPATH_USERS:
4381 case XPATH_POINT:
4382 case XPATH_RANGE:
4383 case XPATH_LOCATIONSET:
4384 TODO
4385 break;
4386 }
4387 break;
4388 case XPATH_BOOLEAN:
4389 switch (arg2->type) {
4390 case XPATH_UNDEFINED:
4391#ifdef DEBUG_EXPR
4392 xmlGenericError(xmlGenericErrorContext,
4393 "Equal: undefined\n");
4394#endif
4395 break;
4396 case XPATH_NODESET:
4397 case XPATH_XSLT_TREE:
4398 if ((arg2->nodesetval == NULL) ||
4399 (arg2->nodesetval->nodeNr == 0)) ret = 0;
4400 else
4401 ret = 1;
4402 break;
4403 case XPATH_BOOLEAN:
4404#ifdef DEBUG_EXPR
4405 xmlGenericError(xmlGenericErrorContext,
4406 "Equal: %d boolean %d \n",
4407 arg1->boolval, arg2->boolval);
4408#endif
4409 ret = (arg1->boolval == arg2->boolval);
4410 break;
4411 case XPATH_NUMBER:
4412 if (arg2->floatval) ret = 1;
4413 else ret = 0;
4414 ret = (arg1->boolval == ret);
4415 break;
4416 case XPATH_STRING:
4417 if ((arg2->stringval == NULL) ||
4418 (arg2->stringval[0] == 0)) ret = 0;
4419 else
4420 ret = 1;
4421 ret = (arg1->boolval == ret);
4422 break;
4423 case XPATH_USERS:
4424 case XPATH_POINT:
4425 case XPATH_RANGE:
4426 case XPATH_LOCATIONSET:
4427 TODO
4428 break;
4429 }
4430 break;
4431 case XPATH_NUMBER:
4432 switch (arg2->type) {
4433 case XPATH_UNDEFINED:
4434#ifdef DEBUG_EXPR
4435 xmlGenericError(xmlGenericErrorContext,
4436 "Equal: undefined\n");
4437#endif
4438 break;
4439 case XPATH_NODESET:
4440 case XPATH_XSLT_TREE:
4441 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
4442 break;
4443 case XPATH_BOOLEAN:
4444 if (arg1->floatval) ret = 1;
4445 else ret = 0;
4446 ret = (arg2->boolval == ret);
4447 break;
4448 case XPATH_STRING:
4449 valuePush(ctxt, arg2);
4450 xmlXPathNumberFunction(ctxt, 1);
4451 arg2 = valuePop(ctxt);
4452 /* no break on purpose */
4453 case XPATH_NUMBER:
4454 ret = (arg1->floatval == arg2->floatval);
4455 break;
4456 case XPATH_USERS:
4457 case XPATH_POINT:
4458 case XPATH_RANGE:
4459 case XPATH_LOCATIONSET:
4460 TODO
4461 break;
4462 }
4463 break;
4464 case XPATH_STRING:
4465 switch (arg2->type) {
4466 case XPATH_UNDEFINED:
4467#ifdef DEBUG_EXPR
4468 xmlGenericError(xmlGenericErrorContext,
4469 "Equal: undefined\n");
4470#endif
4471 break;
4472 case XPATH_NODESET:
4473 case XPATH_XSLT_TREE:
4474 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
4475 break;
4476 case XPATH_BOOLEAN:
4477 if ((arg1->stringval == NULL) ||
4478 (arg1->stringval[0] == 0)) ret = 0;
4479 else
4480 ret = 1;
4481 ret = (arg2->boolval == ret);
4482 break;
4483 case XPATH_STRING:
4484 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4485 break;
4486 case XPATH_NUMBER:
4487 valuePush(ctxt, arg1);
4488 xmlXPathNumberFunction(ctxt, 1);
4489 arg1 = valuePop(ctxt);
4490 ret = (arg1->floatval == arg2->floatval);
4491 break;
4492 case XPATH_USERS:
4493 case XPATH_POINT:
4494 case XPATH_RANGE:
4495 case XPATH_LOCATIONSET:
4496 TODO
4497 break;
4498 }
4499 break;
4500 case XPATH_USERS:
4501 case XPATH_POINT:
4502 case XPATH_RANGE:
4503 case XPATH_LOCATIONSET:
4504 TODO
4505 break;
4506 }
4507 xmlXPathFreeObject(arg1);
4508 xmlXPathFreeObject(arg2);
4509 return(ret);
4510}
4511
4512
4513/**
4514 * xmlXPathCompareValues:
4515 * @ctxt: the XPath Parser context
4516 * @inf: less than (1) or greater than (0)
4517 * @strict: is the comparison strict
4518 *
4519 * Implement the compare operation on XPath objects:
4520 * @arg1 < @arg2 (1, 1, ...
4521 * @arg1 <= @arg2 (1, 0, ...
4522 * @arg1 > @arg2 (0, 1, ...
4523 * @arg1 >= @arg2 (0, 0, ...
4524 *
4525 * When neither object to be compared is a node-set and the operator is
4526 * <=, <, >=, >, then the objects are compared by converted both objects
4527 * to numbers and comparing the numbers according to IEEE 754. The <
4528 * comparison will be true if and only if the first number is less than the
4529 * second number. The <= comparison will be true if and only if the first
4530 * number is less than or equal to the second number. The > comparison
4531 * will be true if and only if the first number is greater than the second
4532 * number. The >= comparison will be true if and only if the first number
4533 * is greater than or equal to the second number.
4534 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004535 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00004536 */
4537int
4538xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
4539 int ret = 0;
4540 xmlXPathObjectPtr arg1, arg2;
4541
4542 arg2 = valuePop(ctxt);
4543 if (arg2 == NULL) {
4544 XP_ERROR0(XPATH_INVALID_OPERAND);
4545 }
4546
4547 arg1 = valuePop(ctxt);
4548 if (arg1 == NULL) {
4549 xmlXPathFreeObject(arg2);
4550 XP_ERROR0(XPATH_INVALID_OPERAND);
4551 }
4552
4553 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
4554 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004555 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004556 } else {
4557 if (arg1->type == XPATH_NODESET) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004558 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4559 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004560 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004561 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4562 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004563 }
4564 }
4565 return(ret);
4566 }
4567
4568 if (arg1->type != XPATH_NUMBER) {
4569 valuePush(ctxt, arg1);
4570 xmlXPathNumberFunction(ctxt, 1);
4571 arg1 = valuePop(ctxt);
4572 }
4573 if (arg1->type != XPATH_NUMBER) {
4574 xmlXPathFreeObject(arg1);
4575 xmlXPathFreeObject(arg2);
4576 XP_ERROR0(XPATH_INVALID_OPERAND);
4577 }
4578 if (arg2->type != XPATH_NUMBER) {
4579 valuePush(ctxt, arg2);
4580 xmlXPathNumberFunction(ctxt, 1);
4581 arg2 = valuePop(ctxt);
4582 }
4583 if (arg2->type != XPATH_NUMBER) {
4584 xmlXPathFreeObject(arg1);
4585 xmlXPathFreeObject(arg2);
4586 XP_ERROR0(XPATH_INVALID_OPERAND);
4587 }
4588 /*
4589 * Add tests for infinity and nan
4590 * => feedback on 3.4 for Inf and NaN
4591 */
4592 if (inf && strict)
4593 ret = (arg1->floatval < arg2->floatval);
4594 else if (inf && !strict)
4595 ret = (arg1->floatval <= arg2->floatval);
4596 else if (!inf && strict)
4597 ret = (arg1->floatval > arg2->floatval);
4598 else if (!inf && !strict)
4599 ret = (arg1->floatval >= arg2->floatval);
4600 xmlXPathFreeObject(arg1);
4601 xmlXPathFreeObject(arg2);
4602 return(ret);
4603}
4604
4605/**
4606 * xmlXPathValueFlipSign:
4607 * @ctxt: the XPath Parser context
4608 *
4609 * Implement the unary - operation on an XPath object
4610 * The numeric operators convert their operands to numbers as if
4611 * by calling the number function.
4612 */
4613void
4614xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004615 CAST_TO_NUMBER;
4616 CHECK_TYPE(XPATH_NUMBER);
4617 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00004618}
4619
4620/**
4621 * xmlXPathAddValues:
4622 * @ctxt: the XPath Parser context
4623 *
4624 * Implement the add operation on XPath objects:
4625 * The numeric operators convert their operands to numbers as if
4626 * by calling the number function.
4627 */
4628void
4629xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
4630 xmlXPathObjectPtr arg;
4631 double val;
4632
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004633 arg = valuePop(ctxt);
4634 if (arg == NULL)
4635 XP_ERROR(XPATH_INVALID_OPERAND);
4636 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004637 xmlXPathFreeObject(arg);
4638
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004639 CAST_TO_NUMBER;
4640 CHECK_TYPE(XPATH_NUMBER);
4641 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00004642}
4643
4644/**
4645 * xmlXPathSubValues:
4646 * @ctxt: the XPath Parser context
4647 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004648 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00004649 * The numeric operators convert their operands to numbers as if
4650 * by calling the number function.
4651 */
4652void
4653xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
4654 xmlXPathObjectPtr arg;
4655 double val;
4656
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004657 arg = valuePop(ctxt);
4658 if (arg == NULL)
4659 XP_ERROR(XPATH_INVALID_OPERAND);
4660 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004661 xmlXPathFreeObject(arg);
4662
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004663 CAST_TO_NUMBER;
4664 CHECK_TYPE(XPATH_NUMBER);
4665 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004666}
4667
4668/**
4669 * xmlXPathMultValues:
4670 * @ctxt: the XPath Parser context
4671 *
4672 * Implement the multiply operation on XPath objects:
4673 * The numeric operators convert their operands to numbers as if
4674 * by calling the number function.
4675 */
4676void
4677xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
4678 xmlXPathObjectPtr arg;
4679 double val;
4680
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004681 arg = valuePop(ctxt);
4682 if (arg == NULL)
4683 XP_ERROR(XPATH_INVALID_OPERAND);
4684 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004685 xmlXPathFreeObject(arg);
4686
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004687 CAST_TO_NUMBER;
4688 CHECK_TYPE(XPATH_NUMBER);
4689 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004690}
4691
4692/**
4693 * xmlXPathDivValues:
4694 * @ctxt: the XPath Parser context
4695 *
4696 * Implement the div operation on XPath objects @arg1 / @arg2:
4697 * The numeric operators convert their operands to numbers as if
4698 * by calling the number function.
4699 */
4700void
4701xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
4702 xmlXPathObjectPtr arg;
4703 double val;
4704
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004705 arg = valuePop(ctxt);
4706 if (arg == NULL)
4707 XP_ERROR(XPATH_INVALID_OPERAND);
4708 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004709 xmlXPathFreeObject(arg);
4710
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004711 CAST_TO_NUMBER;
4712 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5f4b5992002-02-20 10:22:49 +00004713 if (val == 0) {
4714 if (ctxt->value->floatval == 0)
4715 ctxt->value->floatval = xmlXPathNAN;
4716 else if (ctxt->value->floatval > 0)
4717 ctxt->value->floatval = xmlXPathPINF;
4718 else if (ctxt->value->floatval < 0)
4719 ctxt->value->floatval = xmlXPathNINF;
4720 } else
4721 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004722}
4723
4724/**
4725 * xmlXPathModValues:
4726 * @ctxt: the XPath Parser context
4727 *
4728 * Implement the mod operation on XPath objects: @arg1 / @arg2
4729 * The numeric operators convert their operands to numbers as if
4730 * by calling the number function.
4731 */
4732void
4733xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
4734 xmlXPathObjectPtr arg;
4735 int arg1, arg2;
4736
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004737 arg = valuePop(ctxt);
4738 if (arg == NULL)
4739 XP_ERROR(XPATH_INVALID_OPERAND);
4740 arg2 = (int) xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004741 xmlXPathFreeObject(arg);
4742
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004743 CAST_TO_NUMBER;
4744 CHECK_TYPE(XPATH_NUMBER);
4745 arg1 = (int) ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00004746 if (arg2 == 0)
4747 ctxt->value->floatval = xmlXPathNAN;
4748 else
4749 ctxt->value->floatval = arg1 % arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00004750}
4751
4752/************************************************************************
4753 * *
4754 * The traversal functions *
4755 * *
4756 ************************************************************************/
4757
Owen Taylor3473f882001-02-23 17:55:21 +00004758/*
4759 * A traversal function enumerates nodes along an axis.
4760 * Initially it must be called with NULL, and it indicates
4761 * termination on the axis by returning NULL.
4762 */
4763typedef xmlNodePtr (*xmlXPathTraversalFunction)
4764 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
4765
4766/**
4767 * xmlXPathNextSelf:
4768 * @ctxt: the XPath Parser context
4769 * @cur: the current node in the traversal
4770 *
4771 * Traversal function for the "self" direction
4772 * The self axis contains just the context node itself
4773 *
4774 * Returns the next element following that axis
4775 */
4776xmlNodePtr
4777xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4778 if (cur == NULL)
4779 return(ctxt->context->node);
4780 return(NULL);
4781}
4782
4783/**
4784 * xmlXPathNextChild:
4785 * @ctxt: the XPath Parser context
4786 * @cur: the current node in the traversal
4787 *
4788 * Traversal function for the "child" direction
4789 * The child axis contains the children of the context node in document order.
4790 *
4791 * Returns the next element following that axis
4792 */
4793xmlNodePtr
4794xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4795 if (cur == NULL) {
4796 if (ctxt->context->node == NULL) return(NULL);
4797 switch (ctxt->context->node->type) {
4798 case XML_ELEMENT_NODE:
4799 case XML_TEXT_NODE:
4800 case XML_CDATA_SECTION_NODE:
4801 case XML_ENTITY_REF_NODE:
4802 case XML_ENTITY_NODE:
4803 case XML_PI_NODE:
4804 case XML_COMMENT_NODE:
4805 case XML_NOTATION_NODE:
4806 case XML_DTD_NODE:
4807 return(ctxt->context->node->children);
4808 case XML_DOCUMENT_NODE:
4809 case XML_DOCUMENT_TYPE_NODE:
4810 case XML_DOCUMENT_FRAG_NODE:
4811 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004812#ifdef LIBXML_DOCB_ENABLED
4813 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004814#endif
4815 return(((xmlDocPtr) ctxt->context->node)->children);
4816 case XML_ELEMENT_DECL:
4817 case XML_ATTRIBUTE_DECL:
4818 case XML_ENTITY_DECL:
4819 case XML_ATTRIBUTE_NODE:
4820 case XML_NAMESPACE_DECL:
4821 case XML_XINCLUDE_START:
4822 case XML_XINCLUDE_END:
4823 return(NULL);
4824 }
4825 return(NULL);
4826 }
4827 if ((cur->type == XML_DOCUMENT_NODE) ||
4828 (cur->type == XML_HTML_DOCUMENT_NODE))
4829 return(NULL);
4830 return(cur->next);
4831}
4832
4833/**
4834 * xmlXPathNextDescendant:
4835 * @ctxt: the XPath Parser context
4836 * @cur: the current node in the traversal
4837 *
4838 * Traversal function for the "descendant" direction
4839 * the descendant axis contains the descendants of the context node in document
4840 * order; a descendant is a child or a child of a child and so on.
4841 *
4842 * Returns the next element following that axis
4843 */
4844xmlNodePtr
4845xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4846 if (cur == NULL) {
4847 if (ctxt->context->node == NULL)
4848 return(NULL);
4849 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4850 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4851 return(NULL);
4852
4853 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
4854 return(ctxt->context->doc->children);
4855 return(ctxt->context->node->children);
4856 }
4857
Daniel Veillard567e1b42001-08-01 15:53:47 +00004858 if (cur->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004859 if (cur->children->type != XML_ENTITY_DECL)
Daniel Veillard567e1b42001-08-01 15:53:47 +00004860 return(cur->children);
4861 }
4862
4863 if (cur == ctxt->context->node) return(NULL);
4864
Owen Taylor3473f882001-02-23 17:55:21 +00004865 if (cur->next != NULL) return(cur->next);
4866
4867 do {
4868 cur = cur->parent;
4869 if (cur == NULL) return(NULL);
4870 if (cur == ctxt->context->node) return(NULL);
4871 if (cur->next != NULL) {
4872 cur = cur->next;
4873 return(cur);
4874 }
4875 } while (cur != NULL);
4876 return(cur);
4877}
4878
4879/**
4880 * xmlXPathNextDescendantOrSelf:
4881 * @ctxt: the XPath Parser context
4882 * @cur: the current node in the traversal
4883 *
4884 * Traversal function for the "descendant-or-self" direction
4885 * the descendant-or-self axis contains the context node and the descendants
4886 * of the context node in document order; thus the context node is the first
4887 * node on the axis, and the first child of the context node is the second node
4888 * on the axis
4889 *
4890 * Returns the next element following that axis
4891 */
4892xmlNodePtr
4893xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4894 if (cur == NULL) {
4895 if (ctxt->context->node == NULL)
4896 return(NULL);
4897 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4898 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4899 return(NULL);
4900 return(ctxt->context->node);
4901 }
4902
4903 return(xmlXPathNextDescendant(ctxt, cur));
4904}
4905
4906/**
4907 * xmlXPathNextParent:
4908 * @ctxt: the XPath Parser context
4909 * @cur: the current node in the traversal
4910 *
4911 * Traversal function for the "parent" direction
4912 * The parent axis contains the parent of the context node, if there is one.
4913 *
4914 * Returns the next element following that axis
4915 */
4916xmlNodePtr
4917xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4918 /*
4919 * the parent of an attribute or namespace node is the element
4920 * to which the attribute or namespace node is attached
4921 * Namespace handling !!!
4922 */
4923 if (cur == NULL) {
4924 if (ctxt->context->node == NULL) return(NULL);
4925 switch (ctxt->context->node->type) {
4926 case XML_ELEMENT_NODE:
4927 case XML_TEXT_NODE:
4928 case XML_CDATA_SECTION_NODE:
4929 case XML_ENTITY_REF_NODE:
4930 case XML_ENTITY_NODE:
4931 case XML_PI_NODE:
4932 case XML_COMMENT_NODE:
4933 case XML_NOTATION_NODE:
4934 case XML_DTD_NODE:
4935 case XML_ELEMENT_DECL:
4936 case XML_ATTRIBUTE_DECL:
4937 case XML_XINCLUDE_START:
4938 case XML_XINCLUDE_END:
4939 case XML_ENTITY_DECL:
4940 if (ctxt->context->node->parent == NULL)
4941 return((xmlNodePtr) ctxt->context->doc);
4942 return(ctxt->context->node->parent);
4943 case XML_ATTRIBUTE_NODE: {
4944 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4945
4946 return(att->parent);
4947 }
4948 case XML_DOCUMENT_NODE:
4949 case XML_DOCUMENT_TYPE_NODE:
4950 case XML_DOCUMENT_FRAG_NODE:
4951 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004952#ifdef LIBXML_DOCB_ENABLED
4953 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004954#endif
4955 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004956 case XML_NAMESPACE_DECL: {
4957 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
4958
4959 if ((ns->next != NULL) &&
4960 (ns->next->type != XML_NAMESPACE_DECL))
4961 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00004962 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004963 }
Owen Taylor3473f882001-02-23 17:55:21 +00004964 }
4965 }
4966 return(NULL);
4967}
4968
4969/**
4970 * xmlXPathNextAncestor:
4971 * @ctxt: the XPath Parser context
4972 * @cur: the current node in the traversal
4973 *
4974 * Traversal function for the "ancestor" direction
4975 * the ancestor axis contains the ancestors of the context node; the ancestors
4976 * of the context node consist of the parent of context node and the parent's
4977 * parent and so on; the nodes are ordered in reverse document order; thus the
4978 * parent is the first node on the axis, and the parent's parent is the second
4979 * node on the axis
4980 *
4981 * Returns the next element following that axis
4982 */
4983xmlNodePtr
4984xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4985 /*
4986 * the parent of an attribute or namespace node is the element
4987 * to which the attribute or namespace node is attached
4988 * !!!!!!!!!!!!!
4989 */
4990 if (cur == NULL) {
4991 if (ctxt->context->node == NULL) return(NULL);
4992 switch (ctxt->context->node->type) {
4993 case XML_ELEMENT_NODE:
4994 case XML_TEXT_NODE:
4995 case XML_CDATA_SECTION_NODE:
4996 case XML_ENTITY_REF_NODE:
4997 case XML_ENTITY_NODE:
4998 case XML_PI_NODE:
4999 case XML_COMMENT_NODE:
5000 case XML_DTD_NODE:
5001 case XML_ELEMENT_DECL:
5002 case XML_ATTRIBUTE_DECL:
5003 case XML_ENTITY_DECL:
5004 case XML_NOTATION_NODE:
5005 case XML_XINCLUDE_START:
5006 case XML_XINCLUDE_END:
5007 if (ctxt->context->node->parent == NULL)
5008 return((xmlNodePtr) ctxt->context->doc);
5009 return(ctxt->context->node->parent);
5010 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005011 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005012
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005013 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005014 }
5015 case XML_DOCUMENT_NODE:
5016 case XML_DOCUMENT_TYPE_NODE:
5017 case XML_DOCUMENT_FRAG_NODE:
5018 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005019#ifdef LIBXML_DOCB_ENABLED
5020 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005021#endif
5022 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005023 case XML_NAMESPACE_DECL: {
5024 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5025
5026 if ((ns->next != NULL) &&
5027 (ns->next->type != XML_NAMESPACE_DECL))
5028 return((xmlNodePtr) ns->next);
5029 /* Bad, how did that namespace ended-up there ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005030 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005031 }
Owen Taylor3473f882001-02-23 17:55:21 +00005032 }
5033 return(NULL);
5034 }
5035 if (cur == ctxt->context->doc->children)
5036 return((xmlNodePtr) ctxt->context->doc);
5037 if (cur == (xmlNodePtr) ctxt->context->doc)
5038 return(NULL);
5039 switch (cur->type) {
5040 case XML_ELEMENT_NODE:
5041 case XML_TEXT_NODE:
5042 case XML_CDATA_SECTION_NODE:
5043 case XML_ENTITY_REF_NODE:
5044 case XML_ENTITY_NODE:
5045 case XML_PI_NODE:
5046 case XML_COMMENT_NODE:
5047 case XML_NOTATION_NODE:
5048 case XML_DTD_NODE:
5049 case XML_ELEMENT_DECL:
5050 case XML_ATTRIBUTE_DECL:
5051 case XML_ENTITY_DECL:
5052 case XML_XINCLUDE_START:
5053 case XML_XINCLUDE_END:
5054 return(cur->parent);
5055 case XML_ATTRIBUTE_NODE: {
5056 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5057
5058 return(att->parent);
5059 }
5060 case XML_DOCUMENT_NODE:
5061 case XML_DOCUMENT_TYPE_NODE:
5062 case XML_DOCUMENT_FRAG_NODE:
5063 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005064#ifdef LIBXML_DOCB_ENABLED
5065 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005066#endif
5067 return(NULL);
5068 case XML_NAMESPACE_DECL:
5069 /*
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005070 * this should not hapen a namespace can't be
5071 * the ancestor of another node
Owen Taylor3473f882001-02-23 17:55:21 +00005072 */
5073 return(NULL);
5074 }
5075 return(NULL);
5076}
5077
5078/**
5079 * xmlXPathNextAncestorOrSelf:
5080 * @ctxt: the XPath Parser context
5081 * @cur: the current node in the traversal
5082 *
5083 * Traversal function for the "ancestor-or-self" direction
5084 * he ancestor-or-self axis contains the context node and ancestors of
5085 * the context node in reverse document order; thus the context node is
5086 * the first node on the axis, and the context node's parent the second;
5087 * parent here is defined the same as with the parent axis.
5088 *
5089 * Returns the next element following that axis
5090 */
5091xmlNodePtr
5092xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5093 if (cur == NULL)
5094 return(ctxt->context->node);
5095 return(xmlXPathNextAncestor(ctxt, cur));
5096}
5097
5098/**
5099 * xmlXPathNextFollowingSibling:
5100 * @ctxt: the XPath Parser context
5101 * @cur: the current node in the traversal
5102 *
5103 * Traversal function for the "following-sibling" direction
5104 * The following-sibling axis contains the following siblings of the context
5105 * node in document order.
5106 *
5107 * Returns the next element following that axis
5108 */
5109xmlNodePtr
5110xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5111 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5112 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5113 return(NULL);
5114 if (cur == (xmlNodePtr) ctxt->context->doc)
5115 return(NULL);
5116 if (cur == NULL)
5117 return(ctxt->context->node->next);
5118 return(cur->next);
5119}
5120
5121/**
5122 * xmlXPathNextPrecedingSibling:
5123 * @ctxt: the XPath Parser context
5124 * @cur: the current node in the traversal
5125 *
5126 * Traversal function for the "preceding-sibling" direction
5127 * The preceding-sibling axis contains the preceding siblings of the context
5128 * node in reverse document order; the first preceding sibling is first on the
5129 * axis; the sibling preceding that node is the second on the axis and so on.
5130 *
5131 * Returns the next element following that axis
5132 */
5133xmlNodePtr
5134xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5135 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5136 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5137 return(NULL);
5138 if (cur == (xmlNodePtr) ctxt->context->doc)
5139 return(NULL);
5140 if (cur == NULL)
5141 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005142 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5143 cur = cur->prev;
5144 if (cur == NULL)
5145 return(ctxt->context->node->prev);
5146 }
Owen Taylor3473f882001-02-23 17:55:21 +00005147 return(cur->prev);
5148}
5149
5150/**
5151 * xmlXPathNextFollowing:
5152 * @ctxt: the XPath Parser context
5153 * @cur: the current node in the traversal
5154 *
5155 * Traversal function for the "following" direction
5156 * The following axis contains all nodes in the same document as the context
5157 * node that are after the context node in document order, excluding any
5158 * descendants and excluding attribute nodes and namespace nodes; the nodes
5159 * are ordered in document order
5160 *
5161 * Returns the next element following that axis
5162 */
5163xmlNodePtr
5164xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5165 if (cur != NULL && cur->children != NULL)
5166 return cur->children ;
5167 if (cur == NULL) cur = ctxt->context->node;
5168 if (cur == NULL) return(NULL) ; /* ERROR */
5169 if (cur->next != NULL) return(cur->next) ;
5170 do {
5171 cur = cur->parent;
5172 if (cur == NULL) return(NULL);
5173 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5174 if (cur->next != NULL) return(cur->next);
5175 } while (cur != NULL);
5176 return(cur);
5177}
5178
5179/*
5180 * xmlXPathIsAncestor:
5181 * @ancestor: the ancestor node
5182 * @node: the current node
5183 *
5184 * Check that @ancestor is a @node's ancestor
5185 *
5186 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5187 */
5188static int
5189xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5190 if ((ancestor == NULL) || (node == NULL)) return(0);
5191 /* nodes need to be in the same document */
5192 if (ancestor->doc != node->doc) return(0);
5193 /* avoid searching if ancestor or node is the root node */
5194 if (ancestor == (xmlNodePtr) node->doc) return(1);
5195 if (node == (xmlNodePtr) ancestor->doc) return(0);
5196 while (node->parent != NULL) {
5197 if (node->parent == ancestor)
5198 return(1);
5199 node = node->parent;
5200 }
5201 return(0);
5202}
5203
5204/**
5205 * xmlXPathNextPreceding:
5206 * @ctxt: the XPath Parser context
5207 * @cur: the current node in the traversal
5208 *
5209 * Traversal function for the "preceding" direction
5210 * the preceding axis contains all nodes in the same document as the context
5211 * node that are before the context node in document order, excluding any
5212 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5213 * ordered in reverse document order
5214 *
5215 * Returns the next element following that axis
5216 */
5217xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005218xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5219{
Owen Taylor3473f882001-02-23 17:55:21 +00005220 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005221 cur = ctxt->context->node;
5222 if (cur == NULL)
5223 return (NULL);
5224 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5225 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005226 do {
5227 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005228 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5229 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005230 }
5231
5232 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005233 if (cur == NULL)
5234 return (NULL);
5235 if (cur == ctxt->context->doc->children)
5236 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005237 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005238 return (cur);
5239}
5240
5241/**
5242 * xmlXPathNextPrecedingInternal:
5243 * @ctxt: the XPath Parser context
5244 * @cur: the current node in the traversal
5245 *
5246 * Traversal function for the "preceding" direction
5247 * the preceding axis contains all nodes in the same document as the context
5248 * node that are before the context node in document order, excluding any
5249 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5250 * ordered in reverse document order
5251 * This is a faster implementation but internal only since it requires a
5252 * state kept in the parser context: ctxt->ancestor.
5253 *
5254 * Returns the next element following that axis
5255 */
5256static xmlNodePtr
5257xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5258 xmlNodePtr cur)
5259{
5260 if (cur == NULL) {
5261 cur = ctxt->context->node;
5262 if (cur == NULL)
5263 return (NULL);
5264 ctxt->ancestor = cur->parent;
5265 }
5266 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5267 cur = cur->prev;
5268 while (cur->prev == NULL) {
5269 cur = cur->parent;
5270 if (cur == NULL)
5271 return (NULL);
5272 if (cur == ctxt->context->doc->children)
5273 return (NULL);
5274 if (cur != ctxt->ancestor)
5275 return (cur);
5276 ctxt->ancestor = cur->parent;
5277 }
5278 cur = cur->prev;
5279 while (cur->last != NULL)
5280 cur = cur->last;
5281 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005282}
5283
5284/**
5285 * xmlXPathNextNamespace:
5286 * @ctxt: the XPath Parser context
5287 * @cur: the current attribute in the traversal
5288 *
5289 * Traversal function for the "namespace" direction
5290 * the namespace axis contains the namespace nodes of the context node;
5291 * the order of nodes on this axis is implementation-defined; the axis will
5292 * be empty unless the context node is an element
5293 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005294 * We keep the XML namespace node at the end of the list.
5295 *
Owen Taylor3473f882001-02-23 17:55:21 +00005296 * Returns the next element following that axis
5297 */
5298xmlNodePtr
5299xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005300 xmlNodePtr ret;
5301
Owen Taylor3473f882001-02-23 17:55:21 +00005302 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005303 if (cur == (xmlNodePtr) xmlXPathXMLNamespace)
5304 return(NULL);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005305 if ((cur == NULL) || (ctxt->context->tmpNsList == NULL)) {
5306 if (ctxt->context->tmpNsList != NULL)
5307 xmlFree(ctxt->context->tmpNsList);
5308 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005309 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005310 if (ctxt->context->tmpNsList == NULL) return(NULL);
5311 ctxt->context->tmpNsNr = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005312 }
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005313 ret = (xmlNodePtr)ctxt->context->tmpNsList[ctxt->context->tmpNsNr++];
5314 if (ret == NULL) {
5315 xmlFree(ctxt->context->tmpNsList);
5316 ctxt->context->tmpNsList = NULL;
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005317 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005318 }
5319 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005320}
5321
5322/**
5323 * xmlXPathNextAttribute:
5324 * @ctxt: the XPath Parser context
5325 * @cur: the current attribute in the traversal
5326 *
5327 * Traversal function for the "attribute" direction
5328 * TODO: support DTD inherited default attributes
5329 *
5330 * Returns the next element following that axis
5331 */
5332xmlNodePtr
5333xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005334 if (ctxt->context->node == NULL)
5335 return(NULL);
5336 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5337 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005338 if (cur == NULL) {
5339 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5340 return(NULL);
5341 return((xmlNodePtr)ctxt->context->node->properties);
5342 }
5343 return((xmlNodePtr)cur->next);
5344}
5345
5346/************************************************************************
5347 * *
5348 * NodeTest Functions *
5349 * *
5350 ************************************************************************/
5351
Owen Taylor3473f882001-02-23 17:55:21 +00005352#define IS_FUNCTION 200
5353
Owen Taylor3473f882001-02-23 17:55:21 +00005354
5355/************************************************************************
5356 * *
5357 * Implicit tree core function library *
5358 * *
5359 ************************************************************************/
5360
5361/**
5362 * xmlXPathRoot:
5363 * @ctxt: the XPath Parser context
5364 *
5365 * Initialize the context to the root of the document
5366 */
5367void
5368xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5369 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5370 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5371}
5372
5373/************************************************************************
5374 * *
5375 * The explicit core function library *
5376 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5377 * *
5378 ************************************************************************/
5379
5380
5381/**
5382 * xmlXPathLastFunction:
5383 * @ctxt: the XPath Parser context
5384 * @nargs: the number of arguments
5385 *
5386 * Implement the last() XPath function
5387 * number last()
5388 * The last function returns the number of nodes in the context node list.
5389 */
5390void
5391xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5392 CHECK_ARITY(0);
5393 if (ctxt->context->contextSize >= 0) {
5394 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5395#ifdef DEBUG_EXPR
5396 xmlGenericError(xmlGenericErrorContext,
5397 "last() : %d\n", ctxt->context->contextSize);
5398#endif
5399 } else {
5400 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5401 }
5402}
5403
5404/**
5405 * xmlXPathPositionFunction:
5406 * @ctxt: the XPath Parser context
5407 * @nargs: the number of arguments
5408 *
5409 * Implement the position() XPath function
5410 * number position()
5411 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005412 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005413 * will be equal to last().
5414 */
5415void
5416xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5417 CHECK_ARITY(0);
5418 if (ctxt->context->proximityPosition >= 0) {
5419 valuePush(ctxt,
5420 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5421#ifdef DEBUG_EXPR
5422 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5423 ctxt->context->proximityPosition);
5424#endif
5425 } else {
5426 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5427 }
5428}
5429
5430/**
5431 * xmlXPathCountFunction:
5432 * @ctxt: the XPath Parser context
5433 * @nargs: the number of arguments
5434 *
5435 * Implement the count() XPath function
5436 * number count(node-set)
5437 */
5438void
5439xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5440 xmlXPathObjectPtr cur;
5441
5442 CHECK_ARITY(1);
5443 if ((ctxt->value == NULL) ||
5444 ((ctxt->value->type != XPATH_NODESET) &&
5445 (ctxt->value->type != XPATH_XSLT_TREE)))
5446 XP_ERROR(XPATH_INVALID_TYPE);
5447 cur = valuePop(ctxt);
5448
Daniel Veillard911f49a2001-04-07 15:39:35 +00005449 if ((cur == NULL) || (cur->nodesetval == NULL))
5450 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00005451 else if (cur->type == XPATH_NODESET) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005452 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005453 } else {
5454 if ((cur->nodesetval->nodeNr != 1) ||
5455 (cur->nodesetval->nodeTab == NULL)) {
5456 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5457 } else {
5458 xmlNodePtr tmp;
5459 int i = 0;
5460
5461 tmp = cur->nodesetval->nodeTab[0];
5462 if (tmp != NULL) {
5463 tmp = tmp->children;
5464 while (tmp != NULL) {
5465 tmp = tmp->next;
5466 i++;
5467 }
5468 }
5469 valuePush(ctxt, xmlXPathNewFloat((double) i));
5470 }
5471 }
Owen Taylor3473f882001-02-23 17:55:21 +00005472 xmlXPathFreeObject(cur);
5473}
5474
5475/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005476 * xmlXPathGetElementsByIds:
5477 * @doc: the document
5478 * @ids: a whitespace separated list of IDs
5479 *
5480 * Selects elements by their unique ID.
5481 *
5482 * Returns a node-set of selected elements.
5483 */
5484static xmlNodeSetPtr
5485xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5486 xmlNodeSetPtr ret;
5487 const xmlChar *cur = ids;
5488 xmlChar *ID;
5489 xmlAttrPtr attr;
5490 xmlNodePtr elem = NULL;
5491
5492 ret = xmlXPathNodeSetCreate(NULL);
5493
5494 while (IS_BLANK(*cur)) cur++;
5495 while (*cur != 0) {
5496 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
5497 (*cur == '.') || (*cur == '-') ||
5498 (*cur == '_') || (*cur == ':') ||
5499 (IS_COMBINING(*cur)) ||
5500 (IS_EXTENDER(*cur)))
5501 cur++;
5502
5503 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
5504
5505 ID = xmlStrndup(ids, cur - ids);
5506 attr = xmlGetID(doc, ID);
5507 if (attr != NULL) {
5508 elem = attr->parent;
5509 xmlXPathNodeSetAdd(ret, elem);
5510 }
5511 if (ID != NULL)
5512 xmlFree(ID);
5513
5514 while (IS_BLANK(*cur)) cur++;
5515 ids = cur;
5516 }
5517 return(ret);
5518}
5519
5520/**
Owen Taylor3473f882001-02-23 17:55:21 +00005521 * xmlXPathIdFunction:
5522 * @ctxt: the XPath Parser context
5523 * @nargs: the number of arguments
5524 *
5525 * Implement the id() XPath function
5526 * node-set id(object)
5527 * The id function selects elements by their unique ID
5528 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5529 * then the result is the union of the result of applying id to the
5530 * string value of each of the nodes in the argument node-set. When the
5531 * argument to id is of any other type, the argument is converted to a
5532 * string as if by a call to the string function; the string is split
5533 * into a whitespace-separated list of tokens (whitespace is any sequence
5534 * of characters matching the production S); the result is a node-set
5535 * containing the elements in the same document as the context node that
5536 * have a unique ID equal to any of the tokens in the list.
5537 */
5538void
5539xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005540 xmlChar *tokens;
5541 xmlNodeSetPtr ret;
5542 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00005543
5544 CHECK_ARITY(1);
5545 obj = valuePop(ctxt);
5546 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
5547 if (obj->type == XPATH_NODESET) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005548 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00005549 int i;
5550
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005551 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005552
Daniel Veillard911f49a2001-04-07 15:39:35 +00005553 if (obj->nodesetval != NULL) {
5554 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005555 tokens =
5556 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
5557 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
5558 ret = xmlXPathNodeSetMerge(ret, ns);
5559 xmlXPathFreeNodeSet(ns);
5560 if (tokens != NULL)
5561 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00005562 }
Owen Taylor3473f882001-02-23 17:55:21 +00005563 }
5564
5565 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005566 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005567 return;
5568 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005569 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00005570
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005571 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
5572 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005573
Owen Taylor3473f882001-02-23 17:55:21 +00005574 xmlXPathFreeObject(obj);
5575 return;
5576}
5577
5578/**
5579 * xmlXPathLocalNameFunction:
5580 * @ctxt: the XPath Parser context
5581 * @nargs: the number of arguments
5582 *
5583 * Implement the local-name() XPath function
5584 * string local-name(node-set?)
5585 * The local-name function returns a string containing the local part
5586 * of the name of the node in the argument node-set that is first in
5587 * document order. If the node-set is empty or the first node has no
5588 * name, an empty string is returned. If the argument is omitted it
5589 * defaults to the context node.
5590 */
5591void
5592xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5593 xmlXPathObjectPtr cur;
5594
5595 if (nargs == 0) {
5596 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5597 nargs = 1;
5598 }
5599
5600 CHECK_ARITY(1);
5601 if ((ctxt->value == NULL) ||
5602 ((ctxt->value->type != XPATH_NODESET) &&
5603 (ctxt->value->type != XPATH_XSLT_TREE)))
5604 XP_ERROR(XPATH_INVALID_TYPE);
5605 cur = valuePop(ctxt);
5606
Daniel Veillard911f49a2001-04-07 15:39:35 +00005607 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005608 valuePush(ctxt, xmlXPathNewCString(""));
5609 } else {
5610 int i = 0; /* Should be first in document order !!!!! */
5611 switch (cur->nodesetval->nodeTab[i]->type) {
5612 case XML_ELEMENT_NODE:
5613 case XML_ATTRIBUTE_NODE:
5614 case XML_PI_NODE:
5615 valuePush(ctxt,
5616 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
5617 break;
5618 case XML_NAMESPACE_DECL:
5619 valuePush(ctxt, xmlXPathNewString(
5620 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
5621 break;
5622 default:
5623 valuePush(ctxt, xmlXPathNewCString(""));
5624 }
5625 }
5626 xmlXPathFreeObject(cur);
5627}
5628
5629/**
5630 * xmlXPathNamespaceURIFunction:
5631 * @ctxt: the XPath Parser context
5632 * @nargs: the number of arguments
5633 *
5634 * Implement the namespace-uri() XPath function
5635 * string namespace-uri(node-set?)
5636 * The namespace-uri function returns a string containing the
5637 * namespace URI of the expanded name of the node in the argument
5638 * node-set that is first in document order. If the node-set is empty,
5639 * the first node has no name, or the expanded name has no namespace
5640 * URI, an empty string is returned. If the argument is omitted it
5641 * defaults to the context node.
5642 */
5643void
5644xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5645 xmlXPathObjectPtr cur;
5646
5647 if (nargs == 0) {
5648 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5649 nargs = 1;
5650 }
5651 CHECK_ARITY(1);
5652 if ((ctxt->value == NULL) ||
5653 ((ctxt->value->type != XPATH_NODESET) &&
5654 (ctxt->value->type != XPATH_XSLT_TREE)))
5655 XP_ERROR(XPATH_INVALID_TYPE);
5656 cur = valuePop(ctxt);
5657
Daniel Veillard911f49a2001-04-07 15:39:35 +00005658 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005659 valuePush(ctxt, xmlXPathNewCString(""));
5660 } else {
5661 int i = 0; /* Should be first in document order !!!!! */
5662 switch (cur->nodesetval->nodeTab[i]->type) {
5663 case XML_ELEMENT_NODE:
5664 case XML_ATTRIBUTE_NODE:
5665 if (cur->nodesetval->nodeTab[i]->ns == NULL)
5666 valuePush(ctxt, xmlXPathNewCString(""));
5667 else
5668 valuePush(ctxt, xmlXPathNewString(
5669 cur->nodesetval->nodeTab[i]->ns->href));
5670 break;
5671 default:
5672 valuePush(ctxt, xmlXPathNewCString(""));
5673 }
5674 }
5675 xmlXPathFreeObject(cur);
5676}
5677
5678/**
5679 * xmlXPathNameFunction:
5680 * @ctxt: the XPath Parser context
5681 * @nargs: the number of arguments
5682 *
5683 * Implement the name() XPath function
5684 * string name(node-set?)
5685 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005686 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00005687 * order. The QName must represent the name with respect to the namespace
5688 * declarations in effect on the node whose name is being represented.
5689 * Typically, this will be the form in which the name occurred in the XML
5690 * source. This need not be the case if there are namespace declarations
5691 * in effect on the node that associate multiple prefixes with the same
5692 * namespace. However, an implementation may include information about
5693 * the original prefix in its representation of nodes; in this case, an
5694 * implementation can ensure that the returned string is always the same
5695 * as the QName used in the XML source. If the argument it omitted it
5696 * defaults to the context node.
5697 * Libxml keep the original prefix so the "real qualified name" used is
5698 * returned.
5699 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005700static void
Daniel Veillard04383752001-07-08 14:27:15 +00005701xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
5702{
Owen Taylor3473f882001-02-23 17:55:21 +00005703 xmlXPathObjectPtr cur;
5704
5705 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00005706 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5707 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00005708 }
5709
5710 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00005711 if ((ctxt->value == NULL) ||
5712 ((ctxt->value->type != XPATH_NODESET) &&
5713 (ctxt->value->type != XPATH_XSLT_TREE)))
5714 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00005715 cur = valuePop(ctxt);
5716
Daniel Veillard911f49a2001-04-07 15:39:35 +00005717 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00005718 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00005719 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00005720 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005721
Daniel Veillard04383752001-07-08 14:27:15 +00005722 switch (cur->nodesetval->nodeTab[i]->type) {
5723 case XML_ELEMENT_NODE:
5724 case XML_ATTRIBUTE_NODE:
5725 if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
5726 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL))
5727 valuePush(ctxt,
5728 xmlXPathNewString(cur->nodesetval->
5729 nodeTab[i]->name));
5730
5731 else {
5732 char name[2000];
5733
5734 snprintf(name, sizeof(name), "%s:%s",
5735 (char *) cur->nodesetval->nodeTab[i]->ns->
5736 prefix,
5737 (char *) cur->nodesetval->nodeTab[i]->name);
5738 name[sizeof(name) - 1] = 0;
5739 valuePush(ctxt, xmlXPathNewCString(name));
5740 }
5741 break;
5742 default:
5743 valuePush(ctxt,
5744 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
5745 xmlXPathLocalNameFunction(ctxt, 1);
5746 }
Owen Taylor3473f882001-02-23 17:55:21 +00005747 }
5748 xmlXPathFreeObject(cur);
5749}
5750
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005751
5752/**
Owen Taylor3473f882001-02-23 17:55:21 +00005753 * xmlXPathStringFunction:
5754 * @ctxt: the XPath Parser context
5755 * @nargs: the number of arguments
5756 *
5757 * Implement the string() XPath function
5758 * string string(object?)
5759 * he string function converts an object to a string as follows:
5760 * - A node-set is converted to a string by returning the value of
5761 * the node in the node-set that is first in document order.
5762 * If the node-set is empty, an empty string is returned.
5763 * - A number is converted to a string as follows
5764 * + NaN is converted to the string NaN
5765 * + positive zero is converted to the string 0
5766 * + negative zero is converted to the string 0
5767 * + positive infinity is converted to the string Infinity
5768 * + negative infinity is converted to the string -Infinity
5769 * + if the number is an integer, the number is represented in
5770 * decimal form as a Number with no decimal point and no leading
5771 * zeros, preceded by a minus sign (-) if the number is negative
5772 * + otherwise, the number is represented in decimal form as a
5773 * Number including a decimal point with at least one digit
5774 * before the decimal point and at least one digit after the
5775 * decimal point, preceded by a minus sign (-) if the number
5776 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005777 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00005778 * before the decimal point; beyond the one required digit
5779 * after the decimal point there must be as many, but only as
5780 * many, more digits as are needed to uniquely distinguish the
5781 * number from all other IEEE 754 numeric values.
5782 * - The boolean false value is converted to the string false.
5783 * The boolean true value is converted to the string true.
5784 *
5785 * If the argument is omitted, it defaults to a node-set with the
5786 * context node as its only member.
5787 */
5788void
5789xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5790 xmlXPathObjectPtr cur;
5791
5792 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005793 valuePush(ctxt,
5794 xmlXPathWrapString(
5795 xmlXPathCastNodeToString(ctxt->context->node)));
5796 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005797 }
5798
5799 CHECK_ARITY(1);
5800 cur = valuePop(ctxt);
5801 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005802 cur = xmlXPathConvertString(cur);
5803 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005804}
5805
5806/**
5807 * xmlXPathStringLengthFunction:
5808 * @ctxt: the XPath Parser context
5809 * @nargs: the number of arguments
5810 *
5811 * Implement the string-length() XPath function
5812 * number string-length(string?)
5813 * The string-length returns the number of characters in the string
5814 * (see [3.6 Strings]). If the argument is omitted, it defaults to
5815 * the context node converted to a string, in other words the value
5816 * of the context node.
5817 */
5818void
5819xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5820 xmlXPathObjectPtr cur;
5821
5822 if (nargs == 0) {
5823 if (ctxt->context->node == NULL) {
5824 valuePush(ctxt, xmlXPathNewFloat(0));
5825 } else {
5826 xmlChar *content;
5827
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005828 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005829 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00005830 xmlFree(content);
5831 }
5832 return;
5833 }
5834 CHECK_ARITY(1);
5835 CAST_TO_STRING;
5836 CHECK_TYPE(XPATH_STRING);
5837 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005838 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00005839 xmlXPathFreeObject(cur);
5840}
5841
5842/**
5843 * xmlXPathConcatFunction:
5844 * @ctxt: the XPath Parser context
5845 * @nargs: the number of arguments
5846 *
5847 * Implement the concat() XPath function
5848 * string concat(string, string, string*)
5849 * The concat function returns the concatenation of its arguments.
5850 */
5851void
5852xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5853 xmlXPathObjectPtr cur, newobj;
5854 xmlChar *tmp;
5855
5856 if (nargs < 2) {
5857 CHECK_ARITY(2);
5858 }
5859
5860 CAST_TO_STRING;
5861 cur = valuePop(ctxt);
5862 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
5863 xmlXPathFreeObject(cur);
5864 return;
5865 }
5866 nargs--;
5867
5868 while (nargs > 0) {
5869 CAST_TO_STRING;
5870 newobj = valuePop(ctxt);
5871 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
5872 xmlXPathFreeObject(newobj);
5873 xmlXPathFreeObject(cur);
5874 XP_ERROR(XPATH_INVALID_TYPE);
5875 }
5876 tmp = xmlStrcat(newobj->stringval, cur->stringval);
5877 newobj->stringval = cur->stringval;
5878 cur->stringval = tmp;
5879
5880 xmlXPathFreeObject(newobj);
5881 nargs--;
5882 }
5883 valuePush(ctxt, cur);
5884}
5885
5886/**
5887 * xmlXPathContainsFunction:
5888 * @ctxt: the XPath Parser context
5889 * @nargs: the number of arguments
5890 *
5891 * Implement the contains() XPath function
5892 * boolean contains(string, string)
5893 * The contains function returns true if the first argument string
5894 * contains the second argument string, and otherwise returns false.
5895 */
5896void
5897xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5898 xmlXPathObjectPtr hay, needle;
5899
5900 CHECK_ARITY(2);
5901 CAST_TO_STRING;
5902 CHECK_TYPE(XPATH_STRING);
5903 needle = valuePop(ctxt);
5904 CAST_TO_STRING;
5905 hay = valuePop(ctxt);
5906 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5907 xmlXPathFreeObject(hay);
5908 xmlXPathFreeObject(needle);
5909 XP_ERROR(XPATH_INVALID_TYPE);
5910 }
5911 if (xmlStrstr(hay->stringval, needle->stringval))
5912 valuePush(ctxt, xmlXPathNewBoolean(1));
5913 else
5914 valuePush(ctxt, xmlXPathNewBoolean(0));
5915 xmlXPathFreeObject(hay);
5916 xmlXPathFreeObject(needle);
5917}
5918
5919/**
5920 * xmlXPathStartsWithFunction:
5921 * @ctxt: the XPath Parser context
5922 * @nargs: the number of arguments
5923 *
5924 * Implement the starts-with() XPath function
5925 * boolean starts-with(string, string)
5926 * The starts-with function returns true if the first argument string
5927 * starts with the second argument string, and otherwise returns false.
5928 */
5929void
5930xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5931 xmlXPathObjectPtr hay, needle;
5932 int n;
5933
5934 CHECK_ARITY(2);
5935 CAST_TO_STRING;
5936 CHECK_TYPE(XPATH_STRING);
5937 needle = valuePop(ctxt);
5938 CAST_TO_STRING;
5939 hay = valuePop(ctxt);
5940 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5941 xmlXPathFreeObject(hay);
5942 xmlXPathFreeObject(needle);
5943 XP_ERROR(XPATH_INVALID_TYPE);
5944 }
5945 n = xmlStrlen(needle->stringval);
5946 if (xmlStrncmp(hay->stringval, needle->stringval, n))
5947 valuePush(ctxt, xmlXPathNewBoolean(0));
5948 else
5949 valuePush(ctxt, xmlXPathNewBoolean(1));
5950 xmlXPathFreeObject(hay);
5951 xmlXPathFreeObject(needle);
5952}
5953
5954/**
5955 * xmlXPathSubstringFunction:
5956 * @ctxt: the XPath Parser context
5957 * @nargs: the number of arguments
5958 *
5959 * Implement the substring() XPath function
5960 * string substring(string, number, number?)
5961 * The substring function returns the substring of the first argument
5962 * starting at the position specified in the second argument with
5963 * length specified in the third argument. For example,
5964 * substring("12345",2,3) returns "234". If the third argument is not
5965 * specified, it returns the substring starting at the position specified
5966 * in the second argument and continuing to the end of the string. For
5967 * example, substring("12345",2) returns "2345". More precisely, each
5968 * character in the string (see [3.6 Strings]) is considered to have a
5969 * numeric position: the position of the first character is 1, the position
5970 * of the second character is 2 and so on. The returned substring contains
5971 * those characters for which the position of the character is greater than
5972 * or equal to the second argument and, if the third argument is specified,
5973 * less than the sum of the second and third arguments; the comparisons
5974 * and addition used for the above follow the standard IEEE 754 rules. Thus:
5975 * - substring("12345", 1.5, 2.6) returns "234"
5976 * - substring("12345", 0, 3) returns "12"
5977 * - substring("12345", 0 div 0, 3) returns ""
5978 * - substring("12345", 1, 0 div 0) returns ""
5979 * - substring("12345", -42, 1 div 0) returns "12345"
5980 * - substring("12345", -1 div 0, 1 div 0) returns ""
5981 */
5982void
5983xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5984 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005985 double le=0, in;
5986 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00005987 xmlChar *ret;
5988
Owen Taylor3473f882001-02-23 17:55:21 +00005989 if (nargs < 2) {
5990 CHECK_ARITY(2);
5991 }
5992 if (nargs > 3) {
5993 CHECK_ARITY(3);
5994 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005995 /*
5996 * take care of possible last (position) argument
5997 */
Owen Taylor3473f882001-02-23 17:55:21 +00005998 if (nargs == 3) {
5999 CAST_TO_NUMBER;
6000 CHECK_TYPE(XPATH_NUMBER);
6001 len = valuePop(ctxt);
6002 le = len->floatval;
6003 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006004 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006005
Owen Taylor3473f882001-02-23 17:55:21 +00006006 CAST_TO_NUMBER;
6007 CHECK_TYPE(XPATH_NUMBER);
6008 start = valuePop(ctxt);
6009 in = start->floatval;
6010 xmlXPathFreeObject(start);
6011 CAST_TO_STRING;
6012 CHECK_TYPE(XPATH_STRING);
6013 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006014 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006015
Daniel Veillard97ac1312001-05-30 19:14:17 +00006016 /*
6017 * If last pos not present, calculate last position
6018 */
6019 if (nargs != 3)
6020 le = m;
6021
6022 /*
6023 * To meet our requirements, initial index calculations
6024 * must be done before we convert to integer format
6025 *
6026 * First we normalize indices
6027 */
6028 in -= 1.0;
6029 le += in;
6030 if (in < 0.0)
6031 in = 0.0;
6032 if (le > (double)m)
6033 le = (double)m;
6034
6035 /*
6036 * Now we go to integer form, rounding up
6037 */
Owen Taylor3473f882001-02-23 17:55:21 +00006038 i = (int) in;
6039 if (((double)i) != in) i++;
6040
Owen Taylor3473f882001-02-23 17:55:21 +00006041 l = (int) le;
6042 if (((double)l) != le) l++;
6043
Daniel Veillard97ac1312001-05-30 19:14:17 +00006044 if (l > m) l=m;
Owen Taylor3473f882001-02-23 17:55:21 +00006045
6046 /* number of chars to copy */
6047 l -= i;
6048
Daniel Veillard97ac1312001-05-30 19:14:17 +00006049 ret = xmlUTF8Strsub(str->stringval, i, l);
Owen Taylor3473f882001-02-23 17:55:21 +00006050 if (ret == NULL)
6051 valuePush(ctxt, xmlXPathNewCString(""));
6052 else {
6053 valuePush(ctxt, xmlXPathNewString(ret));
6054 xmlFree(ret);
6055 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006056
Owen Taylor3473f882001-02-23 17:55:21 +00006057 xmlXPathFreeObject(str);
6058}
6059
6060/**
6061 * xmlXPathSubstringBeforeFunction:
6062 * @ctxt: the XPath Parser context
6063 * @nargs: the number of arguments
6064 *
6065 * Implement the substring-before() XPath function
6066 * string substring-before(string, string)
6067 * The substring-before function returns the substring of the first
6068 * argument string that precedes the first occurrence of the second
6069 * argument string in the first argument string, or the empty string
6070 * if the first argument string does not contain the second argument
6071 * string. For example, substring-before("1999/04/01","/") returns 1999.
6072 */
6073void
6074xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6075 xmlXPathObjectPtr str;
6076 xmlXPathObjectPtr find;
6077 xmlBufferPtr target;
6078 const xmlChar *point;
6079 int offset;
6080
6081 CHECK_ARITY(2);
6082 CAST_TO_STRING;
6083 find = valuePop(ctxt);
6084 CAST_TO_STRING;
6085 str = valuePop(ctxt);
6086
6087 target = xmlBufferCreate();
6088 if (target) {
6089 point = xmlStrstr(str->stringval, find->stringval);
6090 if (point) {
6091 offset = (int)(point - str->stringval);
6092 xmlBufferAdd(target, str->stringval, offset);
6093 }
6094 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6095 xmlBufferFree(target);
6096 }
6097
6098 xmlXPathFreeObject(str);
6099 xmlXPathFreeObject(find);
6100}
6101
6102/**
6103 * xmlXPathSubstringAfterFunction:
6104 * @ctxt: the XPath Parser context
6105 * @nargs: the number of arguments
6106 *
6107 * Implement the substring-after() XPath function
6108 * string substring-after(string, string)
6109 * The substring-after function returns the substring of the first
6110 * argument string that follows the first occurrence of the second
6111 * argument string in the first argument string, or the empty stringi
6112 * if the first argument string does not contain the second argument
6113 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6114 * and substring-after("1999/04/01","19") returns 99/04/01.
6115 */
6116void
6117xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6118 xmlXPathObjectPtr str;
6119 xmlXPathObjectPtr find;
6120 xmlBufferPtr target;
6121 const xmlChar *point;
6122 int offset;
6123
6124 CHECK_ARITY(2);
6125 CAST_TO_STRING;
6126 find = valuePop(ctxt);
6127 CAST_TO_STRING;
6128 str = valuePop(ctxt);
6129
6130 target = xmlBufferCreate();
6131 if (target) {
6132 point = xmlStrstr(str->stringval, find->stringval);
6133 if (point) {
6134 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6135 xmlBufferAdd(target, &str->stringval[offset],
6136 xmlStrlen(str->stringval) - offset);
6137 }
6138 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6139 xmlBufferFree(target);
6140 }
6141
6142 xmlXPathFreeObject(str);
6143 xmlXPathFreeObject(find);
6144}
6145
6146/**
6147 * xmlXPathNormalizeFunction:
6148 * @ctxt: the XPath Parser context
6149 * @nargs: the number of arguments
6150 *
6151 * Implement the normalize-space() XPath function
6152 * string normalize-space(string?)
6153 * The normalize-space function returns the argument string with white
6154 * space normalized by stripping leading and trailing whitespace
6155 * and replacing sequences of whitespace characters by a single
6156 * space. Whitespace characters are the same allowed by the S production
6157 * in XML. If the argument is omitted, it defaults to the context
6158 * node converted to a string, in other words the value of the context node.
6159 */
6160void
6161xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6162 xmlXPathObjectPtr obj = NULL;
6163 xmlChar *source = NULL;
6164 xmlBufferPtr target;
6165 xmlChar blank;
6166
6167 if (nargs == 0) {
6168 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006169 valuePush(ctxt,
6170 xmlXPathWrapString(
6171 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006172 nargs = 1;
6173 }
6174
6175 CHECK_ARITY(1);
6176 CAST_TO_STRING;
6177 CHECK_TYPE(XPATH_STRING);
6178 obj = valuePop(ctxt);
6179 source = obj->stringval;
6180
6181 target = xmlBufferCreate();
6182 if (target && source) {
6183
6184 /* Skip leading whitespaces */
6185 while (IS_BLANK(*source))
6186 source++;
6187
6188 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6189 blank = 0;
6190 while (*source) {
6191 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006192 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006193 } else {
6194 if (blank) {
6195 xmlBufferAdd(target, &blank, 1);
6196 blank = 0;
6197 }
6198 xmlBufferAdd(target, source, 1);
6199 }
6200 source++;
6201 }
6202
6203 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6204 xmlBufferFree(target);
6205 }
6206 xmlXPathFreeObject(obj);
6207}
6208
6209/**
6210 * xmlXPathTranslateFunction:
6211 * @ctxt: the XPath Parser context
6212 * @nargs: the number of arguments
6213 *
6214 * Implement the translate() XPath function
6215 * string translate(string, string, string)
6216 * The translate function returns the first argument string with
6217 * occurrences of characters in the second argument string replaced
6218 * by the character at the corresponding position in the third argument
6219 * string. For example, translate("bar","abc","ABC") returns the string
6220 * BAr. If there is a character in the second argument string with no
6221 * character at a corresponding position in the third argument string
6222 * (because the second argument string is longer than the third argument
6223 * string), then occurrences of that character in the first argument
6224 * string are removed. For example, translate("--aaa--","abc-","ABC")
6225 * returns "AAA". If a character occurs more than once in second
6226 * argument string, then the first occurrence determines the replacement
6227 * character. If the third argument string is longer than the second
6228 * argument string, then excess characters are ignored.
6229 */
6230void
6231xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006232 xmlXPathObjectPtr str;
6233 xmlXPathObjectPtr from;
6234 xmlXPathObjectPtr to;
6235 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006236 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006237 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006238 xmlChar *point;
6239 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006240
Daniel Veillarde043ee12001-04-16 14:08:07 +00006241 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006242
Daniel Veillarde043ee12001-04-16 14:08:07 +00006243 CAST_TO_STRING;
6244 to = valuePop(ctxt);
6245 CAST_TO_STRING;
6246 from = valuePop(ctxt);
6247 CAST_TO_STRING;
6248 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006249
Daniel Veillarde043ee12001-04-16 14:08:07 +00006250 target = xmlBufferCreate();
6251 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006252 max = xmlUTF8Strlen(to->stringval);
6253 for (cptr = str->stringval; (ch=*cptr); ) {
6254 offset = xmlUTF8Strloc(from->stringval, cptr);
6255 if (offset >= 0) {
6256 if (offset < max) {
6257 point = xmlUTF8Strpos(to->stringval, offset);
6258 if (point)
6259 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6260 }
6261 } else
6262 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6263
6264 /* Step to next character in input */
6265 cptr++;
6266 if ( ch & 0x80 ) {
6267 /* if not simple ascii, verify proper format */
6268 if ( (ch & 0xc0) != 0xc0 ) {
6269 xmlGenericError(xmlGenericErrorContext,
6270 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6271 break;
6272 }
6273 /* then skip over remaining bytes for this char */
6274 while ( (ch <<= 1) & 0x80 )
6275 if ( (*cptr++ & 0xc0) != 0x80 ) {
6276 xmlGenericError(xmlGenericErrorContext,
6277 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6278 break;
6279 }
6280 if (ch & 0x80) /* must have had error encountered */
6281 break;
6282 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006283 }
Owen Taylor3473f882001-02-23 17:55:21 +00006284 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006285 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6286 xmlBufferFree(target);
6287 xmlXPathFreeObject(str);
6288 xmlXPathFreeObject(from);
6289 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006290}
6291
6292/**
6293 * xmlXPathBooleanFunction:
6294 * @ctxt: the XPath Parser context
6295 * @nargs: the number of arguments
6296 *
6297 * Implement the boolean() XPath function
6298 * boolean boolean(object)
6299 * he boolean function converts its argument to a boolean as follows:
6300 * - a number is true if and only if it is neither positive or
6301 * negative zero nor NaN
6302 * - a node-set is true if and only if it is non-empty
6303 * - a string is true if and only if its length is non-zero
6304 */
6305void
6306xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6307 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006308
6309 CHECK_ARITY(1);
6310 cur = valuePop(ctxt);
6311 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006312 cur = xmlXPathConvertBoolean(cur);
6313 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006314}
6315
6316/**
6317 * xmlXPathNotFunction:
6318 * @ctxt: the XPath Parser context
6319 * @nargs: the number of arguments
6320 *
6321 * Implement the not() XPath function
6322 * boolean not(boolean)
6323 * The not function returns true if its argument is false,
6324 * and false otherwise.
6325 */
6326void
6327xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6328 CHECK_ARITY(1);
6329 CAST_TO_BOOLEAN;
6330 CHECK_TYPE(XPATH_BOOLEAN);
6331 ctxt->value->boolval = ! ctxt->value->boolval;
6332}
6333
6334/**
6335 * xmlXPathTrueFunction:
6336 * @ctxt: the XPath Parser context
6337 * @nargs: the number of arguments
6338 *
6339 * Implement the true() XPath function
6340 * boolean true()
6341 */
6342void
6343xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6344 CHECK_ARITY(0);
6345 valuePush(ctxt, xmlXPathNewBoolean(1));
6346}
6347
6348/**
6349 * xmlXPathFalseFunction:
6350 * @ctxt: the XPath Parser context
6351 * @nargs: the number of arguments
6352 *
6353 * Implement the false() XPath function
6354 * boolean false()
6355 */
6356void
6357xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6358 CHECK_ARITY(0);
6359 valuePush(ctxt, xmlXPathNewBoolean(0));
6360}
6361
6362/**
6363 * xmlXPathLangFunction:
6364 * @ctxt: the XPath Parser context
6365 * @nargs: the number of arguments
6366 *
6367 * Implement the lang() XPath function
6368 * boolean lang(string)
6369 * The lang function returns true or false depending on whether the
6370 * language of the context node as specified by xml:lang attributes
6371 * is the same as or is a sublanguage of the language specified by
6372 * the argument string. The language of the context node is determined
6373 * by the value of the xml:lang attribute on the context node, or, if
6374 * the context node has no xml:lang attribute, by the value of the
6375 * xml:lang attribute on the nearest ancestor of the context node that
6376 * has an xml:lang attribute. If there is no such attribute, then lang
6377 * returns false. If there is such an attribute, then lang returns
6378 * true if the attribute value is equal to the argument ignoring case,
6379 * or if there is some suffix starting with - such that the attribute
6380 * value is equal to the argument ignoring that suffix of the attribute
6381 * value and ignoring case.
6382 */
6383void
6384xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6385 xmlXPathObjectPtr val;
6386 const xmlChar *theLang;
6387 const xmlChar *lang;
6388 int ret = 0;
6389 int i;
6390
6391 CHECK_ARITY(1);
6392 CAST_TO_STRING;
6393 CHECK_TYPE(XPATH_STRING);
6394 val = valuePop(ctxt);
6395 lang = val->stringval;
6396 theLang = xmlNodeGetLang(ctxt->context->node);
6397 if ((theLang != NULL) && (lang != NULL)) {
6398 for (i = 0;lang[i] != 0;i++)
6399 if (toupper(lang[i]) != toupper(theLang[i]))
6400 goto not_equal;
6401 ret = 1;
6402 }
6403not_equal:
6404 xmlXPathFreeObject(val);
6405 valuePush(ctxt, xmlXPathNewBoolean(ret));
6406}
6407
6408/**
6409 * xmlXPathNumberFunction:
6410 * @ctxt: the XPath Parser context
6411 * @nargs: the number of arguments
6412 *
6413 * Implement the number() XPath function
6414 * number number(object?)
6415 */
6416void
6417xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6418 xmlXPathObjectPtr cur;
6419 double res;
6420
6421 if (nargs == 0) {
6422 if (ctxt->context->node == NULL) {
6423 valuePush(ctxt, xmlXPathNewFloat(0.0));
6424 } else {
6425 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6426
6427 res = xmlXPathStringEvalNumber(content);
6428 valuePush(ctxt, xmlXPathNewFloat(res));
6429 xmlFree(content);
6430 }
6431 return;
6432 }
6433
6434 CHECK_ARITY(1);
6435 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006436 cur = xmlXPathConvertNumber(cur);
6437 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006438}
6439
6440/**
6441 * xmlXPathSumFunction:
6442 * @ctxt: the XPath Parser context
6443 * @nargs: the number of arguments
6444 *
6445 * Implement the sum() XPath function
6446 * number sum(node-set)
6447 * The sum function returns the sum of the values of the nodes in
6448 * the argument node-set.
6449 */
6450void
6451xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6452 xmlXPathObjectPtr cur;
6453 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006454 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006455
6456 CHECK_ARITY(1);
6457 if ((ctxt->value == NULL) ||
6458 ((ctxt->value->type != XPATH_NODESET) &&
6459 (ctxt->value->type != XPATH_XSLT_TREE)))
6460 XP_ERROR(XPATH_INVALID_TYPE);
6461 cur = valuePop(ctxt);
6462
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006463 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006464 valuePush(ctxt, xmlXPathNewFloat(0.0));
6465 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006466 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6467 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006468 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006469 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006470 }
6471 xmlXPathFreeObject(cur);
6472}
6473
6474/**
6475 * xmlXPathFloorFunction:
6476 * @ctxt: the XPath Parser context
6477 * @nargs: the number of arguments
6478 *
6479 * Implement the floor() XPath function
6480 * number floor(number)
6481 * The floor function returns the largest (closest to positive infinity)
6482 * number that is not greater than the argument and that is an integer.
6483 */
6484void
6485xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006486 double f;
6487
Owen Taylor3473f882001-02-23 17:55:21 +00006488 CHECK_ARITY(1);
6489 CAST_TO_NUMBER;
6490 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006491
6492 f = (double)((int) ctxt->value->floatval);
6493 if (f != ctxt->value->floatval) {
6494 if (ctxt->value->floatval > 0)
6495 ctxt->value->floatval = f;
6496 else
6497 ctxt->value->floatval = f - 1;
6498 }
Owen Taylor3473f882001-02-23 17:55:21 +00006499}
6500
6501/**
6502 * xmlXPathCeilingFunction:
6503 * @ctxt: the XPath Parser context
6504 * @nargs: the number of arguments
6505 *
6506 * Implement the ceiling() XPath function
6507 * number ceiling(number)
6508 * The ceiling function returns the smallest (closest to negative infinity)
6509 * number that is not less than the argument and that is an integer.
6510 */
6511void
6512xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6513 double f;
6514
6515 CHECK_ARITY(1);
6516 CAST_TO_NUMBER;
6517 CHECK_TYPE(XPATH_NUMBER);
6518
6519#if 0
6520 ctxt->value->floatval = ceil(ctxt->value->floatval);
6521#else
6522 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006523 if (f != ctxt->value->floatval) {
6524 if (ctxt->value->floatval > 0)
6525 ctxt->value->floatval = f + 1;
6526 else
6527 ctxt->value->floatval = f;
6528 }
Owen Taylor3473f882001-02-23 17:55:21 +00006529#endif
6530}
6531
6532/**
6533 * xmlXPathRoundFunction:
6534 * @ctxt: the XPath Parser context
6535 * @nargs: the number of arguments
6536 *
6537 * Implement the round() XPath function
6538 * number round(number)
6539 * The round function returns the number that is closest to the
6540 * argument and that is an integer. If there are two such numbers,
6541 * then the one that is even is returned.
6542 */
6543void
6544xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6545 double f;
6546
6547 CHECK_ARITY(1);
6548 CAST_TO_NUMBER;
6549 CHECK_TYPE(XPATH_NUMBER);
6550
Daniel Veillardcda96922001-08-21 10:56:31 +00006551 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
6552 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
6553 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00006554 (ctxt->value->floatval == 0.0))
6555 return;
6556
Owen Taylor3473f882001-02-23 17:55:21 +00006557 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00006558 if (ctxt->value->floatval < 0) {
6559 if (ctxt->value->floatval < f - 0.5)
6560 ctxt->value->floatval = f - 1;
6561 else
6562 ctxt->value->floatval = f;
6563 } else {
6564 if (ctxt->value->floatval < f + 0.5)
6565 ctxt->value->floatval = f;
6566 else
6567 ctxt->value->floatval = f + 1;
6568 }
Owen Taylor3473f882001-02-23 17:55:21 +00006569}
6570
6571/************************************************************************
6572 * *
6573 * The Parser *
6574 * *
6575 ************************************************************************/
6576
6577/*
6578 * a couple of forward declarations since we use a recursive call based
6579 * implementation.
6580 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006581static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006582static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006583static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006584#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006585static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
6586#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006587#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006588static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006589#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00006590static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
6591 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00006592
6593/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00006594 * xmlXPathCurrentChar:
6595 * @ctxt: the XPath parser context
6596 * @cur: pointer to the beginning of the char
6597 * @len: pointer to the length of the char read
6598 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006599 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00006600 * bytes in the input buffer.
6601 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006602 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00006603 */
6604
6605static int
6606xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
6607 unsigned char c;
6608 unsigned int val;
6609 const xmlChar *cur;
6610
6611 if (ctxt == NULL)
6612 return(0);
6613 cur = ctxt->cur;
6614
6615 /*
6616 * We are supposed to handle UTF8, check it's valid
6617 * From rfc2044: encoding of the Unicode values on UTF-8:
6618 *
6619 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
6620 * 0000 0000-0000 007F 0xxxxxxx
6621 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
6622 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
6623 *
6624 * Check for the 0x110000 limit too
6625 */
6626 c = *cur;
6627 if (c & 0x80) {
6628 if ((cur[1] & 0xc0) != 0x80)
6629 goto encoding_error;
6630 if ((c & 0xe0) == 0xe0) {
6631
6632 if ((cur[2] & 0xc0) != 0x80)
6633 goto encoding_error;
6634 if ((c & 0xf0) == 0xf0) {
6635 if (((c & 0xf8) != 0xf0) ||
6636 ((cur[3] & 0xc0) != 0x80))
6637 goto encoding_error;
6638 /* 4-byte code */
6639 *len = 4;
6640 val = (cur[0] & 0x7) << 18;
6641 val |= (cur[1] & 0x3f) << 12;
6642 val |= (cur[2] & 0x3f) << 6;
6643 val |= cur[3] & 0x3f;
6644 } else {
6645 /* 3-byte code */
6646 *len = 3;
6647 val = (cur[0] & 0xf) << 12;
6648 val |= (cur[1] & 0x3f) << 6;
6649 val |= cur[2] & 0x3f;
6650 }
6651 } else {
6652 /* 2-byte code */
6653 *len = 2;
6654 val = (cur[0] & 0x1f) << 6;
6655 val |= cur[1] & 0x3f;
6656 }
6657 if (!IS_CHAR(val)) {
6658 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
6659 }
6660 return(val);
6661 } else {
6662 /* 1-byte code */
6663 *len = 1;
6664 return((int) *cur);
6665 }
6666encoding_error:
6667 /*
6668 * If we detect an UTF8 error that probably mean that the
6669 * input encoding didn't get properly advertized in the
6670 * declaration header. Report the error and switch the encoding
6671 * to ISO-Latin-1 (if you don't like this policy, just declare the
6672 * encoding !)
6673 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00006674 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00006675 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006676}
6677
6678/**
Owen Taylor3473f882001-02-23 17:55:21 +00006679 * xmlXPathParseNCName:
6680 * @ctxt: the XPath Parser context
6681 *
6682 * parse an XML namespace non qualified name.
6683 *
6684 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
6685 *
6686 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
6687 * CombiningChar | Extender
6688 *
6689 * Returns the namespace name or NULL
6690 */
6691
6692xmlChar *
6693xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00006694 const xmlChar *in;
6695 xmlChar *ret;
6696 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006697
Daniel Veillard2156a562001-04-28 12:24:34 +00006698 /*
6699 * Accelerator for simple ASCII names
6700 */
6701 in = ctxt->cur;
6702 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6703 ((*in >= 0x41) && (*in <= 0x5A)) ||
6704 (*in == '_')) {
6705 in++;
6706 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6707 ((*in >= 0x41) && (*in <= 0x5A)) ||
6708 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00006709 (*in == '_') || (*in == '.') ||
6710 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00006711 in++;
6712 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
6713 (*in == '[') || (*in == ']') || (*in == ':') ||
6714 (*in == '@') || (*in == '*')) {
6715 count = in - ctxt->cur;
6716 if (count == 0)
6717 return(NULL);
6718 ret = xmlStrndup(ctxt->cur, count);
6719 ctxt->cur = in;
6720 return(ret);
6721 }
6722 }
6723 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00006724}
6725
Daniel Veillard2156a562001-04-28 12:24:34 +00006726
Owen Taylor3473f882001-02-23 17:55:21 +00006727/**
6728 * xmlXPathParseQName:
6729 * @ctxt: the XPath Parser context
6730 * @prefix: a xmlChar **
6731 *
6732 * parse an XML qualified name
6733 *
6734 * [NS 5] QName ::= (Prefix ':')? LocalPart
6735 *
6736 * [NS 6] Prefix ::= NCName
6737 *
6738 * [NS 7] LocalPart ::= NCName
6739 *
6740 * Returns the function returns the local part, and prefix is updated
6741 * to get the Prefix if any.
6742 */
6743
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006744static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006745xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
6746 xmlChar *ret = NULL;
6747
6748 *prefix = NULL;
6749 ret = xmlXPathParseNCName(ctxt);
6750 if (CUR == ':') {
6751 *prefix = ret;
6752 NEXT;
6753 ret = xmlXPathParseNCName(ctxt);
6754 }
6755 return(ret);
6756}
6757
6758/**
6759 * xmlXPathParseName:
6760 * @ctxt: the XPath Parser context
6761 *
6762 * parse an XML name
6763 *
6764 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6765 * CombiningChar | Extender
6766 *
6767 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6768 *
6769 * Returns the namespace name or NULL
6770 */
6771
6772xmlChar *
6773xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006774 const xmlChar *in;
6775 xmlChar *ret;
6776 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006777
Daniel Veillard61d80a22001-04-27 17:13:01 +00006778 /*
6779 * Accelerator for simple ASCII names
6780 */
6781 in = ctxt->cur;
6782 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6783 ((*in >= 0x41) && (*in <= 0x5A)) ||
6784 (*in == '_') || (*in == ':')) {
6785 in++;
6786 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6787 ((*in >= 0x41) && (*in <= 0x5A)) ||
6788 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00006789 (*in == '_') || (*in == '-') ||
6790 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00006791 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00006792 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006793 count = in - ctxt->cur;
6794 ret = xmlStrndup(ctxt->cur, count);
6795 ctxt->cur = in;
6796 return(ret);
6797 }
6798 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006799 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00006800}
6801
Daniel Veillard61d80a22001-04-27 17:13:01 +00006802static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00006803xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006804 xmlChar buf[XML_MAX_NAMELEN + 5];
6805 int len = 0, l;
6806 int c;
6807
6808 /*
6809 * Handler for more complex cases
6810 */
6811 c = CUR_CHAR(l);
6812 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00006813 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
6814 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00006815 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00006816 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006817 return(NULL);
6818 }
6819
6820 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
6821 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
6822 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006823 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006824 (IS_COMBINING(c)) ||
6825 (IS_EXTENDER(c)))) {
6826 COPY_BUF(l,buf,len,c);
6827 NEXTL(l);
6828 c = CUR_CHAR(l);
6829 if (len >= XML_MAX_NAMELEN) {
6830 /*
6831 * Okay someone managed to make a huge name, so he's ready to pay
6832 * for the processing speed.
6833 */
6834 xmlChar *buffer;
6835 int max = len * 2;
6836
6837 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
6838 if (buffer == NULL) {
6839 XP_ERROR0(XPATH_MEMORY_ERROR);
6840 }
6841 memcpy(buffer, buf, len);
6842 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
6843 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006844 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006845 (IS_COMBINING(c)) ||
6846 (IS_EXTENDER(c))) {
6847 if (len + 10 > max) {
6848 max *= 2;
6849 buffer = (xmlChar *) xmlRealloc(buffer,
6850 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00006851 if (buffer == NULL) {
6852 XP_ERROR0(XPATH_MEMORY_ERROR);
6853 }
6854 }
6855 COPY_BUF(l,buffer,len,c);
6856 NEXTL(l);
6857 c = CUR_CHAR(l);
6858 }
6859 buffer[len] = 0;
6860 return(buffer);
6861 }
6862 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006863 if (len == 0)
6864 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006865 return(xmlStrndup(buf, len));
6866}
Owen Taylor3473f882001-02-23 17:55:21 +00006867/**
6868 * xmlXPathStringEvalNumber:
6869 * @str: A string to scan
6870 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00006871 * [30a] Float ::= Number ('e' Digits?)?
6872 *
Owen Taylor3473f882001-02-23 17:55:21 +00006873 * [30] Number ::= Digits ('.' Digits?)?
6874 * | '.' Digits
6875 * [31] Digits ::= [0-9]+
6876 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006877 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00006878 * In complement of the Number expression, this function also handles
6879 * negative values : '-' Number.
6880 *
6881 * Returns the double value.
6882 */
6883double
6884xmlXPathStringEvalNumber(const xmlChar *str) {
6885 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00006886 double ret;
Owen Taylor3473f882001-02-23 17:55:21 +00006887 double mult = 1;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006888 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006889 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006890 int exponent = 0;
6891 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006892#ifdef __GNUC__
6893 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00006894 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006895#endif
Bjorn Reese70a9da52001-04-21 16:57:29 +00006896
Owen Taylor3473f882001-02-23 17:55:21 +00006897 while (IS_BLANK(*cur)) cur++;
6898 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
6899 return(xmlXPathNAN);
6900 }
6901 if (*cur == '-') {
6902 isneg = 1;
6903 cur++;
6904 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00006905
6906#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006907 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00006908 * tmp/temp is a workaround against a gcc compiler bug
6909 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006910 */
Daniel Veillard7b416132002-03-07 08:36:03 +00006911 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006912 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00006913 ret = ret * 10;
6914 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00006915 ok = 1;
6916 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00006917 temp = (double) tmp;
6918 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00006919 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00006920#else
Daniel Veillard7b416132002-03-07 08:36:03 +00006921 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006922 while ((*cur >= '0') && (*cur <= '9')) {
6923 ret = ret * 10 + (*cur - '0');
6924 ok = 1;
6925 cur++;
6926 }
6927#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006928
Owen Taylor3473f882001-02-23 17:55:21 +00006929 if (*cur == '.') {
6930 cur++;
6931 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
6932 return(xmlXPathNAN);
6933 }
6934 while ((*cur >= '0') && (*cur <= '9')) {
6935 mult /= 10;
6936 ret = ret + (*cur - '0') * mult;
6937 cur++;
6938 }
6939 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006940 if ((*cur == 'e') || (*cur == 'E')) {
6941 cur++;
6942 if (*cur == '-') {
6943 is_exponent_negative = 1;
6944 cur++;
6945 }
6946 while ((*cur >= '0') && (*cur <= '9')) {
6947 exponent = exponent * 10 + (*cur - '0');
6948 cur++;
6949 }
6950 }
Owen Taylor3473f882001-02-23 17:55:21 +00006951 while (IS_BLANK(*cur)) cur++;
6952 if (*cur != 0) return(xmlXPathNAN);
6953 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006954 if (is_exponent_negative) exponent = -exponent;
6955 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00006956 return(ret);
6957}
6958
6959/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006960 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00006961 * @ctxt: the XPath Parser context
6962 *
6963 * [30] Number ::= Digits ('.' Digits?)?
6964 * | '.' Digits
6965 * [31] Digits ::= [0-9]+
6966 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006967 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00006968 *
6969 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006970static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006971xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
6972{
Owen Taylor3473f882001-02-23 17:55:21 +00006973 double ret = 0.0;
6974 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00006975 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006976 int exponent = 0;
6977 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00006978#ifdef __GNUC__
6979 unsigned long tmp = 0;
6980 double temp;
6981#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006982
6983 CHECK_ERROR;
6984 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
6985 XP_ERROR(XPATH_NUMBER_ERROR);
6986 }
Daniel Veillard7b416132002-03-07 08:36:03 +00006987#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006988 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00006989 * tmp/temp is a workaround against a gcc compiler bug
6990 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006991 */
Daniel Veillard7b416132002-03-07 08:36:03 +00006992 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006993 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00006994 ret = ret * 10;
6995 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006996 ok = 1;
6997 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00006998 temp = (double) tmp;
6999 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007000 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007001#else
7002 ret = 0;
7003 while ((CUR >= '0') && (CUR <= '9')) {
7004 ret = ret * 10 + (CUR - '0');
7005 ok = 1;
7006 NEXT;
7007 }
7008#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007009 if (CUR == '.') {
7010 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007011 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7012 XP_ERROR(XPATH_NUMBER_ERROR);
7013 }
7014 while ((CUR >= '0') && (CUR <= '9')) {
7015 mult /= 10;
7016 ret = ret + (CUR - '0') * mult;
7017 NEXT;
7018 }
Owen Taylor3473f882001-02-23 17:55:21 +00007019 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007020 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007021 NEXT;
7022 if (CUR == '-') {
7023 is_exponent_negative = 1;
7024 NEXT;
7025 }
7026 while ((CUR >= '0') && (CUR <= '9')) {
7027 exponent = exponent * 10 + (CUR - '0');
7028 NEXT;
7029 }
7030 if (is_exponent_negative)
7031 exponent = -exponent;
7032 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007033 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007034 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007035 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007036}
7037
7038/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007039 * xmlXPathParseLiteral:
7040 * @ctxt: the XPath Parser context
7041 *
7042 * Parse a Literal
7043 *
7044 * [29] Literal ::= '"' [^"]* '"'
7045 * | "'" [^']* "'"
7046 *
7047 * Returns the value found or NULL in case of error
7048 */
7049static xmlChar *
7050xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7051 const xmlChar *q;
7052 xmlChar *ret = NULL;
7053
7054 if (CUR == '"') {
7055 NEXT;
7056 q = CUR_PTR;
7057 while ((IS_CHAR(CUR)) && (CUR != '"'))
7058 NEXT;
7059 if (!IS_CHAR(CUR)) {
7060 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7061 } else {
7062 ret = xmlStrndup(q, CUR_PTR - q);
7063 NEXT;
7064 }
7065 } else if (CUR == '\'') {
7066 NEXT;
7067 q = CUR_PTR;
7068 while ((IS_CHAR(CUR)) && (CUR != '\''))
7069 NEXT;
7070 if (!IS_CHAR(CUR)) {
7071 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7072 } else {
7073 ret = xmlStrndup(q, CUR_PTR - q);
7074 NEXT;
7075 }
7076 } else {
7077 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7078 }
7079 return(ret);
7080}
7081
7082/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007083 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007084 * @ctxt: the XPath Parser context
7085 *
7086 * Parse a Literal and push it on the stack.
7087 *
7088 * [29] Literal ::= '"' [^"]* '"'
7089 * | "'" [^']* "'"
7090 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007091 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007092 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007093static void
7094xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007095 const xmlChar *q;
7096 xmlChar *ret = NULL;
7097
7098 if (CUR == '"') {
7099 NEXT;
7100 q = CUR_PTR;
7101 while ((IS_CHAR(CUR)) && (CUR != '"'))
7102 NEXT;
7103 if (!IS_CHAR(CUR)) {
7104 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7105 } else {
7106 ret = xmlStrndup(q, CUR_PTR - q);
7107 NEXT;
7108 }
7109 } else if (CUR == '\'') {
7110 NEXT;
7111 q = CUR_PTR;
7112 while ((IS_CHAR(CUR)) && (CUR != '\''))
7113 NEXT;
7114 if (!IS_CHAR(CUR)) {
7115 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7116 } else {
7117 ret = xmlStrndup(q, CUR_PTR - q);
7118 NEXT;
7119 }
7120 } else {
7121 XP_ERROR(XPATH_START_LITERAL_ERROR);
7122 }
7123 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007124 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7125 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007126 xmlFree(ret);
7127}
7128
7129/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007130 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007131 * @ctxt: the XPath Parser context
7132 *
7133 * Parse a VariableReference, evaluate it and push it on the stack.
7134 *
7135 * The variable bindings consist of a mapping from variable names
7136 * to variable values. The value of a variable is an object, which
7137 * of any of the types that are possible for the value of an expression,
7138 * and may also be of additional types not specified here.
7139 *
7140 * Early evaluation is possible since:
7141 * The variable bindings [...] used to evaluate a subexpression are
7142 * always the same as those used to evaluate the containing expression.
7143 *
7144 * [36] VariableReference ::= '$' QName
7145 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007146static void
7147xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007148 xmlChar *name;
7149 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007150
7151 SKIP_BLANKS;
7152 if (CUR != '$') {
7153 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7154 }
7155 NEXT;
7156 name = xmlXPathParseQName(ctxt, &prefix);
7157 if (name == NULL) {
7158 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7159 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007160 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007161 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7162 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007163 SKIP_BLANKS;
7164}
7165
7166/**
7167 * xmlXPathIsNodeType:
7168 * @ctxt: the XPath Parser context
7169 * @name: a name string
7170 *
7171 * Is the name given a NodeType one.
7172 *
7173 * [38] NodeType ::= 'comment'
7174 * | 'text'
7175 * | 'processing-instruction'
7176 * | 'node'
7177 *
7178 * Returns 1 if true 0 otherwise
7179 */
7180int
7181xmlXPathIsNodeType(const xmlChar *name) {
7182 if (name == NULL)
7183 return(0);
7184
Daniel Veillard1971ee22002-01-31 20:29:19 +00007185 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007186 return(1);
7187 if (xmlStrEqual(name, BAD_CAST "text"))
7188 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007189 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007190 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007191 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007192 return(1);
7193 return(0);
7194}
7195
7196/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007197 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007198 * @ctxt: the XPath Parser context
7199 *
7200 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7201 * [17] Argument ::= Expr
7202 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007203 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007204 * pushed on the stack
7205 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007206static void
7207xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007208 xmlChar *name;
7209 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007210 int nbargs = 0;
7211
7212 name = xmlXPathParseQName(ctxt, &prefix);
7213 if (name == NULL) {
7214 XP_ERROR(XPATH_EXPR_ERROR);
7215 }
7216 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007217#ifdef DEBUG_EXPR
7218 if (prefix == NULL)
7219 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7220 name);
7221 else
7222 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7223 prefix, name);
7224#endif
7225
Owen Taylor3473f882001-02-23 17:55:21 +00007226 if (CUR != '(') {
7227 XP_ERROR(XPATH_EXPR_ERROR);
7228 }
7229 NEXT;
7230 SKIP_BLANKS;
7231
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007232 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007233 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007234 int op1 = ctxt->comp->last;
7235 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007236 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007237 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007238 nbargs++;
7239 if (CUR == ')') break;
7240 if (CUR != ',') {
7241 XP_ERROR(XPATH_EXPR_ERROR);
7242 }
7243 NEXT;
7244 SKIP_BLANKS;
7245 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007246 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7247 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007248 NEXT;
7249 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007250}
7251
7252/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007253 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007254 * @ctxt: the XPath Parser context
7255 *
7256 * [15] PrimaryExpr ::= VariableReference
7257 * | '(' Expr ')'
7258 * | Literal
7259 * | Number
7260 * | FunctionCall
7261 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007262 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007263 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007264static void
7265xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007266 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007267 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007268 else if (CUR == '(') {
7269 NEXT;
7270 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007271 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007272 if (CUR != ')') {
7273 XP_ERROR(XPATH_EXPR_ERROR);
7274 }
7275 NEXT;
7276 SKIP_BLANKS;
7277 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007278 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007279 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007280 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007281 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007282 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007283 }
7284 SKIP_BLANKS;
7285}
7286
7287/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007288 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007289 * @ctxt: the XPath Parser context
7290 *
7291 * [20] FilterExpr ::= PrimaryExpr
7292 * | FilterExpr Predicate
7293 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007294 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007295 * Square brackets are used to filter expressions in the same way that
7296 * they are used in location paths. It is an error if the expression to
7297 * be filtered does not evaluate to a node-set. The context node list
7298 * used for evaluating the expression in square brackets is the node-set
7299 * to be filtered listed in document order.
7300 */
7301
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007302static void
7303xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7304 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007305 CHECK_ERROR;
7306 SKIP_BLANKS;
7307
7308 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007309 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007310 SKIP_BLANKS;
7311 }
7312
7313
7314}
7315
7316/**
7317 * xmlXPathScanName:
7318 * @ctxt: the XPath Parser context
7319 *
7320 * Trickery: parse an XML name but without consuming the input flow
7321 * Needed to avoid insanity in the parser state.
7322 *
7323 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7324 * CombiningChar | Extender
7325 *
7326 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7327 *
7328 * [6] Names ::= Name (S Name)*
7329 *
7330 * Returns the Name parsed or NULL
7331 */
7332
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007333static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007334xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7335 xmlChar buf[XML_MAX_NAMELEN];
7336 int len = 0;
7337
7338 SKIP_BLANKS;
7339 if (!IS_LETTER(CUR) && (CUR != '_') &&
7340 (CUR != ':')) {
7341 return(NULL);
7342 }
7343
7344 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7345 (NXT(len) == '.') || (NXT(len) == '-') ||
7346 (NXT(len) == '_') || (NXT(len) == ':') ||
7347 (IS_COMBINING(NXT(len))) ||
7348 (IS_EXTENDER(NXT(len)))) {
7349 buf[len] = NXT(len);
7350 len++;
7351 if (len >= XML_MAX_NAMELEN) {
7352 xmlGenericError(xmlGenericErrorContext,
7353 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7354 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7355 (NXT(len) == '.') || (NXT(len) == '-') ||
7356 (NXT(len) == '_') || (NXT(len) == ':') ||
7357 (IS_COMBINING(NXT(len))) ||
7358 (IS_EXTENDER(NXT(len))))
7359 len++;
7360 break;
7361 }
7362 }
7363 return(xmlStrndup(buf, len));
7364}
7365
7366/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007367 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007368 * @ctxt: the XPath Parser context
7369 *
7370 * [19] PathExpr ::= LocationPath
7371 * | FilterExpr
7372 * | FilterExpr '/' RelativeLocationPath
7373 * | FilterExpr '//' RelativeLocationPath
7374 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007375 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007376 * The / operator and // operators combine an arbitrary expression
7377 * and a relative location path. It is an error if the expression
7378 * does not evaluate to a node-set.
7379 * The / operator does composition in the same way as when / is
7380 * used in a location path. As in location paths, // is short for
7381 * /descendant-or-self::node()/.
7382 */
7383
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007384static void
7385xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007386 int lc = 1; /* Should we branch to LocationPath ? */
7387 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7388
7389 SKIP_BLANKS;
7390 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
7391 (CUR == '\'') || (CUR == '"')) {
7392 lc = 0;
7393 } else if (CUR == '*') {
7394 /* relative or absolute location path */
7395 lc = 1;
7396 } else if (CUR == '/') {
7397 /* relative or absolute location path */
7398 lc = 1;
7399 } else if (CUR == '@') {
7400 /* relative abbreviated attribute location path */
7401 lc = 1;
7402 } else if (CUR == '.') {
7403 /* relative abbreviated attribute location path */
7404 lc = 1;
7405 } else {
7406 /*
7407 * Problem is finding if we have a name here whether it's:
7408 * - a nodetype
7409 * - a function call in which case it's followed by '('
7410 * - an axis in which case it's followed by ':'
7411 * - a element name
7412 * We do an a priori analysis here rather than having to
7413 * maintain parsed token content through the recursive function
7414 * calls. This looks uglier but makes the code quite easier to
7415 * read/write/debug.
7416 */
7417 SKIP_BLANKS;
7418 name = xmlXPathScanName(ctxt);
7419 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7420#ifdef DEBUG_STEP
7421 xmlGenericError(xmlGenericErrorContext,
7422 "PathExpr: Axis\n");
7423#endif
7424 lc = 1;
7425 xmlFree(name);
7426 } else if (name != NULL) {
7427 int len =xmlStrlen(name);
7428 int blank = 0;
7429
7430
7431 while (NXT(len) != 0) {
7432 if (NXT(len) == '/') {
7433 /* element name */
7434#ifdef DEBUG_STEP
7435 xmlGenericError(xmlGenericErrorContext,
7436 "PathExpr: AbbrRelLocation\n");
7437#endif
7438 lc = 1;
7439 break;
7440 } else if (IS_BLANK(NXT(len))) {
7441 /* skip to next */
7442 blank = 1;
7443 } else if (NXT(len) == ':') {
7444#ifdef DEBUG_STEP
7445 xmlGenericError(xmlGenericErrorContext,
7446 "PathExpr: AbbrRelLocation\n");
7447#endif
7448 lc = 1;
7449 break;
7450 } else if ((NXT(len) == '(')) {
7451 /* Note Type or Function */
7452 if (xmlXPathIsNodeType(name)) {
7453#ifdef DEBUG_STEP
7454 xmlGenericError(xmlGenericErrorContext,
7455 "PathExpr: Type search\n");
7456#endif
7457 lc = 1;
7458 } else {
7459#ifdef DEBUG_STEP
7460 xmlGenericError(xmlGenericErrorContext,
7461 "PathExpr: function call\n");
7462#endif
7463 lc = 0;
7464 }
7465 break;
7466 } else if ((NXT(len) == '[')) {
7467 /* element name */
7468#ifdef DEBUG_STEP
7469 xmlGenericError(xmlGenericErrorContext,
7470 "PathExpr: AbbrRelLocation\n");
7471#endif
7472 lc = 1;
7473 break;
7474 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7475 (NXT(len) == '=')) {
7476 lc = 1;
7477 break;
7478 } else {
7479 lc = 1;
7480 break;
7481 }
7482 len++;
7483 }
7484 if (NXT(len) == 0) {
7485#ifdef DEBUG_STEP
7486 xmlGenericError(xmlGenericErrorContext,
7487 "PathExpr: AbbrRelLocation\n");
7488#endif
7489 /* element name */
7490 lc = 1;
7491 }
7492 xmlFree(name);
7493 } else {
7494 /* make sure all cases are covered explicitely */
7495 XP_ERROR(XPATH_EXPR_ERROR);
7496 }
7497 }
7498
7499 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007500 if (CUR == '/') {
7501 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7502 } else {
7503 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007504 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007505 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007506 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007507 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007508 CHECK_ERROR;
7509 if ((CUR == '/') && (NXT(1) == '/')) {
7510 SKIP(2);
7511 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007512
7513 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7514 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7515 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7516
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007517 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007518 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007519 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007520 }
7521 }
7522 SKIP_BLANKS;
7523}
7524
7525/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007526 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007527 * @ctxt: the XPath Parser context
7528 *
7529 * [18] UnionExpr ::= PathExpr
7530 * | UnionExpr '|' PathExpr
7531 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007532 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007533 */
7534
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007535static void
7536xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7537 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007538 CHECK_ERROR;
7539 SKIP_BLANKS;
7540 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007541 int op1 = ctxt->comp->last;
7542 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007543
7544 NEXT;
7545 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007546 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007547
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007548 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
7549
Owen Taylor3473f882001-02-23 17:55:21 +00007550 SKIP_BLANKS;
7551 }
Owen Taylor3473f882001-02-23 17:55:21 +00007552}
7553
7554/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007555 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007556 * @ctxt: the XPath Parser context
7557 *
7558 * [27] UnaryExpr ::= UnionExpr
7559 * | '-' UnaryExpr
7560 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007561 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007562 */
7563
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007564static void
7565xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007566 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007567 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007568
7569 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00007570 while (CUR == '-') {
7571 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007572 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007573 NEXT;
7574 SKIP_BLANKS;
7575 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007576
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007577 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007578 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007579 if (found) {
7580 if (minus)
7581 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
7582 else
7583 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007584 }
7585}
7586
7587/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007588 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007589 * @ctxt: the XPath Parser context
7590 *
7591 * [26] MultiplicativeExpr ::= UnaryExpr
7592 * | MultiplicativeExpr MultiplyOperator UnaryExpr
7593 * | MultiplicativeExpr 'div' UnaryExpr
7594 * | MultiplicativeExpr 'mod' UnaryExpr
7595 * [34] MultiplyOperator ::= '*'
7596 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007597 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007598 */
7599
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007600static void
7601xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
7602 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007603 CHECK_ERROR;
7604 SKIP_BLANKS;
7605 while ((CUR == '*') ||
7606 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
7607 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
7608 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007609 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007610
7611 if (CUR == '*') {
7612 op = 0;
7613 NEXT;
7614 } else if (CUR == 'd') {
7615 op = 1;
7616 SKIP(3);
7617 } else if (CUR == 'm') {
7618 op = 2;
7619 SKIP(3);
7620 }
7621 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007622 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007623 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007624 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007625 SKIP_BLANKS;
7626 }
7627}
7628
7629/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007630 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007631 * @ctxt: the XPath Parser context
7632 *
7633 * [25] AdditiveExpr ::= MultiplicativeExpr
7634 * | AdditiveExpr '+' MultiplicativeExpr
7635 * | AdditiveExpr '-' MultiplicativeExpr
7636 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007637 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007638 */
7639
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007640static void
7641xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007642
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007643 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007644 CHECK_ERROR;
7645 SKIP_BLANKS;
7646 while ((CUR == '+') || (CUR == '-')) {
7647 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007648 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007649
7650 if (CUR == '+') plus = 1;
7651 else plus = 0;
7652 NEXT;
7653 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007654 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007655 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007656 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007657 SKIP_BLANKS;
7658 }
7659}
7660
7661/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007662 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007663 * @ctxt: the XPath Parser context
7664 *
7665 * [24] RelationalExpr ::= AdditiveExpr
7666 * | RelationalExpr '<' AdditiveExpr
7667 * | RelationalExpr '>' AdditiveExpr
7668 * | RelationalExpr '<=' AdditiveExpr
7669 * | RelationalExpr '>=' AdditiveExpr
7670 *
7671 * A <= B > C is allowed ? Answer from James, yes with
7672 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
7673 * which is basically what got implemented.
7674 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007675 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00007676 * on the stack
7677 */
7678
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007679static void
7680xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
7681 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007682 CHECK_ERROR;
7683 SKIP_BLANKS;
7684 while ((CUR == '<') ||
7685 (CUR == '>') ||
7686 ((CUR == '<') && (NXT(1) == '=')) ||
7687 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007688 int inf, strict;
7689 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007690
7691 if (CUR == '<') inf = 1;
7692 else inf = 0;
7693 if (NXT(1) == '=') strict = 0;
7694 else strict = 1;
7695 NEXT;
7696 if (!strict) NEXT;
7697 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007698 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007699 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007700 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00007701 SKIP_BLANKS;
7702 }
7703}
7704
7705/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007706 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007707 * @ctxt: the XPath Parser context
7708 *
7709 * [23] EqualityExpr ::= RelationalExpr
7710 * | EqualityExpr '=' RelationalExpr
7711 * | EqualityExpr '!=' RelationalExpr
7712 *
7713 * A != B != C is allowed ? Answer from James, yes with
7714 * (RelationalExpr = RelationalExpr) = RelationalExpr
7715 * (RelationalExpr != RelationalExpr) != RelationalExpr
7716 * which is basically what got implemented.
7717 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007718 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007719 *
7720 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007721static void
7722xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
7723 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007724 CHECK_ERROR;
7725 SKIP_BLANKS;
7726 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007727 int eq;
7728 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007729
7730 if (CUR == '=') eq = 1;
7731 else eq = 0;
7732 NEXT;
7733 if (!eq) NEXT;
7734 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007735 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007736 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007737 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007738 SKIP_BLANKS;
7739 }
7740}
7741
7742/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007743 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007744 * @ctxt: the XPath Parser context
7745 *
7746 * [22] AndExpr ::= EqualityExpr
7747 * | AndExpr 'and' EqualityExpr
7748 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007749 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007750 *
7751 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007752static void
7753xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
7754 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007755 CHECK_ERROR;
7756 SKIP_BLANKS;
7757 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007758 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007759 SKIP(3);
7760 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007761 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007762 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007763 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007764 SKIP_BLANKS;
7765 }
7766}
7767
7768/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007769 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007770 * @ctxt: the XPath Parser context
7771 *
7772 * [14] Expr ::= OrExpr
7773 * [21] OrExpr ::= AndExpr
7774 * | OrExpr 'or' AndExpr
7775 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007776 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00007777 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007778static void
7779xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
7780 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007781 CHECK_ERROR;
7782 SKIP_BLANKS;
7783 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007784 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007785 SKIP(2);
7786 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007787 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007788 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007789 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
7790 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00007791 SKIP_BLANKS;
7792 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007793 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
7794 /* more ops could be optimized too */
7795 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
7796 }
Owen Taylor3473f882001-02-23 17:55:21 +00007797}
7798
7799/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007800 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00007801 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007802 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00007803 *
7804 * [8] Predicate ::= '[' PredicateExpr ']'
7805 * [9] PredicateExpr ::= Expr
7806 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007807 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00007808 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007809static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007810xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007811 int op1 = ctxt->comp->last;
7812
7813 SKIP_BLANKS;
7814 if (CUR != '[') {
7815 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7816 }
7817 NEXT;
7818 SKIP_BLANKS;
7819
7820 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007821 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007822 CHECK_ERROR;
7823
7824 if (CUR != ']') {
7825 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7826 }
7827
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007828 if (filter)
7829 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
7830 else
7831 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007832
7833 NEXT;
7834 SKIP_BLANKS;
7835}
7836
7837/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007838 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00007839 * @ctxt: the XPath Parser context
7840 * @test: pointer to a xmlXPathTestVal
7841 * @type: pointer to a xmlXPathTypeVal
7842 * @prefix: placeholder for a possible name prefix
7843 *
7844 * [7] NodeTest ::= NameTest
7845 * | NodeType '(' ')'
7846 * | 'processing-instruction' '(' Literal ')'
7847 *
7848 * [37] NameTest ::= '*'
7849 * | NCName ':' '*'
7850 * | QName
7851 * [38] NodeType ::= 'comment'
7852 * | 'text'
7853 * | 'processing-instruction'
7854 * | 'node'
7855 *
7856 * Returns the name found and update @test, @type and @prefix appropriately
7857 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007858static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007859xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
7860 xmlXPathTypeVal *type, const xmlChar **prefix,
7861 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00007862 int blanks;
7863
7864 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
7865 STRANGE;
7866 return(NULL);
7867 }
7868 *type = 0;
7869 *test = 0;
7870 *prefix = NULL;
7871 SKIP_BLANKS;
7872
7873 if ((name == NULL) && (CUR == '*')) {
7874 /*
7875 * All elements
7876 */
7877 NEXT;
7878 *test = NODE_TEST_ALL;
7879 return(NULL);
7880 }
7881
7882 if (name == NULL)
7883 name = xmlXPathParseNCName(ctxt);
7884 if (name == NULL) {
7885 XP_ERROR0(XPATH_EXPR_ERROR);
7886 }
7887
7888 blanks = IS_BLANK(CUR);
7889 SKIP_BLANKS;
7890 if (CUR == '(') {
7891 NEXT;
7892 /*
7893 * NodeType or PI search
7894 */
7895 if (xmlStrEqual(name, BAD_CAST "comment"))
7896 *type = NODE_TYPE_COMMENT;
7897 else if (xmlStrEqual(name, BAD_CAST "node"))
7898 *type = NODE_TYPE_NODE;
7899 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
7900 *type = NODE_TYPE_PI;
7901 else if (xmlStrEqual(name, BAD_CAST "text"))
7902 *type = NODE_TYPE_TEXT;
7903 else {
7904 if (name != NULL)
7905 xmlFree(name);
7906 XP_ERROR0(XPATH_EXPR_ERROR);
7907 }
7908
7909 *test = NODE_TEST_TYPE;
7910
7911 SKIP_BLANKS;
7912 if (*type == NODE_TYPE_PI) {
7913 /*
7914 * Specific case: search a PI by name.
7915 */
Owen Taylor3473f882001-02-23 17:55:21 +00007916 if (name != NULL)
7917 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00007918 name = NULL;
7919 if (CUR != ')') {
7920 name = xmlXPathParseLiteral(ctxt);
7921 CHECK_ERROR 0;
7922 SKIP_BLANKS;
7923 }
Owen Taylor3473f882001-02-23 17:55:21 +00007924 }
7925 if (CUR != ')') {
7926 if (name != NULL)
7927 xmlFree(name);
7928 XP_ERROR0(XPATH_UNCLOSED_ERROR);
7929 }
7930 NEXT;
7931 return(name);
7932 }
7933 *test = NODE_TEST_NAME;
7934 if ((!blanks) && (CUR == ':')) {
7935 NEXT;
7936
7937 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007938 * Since currently the parser context don't have a
7939 * namespace list associated:
7940 * The namespace name for this prefix can be computed
7941 * only at evaluation time. The compilation is done
7942 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00007943 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007944#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00007945 *prefix = xmlXPathNsLookup(ctxt->context, name);
7946 if (name != NULL)
7947 xmlFree(name);
7948 if (*prefix == NULL) {
7949 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
7950 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007951#else
7952 *prefix = name;
7953#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007954
7955 if (CUR == '*') {
7956 /*
7957 * All elements
7958 */
7959 NEXT;
7960 *test = NODE_TEST_ALL;
7961 return(NULL);
7962 }
7963
7964 name = xmlXPathParseNCName(ctxt);
7965 if (name == NULL) {
7966 XP_ERROR0(XPATH_EXPR_ERROR);
7967 }
7968 }
7969 return(name);
7970}
7971
7972/**
7973 * xmlXPathIsAxisName:
7974 * @name: a preparsed name token
7975 *
7976 * [6] AxisName ::= 'ancestor'
7977 * | 'ancestor-or-self'
7978 * | 'attribute'
7979 * | 'child'
7980 * | 'descendant'
7981 * | 'descendant-or-self'
7982 * | 'following'
7983 * | 'following-sibling'
7984 * | 'namespace'
7985 * | 'parent'
7986 * | 'preceding'
7987 * | 'preceding-sibling'
7988 * | 'self'
7989 *
7990 * Returns the axis or 0
7991 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007992static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00007993xmlXPathIsAxisName(const xmlChar *name) {
7994 xmlXPathAxisVal ret = 0;
7995 switch (name[0]) {
7996 case 'a':
7997 if (xmlStrEqual(name, BAD_CAST "ancestor"))
7998 ret = AXIS_ANCESTOR;
7999 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8000 ret = AXIS_ANCESTOR_OR_SELF;
8001 if (xmlStrEqual(name, BAD_CAST "attribute"))
8002 ret = AXIS_ATTRIBUTE;
8003 break;
8004 case 'c':
8005 if (xmlStrEqual(name, BAD_CAST "child"))
8006 ret = AXIS_CHILD;
8007 break;
8008 case 'd':
8009 if (xmlStrEqual(name, BAD_CAST "descendant"))
8010 ret = AXIS_DESCENDANT;
8011 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8012 ret = AXIS_DESCENDANT_OR_SELF;
8013 break;
8014 case 'f':
8015 if (xmlStrEqual(name, BAD_CAST "following"))
8016 ret = AXIS_FOLLOWING;
8017 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8018 ret = AXIS_FOLLOWING_SIBLING;
8019 break;
8020 case 'n':
8021 if (xmlStrEqual(name, BAD_CAST "namespace"))
8022 ret = AXIS_NAMESPACE;
8023 break;
8024 case 'p':
8025 if (xmlStrEqual(name, BAD_CAST "parent"))
8026 ret = AXIS_PARENT;
8027 if (xmlStrEqual(name, BAD_CAST "preceding"))
8028 ret = AXIS_PRECEDING;
8029 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8030 ret = AXIS_PRECEDING_SIBLING;
8031 break;
8032 case 's':
8033 if (xmlStrEqual(name, BAD_CAST "self"))
8034 ret = AXIS_SELF;
8035 break;
8036 }
8037 return(ret);
8038}
8039
8040/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008041 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008042 * @ctxt: the XPath Parser context
8043 *
8044 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8045 * | AbbreviatedStep
8046 *
8047 * [12] AbbreviatedStep ::= '.' | '..'
8048 *
8049 * [5] AxisSpecifier ::= AxisName '::'
8050 * | AbbreviatedAxisSpecifier
8051 *
8052 * [13] AbbreviatedAxisSpecifier ::= '@'?
8053 *
8054 * Modified for XPtr range support as:
8055 *
8056 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8057 * | AbbreviatedStep
8058 * | 'range-to' '(' Expr ')' Predicate*
8059 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008060 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008061 * A location step of . is short for self::node(). This is
8062 * particularly useful in conjunction with //. For example, the
8063 * location path .//para is short for
8064 * self::node()/descendant-or-self::node()/child::para
8065 * and so will select all para descendant elements of the context
8066 * node.
8067 * Similarly, a location step of .. is short for parent::node().
8068 * For example, ../title is short for parent::node()/child::title
8069 * and so will select the title children of the parent of the context
8070 * node.
8071 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008072static void
8073xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008074#ifdef LIBXML_XPTR_ENABLED
8075 int rangeto = 0;
8076 int op2 = -1;
8077#endif
8078
Owen Taylor3473f882001-02-23 17:55:21 +00008079 SKIP_BLANKS;
8080 if ((CUR == '.') && (NXT(1) == '.')) {
8081 SKIP(2);
8082 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008083 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8084 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008085 } else if (CUR == '.') {
8086 NEXT;
8087 SKIP_BLANKS;
8088 } else {
8089 xmlChar *name = NULL;
8090 const xmlChar *prefix = NULL;
8091 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008092 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008093 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008094 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008095
8096 /*
8097 * The modification needed for XPointer change to the production
8098 */
8099#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008100 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008101 name = xmlXPathParseNCName(ctxt);
8102 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008103 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008104 xmlFree(name);
8105 SKIP_BLANKS;
8106 if (CUR != '(') {
8107 XP_ERROR(XPATH_EXPR_ERROR);
8108 }
8109 NEXT;
8110 SKIP_BLANKS;
8111
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008112 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008113 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008114 CHECK_ERROR;
8115
8116 SKIP_BLANKS;
8117 if (CUR != ')') {
8118 XP_ERROR(XPATH_EXPR_ERROR);
8119 }
8120 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008121 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008122 goto eval_predicates;
8123 }
8124 }
8125#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008126 if (CUR == '*') {
8127 axis = AXIS_CHILD;
8128 } else {
8129 if (name == NULL)
8130 name = xmlXPathParseNCName(ctxt);
8131 if (name != NULL) {
8132 axis = xmlXPathIsAxisName(name);
8133 if (axis != 0) {
8134 SKIP_BLANKS;
8135 if ((CUR == ':') && (NXT(1) == ':')) {
8136 SKIP(2);
8137 xmlFree(name);
8138 name = NULL;
8139 } else {
8140 /* an element name can conflict with an axis one :-\ */
8141 axis = AXIS_CHILD;
8142 }
Owen Taylor3473f882001-02-23 17:55:21 +00008143 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008144 axis = AXIS_CHILD;
8145 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008146 } else if (CUR == '@') {
8147 NEXT;
8148 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008149 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008150 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008151 }
Owen Taylor3473f882001-02-23 17:55:21 +00008152 }
8153
8154 CHECK_ERROR;
8155
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008156 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008157 if (test == 0)
8158 return;
8159
8160#ifdef DEBUG_STEP
8161 xmlGenericError(xmlGenericErrorContext,
8162 "Basis : computing new set\n");
8163#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008164
Owen Taylor3473f882001-02-23 17:55:21 +00008165#ifdef DEBUG_STEP
8166 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008167 if (ctxt->value == NULL)
8168 xmlGenericError(xmlGenericErrorContext, "no value\n");
8169 else if (ctxt->value->nodesetval == NULL)
8170 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8171 else
8172 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008173#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008174
8175eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008176 op1 = ctxt->comp->last;
8177 ctxt->comp->last = -1;
8178
Owen Taylor3473f882001-02-23 17:55:21 +00008179 SKIP_BLANKS;
8180 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008181 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008182 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008183
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008184#ifdef LIBXML_XPTR_ENABLED
8185 if (rangeto) {
8186 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8187 } else
8188#endif
8189 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8190 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008191
Owen Taylor3473f882001-02-23 17:55:21 +00008192 }
8193#ifdef DEBUG_STEP
8194 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008195 if (ctxt->value == NULL)
8196 xmlGenericError(xmlGenericErrorContext, "no value\n");
8197 else if (ctxt->value->nodesetval == NULL)
8198 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8199 else
8200 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8201 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008202#endif
8203}
8204
8205/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008206 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008207 * @ctxt: the XPath Parser context
8208 *
8209 * [3] RelativeLocationPath ::= Step
8210 * | RelativeLocationPath '/' Step
8211 * | AbbreviatedRelativeLocationPath
8212 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8213 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008214 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008215 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008216static void
Owen Taylor3473f882001-02-23 17:55:21 +00008217#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008218xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008219#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008220xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008221#endif
8222(xmlXPathParserContextPtr ctxt) {
8223 SKIP_BLANKS;
8224 if ((CUR == '/') && (NXT(1) == '/')) {
8225 SKIP(2);
8226 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008227 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8228 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008229 } else if (CUR == '/') {
8230 NEXT;
8231 SKIP_BLANKS;
8232 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008233 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008234 SKIP_BLANKS;
8235 while (CUR == '/') {
8236 if ((CUR == '/') && (NXT(1) == '/')) {
8237 SKIP(2);
8238 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008239 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008240 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008241 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008242 } else if (CUR == '/') {
8243 NEXT;
8244 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008245 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008246 }
8247 SKIP_BLANKS;
8248 }
8249}
8250
8251/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008252 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008253 * @ctxt: the XPath Parser context
8254 *
8255 * [1] LocationPath ::= RelativeLocationPath
8256 * | AbsoluteLocationPath
8257 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8258 * | AbbreviatedAbsoluteLocationPath
8259 * [10] AbbreviatedAbsoluteLocationPath ::=
8260 * '//' RelativeLocationPath
8261 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008262 * Compile a location path
8263 *
Owen Taylor3473f882001-02-23 17:55:21 +00008264 * // is short for /descendant-or-self::node()/. For example,
8265 * //para is short for /descendant-or-self::node()/child::para and
8266 * so will select any para element in the document (even a para element
8267 * that is a document element will be selected by //para since the
8268 * document element node is a child of the root node); div//para is
8269 * short for div/descendant-or-self::node()/child::para and so will
8270 * select all para descendants of div children.
8271 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008272static void
8273xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008274 SKIP_BLANKS;
8275 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008276 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008277 } else {
8278 while (CUR == '/') {
8279 if ((CUR == '/') && (NXT(1) == '/')) {
8280 SKIP(2);
8281 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008282 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8283 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008284 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008285 } else if (CUR == '/') {
8286 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008287 SKIP_BLANKS;
8288 if ((CUR != 0 ) &&
8289 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
8290 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008291 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008292 }
8293 }
8294 }
8295}
8296
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008297/************************************************************************
8298 * *
8299 * XPath precompiled expression evaluation *
8300 * *
8301 ************************************************************************/
8302
Daniel Veillardf06307e2001-07-03 10:35:50 +00008303static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008304xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8305
8306/**
8307 * xmlXPathNodeCollectAndTest:
8308 * @ctxt: the XPath Parser context
8309 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008310 * @first: pointer to the first element in document order
8311 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008312 *
8313 * This is the function implementing a step: based on the current list
8314 * of nodes, it builds up a new list, looking at all nodes under that
8315 * axis and selecting them it also do the predicate filtering
8316 *
8317 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008318 *
8319 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008320 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008321static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008322xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008323 xmlXPathStepOpPtr op,
8324 xmlNodePtr * first, xmlNodePtr * last)
8325{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008326 xmlXPathAxisVal axis = op->value;
8327 xmlXPathTestVal test = op->value2;
8328 xmlXPathTypeVal type = op->value3;
8329 const xmlChar *prefix = op->value4;
8330 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008331 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008332
8333#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008334 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008335#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008336 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008337 xmlNodeSetPtr ret, list;
8338 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008339 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008340 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008341 xmlNodePtr cur = NULL;
8342 xmlXPathObjectPtr obj;
8343 xmlNodeSetPtr nodelist;
8344 xmlNodePtr tmp;
8345
Daniel Veillardf06307e2001-07-03 10:35:50 +00008346 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008347 obj = valuePop(ctxt);
8348 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008349 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008350 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008351 URI = xmlXPathNsLookup(ctxt->context, prefix);
8352 if (URI == NULL)
8353 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008354 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008355#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008356 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008357#endif
8358 switch (axis) {
8359 case AXIS_ANCESTOR:
8360#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008361 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008362#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008363 first = NULL;
8364 next = xmlXPathNextAncestor;
8365 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008366 case AXIS_ANCESTOR_OR_SELF:
8367#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008368 xmlGenericError(xmlGenericErrorContext,
8369 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008370#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008371 first = NULL;
8372 next = xmlXPathNextAncestorOrSelf;
8373 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008374 case AXIS_ATTRIBUTE:
8375#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008376 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008377#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008378 first = NULL;
8379 last = NULL;
8380 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00008381 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008382 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008383 case AXIS_CHILD:
8384#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008385 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008386#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008387 last = NULL;
8388 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00008389 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008390 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008391 case AXIS_DESCENDANT:
8392#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008393 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008394#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008395 last = NULL;
8396 next = xmlXPathNextDescendant;
8397 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008398 case AXIS_DESCENDANT_OR_SELF:
8399#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008400 xmlGenericError(xmlGenericErrorContext,
8401 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008402#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008403 last = NULL;
8404 next = xmlXPathNextDescendantOrSelf;
8405 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008406 case AXIS_FOLLOWING:
8407#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008408 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008409#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008410 last = NULL;
8411 next = xmlXPathNextFollowing;
8412 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008413 case AXIS_FOLLOWING_SIBLING:
8414#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008415 xmlGenericError(xmlGenericErrorContext,
8416 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008417#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008418 last = NULL;
8419 next = xmlXPathNextFollowingSibling;
8420 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008421 case AXIS_NAMESPACE:
8422#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008423 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008424#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008425 first = NULL;
8426 last = NULL;
8427 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00008428 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008429 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008430 case AXIS_PARENT:
8431#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008432 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008433#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008434 first = NULL;
8435 next = xmlXPathNextParent;
8436 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008437 case AXIS_PRECEDING:
8438#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008439 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008440#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008441 first = NULL;
8442 next = xmlXPathNextPrecedingInternal;
8443 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008444 case AXIS_PRECEDING_SIBLING:
8445#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008446 xmlGenericError(xmlGenericErrorContext,
8447 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008448#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008449 first = NULL;
8450 next = xmlXPathNextPrecedingSibling;
8451 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008452 case AXIS_SELF:
8453#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008454 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008455#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008456 first = NULL;
8457 last = NULL;
8458 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00008459 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008460 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008461 }
8462 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008463 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008464
8465 nodelist = obj->nodesetval;
8466 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008467 xmlXPathFreeObject(obj);
8468 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8469 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008470 }
8471 addNode = xmlXPathNodeSetAddUnique;
8472 ret = NULL;
8473#ifdef DEBUG_STEP
8474 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008475 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008476 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008477 case NODE_TEST_NONE:
8478 xmlGenericError(xmlGenericErrorContext,
8479 " searching for none !!!\n");
8480 break;
8481 case NODE_TEST_TYPE:
8482 xmlGenericError(xmlGenericErrorContext,
8483 " searching for type %d\n", type);
8484 break;
8485 case NODE_TEST_PI:
8486 xmlGenericError(xmlGenericErrorContext,
8487 " searching for PI !!!\n");
8488 break;
8489 case NODE_TEST_ALL:
8490 xmlGenericError(xmlGenericErrorContext,
8491 " searching for *\n");
8492 break;
8493 case NODE_TEST_NS:
8494 xmlGenericError(xmlGenericErrorContext,
8495 " searching for namespace %s\n",
8496 prefix);
8497 break;
8498 case NODE_TEST_NAME:
8499 xmlGenericError(xmlGenericErrorContext,
8500 " searching for name %s\n", name);
8501 if (prefix != NULL)
8502 xmlGenericError(xmlGenericErrorContext,
8503 " with namespace %s\n", prefix);
8504 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008505 }
8506 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8507#endif
8508 /*
8509 * 2.3 Node Tests
8510 * - For the attribute axis, the principal node type is attribute.
8511 * - For the namespace axis, the principal node type is namespace.
8512 * - For other axes, the principal node type is element.
8513 *
8514 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008515 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008516 * select all element children of the context node
8517 */
8518 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008519 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008520 ctxt->context->node = nodelist->nodeTab[i];
8521
Daniel Veillardf06307e2001-07-03 10:35:50 +00008522 cur = NULL;
8523 list = xmlXPathNodeSetCreate(NULL);
8524 do {
8525 cur = next(ctxt, cur);
8526 if (cur == NULL)
8527 break;
8528 if ((first != NULL) && (*first == cur))
8529 break;
8530 if (((t % 256) == 0) &&
8531 (first != NULL) && (*first != NULL) &&
8532 (xmlXPathCmpNodes(*first, cur) >= 0))
8533 break;
8534 if ((last != NULL) && (*last == cur))
8535 break;
8536 if (((t % 256) == 0) &&
8537 (last != NULL) && (*last != NULL) &&
8538 (xmlXPathCmpNodes(cur, *last) >= 0))
8539 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008540 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008541#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008542 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8543#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008544 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008545 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008546 ctxt->context->node = tmp;
8547 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008548 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008549 if ((cur->type == type) ||
8550 ((type == NODE_TYPE_NODE) &&
8551 ((cur->type == XML_DOCUMENT_NODE) ||
8552 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8553 (cur->type == XML_ELEMENT_NODE) ||
8554 (cur->type == XML_PI_NODE) ||
8555 (cur->type == XML_COMMENT_NODE) ||
8556 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00008557 (cur->type == XML_TEXT_NODE))) ||
8558 ((type == NODE_TYPE_TEXT) &&
8559 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008560#ifdef DEBUG_STEP
8561 n++;
8562#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008563 addNode(list, cur);
8564 }
8565 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008566 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008567 if (cur->type == XML_PI_NODE) {
8568 if ((name != NULL) &&
8569 (!xmlStrEqual(name, cur->name)))
8570 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008571#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008572 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008573#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008574 addNode(list, cur);
8575 }
8576 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008577 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008578 if (axis == AXIS_ATTRIBUTE) {
8579 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008580#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008581 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008582#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008583 addNode(list, cur);
8584 }
8585 } else if (axis == AXIS_NAMESPACE) {
8586 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008587#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008588 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008589#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008590 xmlXPathNodeSetAddNs(list, ctxt->context->node,
8591 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008592 }
8593 } else {
8594 if (cur->type == XML_ELEMENT_NODE) {
8595 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008596#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008597 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008598#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008599 addNode(list, cur);
8600 } else if ((cur->ns != NULL) &&
8601 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008602#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008603 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008604#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008605 addNode(list, cur);
8606 }
8607 }
8608 }
8609 break;
8610 case NODE_TEST_NS:{
8611 TODO;
8612 break;
8613 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008614 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008615 switch (cur->type) {
8616 case XML_ELEMENT_NODE:
8617 if (xmlStrEqual(name, cur->name)) {
8618 if (prefix == NULL) {
8619 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008620#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008621 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008622#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008623 addNode(list, cur);
8624 }
8625 } else {
8626 if ((cur->ns != NULL) &&
8627 (xmlStrEqual(URI,
8628 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008629#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008630 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008631#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008632 addNode(list, cur);
8633 }
8634 }
8635 }
8636 break;
8637 case XML_ATTRIBUTE_NODE:{
8638 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008639
Daniel Veillardf06307e2001-07-03 10:35:50 +00008640 if (xmlStrEqual(name, attr->name)) {
8641 if (prefix == NULL) {
8642 if ((attr->ns == NULL) ||
8643 (attr->ns->prefix == NULL)) {
8644#ifdef DEBUG_STEP
8645 n++;
8646#endif
8647 addNode(list,
8648 (xmlNodePtr) attr);
8649 }
8650 } else {
8651 if ((attr->ns != NULL) &&
8652 (xmlStrEqual(URI,
8653 attr->ns->
8654 href))) {
8655#ifdef DEBUG_STEP
8656 n++;
8657#endif
8658 addNode(list,
8659 (xmlNodePtr) attr);
8660 }
8661 }
8662 }
8663 break;
8664 }
8665 case XML_NAMESPACE_DECL:
8666 if (cur->type == XML_NAMESPACE_DECL) {
8667 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008668
Daniel Veillardf06307e2001-07-03 10:35:50 +00008669 if ((ns->prefix != NULL) && (name != NULL)
8670 && (xmlStrEqual(ns->prefix, name))) {
8671#ifdef DEBUG_STEP
8672 n++;
8673#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008674 xmlXPathNodeSetAddNs(list,
8675 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008676 }
8677 }
8678 break;
8679 default:
8680 break;
8681 }
8682 break;
8683 break;
8684 }
8685 } while (cur != NULL);
8686
8687 /*
8688 * If there is some predicate filtering do it now
8689 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00008690 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008691 xmlXPathObjectPtr obj2;
8692
8693 valuePush(ctxt, xmlXPathWrapNodeSet(list));
8694 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
8695 CHECK_TYPE0(XPATH_NODESET);
8696 obj2 = valuePop(ctxt);
8697 list = obj2->nodesetval;
8698 obj2->nodesetval = NULL;
8699 xmlXPathFreeObject(obj2);
8700 }
8701 if (ret == NULL) {
8702 ret = list;
8703 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00008704 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008705 xmlXPathFreeNodeSet(list);
8706 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008707 }
8708 ctxt->context->node = tmp;
8709#ifdef DEBUG_STEP
8710 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008711 "\nExamined %d nodes, found %d nodes at that step\n",
8712 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008713#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008714 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00008715 if ((obj->boolval) && (obj->user != NULL)) {
8716 ctxt->value->boolval = 1;
8717 ctxt->value->user = obj->user;
8718 obj->user = NULL;
8719 obj->boolval = 0;
8720 }
8721 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008722 return(t);
8723}
8724
8725/**
8726 * xmlXPathNodeCollectAndTestNth:
8727 * @ctxt: the XPath Parser context
8728 * @op: the XPath precompiled step operation
8729 * @indx: the index to collect
8730 * @first: pointer to the first element in document order
8731 * @last: pointer to the last element in document order
8732 *
8733 * This is the function implementing a step: based on the current list
8734 * of nodes, it builds up a new list, looking at all nodes under that
8735 * axis and selecting them it also do the predicate filtering
8736 *
8737 * Pushes the new NodeSet resulting from the search.
8738 * Returns the number of node traversed
8739 */
8740static int
8741xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
8742 xmlXPathStepOpPtr op, int indx,
8743 xmlNodePtr * first, xmlNodePtr * last)
8744{
8745 xmlXPathAxisVal axis = op->value;
8746 xmlXPathTestVal test = op->value2;
8747 xmlXPathTypeVal type = op->value3;
8748 const xmlChar *prefix = op->value4;
8749 const xmlChar *name = op->value5;
8750 const xmlChar *URI = NULL;
8751 int n = 0, t = 0;
8752
8753 int i;
8754 xmlNodeSetPtr list;
8755 xmlXPathTraversalFunction next = NULL;
8756 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
8757 xmlNodePtr cur = NULL;
8758 xmlXPathObjectPtr obj;
8759 xmlNodeSetPtr nodelist;
8760 xmlNodePtr tmp;
8761
8762 CHECK_TYPE0(XPATH_NODESET);
8763 obj = valuePop(ctxt);
8764 addNode = xmlXPathNodeSetAdd;
8765 if (prefix != NULL) {
8766 URI = xmlXPathNsLookup(ctxt->context, prefix);
8767 if (URI == NULL)
8768 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8769 }
8770#ifdef DEBUG_STEP_NTH
8771 xmlGenericError(xmlGenericErrorContext, "new step : ");
8772 if (first != NULL) {
8773 if (*first != NULL)
8774 xmlGenericError(xmlGenericErrorContext, "first = %s ",
8775 (*first)->name);
8776 else
8777 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
8778 }
8779 if (last != NULL) {
8780 if (*last != NULL)
8781 xmlGenericError(xmlGenericErrorContext, "last = %s ",
8782 (*last)->name);
8783 else
8784 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
8785 }
8786#endif
8787 switch (axis) {
8788 case AXIS_ANCESTOR:
8789#ifdef DEBUG_STEP_NTH
8790 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
8791#endif
8792 first = NULL;
8793 next = xmlXPathNextAncestor;
8794 break;
8795 case AXIS_ANCESTOR_OR_SELF:
8796#ifdef DEBUG_STEP_NTH
8797 xmlGenericError(xmlGenericErrorContext,
8798 "axis 'ancestors-or-self' ");
8799#endif
8800 first = NULL;
8801 next = xmlXPathNextAncestorOrSelf;
8802 break;
8803 case AXIS_ATTRIBUTE:
8804#ifdef DEBUG_STEP_NTH
8805 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
8806#endif
8807 first = NULL;
8808 last = NULL;
8809 next = xmlXPathNextAttribute;
8810 break;
8811 case AXIS_CHILD:
8812#ifdef DEBUG_STEP_NTH
8813 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
8814#endif
8815 last = NULL;
8816 next = xmlXPathNextChild;
8817 break;
8818 case AXIS_DESCENDANT:
8819#ifdef DEBUG_STEP_NTH
8820 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
8821#endif
8822 last = NULL;
8823 next = xmlXPathNextDescendant;
8824 break;
8825 case AXIS_DESCENDANT_OR_SELF:
8826#ifdef DEBUG_STEP_NTH
8827 xmlGenericError(xmlGenericErrorContext,
8828 "axis 'descendant-or-self' ");
8829#endif
8830 last = NULL;
8831 next = xmlXPathNextDescendantOrSelf;
8832 break;
8833 case AXIS_FOLLOWING:
8834#ifdef DEBUG_STEP_NTH
8835 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
8836#endif
8837 last = NULL;
8838 next = xmlXPathNextFollowing;
8839 break;
8840 case AXIS_FOLLOWING_SIBLING:
8841#ifdef DEBUG_STEP_NTH
8842 xmlGenericError(xmlGenericErrorContext,
8843 "axis 'following-siblings' ");
8844#endif
8845 last = NULL;
8846 next = xmlXPathNextFollowingSibling;
8847 break;
8848 case AXIS_NAMESPACE:
8849#ifdef DEBUG_STEP_NTH
8850 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
8851#endif
8852 last = NULL;
8853 first = NULL;
8854 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8855 break;
8856 case AXIS_PARENT:
8857#ifdef DEBUG_STEP_NTH
8858 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
8859#endif
8860 first = NULL;
8861 next = xmlXPathNextParent;
8862 break;
8863 case AXIS_PRECEDING:
8864#ifdef DEBUG_STEP_NTH
8865 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
8866#endif
8867 first = NULL;
8868 next = xmlXPathNextPrecedingInternal;
8869 break;
8870 case AXIS_PRECEDING_SIBLING:
8871#ifdef DEBUG_STEP_NTH
8872 xmlGenericError(xmlGenericErrorContext,
8873 "axis 'preceding-sibling' ");
8874#endif
8875 first = NULL;
8876 next = xmlXPathNextPrecedingSibling;
8877 break;
8878 case AXIS_SELF:
8879#ifdef DEBUG_STEP_NTH
8880 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
8881#endif
8882 first = NULL;
8883 last = NULL;
8884 next = xmlXPathNextSelf;
8885 break;
8886 }
8887 if (next == NULL)
8888 return(0);
8889
8890 nodelist = obj->nodesetval;
8891 if (nodelist == NULL) {
8892 xmlXPathFreeObject(obj);
8893 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8894 return(0);
8895 }
8896 addNode = xmlXPathNodeSetAddUnique;
8897#ifdef DEBUG_STEP_NTH
8898 xmlGenericError(xmlGenericErrorContext,
8899 " context contains %d nodes\n", nodelist->nodeNr);
8900 switch (test) {
8901 case NODE_TEST_NONE:
8902 xmlGenericError(xmlGenericErrorContext,
8903 " searching for none !!!\n");
8904 break;
8905 case NODE_TEST_TYPE:
8906 xmlGenericError(xmlGenericErrorContext,
8907 " searching for type %d\n", type);
8908 break;
8909 case NODE_TEST_PI:
8910 xmlGenericError(xmlGenericErrorContext,
8911 " searching for PI !!!\n");
8912 break;
8913 case NODE_TEST_ALL:
8914 xmlGenericError(xmlGenericErrorContext,
8915 " searching for *\n");
8916 break;
8917 case NODE_TEST_NS:
8918 xmlGenericError(xmlGenericErrorContext,
8919 " searching for namespace %s\n",
8920 prefix);
8921 break;
8922 case NODE_TEST_NAME:
8923 xmlGenericError(xmlGenericErrorContext,
8924 " searching for name %s\n", name);
8925 if (prefix != NULL)
8926 xmlGenericError(xmlGenericErrorContext,
8927 " with namespace %s\n", prefix);
8928 break;
8929 }
8930 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8931#endif
8932 /*
8933 * 2.3 Node Tests
8934 * - For the attribute axis, the principal node type is attribute.
8935 * - For the namespace axis, the principal node type is namespace.
8936 * - For other axes, the principal node type is element.
8937 *
8938 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008939 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00008940 * select all element children of the context node
8941 */
8942 tmp = ctxt->context->node;
8943 list = xmlXPathNodeSetCreate(NULL);
8944 for (i = 0; i < nodelist->nodeNr; i++) {
8945 ctxt->context->node = nodelist->nodeTab[i];
8946
8947 cur = NULL;
8948 n = 0;
8949 do {
8950 cur = next(ctxt, cur);
8951 if (cur == NULL)
8952 break;
8953 if ((first != NULL) && (*first == cur))
8954 break;
8955 if (((t % 256) == 0) &&
8956 (first != NULL) && (*first != NULL) &&
8957 (xmlXPathCmpNodes(*first, cur) >= 0))
8958 break;
8959 if ((last != NULL) && (*last == cur))
8960 break;
8961 if (((t % 256) == 0) &&
8962 (last != NULL) && (*last != NULL) &&
8963 (xmlXPathCmpNodes(cur, *last) >= 0))
8964 break;
8965 t++;
8966 switch (test) {
8967 case NODE_TEST_NONE:
8968 ctxt->context->node = tmp;
8969 STRANGE return(0);
8970 case NODE_TEST_TYPE:
8971 if ((cur->type == type) ||
8972 ((type == NODE_TYPE_NODE) &&
8973 ((cur->type == XML_DOCUMENT_NODE) ||
8974 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8975 (cur->type == XML_ELEMENT_NODE) ||
8976 (cur->type == XML_PI_NODE) ||
8977 (cur->type == XML_COMMENT_NODE) ||
8978 (cur->type == XML_CDATA_SECTION_NODE) ||
8979 (cur->type == XML_TEXT_NODE)))) {
8980 n++;
8981 if (n == indx)
8982 addNode(list, cur);
8983 }
8984 break;
8985 case NODE_TEST_PI:
8986 if (cur->type == XML_PI_NODE) {
8987 if ((name != NULL) &&
8988 (!xmlStrEqual(name, cur->name)))
8989 break;
8990 n++;
8991 if (n == indx)
8992 addNode(list, cur);
8993 }
8994 break;
8995 case NODE_TEST_ALL:
8996 if (axis == AXIS_ATTRIBUTE) {
8997 if (cur->type == XML_ATTRIBUTE_NODE) {
8998 n++;
8999 if (n == indx)
9000 addNode(list, cur);
9001 }
9002 } else if (axis == AXIS_NAMESPACE) {
9003 if (cur->type == XML_NAMESPACE_DECL) {
9004 n++;
9005 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009006 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9007 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009008 }
9009 } else {
9010 if (cur->type == XML_ELEMENT_NODE) {
9011 if (prefix == NULL) {
9012 n++;
9013 if (n == indx)
9014 addNode(list, cur);
9015 } else if ((cur->ns != NULL) &&
9016 (xmlStrEqual(URI, cur->ns->href))) {
9017 n++;
9018 if (n == indx)
9019 addNode(list, cur);
9020 }
9021 }
9022 }
9023 break;
9024 case NODE_TEST_NS:{
9025 TODO;
9026 break;
9027 }
9028 case NODE_TEST_NAME:
9029 switch (cur->type) {
9030 case XML_ELEMENT_NODE:
9031 if (xmlStrEqual(name, cur->name)) {
9032 if (prefix == NULL) {
9033 if (cur->ns == NULL) {
9034 n++;
9035 if (n == indx)
9036 addNode(list, cur);
9037 }
9038 } else {
9039 if ((cur->ns != NULL) &&
9040 (xmlStrEqual(URI,
9041 cur->ns->href))) {
9042 n++;
9043 if (n == indx)
9044 addNode(list, cur);
9045 }
9046 }
9047 }
9048 break;
9049 case XML_ATTRIBUTE_NODE:{
9050 xmlAttrPtr attr = (xmlAttrPtr) cur;
9051
9052 if (xmlStrEqual(name, attr->name)) {
9053 if (prefix == NULL) {
9054 if ((attr->ns == NULL) ||
9055 (attr->ns->prefix == NULL)) {
9056 n++;
9057 if (n == indx)
9058 addNode(list, cur);
9059 }
9060 } else {
9061 if ((attr->ns != NULL) &&
9062 (xmlStrEqual(URI,
9063 attr->ns->
9064 href))) {
9065 n++;
9066 if (n == indx)
9067 addNode(list, cur);
9068 }
9069 }
9070 }
9071 break;
9072 }
9073 case XML_NAMESPACE_DECL:
9074 if (cur->type == XML_NAMESPACE_DECL) {
9075 xmlNsPtr ns = (xmlNsPtr) cur;
9076
9077 if ((ns->prefix != NULL) && (name != NULL)
9078 && (xmlStrEqual(ns->prefix, name))) {
9079 n++;
9080 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009081 xmlXPathNodeSetAddNs(list,
9082 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009083 }
9084 }
9085 break;
9086 default:
9087 break;
9088 }
9089 break;
9090 break;
9091 }
9092 } while (n < indx);
9093 }
9094 ctxt->context->node = tmp;
9095#ifdef DEBUG_STEP_NTH
9096 xmlGenericError(xmlGenericErrorContext,
9097 "\nExamined %d nodes, found %d nodes at that step\n",
9098 t, list->nodeNr);
9099#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009100 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009101 if ((obj->boolval) && (obj->user != NULL)) {
9102 ctxt->value->boolval = 1;
9103 ctxt->value->user = obj->user;
9104 obj->user = NULL;
9105 obj->boolval = 0;
9106 }
9107 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009108 return(t);
9109}
9110
9111/**
9112 * xmlXPathCompOpEvalFirst:
9113 * @ctxt: the XPath parser context with the compiled expression
9114 * @op: an XPath compiled operation
9115 * @first: the first elem found so far
9116 *
9117 * Evaluate the Precompiled XPath operation searching only the first
9118 * element in document order
9119 *
9120 * Returns the number of examined objects.
9121 */
9122static int
9123xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9124 xmlXPathStepOpPtr op, xmlNodePtr * first)
9125{
9126 int total = 0, cur;
9127 xmlXPathCompExprPtr comp;
9128 xmlXPathObjectPtr arg1, arg2;
9129
Daniel Veillard556c6682001-10-06 09:59:51 +00009130 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009131 comp = ctxt->comp;
9132 switch (op->op) {
9133 case XPATH_OP_END:
9134 return (0);
9135 case XPATH_OP_UNION:
9136 total =
9137 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9138 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009139 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009140 if ((ctxt->value != NULL)
9141 && (ctxt->value->type == XPATH_NODESET)
9142 && (ctxt->value->nodesetval != NULL)
9143 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9144 /*
9145 * limit tree traversing to first node in the result
9146 */
9147 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9148 *first = ctxt->value->nodesetval->nodeTab[0];
9149 }
9150 cur =
9151 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9152 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009153 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009154 CHECK_TYPE0(XPATH_NODESET);
9155 arg2 = valuePop(ctxt);
9156
9157 CHECK_TYPE0(XPATH_NODESET);
9158 arg1 = valuePop(ctxt);
9159
9160 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9161 arg2->nodesetval);
9162 valuePush(ctxt, arg1);
9163 xmlXPathFreeObject(arg2);
9164 /* optimizer */
9165 if (total > cur)
9166 xmlXPathCompSwap(op);
9167 return (total + cur);
9168 case XPATH_OP_ROOT:
9169 xmlXPathRoot(ctxt);
9170 return (0);
9171 case XPATH_OP_NODE:
9172 if (op->ch1 != -1)
9173 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009174 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009175 if (op->ch2 != -1)
9176 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009177 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009178 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9179 return (total);
9180 case XPATH_OP_RESET:
9181 if (op->ch1 != -1)
9182 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009183 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009184 if (op->ch2 != -1)
9185 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009186 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009187 ctxt->context->node = NULL;
9188 return (total);
9189 case XPATH_OP_COLLECT:{
9190 if (op->ch1 == -1)
9191 return (total);
9192
9193 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009194 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009195
9196 /*
9197 * Optimization for [n] selection where n is a number
9198 */
9199 if ((op->ch2 != -1) &&
9200 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9201 (comp->steps[op->ch2].ch1 == -1) &&
9202 (comp->steps[op->ch2].ch2 != -1) &&
9203 (comp->steps[comp->steps[op->ch2].ch2].op ==
9204 XPATH_OP_VALUE)) {
9205 xmlXPathObjectPtr val;
9206
9207 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9208 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9209 int indx = (int) val->floatval;
9210
9211 if (val->floatval == (float) indx) {
9212 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9213 first, NULL);
9214 return (total);
9215 }
9216 }
9217 }
9218 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9219 return (total);
9220 }
9221 case XPATH_OP_VALUE:
9222 valuePush(ctxt,
9223 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9224 return (0);
9225 case XPATH_OP_SORT:
9226 if (op->ch1 != -1)
9227 total +=
9228 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9229 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009230 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009231 if ((ctxt->value != NULL)
9232 && (ctxt->value->type == XPATH_NODESET)
9233 && (ctxt->value->nodesetval != NULL))
9234 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9235 return (total);
9236 default:
9237 return (xmlXPathCompOpEval(ctxt, op));
9238 }
9239}
9240
9241/**
9242 * xmlXPathCompOpEvalLast:
9243 * @ctxt: the XPath parser context with the compiled expression
9244 * @op: an XPath compiled operation
9245 * @last: the last elem found so far
9246 *
9247 * Evaluate the Precompiled XPath operation searching only the last
9248 * element in document order
9249 *
9250 * Returns the number of node traversed
9251 */
9252static int
9253xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9254 xmlNodePtr * last)
9255{
9256 int total = 0, cur;
9257 xmlXPathCompExprPtr comp;
9258 xmlXPathObjectPtr arg1, arg2;
9259
Daniel Veillard556c6682001-10-06 09:59:51 +00009260 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009261 comp = ctxt->comp;
9262 switch (op->op) {
9263 case XPATH_OP_END:
9264 return (0);
9265 case XPATH_OP_UNION:
9266 total =
9267 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009268 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009269 if ((ctxt->value != NULL)
9270 && (ctxt->value->type == XPATH_NODESET)
9271 && (ctxt->value->nodesetval != NULL)
9272 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9273 /*
9274 * limit tree traversing to first node in the result
9275 */
9276 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9277 *last =
9278 ctxt->value->nodesetval->nodeTab[ctxt->value->
9279 nodesetval->nodeNr -
9280 1];
9281 }
9282 cur =
9283 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009284 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009285 if ((ctxt->value != NULL)
9286 && (ctxt->value->type == XPATH_NODESET)
9287 && (ctxt->value->nodesetval != NULL)
9288 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9289 }
9290 CHECK_TYPE0(XPATH_NODESET);
9291 arg2 = valuePop(ctxt);
9292
9293 CHECK_TYPE0(XPATH_NODESET);
9294 arg1 = valuePop(ctxt);
9295
9296 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9297 arg2->nodesetval);
9298 valuePush(ctxt, arg1);
9299 xmlXPathFreeObject(arg2);
9300 /* optimizer */
9301 if (total > cur)
9302 xmlXPathCompSwap(op);
9303 return (total + cur);
9304 case XPATH_OP_ROOT:
9305 xmlXPathRoot(ctxt);
9306 return (0);
9307 case XPATH_OP_NODE:
9308 if (op->ch1 != -1)
9309 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009310 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009311 if (op->ch2 != -1)
9312 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009313 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009314 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9315 return (total);
9316 case XPATH_OP_RESET:
9317 if (op->ch1 != -1)
9318 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009319 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009320 if (op->ch2 != -1)
9321 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009322 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009323 ctxt->context->node = NULL;
9324 return (total);
9325 case XPATH_OP_COLLECT:{
9326 if (op->ch1 == -1)
9327 return (0);
9328
9329 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009330 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009331
9332 /*
9333 * Optimization for [n] selection where n is a number
9334 */
9335 if ((op->ch2 != -1) &&
9336 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9337 (comp->steps[op->ch2].ch1 == -1) &&
9338 (comp->steps[op->ch2].ch2 != -1) &&
9339 (comp->steps[comp->steps[op->ch2].ch2].op ==
9340 XPATH_OP_VALUE)) {
9341 xmlXPathObjectPtr val;
9342
9343 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9344 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9345 int indx = (int) val->floatval;
9346
9347 if (val->floatval == (float) indx) {
9348 total +=
9349 xmlXPathNodeCollectAndTestNth(ctxt, op,
9350 indx, NULL,
9351 last);
9352 return (total);
9353 }
9354 }
9355 }
9356 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9357 return (total);
9358 }
9359 case XPATH_OP_VALUE:
9360 valuePush(ctxt,
9361 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9362 return (0);
9363 case XPATH_OP_SORT:
9364 if (op->ch1 != -1)
9365 total +=
9366 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9367 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009368 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009369 if ((ctxt->value != NULL)
9370 && (ctxt->value->type == XPATH_NODESET)
9371 && (ctxt->value->nodesetval != NULL))
9372 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9373 return (total);
9374 default:
9375 return (xmlXPathCompOpEval(ctxt, op));
9376 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009377}
9378
Owen Taylor3473f882001-02-23 17:55:21 +00009379/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009380 * xmlXPathCompOpEval:
9381 * @ctxt: the XPath parser context with the compiled expression
9382 * @op: an XPath compiled operation
9383 *
9384 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009385 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009386 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009387static int
9388xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9389{
9390 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009391 int equal, ret;
9392 xmlXPathCompExprPtr comp;
9393 xmlXPathObjectPtr arg1, arg2;
9394
Daniel Veillard556c6682001-10-06 09:59:51 +00009395 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009396 comp = ctxt->comp;
9397 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009398 case XPATH_OP_END:
9399 return (0);
9400 case XPATH_OP_AND:
9401 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009402 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009403 xmlXPathBooleanFunction(ctxt, 1);
9404 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9405 return (total);
9406 arg2 = valuePop(ctxt);
9407 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009408 if (ctxt->error) {
9409 xmlXPathFreeObject(arg2);
9410 return(0);
9411 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009412 xmlXPathBooleanFunction(ctxt, 1);
9413 arg1 = valuePop(ctxt);
9414 arg1->boolval &= arg2->boolval;
9415 valuePush(ctxt, arg1);
9416 xmlXPathFreeObject(arg2);
9417 return (total);
9418 case XPATH_OP_OR:
9419 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009420 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009421 xmlXPathBooleanFunction(ctxt, 1);
9422 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9423 return (total);
9424 arg2 = valuePop(ctxt);
9425 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009426 if (ctxt->error) {
9427 xmlXPathFreeObject(arg2);
9428 return(0);
9429 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009430 xmlXPathBooleanFunction(ctxt, 1);
9431 arg1 = valuePop(ctxt);
9432 arg1->boolval |= arg2->boolval;
9433 valuePush(ctxt, arg1);
9434 xmlXPathFreeObject(arg2);
9435 return (total);
9436 case XPATH_OP_EQUAL:
9437 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009438 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009439 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009440 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009441 equal = xmlXPathEqualValues(ctxt);
9442 if (op->value)
9443 valuePush(ctxt, xmlXPathNewBoolean(equal));
9444 else
9445 valuePush(ctxt, xmlXPathNewBoolean(!equal));
9446 return (total);
9447 case XPATH_OP_CMP:
9448 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009449 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009450 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009451 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009452 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9453 valuePush(ctxt, xmlXPathNewBoolean(ret));
9454 return (total);
9455 case XPATH_OP_PLUS:
9456 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009457 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009458 if (op->ch2 != -1)
9459 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009460 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009461 if (op->value == 0)
9462 xmlXPathSubValues(ctxt);
9463 else if (op->value == 1)
9464 xmlXPathAddValues(ctxt);
9465 else if (op->value == 2)
9466 xmlXPathValueFlipSign(ctxt);
9467 else if (op->value == 3) {
9468 CAST_TO_NUMBER;
9469 CHECK_TYPE0(XPATH_NUMBER);
9470 }
9471 return (total);
9472 case XPATH_OP_MULT:
9473 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009474 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009475 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009476 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009477 if (op->value == 0)
9478 xmlXPathMultValues(ctxt);
9479 else if (op->value == 1)
9480 xmlXPathDivValues(ctxt);
9481 else if (op->value == 2)
9482 xmlXPathModValues(ctxt);
9483 return (total);
9484 case XPATH_OP_UNION:
9485 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009486 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009487 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009488 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009489 CHECK_TYPE0(XPATH_NODESET);
9490 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009491
Daniel Veillardf06307e2001-07-03 10:35:50 +00009492 CHECK_TYPE0(XPATH_NODESET);
9493 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009494
Daniel Veillardf06307e2001-07-03 10:35:50 +00009495 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9496 arg2->nodesetval);
9497 valuePush(ctxt, arg1);
9498 xmlXPathFreeObject(arg2);
9499 return (total);
9500 case XPATH_OP_ROOT:
9501 xmlXPathRoot(ctxt);
9502 return (total);
9503 case XPATH_OP_NODE:
9504 if (op->ch1 != -1)
9505 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009506 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009507 if (op->ch2 != -1)
9508 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009509 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009510 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9511 return (total);
9512 case XPATH_OP_RESET:
9513 if (op->ch1 != -1)
9514 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009515 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009516 if (op->ch2 != -1)
9517 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009518 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009519 ctxt->context->node = NULL;
9520 return (total);
9521 case XPATH_OP_COLLECT:{
9522 if (op->ch1 == -1)
9523 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009524
Daniel Veillardf06307e2001-07-03 10:35:50 +00009525 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009526 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009527
Daniel Veillardf06307e2001-07-03 10:35:50 +00009528 /*
9529 * Optimization for [n] selection where n is a number
9530 */
9531 if ((op->ch2 != -1) &&
9532 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9533 (comp->steps[op->ch2].ch1 == -1) &&
9534 (comp->steps[op->ch2].ch2 != -1) &&
9535 (comp->steps[comp->steps[op->ch2].ch2].op ==
9536 XPATH_OP_VALUE)) {
9537 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00009538
Daniel Veillardf06307e2001-07-03 10:35:50 +00009539 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9540 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9541 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009542
Daniel Veillardf06307e2001-07-03 10:35:50 +00009543 if (val->floatval == (float) indx) {
9544 total +=
9545 xmlXPathNodeCollectAndTestNth(ctxt, op,
9546 indx, NULL,
9547 NULL);
9548 return (total);
9549 }
9550 }
9551 }
9552 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
9553 return (total);
9554 }
9555 case XPATH_OP_VALUE:
9556 valuePush(ctxt,
9557 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9558 return (total);
9559 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +00009560 xmlXPathObjectPtr val;
9561
Daniel Veillardf06307e2001-07-03 10:35:50 +00009562 if (op->ch1 != -1)
9563 total +=
9564 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009565 if (op->value5 == NULL) {
9566 val = xmlXPathVariableLookup(ctxt->context, op->value4);
9567 if (val == NULL) {
9568 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9569 return(0);
9570 }
9571 valuePush(ctxt, val);
9572 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009573 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009574
Daniel Veillardf06307e2001-07-03 10:35:50 +00009575 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9576 if (URI == NULL) {
9577 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009578 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009579 op->value4, op->value5);
9580 return (total);
9581 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009582 val = xmlXPathVariableLookupNS(ctxt->context,
9583 op->value4, URI);
9584 if (val == NULL) {
9585 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9586 return(0);
9587 }
9588 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009589 }
9590 return (total);
9591 }
9592 case XPATH_OP_FUNCTION:{
9593 xmlXPathFunction func;
9594 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +00009595 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009596
9597 if (op->ch1 != -1)
9598 total +=
9599 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009600 if (ctxt->valueNr < op->value) {
9601 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009602 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +00009603 ctxt->error = XPATH_INVALID_OPERAND;
9604 return (total);
9605 }
9606 for (i = 0; i < op->value; i++)
9607 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
9608 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009609 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +00009610 ctxt->error = XPATH_INVALID_OPERAND;
9611 return (total);
9612 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009613 if (op->cache != NULL)
9614 func = (xmlXPathFunction) op->cache;
9615 else {
9616 const xmlChar *URI = NULL;
9617
9618 if (op->value5 == NULL)
9619 func =
9620 xmlXPathFunctionLookup(ctxt->context,
9621 op->value4);
9622 else {
9623 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9624 if (URI == NULL) {
9625 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009626 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009627 op->value4, op->value5);
9628 return (total);
9629 }
9630 func = xmlXPathFunctionLookupNS(ctxt->context,
9631 op->value4, URI);
9632 }
9633 if (func == NULL) {
9634 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009635 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009636 op->value4);
9637 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009638 }
9639 op->cache = (void *) func;
9640 op->cacheURI = (void *) URI;
9641 }
9642 oldFunc = ctxt->context->function;
9643 oldFuncURI = ctxt->context->functionURI;
9644 ctxt->context->function = op->value4;
9645 ctxt->context->functionURI = op->cacheURI;
9646 func(ctxt, op->value);
9647 ctxt->context->function = oldFunc;
9648 ctxt->context->functionURI = oldFuncURI;
9649 return (total);
9650 }
9651 case XPATH_OP_ARG:
9652 if (op->ch1 != -1)
9653 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009654 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009655 if (op->ch2 != -1)
9656 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009657 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009658 return (total);
9659 case XPATH_OP_PREDICATE:
9660 case XPATH_OP_FILTER:{
9661 xmlXPathObjectPtr res;
9662 xmlXPathObjectPtr obj, tmp;
9663 xmlNodeSetPtr newset = NULL;
9664 xmlNodeSetPtr oldset;
9665 xmlNodePtr oldnode;
9666 int i;
9667
9668 /*
9669 * Optimization for ()[1] selection i.e. the first elem
9670 */
9671 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9672 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9673 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
9674 xmlXPathObjectPtr val;
9675
9676 val = comp->steps[op->ch2].value4;
9677 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
9678 (val->floatval == 1.0)) {
9679 xmlNodePtr first = NULL;
9680
9681 total +=
9682 xmlXPathCompOpEvalFirst(ctxt,
9683 &comp->steps[op->ch1],
9684 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009685 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009686 /*
9687 * The nodeset should be in document order,
9688 * Keep only the first value
9689 */
9690 if ((ctxt->value != NULL) &&
9691 (ctxt->value->type == XPATH_NODESET) &&
9692 (ctxt->value->nodesetval != NULL) &&
9693 (ctxt->value->nodesetval->nodeNr > 1))
9694 ctxt->value->nodesetval->nodeNr = 1;
9695 return (total);
9696 }
9697 }
9698 /*
9699 * Optimization for ()[last()] selection i.e. the last elem
9700 */
9701 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9702 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9703 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
9704 int f = comp->steps[op->ch2].ch1;
9705
9706 if ((f != -1) &&
9707 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
9708 (comp->steps[f].value5 == NULL) &&
9709 (comp->steps[f].value == 0) &&
9710 (comp->steps[f].value4 != NULL) &&
9711 (xmlStrEqual
9712 (comp->steps[f].value4, BAD_CAST "last"))) {
9713 xmlNodePtr last = NULL;
9714
9715 total +=
9716 xmlXPathCompOpEvalLast(ctxt,
9717 &comp->steps[op->ch1],
9718 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009719 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009720 /*
9721 * The nodeset should be in document order,
9722 * Keep only the last value
9723 */
9724 if ((ctxt->value != NULL) &&
9725 (ctxt->value->type == XPATH_NODESET) &&
9726 (ctxt->value->nodesetval != NULL) &&
9727 (ctxt->value->nodesetval->nodeTab != NULL) &&
9728 (ctxt->value->nodesetval->nodeNr > 1)) {
9729 ctxt->value->nodesetval->nodeTab[0] =
9730 ctxt->value->nodesetval->nodeTab[ctxt->
9731 value->
9732 nodesetval->
9733 nodeNr -
9734 1];
9735 ctxt->value->nodesetval->nodeNr = 1;
9736 }
9737 return (total);
9738 }
9739 }
9740
9741 if (op->ch1 != -1)
9742 total +=
9743 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009744 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009745 if (op->ch2 == -1)
9746 return (total);
9747 if (ctxt->value == NULL)
9748 return (total);
9749
9750 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009751
9752#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009753 /*
9754 * Hum are we filtering the result of an XPointer expression
9755 */
9756 if (ctxt->value->type == XPATH_LOCATIONSET) {
9757 xmlLocationSetPtr newlocset = NULL;
9758 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009759
Daniel Veillardf06307e2001-07-03 10:35:50 +00009760 /*
9761 * Extract the old locset, and then evaluate the result of the
9762 * expression for all the element in the locset. use it to grow
9763 * up a new locset.
9764 */
9765 CHECK_TYPE0(XPATH_LOCATIONSET);
9766 obj = valuePop(ctxt);
9767 oldlocset = obj->user;
9768 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009769
Daniel Veillardf06307e2001-07-03 10:35:50 +00009770 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
9771 ctxt->context->contextSize = 0;
9772 ctxt->context->proximityPosition = 0;
9773 if (op->ch2 != -1)
9774 total +=
9775 xmlXPathCompOpEval(ctxt,
9776 &comp->steps[op->ch2]);
9777 res = valuePop(ctxt);
9778 if (res != NULL)
9779 xmlXPathFreeObject(res);
9780 valuePush(ctxt, obj);
9781 CHECK_ERROR0;
9782 return (total);
9783 }
9784 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009785
Daniel Veillardf06307e2001-07-03 10:35:50 +00009786 for (i = 0; i < oldlocset->locNr; i++) {
9787 /*
9788 * Run the evaluation with a node list made of a
9789 * single item in the nodelocset.
9790 */
9791 ctxt->context->node = oldlocset->locTab[i]->user;
9792 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9793 valuePush(ctxt, tmp);
9794 ctxt->context->contextSize = oldlocset->locNr;
9795 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009796
Daniel Veillardf06307e2001-07-03 10:35:50 +00009797 if (op->ch2 != -1)
9798 total +=
9799 xmlXPathCompOpEval(ctxt,
9800 &comp->steps[op->ch2]);
9801 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009802
Daniel Veillardf06307e2001-07-03 10:35:50 +00009803 /*
9804 * The result of the evaluation need to be tested to
9805 * decided whether the filter succeeded or not
9806 */
9807 res = valuePop(ctxt);
9808 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9809 xmlXPtrLocationSetAdd(newlocset,
9810 xmlXPathObjectCopy
9811 (oldlocset->locTab[i]));
9812 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009813
Daniel Veillardf06307e2001-07-03 10:35:50 +00009814 /*
9815 * Cleanup
9816 */
9817 if (res != NULL)
9818 xmlXPathFreeObject(res);
9819 if (ctxt->value == tmp) {
9820 res = valuePop(ctxt);
9821 xmlXPathFreeObject(res);
9822 }
9823
9824 ctxt->context->node = NULL;
9825 }
9826
9827 /*
9828 * The result is used as the new evaluation locset.
9829 */
9830 xmlXPathFreeObject(obj);
9831 ctxt->context->node = NULL;
9832 ctxt->context->contextSize = -1;
9833 ctxt->context->proximityPosition = -1;
9834 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
9835 ctxt->context->node = oldnode;
9836 return (total);
9837 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009838#endif /* LIBXML_XPTR_ENABLED */
9839
Daniel Veillardf06307e2001-07-03 10:35:50 +00009840 /*
9841 * Extract the old set, and then evaluate the result of the
9842 * expression for all the element in the set. use it to grow
9843 * up a new set.
9844 */
9845 CHECK_TYPE0(XPATH_NODESET);
9846 obj = valuePop(ctxt);
9847 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00009848
Daniel Veillardf06307e2001-07-03 10:35:50 +00009849 oldnode = ctxt->context->node;
9850 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009851
Daniel Veillardf06307e2001-07-03 10:35:50 +00009852 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
9853 ctxt->context->contextSize = 0;
9854 ctxt->context->proximityPosition = 0;
9855 if (op->ch2 != -1)
9856 total +=
9857 xmlXPathCompOpEval(ctxt,
9858 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009859 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009860 res = valuePop(ctxt);
9861 if (res != NULL)
9862 xmlXPathFreeObject(res);
9863 valuePush(ctxt, obj);
9864 ctxt->context->node = oldnode;
9865 CHECK_ERROR0;
9866 } else {
9867 /*
9868 * Initialize the new set.
9869 */
9870 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009871
Daniel Veillardf06307e2001-07-03 10:35:50 +00009872 for (i = 0; i < oldset->nodeNr; i++) {
9873 /*
9874 * Run the evaluation with a node list made of
9875 * a single item in the nodeset.
9876 */
9877 ctxt->context->node = oldset->nodeTab[i];
9878 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9879 valuePush(ctxt, tmp);
9880 ctxt->context->contextSize = oldset->nodeNr;
9881 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009882
Daniel Veillardf06307e2001-07-03 10:35:50 +00009883 if (op->ch2 != -1)
9884 total +=
9885 xmlXPathCompOpEval(ctxt,
9886 &comp->steps[op->ch2]);
9887 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009888
Daniel Veillardf06307e2001-07-03 10:35:50 +00009889 /*
9890 * The result of the evaluation need to be tested to
9891 * decided whether the filter succeeded or not
9892 */
9893 res = valuePop(ctxt);
9894 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9895 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
9896 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009897
Daniel Veillardf06307e2001-07-03 10:35:50 +00009898 /*
9899 * Cleanup
9900 */
9901 if (res != NULL)
9902 xmlXPathFreeObject(res);
9903 if (ctxt->value == tmp) {
9904 res = valuePop(ctxt);
9905 xmlXPathFreeObject(res);
9906 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009907
Daniel Veillardf06307e2001-07-03 10:35:50 +00009908 ctxt->context->node = NULL;
9909 }
9910
9911 /*
9912 * The result is used as the new evaluation set.
9913 */
9914 xmlXPathFreeObject(obj);
9915 ctxt->context->node = NULL;
9916 ctxt->context->contextSize = -1;
9917 ctxt->context->proximityPosition = -1;
9918 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
9919 }
9920 ctxt->context->node = oldnode;
9921 return (total);
9922 }
9923 case XPATH_OP_SORT:
9924 if (op->ch1 != -1)
9925 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009926 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009927 if ((ctxt->value != NULL) &&
9928 (ctxt->value->type == XPATH_NODESET) &&
9929 (ctxt->value->nodesetval != NULL))
9930 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9931 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009932#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009933 case XPATH_OP_RANGETO:{
9934 xmlXPathObjectPtr range;
9935 xmlXPathObjectPtr res, obj;
9936 xmlXPathObjectPtr tmp;
9937 xmlLocationSetPtr newset = NULL;
9938 xmlNodeSetPtr oldset;
9939 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009940
Daniel Veillardf06307e2001-07-03 10:35:50 +00009941 if (op->ch1 != -1)
9942 total +=
9943 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9944 if (op->ch2 == -1)
9945 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009946
Daniel Veillardf06307e2001-07-03 10:35:50 +00009947 CHECK_TYPE0(XPATH_NODESET);
9948 obj = valuePop(ctxt);
9949 oldset = obj->nodesetval;
9950 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009951
Daniel Veillardf06307e2001-07-03 10:35:50 +00009952 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009953
Daniel Veillardf06307e2001-07-03 10:35:50 +00009954 if (oldset != NULL) {
9955 for (i = 0; i < oldset->nodeNr; i++) {
9956 /*
9957 * Run the evaluation with a node list made of a single item
9958 * in the nodeset.
9959 */
9960 ctxt->context->node = oldset->nodeTab[i];
9961 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9962 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009963
Daniel Veillardf06307e2001-07-03 10:35:50 +00009964 if (op->ch2 != -1)
9965 total +=
9966 xmlXPathCompOpEval(ctxt,
9967 &comp->steps[op->ch2]);
9968 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009969
Daniel Veillardf06307e2001-07-03 10:35:50 +00009970 /*
9971 * The result of the evaluation need to be tested to
9972 * decided whether the filter succeeded or not
9973 */
9974 res = valuePop(ctxt);
9975 range =
9976 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
9977 res);
9978 if (range != NULL) {
9979 xmlXPtrLocationSetAdd(newset, range);
9980 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009981
Daniel Veillardf06307e2001-07-03 10:35:50 +00009982 /*
9983 * Cleanup
9984 */
9985 if (res != NULL)
9986 xmlXPathFreeObject(res);
9987 if (ctxt->value == tmp) {
9988 res = valuePop(ctxt);
9989 xmlXPathFreeObject(res);
9990 }
9991
9992 ctxt->context->node = NULL;
9993 }
9994 }
9995
9996 /*
9997 * The result is used as the new evaluation set.
9998 */
9999 xmlXPathFreeObject(obj);
10000 ctxt->context->node = NULL;
10001 ctxt->context->contextSize = -1;
10002 ctxt->context->proximityPosition = -1;
10003 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
10004 return (total);
10005 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010006#endif /* LIBXML_XPTR_ENABLED */
10007 }
10008 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010009 "XPath: unknown precompiled operation %d\n", op->op);
10010 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010011}
10012
10013/**
10014 * xmlXPathRunEval:
10015 * @ctxt: the XPath parser context with the compiled expression
10016 *
10017 * Evaluate the Precompiled XPath expression in the given context.
10018 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010019static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010020xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10021 xmlXPathCompExprPtr comp;
10022
10023 if ((ctxt == NULL) || (ctxt->comp == NULL))
10024 return;
10025
10026 if (ctxt->valueTab == NULL) {
10027 /* Allocate the value stack */
10028 ctxt->valueTab = (xmlXPathObjectPtr *)
10029 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10030 if (ctxt->valueTab == NULL) {
10031 xmlFree(ctxt);
10032 xmlGenericError(xmlGenericErrorContext,
10033 "xmlXPathRunEval: out of memory\n");
10034 return;
10035 }
10036 ctxt->valueNr = 0;
10037 ctxt->valueMax = 10;
10038 ctxt->value = NULL;
10039 }
10040 comp = ctxt->comp;
10041 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10042}
10043
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010044/************************************************************************
10045 * *
10046 * Public interfaces *
10047 * *
10048 ************************************************************************/
10049
10050/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010051 * xmlXPathEvalPredicate:
10052 * @ctxt: the XPath context
10053 * @res: the Predicate Expression evaluation result
10054 *
10055 * Evaluate a predicate result for the current node.
10056 * A PredicateExpr is evaluated by evaluating the Expr and converting
10057 * the result to a boolean. If the result is a number, the result will
10058 * be converted to true if the number is equal to the position of the
10059 * context node in the context node list (as returned by the position
10060 * function) and will be converted to false otherwise; if the result
10061 * is not a number, then the result will be converted as if by a call
10062 * to the boolean function.
10063 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010064 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010065 */
10066int
10067xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10068 if (res == NULL) return(0);
10069 switch (res->type) {
10070 case XPATH_BOOLEAN:
10071 return(res->boolval);
10072 case XPATH_NUMBER:
10073 return(res->floatval == ctxt->proximityPosition);
10074 case XPATH_NODESET:
10075 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010076 if (res->nodesetval == NULL)
10077 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010078 return(res->nodesetval->nodeNr != 0);
10079 case XPATH_STRING:
10080 return((res->stringval != NULL) &&
10081 (xmlStrlen(res->stringval) != 0));
10082 default:
10083 STRANGE
10084 }
10085 return(0);
10086}
10087
10088/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010089 * xmlXPathEvaluatePredicateResult:
10090 * @ctxt: the XPath Parser context
10091 * @res: the Predicate Expression evaluation result
10092 *
10093 * Evaluate a predicate result for the current node.
10094 * A PredicateExpr is evaluated by evaluating the Expr and converting
10095 * the result to a boolean. If the result is a number, the result will
10096 * be converted to true if the number is equal to the position of the
10097 * context node in the context node list (as returned by the position
10098 * function) and will be converted to false otherwise; if the result
10099 * is not a number, then the result will be converted as if by a call
10100 * to the boolean function.
10101 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010102 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010103 */
10104int
10105xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10106 xmlXPathObjectPtr res) {
10107 if (res == NULL) return(0);
10108 switch (res->type) {
10109 case XPATH_BOOLEAN:
10110 return(res->boolval);
10111 case XPATH_NUMBER:
10112 return(res->floatval == ctxt->context->proximityPosition);
10113 case XPATH_NODESET:
10114 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010115 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010116 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010117 return(res->nodesetval->nodeNr != 0);
10118 case XPATH_STRING:
10119 return((res->stringval != NULL) &&
10120 (xmlStrlen(res->stringval) != 0));
10121 default:
10122 STRANGE
10123 }
10124 return(0);
10125}
10126
10127/**
10128 * xmlXPathCompile:
10129 * @str: the XPath expression
10130 *
10131 * Compile an XPath expression
10132 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010133 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010134 * the caller has to free the object.
10135 */
10136xmlXPathCompExprPtr
10137xmlXPathCompile(const xmlChar *str) {
10138 xmlXPathParserContextPtr ctxt;
10139 xmlXPathCompExprPtr comp;
10140
10141 xmlXPathInit();
10142
10143 ctxt = xmlXPathNewParserContext(str, NULL);
10144 xmlXPathCompileExpr(ctxt);
10145
Daniel Veillard40af6492001-04-22 08:50:55 +000010146 if (*ctxt->cur != 0) {
10147 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10148 comp = NULL;
10149 } else {
10150 comp = ctxt->comp;
10151 ctxt->comp = NULL;
10152 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010153 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010154#ifdef DEBUG_EVAL_COUNTS
10155 if (comp != NULL) {
10156 comp->string = xmlStrdup(str);
10157 comp->nb = 0;
10158 }
10159#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010160 return(comp);
10161}
10162
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010163/**
10164 * xmlXPathCompiledEval:
10165 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010166 * @ctx: the XPath context
10167 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010168 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010169 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010170 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010171 * the caller has to free the object.
10172 */
10173xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010174xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010175 xmlXPathParserContextPtr ctxt;
10176 xmlXPathObjectPtr res, tmp, init = NULL;
10177 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010178#ifndef LIBXML_THREAD_ENABLED
10179 static int reentance = 0;
10180#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010181
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010182 if ((comp == NULL) || (ctx == NULL))
10183 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010184 xmlXPathInit();
10185
10186 CHECK_CONTEXT(ctx)
10187
Daniel Veillard81463942001-10-16 12:34:39 +000010188#ifndef LIBXML_THREAD_ENABLED
10189 reentance++;
10190 if (reentance > 1)
10191 xmlXPathDisableOptimizer = 1;
10192#endif
10193
Daniel Veillardf06307e2001-07-03 10:35:50 +000010194#ifdef DEBUG_EVAL_COUNTS
10195 comp->nb++;
10196 if ((comp->string != NULL) && (comp->nb > 100)) {
10197 fprintf(stderr, "100 x %s\n", comp->string);
10198 comp->nb = 0;
10199 }
10200#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010201 ctxt = xmlXPathCompParserContext(comp, ctx);
10202 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010203
10204 if (ctxt->value == NULL) {
10205 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010206 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010207 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010208 } else {
10209 res = valuePop(ctxt);
10210 }
10211
Daniel Veillardf06307e2001-07-03 10:35:50 +000010212
Owen Taylor3473f882001-02-23 17:55:21 +000010213 do {
10214 tmp = valuePop(ctxt);
10215 if (tmp != NULL) {
10216 if (tmp != init)
10217 stack++;
10218 xmlXPathFreeObject(tmp);
10219 }
10220 } while (tmp != NULL);
10221 if ((stack != 0) && (res != NULL)) {
10222 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010223 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010224 stack);
10225 }
10226 if (ctxt->error != XPATH_EXPRESSION_OK) {
10227 xmlXPathFreeObject(res);
10228 res = NULL;
10229 }
10230
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010231
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010232 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010233 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010234#ifndef LIBXML_THREAD_ENABLED
10235 reentance--;
10236#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010237 return(res);
10238}
10239
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010240/**
10241 * xmlXPathEvalExpr:
10242 * @ctxt: the XPath Parser context
10243 *
10244 * Parse and evaluate an XPath expression in the given context,
10245 * then push the result on the context stack
10246 */
10247void
10248xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10249 xmlXPathCompileExpr(ctxt);
10250 xmlXPathRunEval(ctxt);
10251}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010252
10253/**
10254 * xmlXPathEval:
10255 * @str: the XPath expression
10256 * @ctx: the XPath context
10257 *
10258 * Evaluate the XPath Location Path in the given context.
10259 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010260 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010261 * the caller has to free the object.
10262 */
10263xmlXPathObjectPtr
10264xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10265 xmlXPathParserContextPtr ctxt;
10266 xmlXPathObjectPtr res, tmp, init = NULL;
10267 int stack = 0;
10268
10269 xmlXPathInit();
10270
10271 CHECK_CONTEXT(ctx)
10272
10273 ctxt = xmlXPathNewParserContext(str, ctx);
10274 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010275
10276 if (ctxt->value == NULL) {
10277 xmlGenericError(xmlGenericErrorContext,
10278 "xmlXPathEval: evaluation failed\n");
10279 res = NULL;
10280 } else if (*ctxt->cur != 0) {
10281 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10282 res = NULL;
10283 } else {
10284 res = valuePop(ctxt);
10285 }
10286
10287 do {
10288 tmp = valuePop(ctxt);
10289 if (tmp != NULL) {
10290 if (tmp != init)
10291 stack++;
10292 xmlXPathFreeObject(tmp);
10293 }
10294 } while (tmp != NULL);
10295 if ((stack != 0) && (res != NULL)) {
10296 xmlGenericError(xmlGenericErrorContext,
10297 "xmlXPathEval: %d object left on the stack\n",
10298 stack);
10299 }
10300 if (ctxt->error != XPATH_EXPRESSION_OK) {
10301 xmlXPathFreeObject(res);
10302 res = NULL;
10303 }
10304
Owen Taylor3473f882001-02-23 17:55:21 +000010305 xmlXPathFreeParserContext(ctxt);
10306 return(res);
10307}
10308
10309/**
10310 * xmlXPathEvalExpression:
10311 * @str: the XPath expression
10312 * @ctxt: the XPath context
10313 *
10314 * Evaluate the XPath expression in the given context.
10315 *
10316 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10317 * the caller has to free the object.
10318 */
10319xmlXPathObjectPtr
10320xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10321 xmlXPathParserContextPtr pctxt;
10322 xmlXPathObjectPtr res, tmp;
10323 int stack = 0;
10324
10325 xmlXPathInit();
10326
10327 CHECK_CONTEXT(ctxt)
10328
10329 pctxt = xmlXPathNewParserContext(str, ctxt);
10330 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010331
10332 if (*pctxt->cur != 0) {
10333 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10334 res = NULL;
10335 } else {
10336 res = valuePop(pctxt);
10337 }
10338 do {
10339 tmp = valuePop(pctxt);
10340 if (tmp != NULL) {
10341 xmlXPathFreeObject(tmp);
10342 stack++;
10343 }
10344 } while (tmp != NULL);
10345 if ((stack != 0) && (res != NULL)) {
10346 xmlGenericError(xmlGenericErrorContext,
10347 "xmlXPathEvalExpression: %d object left on the stack\n",
10348 stack);
10349 }
10350 xmlXPathFreeParserContext(pctxt);
10351 return(res);
10352}
10353
10354/**
10355 * xmlXPathRegisterAllFunctions:
10356 * @ctxt: the XPath context
10357 *
10358 * Registers all default XPath functions in this context
10359 */
10360void
10361xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
10362{
10363 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
10364 xmlXPathBooleanFunction);
10365 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
10366 xmlXPathCeilingFunction);
10367 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
10368 xmlXPathCountFunction);
10369 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
10370 xmlXPathConcatFunction);
10371 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
10372 xmlXPathContainsFunction);
10373 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
10374 xmlXPathIdFunction);
10375 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
10376 xmlXPathFalseFunction);
10377 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
10378 xmlXPathFloorFunction);
10379 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
10380 xmlXPathLastFunction);
10381 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
10382 xmlXPathLangFunction);
10383 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
10384 xmlXPathLocalNameFunction);
10385 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
10386 xmlXPathNotFunction);
10387 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
10388 xmlXPathNameFunction);
10389 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
10390 xmlXPathNamespaceURIFunction);
10391 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
10392 xmlXPathNormalizeFunction);
10393 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
10394 xmlXPathNumberFunction);
10395 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
10396 xmlXPathPositionFunction);
10397 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
10398 xmlXPathRoundFunction);
10399 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
10400 xmlXPathStringFunction);
10401 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
10402 xmlXPathStringLengthFunction);
10403 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
10404 xmlXPathStartsWithFunction);
10405 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
10406 xmlXPathSubstringFunction);
10407 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
10408 xmlXPathSubstringBeforeFunction);
10409 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
10410 xmlXPathSubstringAfterFunction);
10411 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
10412 xmlXPathSumFunction);
10413 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
10414 xmlXPathTrueFunction);
10415 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
10416 xmlXPathTranslateFunction);
10417}
10418
10419#endif /* LIBXML_XPATH_ENABLED */