blob: 484975c76e77f78c09bcce75735f60181b963bdd [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:
3240 return(val->stringval);
3241 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) {
6486 CHECK_ARITY(1);
6487 CAST_TO_NUMBER;
6488 CHECK_TYPE(XPATH_NUMBER);
6489#if 0
6490 ctxt->value->floatval = floor(ctxt->value->floatval);
6491#else
6492 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
6493 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
6494#endif
6495}
6496
6497/**
6498 * xmlXPathCeilingFunction:
6499 * @ctxt: the XPath Parser context
6500 * @nargs: the number of arguments
6501 *
6502 * Implement the ceiling() XPath function
6503 * number ceiling(number)
6504 * The ceiling function returns the smallest (closest to negative infinity)
6505 * number that is not less than the argument and that is an integer.
6506 */
6507void
6508xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6509 double f;
6510
6511 CHECK_ARITY(1);
6512 CAST_TO_NUMBER;
6513 CHECK_TYPE(XPATH_NUMBER);
6514
6515#if 0
6516 ctxt->value->floatval = ceil(ctxt->value->floatval);
6517#else
6518 f = (double)((int) ctxt->value->floatval);
6519 if (f != ctxt->value->floatval)
6520 ctxt->value->floatval = f + 1;
6521#endif
6522}
6523
6524/**
6525 * xmlXPathRoundFunction:
6526 * @ctxt: the XPath Parser context
6527 * @nargs: the number of arguments
6528 *
6529 * Implement the round() XPath function
6530 * number round(number)
6531 * The round function returns the number that is closest to the
6532 * argument and that is an integer. If there are two such numbers,
6533 * then the one that is even is returned.
6534 */
6535void
6536xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6537 double f;
6538
6539 CHECK_ARITY(1);
6540 CAST_TO_NUMBER;
6541 CHECK_TYPE(XPATH_NUMBER);
6542
Daniel Veillardcda96922001-08-21 10:56:31 +00006543 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
6544 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
6545 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00006546 (ctxt->value->floatval == 0.0))
6547 return;
6548
6549#if 0
6550 f = floor(ctxt->value->floatval);
6551#else
6552 f = (double)((int) ctxt->value->floatval);
6553#endif
6554 if (ctxt->value->floatval < f + 0.5)
6555 ctxt->value->floatval = f;
6556 else
6557 ctxt->value->floatval = f + 1;
6558}
6559
6560/************************************************************************
6561 * *
6562 * The Parser *
6563 * *
6564 ************************************************************************/
6565
6566/*
6567 * a couple of forward declarations since we use a recursive call based
6568 * implementation.
6569 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006570static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006571static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006572static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006573#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006574static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
6575#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006576#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006577static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006578#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00006579static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
6580 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00006581
6582/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00006583 * xmlXPathCurrentChar:
6584 * @ctxt: the XPath parser context
6585 * @cur: pointer to the beginning of the char
6586 * @len: pointer to the length of the char read
6587 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006588 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00006589 * bytes in the input buffer.
6590 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006591 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00006592 */
6593
6594static int
6595xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
6596 unsigned char c;
6597 unsigned int val;
6598 const xmlChar *cur;
6599
6600 if (ctxt == NULL)
6601 return(0);
6602 cur = ctxt->cur;
6603
6604 /*
6605 * We are supposed to handle UTF8, check it's valid
6606 * From rfc2044: encoding of the Unicode values on UTF-8:
6607 *
6608 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
6609 * 0000 0000-0000 007F 0xxxxxxx
6610 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
6611 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
6612 *
6613 * Check for the 0x110000 limit too
6614 */
6615 c = *cur;
6616 if (c & 0x80) {
6617 if ((cur[1] & 0xc0) != 0x80)
6618 goto encoding_error;
6619 if ((c & 0xe0) == 0xe0) {
6620
6621 if ((cur[2] & 0xc0) != 0x80)
6622 goto encoding_error;
6623 if ((c & 0xf0) == 0xf0) {
6624 if (((c & 0xf8) != 0xf0) ||
6625 ((cur[3] & 0xc0) != 0x80))
6626 goto encoding_error;
6627 /* 4-byte code */
6628 *len = 4;
6629 val = (cur[0] & 0x7) << 18;
6630 val |= (cur[1] & 0x3f) << 12;
6631 val |= (cur[2] & 0x3f) << 6;
6632 val |= cur[3] & 0x3f;
6633 } else {
6634 /* 3-byte code */
6635 *len = 3;
6636 val = (cur[0] & 0xf) << 12;
6637 val |= (cur[1] & 0x3f) << 6;
6638 val |= cur[2] & 0x3f;
6639 }
6640 } else {
6641 /* 2-byte code */
6642 *len = 2;
6643 val = (cur[0] & 0x1f) << 6;
6644 val |= cur[1] & 0x3f;
6645 }
6646 if (!IS_CHAR(val)) {
6647 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
6648 }
6649 return(val);
6650 } else {
6651 /* 1-byte code */
6652 *len = 1;
6653 return((int) *cur);
6654 }
6655encoding_error:
6656 /*
6657 * If we detect an UTF8 error that probably mean that the
6658 * input encoding didn't get properly advertized in the
6659 * declaration header. Report the error and switch the encoding
6660 * to ISO-Latin-1 (if you don't like this policy, just declare the
6661 * encoding !)
6662 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00006663 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00006664 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006665}
6666
6667/**
Owen Taylor3473f882001-02-23 17:55:21 +00006668 * xmlXPathParseNCName:
6669 * @ctxt: the XPath Parser context
6670 *
6671 * parse an XML namespace non qualified name.
6672 *
6673 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
6674 *
6675 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
6676 * CombiningChar | Extender
6677 *
6678 * Returns the namespace name or NULL
6679 */
6680
6681xmlChar *
6682xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00006683 const xmlChar *in;
6684 xmlChar *ret;
6685 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006686
Daniel Veillard2156a562001-04-28 12:24:34 +00006687 /*
6688 * Accelerator for simple ASCII names
6689 */
6690 in = ctxt->cur;
6691 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6692 ((*in >= 0x41) && (*in <= 0x5A)) ||
6693 (*in == '_')) {
6694 in++;
6695 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6696 ((*in >= 0x41) && (*in <= 0x5A)) ||
6697 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00006698 (*in == '_') || (*in == '.') ||
6699 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00006700 in++;
6701 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
6702 (*in == '[') || (*in == ']') || (*in == ':') ||
6703 (*in == '@') || (*in == '*')) {
6704 count = in - ctxt->cur;
6705 if (count == 0)
6706 return(NULL);
6707 ret = xmlStrndup(ctxt->cur, count);
6708 ctxt->cur = in;
6709 return(ret);
6710 }
6711 }
6712 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00006713}
6714
Daniel Veillard2156a562001-04-28 12:24:34 +00006715
Owen Taylor3473f882001-02-23 17:55:21 +00006716/**
6717 * xmlXPathParseQName:
6718 * @ctxt: the XPath Parser context
6719 * @prefix: a xmlChar **
6720 *
6721 * parse an XML qualified name
6722 *
6723 * [NS 5] QName ::= (Prefix ':')? LocalPart
6724 *
6725 * [NS 6] Prefix ::= NCName
6726 *
6727 * [NS 7] LocalPart ::= NCName
6728 *
6729 * Returns the function returns the local part, and prefix is updated
6730 * to get the Prefix if any.
6731 */
6732
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006733static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006734xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
6735 xmlChar *ret = NULL;
6736
6737 *prefix = NULL;
6738 ret = xmlXPathParseNCName(ctxt);
6739 if (CUR == ':') {
6740 *prefix = ret;
6741 NEXT;
6742 ret = xmlXPathParseNCName(ctxt);
6743 }
6744 return(ret);
6745}
6746
6747/**
6748 * xmlXPathParseName:
6749 * @ctxt: the XPath Parser context
6750 *
6751 * parse an XML name
6752 *
6753 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6754 * CombiningChar | Extender
6755 *
6756 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6757 *
6758 * Returns the namespace name or NULL
6759 */
6760
6761xmlChar *
6762xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006763 const xmlChar *in;
6764 xmlChar *ret;
6765 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006766
Daniel Veillard61d80a22001-04-27 17:13:01 +00006767 /*
6768 * Accelerator for simple ASCII names
6769 */
6770 in = ctxt->cur;
6771 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6772 ((*in >= 0x41) && (*in <= 0x5A)) ||
6773 (*in == '_') || (*in == ':')) {
6774 in++;
6775 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6776 ((*in >= 0x41) && (*in <= 0x5A)) ||
6777 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00006778 (*in == '_') || (*in == '-') ||
6779 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00006780 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00006781 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006782 count = in - ctxt->cur;
6783 ret = xmlStrndup(ctxt->cur, count);
6784 ctxt->cur = in;
6785 return(ret);
6786 }
6787 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006788 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00006789}
6790
Daniel Veillard61d80a22001-04-27 17:13:01 +00006791static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00006792xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006793 xmlChar buf[XML_MAX_NAMELEN + 5];
6794 int len = 0, l;
6795 int c;
6796
6797 /*
6798 * Handler for more complex cases
6799 */
6800 c = CUR_CHAR(l);
6801 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00006802 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
6803 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00006804 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00006805 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006806 return(NULL);
6807 }
6808
6809 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
6810 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
6811 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006812 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006813 (IS_COMBINING(c)) ||
6814 (IS_EXTENDER(c)))) {
6815 COPY_BUF(l,buf,len,c);
6816 NEXTL(l);
6817 c = CUR_CHAR(l);
6818 if (len >= XML_MAX_NAMELEN) {
6819 /*
6820 * Okay someone managed to make a huge name, so he's ready to pay
6821 * for the processing speed.
6822 */
6823 xmlChar *buffer;
6824 int max = len * 2;
6825
6826 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
6827 if (buffer == NULL) {
6828 XP_ERROR0(XPATH_MEMORY_ERROR);
6829 }
6830 memcpy(buffer, buf, len);
6831 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
6832 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006833 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006834 (IS_COMBINING(c)) ||
6835 (IS_EXTENDER(c))) {
6836 if (len + 10 > max) {
6837 max *= 2;
6838 buffer = (xmlChar *) xmlRealloc(buffer,
6839 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00006840 if (buffer == NULL) {
6841 XP_ERROR0(XPATH_MEMORY_ERROR);
6842 }
6843 }
6844 COPY_BUF(l,buffer,len,c);
6845 NEXTL(l);
6846 c = CUR_CHAR(l);
6847 }
6848 buffer[len] = 0;
6849 return(buffer);
6850 }
6851 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006852 if (len == 0)
6853 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006854 return(xmlStrndup(buf, len));
6855}
Owen Taylor3473f882001-02-23 17:55:21 +00006856/**
6857 * xmlXPathStringEvalNumber:
6858 * @str: A string to scan
6859 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00006860 * [30a] Float ::= Number ('e' Digits?)?
6861 *
Owen Taylor3473f882001-02-23 17:55:21 +00006862 * [30] Number ::= Digits ('.' Digits?)?
6863 * | '.' Digits
6864 * [31] Digits ::= [0-9]+
6865 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006866 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00006867 * In complement of the Number expression, this function also handles
6868 * negative values : '-' Number.
6869 *
6870 * Returns the double value.
6871 */
6872double
6873xmlXPathStringEvalNumber(const xmlChar *str) {
6874 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00006875 double ret;
Owen Taylor3473f882001-02-23 17:55:21 +00006876 double mult = 1;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006877 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006878 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006879 int exponent = 0;
6880 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006881#ifdef __GNUC__
6882 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00006883 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006884#endif
Bjorn Reese70a9da52001-04-21 16:57:29 +00006885
Owen Taylor3473f882001-02-23 17:55:21 +00006886 while (IS_BLANK(*cur)) cur++;
6887 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
6888 return(xmlXPathNAN);
6889 }
6890 if (*cur == '-') {
6891 isneg = 1;
6892 cur++;
6893 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00006894
6895#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006896 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00006897 * tmp/temp is a workaround against a gcc compiler bug
6898 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006899 */
Daniel Veillard7b416132002-03-07 08:36:03 +00006900 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006901 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00006902 ret = ret * 10;
6903 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00006904 ok = 1;
6905 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00006906 temp = (double) tmp;
6907 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00006908 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00006909#else
Daniel Veillard7b416132002-03-07 08:36:03 +00006910 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006911 while ((*cur >= '0') && (*cur <= '9')) {
6912 ret = ret * 10 + (*cur - '0');
6913 ok = 1;
6914 cur++;
6915 }
6916#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006917
Owen Taylor3473f882001-02-23 17:55:21 +00006918 if (*cur == '.') {
6919 cur++;
6920 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
6921 return(xmlXPathNAN);
6922 }
6923 while ((*cur >= '0') && (*cur <= '9')) {
6924 mult /= 10;
6925 ret = ret + (*cur - '0') * mult;
6926 cur++;
6927 }
6928 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006929 if ((*cur == 'e') || (*cur == 'E')) {
6930 cur++;
6931 if (*cur == '-') {
6932 is_exponent_negative = 1;
6933 cur++;
6934 }
6935 while ((*cur >= '0') && (*cur <= '9')) {
6936 exponent = exponent * 10 + (*cur - '0');
6937 cur++;
6938 }
6939 }
Owen Taylor3473f882001-02-23 17:55:21 +00006940 while (IS_BLANK(*cur)) cur++;
6941 if (*cur != 0) return(xmlXPathNAN);
6942 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006943 if (is_exponent_negative) exponent = -exponent;
6944 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00006945 return(ret);
6946}
6947
6948/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006949 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00006950 * @ctxt: the XPath Parser context
6951 *
6952 * [30] Number ::= Digits ('.' Digits?)?
6953 * | '.' Digits
6954 * [31] Digits ::= [0-9]+
6955 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006956 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00006957 *
6958 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006959static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006960xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
6961{
Owen Taylor3473f882001-02-23 17:55:21 +00006962 double ret = 0.0;
6963 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00006964 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006965 int exponent = 0;
6966 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00006967#ifdef __GNUC__
6968 unsigned long tmp = 0;
6969 double temp;
6970#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006971
6972 CHECK_ERROR;
6973 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
6974 XP_ERROR(XPATH_NUMBER_ERROR);
6975 }
Daniel Veillard7b416132002-03-07 08:36:03 +00006976#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006977 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00006978 * tmp/temp is a workaround against a gcc compiler bug
6979 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006980 */
Daniel Veillard7b416132002-03-07 08:36:03 +00006981 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006982 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00006983 ret = ret * 10;
6984 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006985 ok = 1;
6986 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00006987 temp = (double) tmp;
6988 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00006989 }
Daniel Veillard7b416132002-03-07 08:36:03 +00006990#else
6991 ret = 0;
6992 while ((CUR >= '0') && (CUR <= '9')) {
6993 ret = ret * 10 + (CUR - '0');
6994 ok = 1;
6995 NEXT;
6996 }
6997#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006998 if (CUR == '.') {
6999 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007000 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7001 XP_ERROR(XPATH_NUMBER_ERROR);
7002 }
7003 while ((CUR >= '0') && (CUR <= '9')) {
7004 mult /= 10;
7005 ret = ret + (CUR - '0') * mult;
7006 NEXT;
7007 }
Owen Taylor3473f882001-02-23 17:55:21 +00007008 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007009 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007010 NEXT;
7011 if (CUR == '-') {
7012 is_exponent_negative = 1;
7013 NEXT;
7014 }
7015 while ((CUR >= '0') && (CUR <= '9')) {
7016 exponent = exponent * 10 + (CUR - '0');
7017 NEXT;
7018 }
7019 if (is_exponent_negative)
7020 exponent = -exponent;
7021 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007022 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007023 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007024 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007025}
7026
7027/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007028 * xmlXPathParseLiteral:
7029 * @ctxt: the XPath Parser context
7030 *
7031 * Parse a Literal
7032 *
7033 * [29] Literal ::= '"' [^"]* '"'
7034 * | "'" [^']* "'"
7035 *
7036 * Returns the value found or NULL in case of error
7037 */
7038static xmlChar *
7039xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7040 const xmlChar *q;
7041 xmlChar *ret = NULL;
7042
7043 if (CUR == '"') {
7044 NEXT;
7045 q = CUR_PTR;
7046 while ((IS_CHAR(CUR)) && (CUR != '"'))
7047 NEXT;
7048 if (!IS_CHAR(CUR)) {
7049 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7050 } else {
7051 ret = xmlStrndup(q, CUR_PTR - q);
7052 NEXT;
7053 }
7054 } else 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 {
7066 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7067 }
7068 return(ret);
7069}
7070
7071/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007072 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007073 * @ctxt: the XPath Parser context
7074 *
7075 * Parse a Literal and push it on the stack.
7076 *
7077 * [29] Literal ::= '"' [^"]* '"'
7078 * | "'" [^']* "'"
7079 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007080 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007081 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007082static void
7083xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007084 const xmlChar *q;
7085 xmlChar *ret = NULL;
7086
7087 if (CUR == '"') {
7088 NEXT;
7089 q = CUR_PTR;
7090 while ((IS_CHAR(CUR)) && (CUR != '"'))
7091 NEXT;
7092 if (!IS_CHAR(CUR)) {
7093 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7094 } else {
7095 ret = xmlStrndup(q, CUR_PTR - q);
7096 NEXT;
7097 }
7098 } else 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 {
7110 XP_ERROR(XPATH_START_LITERAL_ERROR);
7111 }
7112 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007113 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7114 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007115 xmlFree(ret);
7116}
7117
7118/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007119 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007120 * @ctxt: the XPath Parser context
7121 *
7122 * Parse a VariableReference, evaluate it and push it on the stack.
7123 *
7124 * The variable bindings consist of a mapping from variable names
7125 * to variable values. The value of a variable is an object, which
7126 * of any of the types that are possible for the value of an expression,
7127 * and may also be of additional types not specified here.
7128 *
7129 * Early evaluation is possible since:
7130 * The variable bindings [...] used to evaluate a subexpression are
7131 * always the same as those used to evaluate the containing expression.
7132 *
7133 * [36] VariableReference ::= '$' QName
7134 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007135static void
7136xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007137 xmlChar *name;
7138 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007139
7140 SKIP_BLANKS;
7141 if (CUR != '$') {
7142 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7143 }
7144 NEXT;
7145 name = xmlXPathParseQName(ctxt, &prefix);
7146 if (name == NULL) {
7147 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7148 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007149 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007150 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7151 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007152 SKIP_BLANKS;
7153}
7154
7155/**
7156 * xmlXPathIsNodeType:
7157 * @ctxt: the XPath Parser context
7158 * @name: a name string
7159 *
7160 * Is the name given a NodeType one.
7161 *
7162 * [38] NodeType ::= 'comment'
7163 * | 'text'
7164 * | 'processing-instruction'
7165 * | 'node'
7166 *
7167 * Returns 1 if true 0 otherwise
7168 */
7169int
7170xmlXPathIsNodeType(const xmlChar *name) {
7171 if (name == NULL)
7172 return(0);
7173
Daniel Veillard1971ee22002-01-31 20:29:19 +00007174 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007175 return(1);
7176 if (xmlStrEqual(name, BAD_CAST "text"))
7177 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007178 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007179 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007180 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007181 return(1);
7182 return(0);
7183}
7184
7185/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007186 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007187 * @ctxt: the XPath Parser context
7188 *
7189 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7190 * [17] Argument ::= Expr
7191 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007192 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007193 * pushed on the stack
7194 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007195static void
7196xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007197 xmlChar *name;
7198 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007199 int nbargs = 0;
7200
7201 name = xmlXPathParseQName(ctxt, &prefix);
7202 if (name == NULL) {
7203 XP_ERROR(XPATH_EXPR_ERROR);
7204 }
7205 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007206#ifdef DEBUG_EXPR
7207 if (prefix == NULL)
7208 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7209 name);
7210 else
7211 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7212 prefix, name);
7213#endif
7214
Owen Taylor3473f882001-02-23 17:55:21 +00007215 if (CUR != '(') {
7216 XP_ERROR(XPATH_EXPR_ERROR);
7217 }
7218 NEXT;
7219 SKIP_BLANKS;
7220
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007221 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007222 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007223 int op1 = ctxt->comp->last;
7224 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007225 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007226 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007227 nbargs++;
7228 if (CUR == ')') break;
7229 if (CUR != ',') {
7230 XP_ERROR(XPATH_EXPR_ERROR);
7231 }
7232 NEXT;
7233 SKIP_BLANKS;
7234 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007235 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7236 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007237 NEXT;
7238 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007239}
7240
7241/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007242 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007243 * @ctxt: the XPath Parser context
7244 *
7245 * [15] PrimaryExpr ::= VariableReference
7246 * | '(' Expr ')'
7247 * | Literal
7248 * | Number
7249 * | FunctionCall
7250 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007251 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007252 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007253static void
7254xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007255 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007256 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007257 else if (CUR == '(') {
7258 NEXT;
7259 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007260 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007261 if (CUR != ')') {
7262 XP_ERROR(XPATH_EXPR_ERROR);
7263 }
7264 NEXT;
7265 SKIP_BLANKS;
7266 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007267 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007268 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007269 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007270 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007271 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007272 }
7273 SKIP_BLANKS;
7274}
7275
7276/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007277 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007278 * @ctxt: the XPath Parser context
7279 *
7280 * [20] FilterExpr ::= PrimaryExpr
7281 * | FilterExpr Predicate
7282 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007283 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007284 * Square brackets are used to filter expressions in the same way that
7285 * they are used in location paths. It is an error if the expression to
7286 * be filtered does not evaluate to a node-set. The context node list
7287 * used for evaluating the expression in square brackets is the node-set
7288 * to be filtered listed in document order.
7289 */
7290
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007291static void
7292xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7293 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007294 CHECK_ERROR;
7295 SKIP_BLANKS;
7296
7297 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007298 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007299 SKIP_BLANKS;
7300 }
7301
7302
7303}
7304
7305/**
7306 * xmlXPathScanName:
7307 * @ctxt: the XPath Parser context
7308 *
7309 * Trickery: parse an XML name but without consuming the input flow
7310 * Needed to avoid insanity in the parser state.
7311 *
7312 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7313 * CombiningChar | Extender
7314 *
7315 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7316 *
7317 * [6] Names ::= Name (S Name)*
7318 *
7319 * Returns the Name parsed or NULL
7320 */
7321
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007322static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007323xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7324 xmlChar buf[XML_MAX_NAMELEN];
7325 int len = 0;
7326
7327 SKIP_BLANKS;
7328 if (!IS_LETTER(CUR) && (CUR != '_') &&
7329 (CUR != ':')) {
7330 return(NULL);
7331 }
7332
7333 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7334 (NXT(len) == '.') || (NXT(len) == '-') ||
7335 (NXT(len) == '_') || (NXT(len) == ':') ||
7336 (IS_COMBINING(NXT(len))) ||
7337 (IS_EXTENDER(NXT(len)))) {
7338 buf[len] = NXT(len);
7339 len++;
7340 if (len >= XML_MAX_NAMELEN) {
7341 xmlGenericError(xmlGenericErrorContext,
7342 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7343 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7344 (NXT(len) == '.') || (NXT(len) == '-') ||
7345 (NXT(len) == '_') || (NXT(len) == ':') ||
7346 (IS_COMBINING(NXT(len))) ||
7347 (IS_EXTENDER(NXT(len))))
7348 len++;
7349 break;
7350 }
7351 }
7352 return(xmlStrndup(buf, len));
7353}
7354
7355/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007356 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007357 * @ctxt: the XPath Parser context
7358 *
7359 * [19] PathExpr ::= LocationPath
7360 * | FilterExpr
7361 * | FilterExpr '/' RelativeLocationPath
7362 * | FilterExpr '//' RelativeLocationPath
7363 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007364 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007365 * The / operator and // operators combine an arbitrary expression
7366 * and a relative location path. It is an error if the expression
7367 * does not evaluate to a node-set.
7368 * The / operator does composition in the same way as when / is
7369 * used in a location path. As in location paths, // is short for
7370 * /descendant-or-self::node()/.
7371 */
7372
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007373static void
7374xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007375 int lc = 1; /* Should we branch to LocationPath ? */
7376 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7377
7378 SKIP_BLANKS;
7379 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
7380 (CUR == '\'') || (CUR == '"')) {
7381 lc = 0;
7382 } else if (CUR == '*') {
7383 /* relative or absolute location path */
7384 lc = 1;
7385 } else if (CUR == '/') {
7386 /* relative or absolute location path */
7387 lc = 1;
7388 } else if (CUR == '@') {
7389 /* relative abbreviated attribute location path */
7390 lc = 1;
7391 } else if (CUR == '.') {
7392 /* relative abbreviated attribute location path */
7393 lc = 1;
7394 } else {
7395 /*
7396 * Problem is finding if we have a name here whether it's:
7397 * - a nodetype
7398 * - a function call in which case it's followed by '('
7399 * - an axis in which case it's followed by ':'
7400 * - a element name
7401 * We do an a priori analysis here rather than having to
7402 * maintain parsed token content through the recursive function
7403 * calls. This looks uglier but makes the code quite easier to
7404 * read/write/debug.
7405 */
7406 SKIP_BLANKS;
7407 name = xmlXPathScanName(ctxt);
7408 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7409#ifdef DEBUG_STEP
7410 xmlGenericError(xmlGenericErrorContext,
7411 "PathExpr: Axis\n");
7412#endif
7413 lc = 1;
7414 xmlFree(name);
7415 } else if (name != NULL) {
7416 int len =xmlStrlen(name);
7417 int blank = 0;
7418
7419
7420 while (NXT(len) != 0) {
7421 if (NXT(len) == '/') {
7422 /* element name */
7423#ifdef DEBUG_STEP
7424 xmlGenericError(xmlGenericErrorContext,
7425 "PathExpr: AbbrRelLocation\n");
7426#endif
7427 lc = 1;
7428 break;
7429 } else if (IS_BLANK(NXT(len))) {
7430 /* skip to next */
7431 blank = 1;
7432 } else if (NXT(len) == ':') {
7433#ifdef DEBUG_STEP
7434 xmlGenericError(xmlGenericErrorContext,
7435 "PathExpr: AbbrRelLocation\n");
7436#endif
7437 lc = 1;
7438 break;
7439 } else if ((NXT(len) == '(')) {
7440 /* Note Type or Function */
7441 if (xmlXPathIsNodeType(name)) {
7442#ifdef DEBUG_STEP
7443 xmlGenericError(xmlGenericErrorContext,
7444 "PathExpr: Type search\n");
7445#endif
7446 lc = 1;
7447 } else {
7448#ifdef DEBUG_STEP
7449 xmlGenericError(xmlGenericErrorContext,
7450 "PathExpr: function call\n");
7451#endif
7452 lc = 0;
7453 }
7454 break;
7455 } else if ((NXT(len) == '[')) {
7456 /* element name */
7457#ifdef DEBUG_STEP
7458 xmlGenericError(xmlGenericErrorContext,
7459 "PathExpr: AbbrRelLocation\n");
7460#endif
7461 lc = 1;
7462 break;
7463 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7464 (NXT(len) == '=')) {
7465 lc = 1;
7466 break;
7467 } else {
7468 lc = 1;
7469 break;
7470 }
7471 len++;
7472 }
7473 if (NXT(len) == 0) {
7474#ifdef DEBUG_STEP
7475 xmlGenericError(xmlGenericErrorContext,
7476 "PathExpr: AbbrRelLocation\n");
7477#endif
7478 /* element name */
7479 lc = 1;
7480 }
7481 xmlFree(name);
7482 } else {
7483 /* make sure all cases are covered explicitely */
7484 XP_ERROR(XPATH_EXPR_ERROR);
7485 }
7486 }
7487
7488 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007489 if (CUR == '/') {
7490 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7491 } else {
7492 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007493 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007494 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007495 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007496 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007497 CHECK_ERROR;
7498 if ((CUR == '/') && (NXT(1) == '/')) {
7499 SKIP(2);
7500 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007501
7502 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7503 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7504 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7505
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007506 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007507 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007508 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007509 }
7510 }
7511 SKIP_BLANKS;
7512}
7513
7514/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007515 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007516 * @ctxt: the XPath Parser context
7517 *
7518 * [18] UnionExpr ::= PathExpr
7519 * | UnionExpr '|' PathExpr
7520 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007521 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007522 */
7523
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007524static void
7525xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7526 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007527 CHECK_ERROR;
7528 SKIP_BLANKS;
7529 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007530 int op1 = ctxt->comp->last;
7531 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007532
7533 NEXT;
7534 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007535 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007536
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007537 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
7538
Owen Taylor3473f882001-02-23 17:55:21 +00007539 SKIP_BLANKS;
7540 }
Owen Taylor3473f882001-02-23 17:55:21 +00007541}
7542
7543/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007544 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007545 * @ctxt: the XPath Parser context
7546 *
7547 * [27] UnaryExpr ::= UnionExpr
7548 * | '-' UnaryExpr
7549 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007550 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007551 */
7552
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007553static void
7554xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007555 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007556 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007557
7558 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00007559 while (CUR == '-') {
7560 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007561 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007562 NEXT;
7563 SKIP_BLANKS;
7564 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007565
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007566 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007567 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007568 if (found) {
7569 if (minus)
7570 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
7571 else
7572 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007573 }
7574}
7575
7576/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007577 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007578 * @ctxt: the XPath Parser context
7579 *
7580 * [26] MultiplicativeExpr ::= UnaryExpr
7581 * | MultiplicativeExpr MultiplyOperator UnaryExpr
7582 * | MultiplicativeExpr 'div' UnaryExpr
7583 * | MultiplicativeExpr 'mod' UnaryExpr
7584 * [34] MultiplyOperator ::= '*'
7585 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007586 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007587 */
7588
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007589static void
7590xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
7591 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007592 CHECK_ERROR;
7593 SKIP_BLANKS;
7594 while ((CUR == '*') ||
7595 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
7596 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
7597 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007598 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007599
7600 if (CUR == '*') {
7601 op = 0;
7602 NEXT;
7603 } else if (CUR == 'd') {
7604 op = 1;
7605 SKIP(3);
7606 } else if (CUR == 'm') {
7607 op = 2;
7608 SKIP(3);
7609 }
7610 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007611 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007612 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007613 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007614 SKIP_BLANKS;
7615 }
7616}
7617
7618/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007619 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007620 * @ctxt: the XPath Parser context
7621 *
7622 * [25] AdditiveExpr ::= MultiplicativeExpr
7623 * | AdditiveExpr '+' MultiplicativeExpr
7624 * | AdditiveExpr '-' MultiplicativeExpr
7625 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007626 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007627 */
7628
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007629static void
7630xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007631
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007632 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007633 CHECK_ERROR;
7634 SKIP_BLANKS;
7635 while ((CUR == '+') || (CUR == '-')) {
7636 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007637 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007638
7639 if (CUR == '+') plus = 1;
7640 else plus = 0;
7641 NEXT;
7642 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007643 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007644 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007645 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007646 SKIP_BLANKS;
7647 }
7648}
7649
7650/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007651 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007652 * @ctxt: the XPath Parser context
7653 *
7654 * [24] RelationalExpr ::= AdditiveExpr
7655 * | RelationalExpr '<' AdditiveExpr
7656 * | RelationalExpr '>' AdditiveExpr
7657 * | RelationalExpr '<=' AdditiveExpr
7658 * | RelationalExpr '>=' AdditiveExpr
7659 *
7660 * A <= B > C is allowed ? Answer from James, yes with
7661 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
7662 * which is basically what got implemented.
7663 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007664 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00007665 * on the stack
7666 */
7667
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007668static void
7669xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
7670 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007671 CHECK_ERROR;
7672 SKIP_BLANKS;
7673 while ((CUR == '<') ||
7674 (CUR == '>') ||
7675 ((CUR == '<') && (NXT(1) == '=')) ||
7676 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007677 int inf, strict;
7678 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007679
7680 if (CUR == '<') inf = 1;
7681 else inf = 0;
7682 if (NXT(1) == '=') strict = 0;
7683 else strict = 1;
7684 NEXT;
7685 if (!strict) NEXT;
7686 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007687 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007688 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007689 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00007690 SKIP_BLANKS;
7691 }
7692}
7693
7694/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007695 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007696 * @ctxt: the XPath Parser context
7697 *
7698 * [23] EqualityExpr ::= RelationalExpr
7699 * | EqualityExpr '=' RelationalExpr
7700 * | EqualityExpr '!=' RelationalExpr
7701 *
7702 * A != B != C is allowed ? Answer from James, yes with
7703 * (RelationalExpr = RelationalExpr) = RelationalExpr
7704 * (RelationalExpr != RelationalExpr) != RelationalExpr
7705 * which is basically what got implemented.
7706 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007707 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007708 *
7709 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007710static void
7711xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
7712 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007713 CHECK_ERROR;
7714 SKIP_BLANKS;
7715 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007716 int eq;
7717 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007718
7719 if (CUR == '=') eq = 1;
7720 else eq = 0;
7721 NEXT;
7722 if (!eq) NEXT;
7723 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007724 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007725 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007726 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007727 SKIP_BLANKS;
7728 }
7729}
7730
7731/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007732 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007733 * @ctxt: the XPath Parser context
7734 *
7735 * [22] AndExpr ::= EqualityExpr
7736 * | AndExpr 'and' EqualityExpr
7737 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007738 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007739 *
7740 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007741static void
7742xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
7743 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007744 CHECK_ERROR;
7745 SKIP_BLANKS;
7746 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007747 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007748 SKIP(3);
7749 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007750 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007751 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007752 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007753 SKIP_BLANKS;
7754 }
7755}
7756
7757/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007758 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007759 * @ctxt: the XPath Parser context
7760 *
7761 * [14] Expr ::= OrExpr
7762 * [21] OrExpr ::= AndExpr
7763 * | OrExpr 'or' AndExpr
7764 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007765 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00007766 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007767static void
7768xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
7769 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007770 CHECK_ERROR;
7771 SKIP_BLANKS;
7772 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007773 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007774 SKIP(2);
7775 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007776 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007777 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007778 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
7779 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00007780 SKIP_BLANKS;
7781 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007782 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
7783 /* more ops could be optimized too */
7784 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
7785 }
Owen Taylor3473f882001-02-23 17:55:21 +00007786}
7787
7788/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007789 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00007790 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007791 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00007792 *
7793 * [8] Predicate ::= '[' PredicateExpr ']'
7794 * [9] PredicateExpr ::= Expr
7795 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007796 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00007797 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007798static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007799xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007800 int op1 = ctxt->comp->last;
7801
7802 SKIP_BLANKS;
7803 if (CUR != '[') {
7804 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7805 }
7806 NEXT;
7807 SKIP_BLANKS;
7808
7809 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007810 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007811 CHECK_ERROR;
7812
7813 if (CUR != ']') {
7814 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7815 }
7816
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007817 if (filter)
7818 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
7819 else
7820 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007821
7822 NEXT;
7823 SKIP_BLANKS;
7824}
7825
7826/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007827 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00007828 * @ctxt: the XPath Parser context
7829 * @test: pointer to a xmlXPathTestVal
7830 * @type: pointer to a xmlXPathTypeVal
7831 * @prefix: placeholder for a possible name prefix
7832 *
7833 * [7] NodeTest ::= NameTest
7834 * | NodeType '(' ')'
7835 * | 'processing-instruction' '(' Literal ')'
7836 *
7837 * [37] NameTest ::= '*'
7838 * | NCName ':' '*'
7839 * | QName
7840 * [38] NodeType ::= 'comment'
7841 * | 'text'
7842 * | 'processing-instruction'
7843 * | 'node'
7844 *
7845 * Returns the name found and update @test, @type and @prefix appropriately
7846 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007847static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007848xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
7849 xmlXPathTypeVal *type, const xmlChar **prefix,
7850 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00007851 int blanks;
7852
7853 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
7854 STRANGE;
7855 return(NULL);
7856 }
7857 *type = 0;
7858 *test = 0;
7859 *prefix = NULL;
7860 SKIP_BLANKS;
7861
7862 if ((name == NULL) && (CUR == '*')) {
7863 /*
7864 * All elements
7865 */
7866 NEXT;
7867 *test = NODE_TEST_ALL;
7868 return(NULL);
7869 }
7870
7871 if (name == NULL)
7872 name = xmlXPathParseNCName(ctxt);
7873 if (name == NULL) {
7874 XP_ERROR0(XPATH_EXPR_ERROR);
7875 }
7876
7877 blanks = IS_BLANK(CUR);
7878 SKIP_BLANKS;
7879 if (CUR == '(') {
7880 NEXT;
7881 /*
7882 * NodeType or PI search
7883 */
7884 if (xmlStrEqual(name, BAD_CAST "comment"))
7885 *type = NODE_TYPE_COMMENT;
7886 else if (xmlStrEqual(name, BAD_CAST "node"))
7887 *type = NODE_TYPE_NODE;
7888 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
7889 *type = NODE_TYPE_PI;
7890 else if (xmlStrEqual(name, BAD_CAST "text"))
7891 *type = NODE_TYPE_TEXT;
7892 else {
7893 if (name != NULL)
7894 xmlFree(name);
7895 XP_ERROR0(XPATH_EXPR_ERROR);
7896 }
7897
7898 *test = NODE_TEST_TYPE;
7899
7900 SKIP_BLANKS;
7901 if (*type == NODE_TYPE_PI) {
7902 /*
7903 * Specific case: search a PI by name.
7904 */
Owen Taylor3473f882001-02-23 17:55:21 +00007905 if (name != NULL)
7906 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00007907 name = NULL;
7908 if (CUR != ')') {
7909 name = xmlXPathParseLiteral(ctxt);
7910 CHECK_ERROR 0;
7911 SKIP_BLANKS;
7912 }
Owen Taylor3473f882001-02-23 17:55:21 +00007913 }
7914 if (CUR != ')') {
7915 if (name != NULL)
7916 xmlFree(name);
7917 XP_ERROR0(XPATH_UNCLOSED_ERROR);
7918 }
7919 NEXT;
7920 return(name);
7921 }
7922 *test = NODE_TEST_NAME;
7923 if ((!blanks) && (CUR == ':')) {
7924 NEXT;
7925
7926 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007927 * Since currently the parser context don't have a
7928 * namespace list associated:
7929 * The namespace name for this prefix can be computed
7930 * only at evaluation time. The compilation is done
7931 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00007932 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007933#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00007934 *prefix = xmlXPathNsLookup(ctxt->context, name);
7935 if (name != NULL)
7936 xmlFree(name);
7937 if (*prefix == NULL) {
7938 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
7939 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007940#else
7941 *prefix = name;
7942#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007943
7944 if (CUR == '*') {
7945 /*
7946 * All elements
7947 */
7948 NEXT;
7949 *test = NODE_TEST_ALL;
7950 return(NULL);
7951 }
7952
7953 name = xmlXPathParseNCName(ctxt);
7954 if (name == NULL) {
7955 XP_ERROR0(XPATH_EXPR_ERROR);
7956 }
7957 }
7958 return(name);
7959}
7960
7961/**
7962 * xmlXPathIsAxisName:
7963 * @name: a preparsed name token
7964 *
7965 * [6] AxisName ::= 'ancestor'
7966 * | 'ancestor-or-self'
7967 * | 'attribute'
7968 * | 'child'
7969 * | 'descendant'
7970 * | 'descendant-or-self'
7971 * | 'following'
7972 * | 'following-sibling'
7973 * | 'namespace'
7974 * | 'parent'
7975 * | 'preceding'
7976 * | 'preceding-sibling'
7977 * | 'self'
7978 *
7979 * Returns the axis or 0
7980 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007981static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00007982xmlXPathIsAxisName(const xmlChar *name) {
7983 xmlXPathAxisVal ret = 0;
7984 switch (name[0]) {
7985 case 'a':
7986 if (xmlStrEqual(name, BAD_CAST "ancestor"))
7987 ret = AXIS_ANCESTOR;
7988 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
7989 ret = AXIS_ANCESTOR_OR_SELF;
7990 if (xmlStrEqual(name, BAD_CAST "attribute"))
7991 ret = AXIS_ATTRIBUTE;
7992 break;
7993 case 'c':
7994 if (xmlStrEqual(name, BAD_CAST "child"))
7995 ret = AXIS_CHILD;
7996 break;
7997 case 'd':
7998 if (xmlStrEqual(name, BAD_CAST "descendant"))
7999 ret = AXIS_DESCENDANT;
8000 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8001 ret = AXIS_DESCENDANT_OR_SELF;
8002 break;
8003 case 'f':
8004 if (xmlStrEqual(name, BAD_CAST "following"))
8005 ret = AXIS_FOLLOWING;
8006 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8007 ret = AXIS_FOLLOWING_SIBLING;
8008 break;
8009 case 'n':
8010 if (xmlStrEqual(name, BAD_CAST "namespace"))
8011 ret = AXIS_NAMESPACE;
8012 break;
8013 case 'p':
8014 if (xmlStrEqual(name, BAD_CAST "parent"))
8015 ret = AXIS_PARENT;
8016 if (xmlStrEqual(name, BAD_CAST "preceding"))
8017 ret = AXIS_PRECEDING;
8018 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8019 ret = AXIS_PRECEDING_SIBLING;
8020 break;
8021 case 's':
8022 if (xmlStrEqual(name, BAD_CAST "self"))
8023 ret = AXIS_SELF;
8024 break;
8025 }
8026 return(ret);
8027}
8028
8029/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008030 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008031 * @ctxt: the XPath Parser context
8032 *
8033 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8034 * | AbbreviatedStep
8035 *
8036 * [12] AbbreviatedStep ::= '.' | '..'
8037 *
8038 * [5] AxisSpecifier ::= AxisName '::'
8039 * | AbbreviatedAxisSpecifier
8040 *
8041 * [13] AbbreviatedAxisSpecifier ::= '@'?
8042 *
8043 * Modified for XPtr range support as:
8044 *
8045 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8046 * | AbbreviatedStep
8047 * | 'range-to' '(' Expr ')' Predicate*
8048 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008049 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008050 * A location step of . is short for self::node(). This is
8051 * particularly useful in conjunction with //. For example, the
8052 * location path .//para is short for
8053 * self::node()/descendant-or-self::node()/child::para
8054 * and so will select all para descendant elements of the context
8055 * node.
8056 * Similarly, a location step of .. is short for parent::node().
8057 * For example, ../title is short for parent::node()/child::title
8058 * and so will select the title children of the parent of the context
8059 * node.
8060 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008061static void
8062xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008063#ifdef LIBXML_XPTR_ENABLED
8064 int rangeto = 0;
8065 int op2 = -1;
8066#endif
8067
Owen Taylor3473f882001-02-23 17:55:21 +00008068 SKIP_BLANKS;
8069 if ((CUR == '.') && (NXT(1) == '.')) {
8070 SKIP(2);
8071 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008072 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8073 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008074 } else if (CUR == '.') {
8075 NEXT;
8076 SKIP_BLANKS;
8077 } else {
8078 xmlChar *name = NULL;
8079 const xmlChar *prefix = NULL;
8080 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008081 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008082 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008083 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008084
8085 /*
8086 * The modification needed for XPointer change to the production
8087 */
8088#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008089 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008090 name = xmlXPathParseNCName(ctxt);
8091 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008092 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008093 xmlFree(name);
8094 SKIP_BLANKS;
8095 if (CUR != '(') {
8096 XP_ERROR(XPATH_EXPR_ERROR);
8097 }
8098 NEXT;
8099 SKIP_BLANKS;
8100
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008101 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008102 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008103 CHECK_ERROR;
8104
8105 SKIP_BLANKS;
8106 if (CUR != ')') {
8107 XP_ERROR(XPATH_EXPR_ERROR);
8108 }
8109 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008110 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008111 goto eval_predicates;
8112 }
8113 }
8114#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008115 if (CUR == '*') {
8116 axis = AXIS_CHILD;
8117 } else {
8118 if (name == NULL)
8119 name = xmlXPathParseNCName(ctxt);
8120 if (name != NULL) {
8121 axis = xmlXPathIsAxisName(name);
8122 if (axis != 0) {
8123 SKIP_BLANKS;
8124 if ((CUR == ':') && (NXT(1) == ':')) {
8125 SKIP(2);
8126 xmlFree(name);
8127 name = NULL;
8128 } else {
8129 /* an element name can conflict with an axis one :-\ */
8130 axis = AXIS_CHILD;
8131 }
Owen Taylor3473f882001-02-23 17:55:21 +00008132 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008133 axis = AXIS_CHILD;
8134 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008135 } else if (CUR == '@') {
8136 NEXT;
8137 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008138 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008139 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008140 }
Owen Taylor3473f882001-02-23 17:55:21 +00008141 }
8142
8143 CHECK_ERROR;
8144
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008145 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008146 if (test == 0)
8147 return;
8148
8149#ifdef DEBUG_STEP
8150 xmlGenericError(xmlGenericErrorContext,
8151 "Basis : computing new set\n");
8152#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008153
Owen Taylor3473f882001-02-23 17:55:21 +00008154#ifdef DEBUG_STEP
8155 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008156 if (ctxt->value == NULL)
8157 xmlGenericError(xmlGenericErrorContext, "no value\n");
8158 else if (ctxt->value->nodesetval == NULL)
8159 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8160 else
8161 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008162#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008163
8164eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008165 op1 = ctxt->comp->last;
8166 ctxt->comp->last = -1;
8167
Owen Taylor3473f882001-02-23 17:55:21 +00008168 SKIP_BLANKS;
8169 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008170 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008171 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008172
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008173#ifdef LIBXML_XPTR_ENABLED
8174 if (rangeto) {
8175 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8176 } else
8177#endif
8178 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8179 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008180
Owen Taylor3473f882001-02-23 17:55:21 +00008181 }
8182#ifdef DEBUG_STEP
8183 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008184 if (ctxt->value == NULL)
8185 xmlGenericError(xmlGenericErrorContext, "no value\n");
8186 else if (ctxt->value->nodesetval == NULL)
8187 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8188 else
8189 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8190 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008191#endif
8192}
8193
8194/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008195 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008196 * @ctxt: the XPath Parser context
8197 *
8198 * [3] RelativeLocationPath ::= Step
8199 * | RelativeLocationPath '/' Step
8200 * | AbbreviatedRelativeLocationPath
8201 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8202 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008203 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008204 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008205static void
Owen Taylor3473f882001-02-23 17:55:21 +00008206#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008207xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008208#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008209xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008210#endif
8211(xmlXPathParserContextPtr ctxt) {
8212 SKIP_BLANKS;
8213 if ((CUR == '/') && (NXT(1) == '/')) {
8214 SKIP(2);
8215 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008216 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8217 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008218 } else if (CUR == '/') {
8219 NEXT;
8220 SKIP_BLANKS;
8221 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008222 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008223 SKIP_BLANKS;
8224 while (CUR == '/') {
8225 if ((CUR == '/') && (NXT(1) == '/')) {
8226 SKIP(2);
8227 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008228 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008229 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008230 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008231 } else if (CUR == '/') {
8232 NEXT;
8233 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008234 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008235 }
8236 SKIP_BLANKS;
8237 }
8238}
8239
8240/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008241 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008242 * @ctxt: the XPath Parser context
8243 *
8244 * [1] LocationPath ::= RelativeLocationPath
8245 * | AbsoluteLocationPath
8246 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8247 * | AbbreviatedAbsoluteLocationPath
8248 * [10] AbbreviatedAbsoluteLocationPath ::=
8249 * '//' RelativeLocationPath
8250 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008251 * Compile a location path
8252 *
Owen Taylor3473f882001-02-23 17:55:21 +00008253 * // is short for /descendant-or-self::node()/. For example,
8254 * //para is short for /descendant-or-self::node()/child::para and
8255 * so will select any para element in the document (even a para element
8256 * that is a document element will be selected by //para since the
8257 * document element node is a child of the root node); div//para is
8258 * short for div/descendant-or-self::node()/child::para and so will
8259 * select all para descendants of div children.
8260 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008261static void
8262xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008263 SKIP_BLANKS;
8264 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008265 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008266 } else {
8267 while (CUR == '/') {
8268 if ((CUR == '/') && (NXT(1) == '/')) {
8269 SKIP(2);
8270 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008271 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8272 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008273 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008274 } else if (CUR == '/') {
8275 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008276 SKIP_BLANKS;
8277 if ((CUR != 0 ) &&
8278 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
8279 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008280 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008281 }
8282 }
8283 }
8284}
8285
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008286/************************************************************************
8287 * *
8288 * XPath precompiled expression evaluation *
8289 * *
8290 ************************************************************************/
8291
Daniel Veillardf06307e2001-07-03 10:35:50 +00008292static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008293xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8294
8295/**
8296 * xmlXPathNodeCollectAndTest:
8297 * @ctxt: the XPath Parser context
8298 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008299 * @first: pointer to the first element in document order
8300 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008301 *
8302 * This is the function implementing a step: based on the current list
8303 * of nodes, it builds up a new list, looking at all nodes under that
8304 * axis and selecting them it also do the predicate filtering
8305 *
8306 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008307 *
8308 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008309 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008310static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008311xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008312 xmlXPathStepOpPtr op,
8313 xmlNodePtr * first, xmlNodePtr * last)
8314{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008315 xmlXPathAxisVal axis = op->value;
8316 xmlXPathTestVal test = op->value2;
8317 xmlXPathTypeVal type = op->value3;
8318 const xmlChar *prefix = op->value4;
8319 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008320 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008321
8322#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008323 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008324#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008325 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008326 xmlNodeSetPtr ret, list;
8327 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008328 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008329 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008330 xmlNodePtr cur = NULL;
8331 xmlXPathObjectPtr obj;
8332 xmlNodeSetPtr nodelist;
8333 xmlNodePtr tmp;
8334
Daniel Veillardf06307e2001-07-03 10:35:50 +00008335 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008336 obj = valuePop(ctxt);
8337 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008338 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008339 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008340 URI = xmlXPathNsLookup(ctxt->context, prefix);
8341 if (URI == NULL)
8342 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008343 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008344#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008345 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008346#endif
8347 switch (axis) {
8348 case AXIS_ANCESTOR:
8349#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008350 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008351#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008352 first = NULL;
8353 next = xmlXPathNextAncestor;
8354 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008355 case AXIS_ANCESTOR_OR_SELF:
8356#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008357 xmlGenericError(xmlGenericErrorContext,
8358 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008359#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008360 first = NULL;
8361 next = xmlXPathNextAncestorOrSelf;
8362 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008363 case AXIS_ATTRIBUTE:
8364#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008365 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008366#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008367 first = NULL;
8368 last = NULL;
8369 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00008370 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008371 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008372 case AXIS_CHILD:
8373#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008374 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008375#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008376 last = NULL;
8377 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00008378 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008379 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008380 case AXIS_DESCENDANT:
8381#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008382 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008383#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008384 last = NULL;
8385 next = xmlXPathNextDescendant;
8386 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008387 case AXIS_DESCENDANT_OR_SELF:
8388#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008389 xmlGenericError(xmlGenericErrorContext,
8390 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008391#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008392 last = NULL;
8393 next = xmlXPathNextDescendantOrSelf;
8394 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008395 case AXIS_FOLLOWING:
8396#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008397 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008398#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008399 last = NULL;
8400 next = xmlXPathNextFollowing;
8401 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008402 case AXIS_FOLLOWING_SIBLING:
8403#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008404 xmlGenericError(xmlGenericErrorContext,
8405 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008406#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008407 last = NULL;
8408 next = xmlXPathNextFollowingSibling;
8409 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008410 case AXIS_NAMESPACE:
8411#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008412 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008413#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008414 first = NULL;
8415 last = NULL;
8416 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00008417 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008418 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008419 case AXIS_PARENT:
8420#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008421 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008422#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008423 first = NULL;
8424 next = xmlXPathNextParent;
8425 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008426 case AXIS_PRECEDING:
8427#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008428 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008429#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008430 first = NULL;
8431 next = xmlXPathNextPrecedingInternal;
8432 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008433 case AXIS_PRECEDING_SIBLING:
8434#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008435 xmlGenericError(xmlGenericErrorContext,
8436 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008437#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008438 first = NULL;
8439 next = xmlXPathNextPrecedingSibling;
8440 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008441 case AXIS_SELF:
8442#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008443 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008444#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008445 first = NULL;
8446 last = NULL;
8447 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00008448 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008449 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008450 }
8451 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008452 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008453
8454 nodelist = obj->nodesetval;
8455 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008456 xmlXPathFreeObject(obj);
8457 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8458 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008459 }
8460 addNode = xmlXPathNodeSetAddUnique;
8461 ret = NULL;
8462#ifdef DEBUG_STEP
8463 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008464 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008465 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008466 case NODE_TEST_NONE:
8467 xmlGenericError(xmlGenericErrorContext,
8468 " searching for none !!!\n");
8469 break;
8470 case NODE_TEST_TYPE:
8471 xmlGenericError(xmlGenericErrorContext,
8472 " searching for type %d\n", type);
8473 break;
8474 case NODE_TEST_PI:
8475 xmlGenericError(xmlGenericErrorContext,
8476 " searching for PI !!!\n");
8477 break;
8478 case NODE_TEST_ALL:
8479 xmlGenericError(xmlGenericErrorContext,
8480 " searching for *\n");
8481 break;
8482 case NODE_TEST_NS:
8483 xmlGenericError(xmlGenericErrorContext,
8484 " searching for namespace %s\n",
8485 prefix);
8486 break;
8487 case NODE_TEST_NAME:
8488 xmlGenericError(xmlGenericErrorContext,
8489 " searching for name %s\n", name);
8490 if (prefix != NULL)
8491 xmlGenericError(xmlGenericErrorContext,
8492 " with namespace %s\n", prefix);
8493 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008494 }
8495 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8496#endif
8497 /*
8498 * 2.3 Node Tests
8499 * - For the attribute axis, the principal node type is attribute.
8500 * - For the namespace axis, the principal node type is namespace.
8501 * - For other axes, the principal node type is element.
8502 *
8503 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008504 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008505 * select all element children of the context node
8506 */
8507 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008508 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008509 ctxt->context->node = nodelist->nodeTab[i];
8510
Daniel Veillardf06307e2001-07-03 10:35:50 +00008511 cur = NULL;
8512 list = xmlXPathNodeSetCreate(NULL);
8513 do {
8514 cur = next(ctxt, cur);
8515 if (cur == NULL)
8516 break;
8517 if ((first != NULL) && (*first == cur))
8518 break;
8519 if (((t % 256) == 0) &&
8520 (first != NULL) && (*first != NULL) &&
8521 (xmlXPathCmpNodes(*first, cur) >= 0))
8522 break;
8523 if ((last != NULL) && (*last == cur))
8524 break;
8525 if (((t % 256) == 0) &&
8526 (last != NULL) && (*last != NULL) &&
8527 (xmlXPathCmpNodes(cur, *last) >= 0))
8528 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008529 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008530#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008531 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8532#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008533 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008534 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008535 ctxt->context->node = tmp;
8536 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008537 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008538 if ((cur->type == type) ||
8539 ((type == NODE_TYPE_NODE) &&
8540 ((cur->type == XML_DOCUMENT_NODE) ||
8541 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8542 (cur->type == XML_ELEMENT_NODE) ||
8543 (cur->type == XML_PI_NODE) ||
8544 (cur->type == XML_COMMENT_NODE) ||
8545 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00008546 (cur->type == XML_TEXT_NODE))) ||
8547 ((type == NODE_TYPE_TEXT) &&
8548 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008549#ifdef DEBUG_STEP
8550 n++;
8551#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008552 addNode(list, cur);
8553 }
8554 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008555 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008556 if (cur->type == XML_PI_NODE) {
8557 if ((name != NULL) &&
8558 (!xmlStrEqual(name, cur->name)))
8559 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008560#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008561 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008562#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_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008567 if (axis == AXIS_ATTRIBUTE) {
8568 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008569#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008570 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008571#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008572 addNode(list, cur);
8573 }
8574 } else if (axis == AXIS_NAMESPACE) {
8575 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008576#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008577 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008578#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008579 xmlXPathNodeSetAddNs(list, ctxt->context->node,
8580 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008581 }
8582 } else {
8583 if (cur->type == XML_ELEMENT_NODE) {
8584 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008585#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008586 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008587#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008588 addNode(list, cur);
8589 } else if ((cur->ns != NULL) &&
8590 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008591#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008592 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008593#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008594 addNode(list, cur);
8595 }
8596 }
8597 }
8598 break;
8599 case NODE_TEST_NS:{
8600 TODO;
8601 break;
8602 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008603 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008604 switch (cur->type) {
8605 case XML_ELEMENT_NODE:
8606 if (xmlStrEqual(name, cur->name)) {
8607 if (prefix == NULL) {
8608 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008609#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008610 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008611#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008612 addNode(list, cur);
8613 }
8614 } else {
8615 if ((cur->ns != NULL) &&
8616 (xmlStrEqual(URI,
8617 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008618#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008619 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008620#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008621 addNode(list, cur);
8622 }
8623 }
8624 }
8625 break;
8626 case XML_ATTRIBUTE_NODE:{
8627 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008628
Daniel Veillardf06307e2001-07-03 10:35:50 +00008629 if (xmlStrEqual(name, attr->name)) {
8630 if (prefix == NULL) {
8631 if ((attr->ns == NULL) ||
8632 (attr->ns->prefix == NULL)) {
8633#ifdef DEBUG_STEP
8634 n++;
8635#endif
8636 addNode(list,
8637 (xmlNodePtr) attr);
8638 }
8639 } else {
8640 if ((attr->ns != NULL) &&
8641 (xmlStrEqual(URI,
8642 attr->ns->
8643 href))) {
8644#ifdef DEBUG_STEP
8645 n++;
8646#endif
8647 addNode(list,
8648 (xmlNodePtr) attr);
8649 }
8650 }
8651 }
8652 break;
8653 }
8654 case XML_NAMESPACE_DECL:
8655 if (cur->type == XML_NAMESPACE_DECL) {
8656 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008657
Daniel Veillardf06307e2001-07-03 10:35:50 +00008658 if ((ns->prefix != NULL) && (name != NULL)
8659 && (xmlStrEqual(ns->prefix, name))) {
8660#ifdef DEBUG_STEP
8661 n++;
8662#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008663 xmlXPathNodeSetAddNs(list,
8664 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008665 }
8666 }
8667 break;
8668 default:
8669 break;
8670 }
8671 break;
8672 break;
8673 }
8674 } while (cur != NULL);
8675
8676 /*
8677 * If there is some predicate filtering do it now
8678 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00008679 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008680 xmlXPathObjectPtr obj2;
8681
8682 valuePush(ctxt, xmlXPathWrapNodeSet(list));
8683 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
8684 CHECK_TYPE0(XPATH_NODESET);
8685 obj2 = valuePop(ctxt);
8686 list = obj2->nodesetval;
8687 obj2->nodesetval = NULL;
8688 xmlXPathFreeObject(obj2);
8689 }
8690 if (ret == NULL) {
8691 ret = list;
8692 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00008693 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008694 xmlXPathFreeNodeSet(list);
8695 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008696 }
8697 ctxt->context->node = tmp;
8698#ifdef DEBUG_STEP
8699 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008700 "\nExamined %d nodes, found %d nodes at that step\n",
8701 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008702#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008703 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00008704 if ((obj->boolval) && (obj->user != NULL)) {
8705 ctxt->value->boolval = 1;
8706 ctxt->value->user = obj->user;
8707 obj->user = NULL;
8708 obj->boolval = 0;
8709 }
8710 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008711 return(t);
8712}
8713
8714/**
8715 * xmlXPathNodeCollectAndTestNth:
8716 * @ctxt: the XPath Parser context
8717 * @op: the XPath precompiled step operation
8718 * @indx: the index to collect
8719 * @first: pointer to the first element in document order
8720 * @last: pointer to the last element in document order
8721 *
8722 * This is the function implementing a step: based on the current list
8723 * of nodes, it builds up a new list, looking at all nodes under that
8724 * axis and selecting them it also do the predicate filtering
8725 *
8726 * Pushes the new NodeSet resulting from the search.
8727 * Returns the number of node traversed
8728 */
8729static int
8730xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
8731 xmlXPathStepOpPtr op, int indx,
8732 xmlNodePtr * first, xmlNodePtr * last)
8733{
8734 xmlXPathAxisVal axis = op->value;
8735 xmlXPathTestVal test = op->value2;
8736 xmlXPathTypeVal type = op->value3;
8737 const xmlChar *prefix = op->value4;
8738 const xmlChar *name = op->value5;
8739 const xmlChar *URI = NULL;
8740 int n = 0, t = 0;
8741
8742 int i;
8743 xmlNodeSetPtr list;
8744 xmlXPathTraversalFunction next = NULL;
8745 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
8746 xmlNodePtr cur = NULL;
8747 xmlXPathObjectPtr obj;
8748 xmlNodeSetPtr nodelist;
8749 xmlNodePtr tmp;
8750
8751 CHECK_TYPE0(XPATH_NODESET);
8752 obj = valuePop(ctxt);
8753 addNode = xmlXPathNodeSetAdd;
8754 if (prefix != NULL) {
8755 URI = xmlXPathNsLookup(ctxt->context, prefix);
8756 if (URI == NULL)
8757 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8758 }
8759#ifdef DEBUG_STEP_NTH
8760 xmlGenericError(xmlGenericErrorContext, "new step : ");
8761 if (first != NULL) {
8762 if (*first != NULL)
8763 xmlGenericError(xmlGenericErrorContext, "first = %s ",
8764 (*first)->name);
8765 else
8766 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
8767 }
8768 if (last != NULL) {
8769 if (*last != NULL)
8770 xmlGenericError(xmlGenericErrorContext, "last = %s ",
8771 (*last)->name);
8772 else
8773 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
8774 }
8775#endif
8776 switch (axis) {
8777 case AXIS_ANCESTOR:
8778#ifdef DEBUG_STEP_NTH
8779 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
8780#endif
8781 first = NULL;
8782 next = xmlXPathNextAncestor;
8783 break;
8784 case AXIS_ANCESTOR_OR_SELF:
8785#ifdef DEBUG_STEP_NTH
8786 xmlGenericError(xmlGenericErrorContext,
8787 "axis 'ancestors-or-self' ");
8788#endif
8789 first = NULL;
8790 next = xmlXPathNextAncestorOrSelf;
8791 break;
8792 case AXIS_ATTRIBUTE:
8793#ifdef DEBUG_STEP_NTH
8794 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
8795#endif
8796 first = NULL;
8797 last = NULL;
8798 next = xmlXPathNextAttribute;
8799 break;
8800 case AXIS_CHILD:
8801#ifdef DEBUG_STEP_NTH
8802 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
8803#endif
8804 last = NULL;
8805 next = xmlXPathNextChild;
8806 break;
8807 case AXIS_DESCENDANT:
8808#ifdef DEBUG_STEP_NTH
8809 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
8810#endif
8811 last = NULL;
8812 next = xmlXPathNextDescendant;
8813 break;
8814 case AXIS_DESCENDANT_OR_SELF:
8815#ifdef DEBUG_STEP_NTH
8816 xmlGenericError(xmlGenericErrorContext,
8817 "axis 'descendant-or-self' ");
8818#endif
8819 last = NULL;
8820 next = xmlXPathNextDescendantOrSelf;
8821 break;
8822 case AXIS_FOLLOWING:
8823#ifdef DEBUG_STEP_NTH
8824 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
8825#endif
8826 last = NULL;
8827 next = xmlXPathNextFollowing;
8828 break;
8829 case AXIS_FOLLOWING_SIBLING:
8830#ifdef DEBUG_STEP_NTH
8831 xmlGenericError(xmlGenericErrorContext,
8832 "axis 'following-siblings' ");
8833#endif
8834 last = NULL;
8835 next = xmlXPathNextFollowingSibling;
8836 break;
8837 case AXIS_NAMESPACE:
8838#ifdef DEBUG_STEP_NTH
8839 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
8840#endif
8841 last = NULL;
8842 first = NULL;
8843 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8844 break;
8845 case AXIS_PARENT:
8846#ifdef DEBUG_STEP_NTH
8847 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
8848#endif
8849 first = NULL;
8850 next = xmlXPathNextParent;
8851 break;
8852 case AXIS_PRECEDING:
8853#ifdef DEBUG_STEP_NTH
8854 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
8855#endif
8856 first = NULL;
8857 next = xmlXPathNextPrecedingInternal;
8858 break;
8859 case AXIS_PRECEDING_SIBLING:
8860#ifdef DEBUG_STEP_NTH
8861 xmlGenericError(xmlGenericErrorContext,
8862 "axis 'preceding-sibling' ");
8863#endif
8864 first = NULL;
8865 next = xmlXPathNextPrecedingSibling;
8866 break;
8867 case AXIS_SELF:
8868#ifdef DEBUG_STEP_NTH
8869 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
8870#endif
8871 first = NULL;
8872 last = NULL;
8873 next = xmlXPathNextSelf;
8874 break;
8875 }
8876 if (next == NULL)
8877 return(0);
8878
8879 nodelist = obj->nodesetval;
8880 if (nodelist == NULL) {
8881 xmlXPathFreeObject(obj);
8882 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8883 return(0);
8884 }
8885 addNode = xmlXPathNodeSetAddUnique;
8886#ifdef DEBUG_STEP_NTH
8887 xmlGenericError(xmlGenericErrorContext,
8888 " context contains %d nodes\n", nodelist->nodeNr);
8889 switch (test) {
8890 case NODE_TEST_NONE:
8891 xmlGenericError(xmlGenericErrorContext,
8892 " searching for none !!!\n");
8893 break;
8894 case NODE_TEST_TYPE:
8895 xmlGenericError(xmlGenericErrorContext,
8896 " searching for type %d\n", type);
8897 break;
8898 case NODE_TEST_PI:
8899 xmlGenericError(xmlGenericErrorContext,
8900 " searching for PI !!!\n");
8901 break;
8902 case NODE_TEST_ALL:
8903 xmlGenericError(xmlGenericErrorContext,
8904 " searching for *\n");
8905 break;
8906 case NODE_TEST_NS:
8907 xmlGenericError(xmlGenericErrorContext,
8908 " searching for namespace %s\n",
8909 prefix);
8910 break;
8911 case NODE_TEST_NAME:
8912 xmlGenericError(xmlGenericErrorContext,
8913 " searching for name %s\n", name);
8914 if (prefix != NULL)
8915 xmlGenericError(xmlGenericErrorContext,
8916 " with namespace %s\n", prefix);
8917 break;
8918 }
8919 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8920#endif
8921 /*
8922 * 2.3 Node Tests
8923 * - For the attribute axis, the principal node type is attribute.
8924 * - For the namespace axis, the principal node type is namespace.
8925 * - For other axes, the principal node type is element.
8926 *
8927 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008928 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00008929 * select all element children of the context node
8930 */
8931 tmp = ctxt->context->node;
8932 list = xmlXPathNodeSetCreate(NULL);
8933 for (i = 0; i < nodelist->nodeNr; i++) {
8934 ctxt->context->node = nodelist->nodeTab[i];
8935
8936 cur = NULL;
8937 n = 0;
8938 do {
8939 cur = next(ctxt, cur);
8940 if (cur == NULL)
8941 break;
8942 if ((first != NULL) && (*first == cur))
8943 break;
8944 if (((t % 256) == 0) &&
8945 (first != NULL) && (*first != NULL) &&
8946 (xmlXPathCmpNodes(*first, cur) >= 0))
8947 break;
8948 if ((last != NULL) && (*last == cur))
8949 break;
8950 if (((t % 256) == 0) &&
8951 (last != NULL) && (*last != NULL) &&
8952 (xmlXPathCmpNodes(cur, *last) >= 0))
8953 break;
8954 t++;
8955 switch (test) {
8956 case NODE_TEST_NONE:
8957 ctxt->context->node = tmp;
8958 STRANGE return(0);
8959 case NODE_TEST_TYPE:
8960 if ((cur->type == type) ||
8961 ((type == NODE_TYPE_NODE) &&
8962 ((cur->type == XML_DOCUMENT_NODE) ||
8963 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8964 (cur->type == XML_ELEMENT_NODE) ||
8965 (cur->type == XML_PI_NODE) ||
8966 (cur->type == XML_COMMENT_NODE) ||
8967 (cur->type == XML_CDATA_SECTION_NODE) ||
8968 (cur->type == XML_TEXT_NODE)))) {
8969 n++;
8970 if (n == indx)
8971 addNode(list, cur);
8972 }
8973 break;
8974 case NODE_TEST_PI:
8975 if (cur->type == XML_PI_NODE) {
8976 if ((name != NULL) &&
8977 (!xmlStrEqual(name, cur->name)))
8978 break;
8979 n++;
8980 if (n == indx)
8981 addNode(list, cur);
8982 }
8983 break;
8984 case NODE_TEST_ALL:
8985 if (axis == AXIS_ATTRIBUTE) {
8986 if (cur->type == XML_ATTRIBUTE_NODE) {
8987 n++;
8988 if (n == indx)
8989 addNode(list, cur);
8990 }
8991 } else if (axis == AXIS_NAMESPACE) {
8992 if (cur->type == XML_NAMESPACE_DECL) {
8993 n++;
8994 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008995 xmlXPathNodeSetAddNs(list, ctxt->context->node,
8996 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008997 }
8998 } else {
8999 if (cur->type == XML_ELEMENT_NODE) {
9000 if (prefix == NULL) {
9001 n++;
9002 if (n == indx)
9003 addNode(list, cur);
9004 } else if ((cur->ns != NULL) &&
9005 (xmlStrEqual(URI, cur->ns->href))) {
9006 n++;
9007 if (n == indx)
9008 addNode(list, cur);
9009 }
9010 }
9011 }
9012 break;
9013 case NODE_TEST_NS:{
9014 TODO;
9015 break;
9016 }
9017 case NODE_TEST_NAME:
9018 switch (cur->type) {
9019 case XML_ELEMENT_NODE:
9020 if (xmlStrEqual(name, cur->name)) {
9021 if (prefix == NULL) {
9022 if (cur->ns == NULL) {
9023 n++;
9024 if (n == indx)
9025 addNode(list, cur);
9026 }
9027 } else {
9028 if ((cur->ns != NULL) &&
9029 (xmlStrEqual(URI,
9030 cur->ns->href))) {
9031 n++;
9032 if (n == indx)
9033 addNode(list, cur);
9034 }
9035 }
9036 }
9037 break;
9038 case XML_ATTRIBUTE_NODE:{
9039 xmlAttrPtr attr = (xmlAttrPtr) cur;
9040
9041 if (xmlStrEqual(name, attr->name)) {
9042 if (prefix == NULL) {
9043 if ((attr->ns == NULL) ||
9044 (attr->ns->prefix == NULL)) {
9045 n++;
9046 if (n == indx)
9047 addNode(list, cur);
9048 }
9049 } else {
9050 if ((attr->ns != NULL) &&
9051 (xmlStrEqual(URI,
9052 attr->ns->
9053 href))) {
9054 n++;
9055 if (n == indx)
9056 addNode(list, cur);
9057 }
9058 }
9059 }
9060 break;
9061 }
9062 case XML_NAMESPACE_DECL:
9063 if (cur->type == XML_NAMESPACE_DECL) {
9064 xmlNsPtr ns = (xmlNsPtr) cur;
9065
9066 if ((ns->prefix != NULL) && (name != NULL)
9067 && (xmlStrEqual(ns->prefix, name))) {
9068 n++;
9069 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009070 xmlXPathNodeSetAddNs(list,
9071 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009072 }
9073 }
9074 break;
9075 default:
9076 break;
9077 }
9078 break;
9079 break;
9080 }
9081 } while (n < indx);
9082 }
9083 ctxt->context->node = tmp;
9084#ifdef DEBUG_STEP_NTH
9085 xmlGenericError(xmlGenericErrorContext,
9086 "\nExamined %d nodes, found %d nodes at that step\n",
9087 t, list->nodeNr);
9088#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009089 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009090 if ((obj->boolval) && (obj->user != NULL)) {
9091 ctxt->value->boolval = 1;
9092 ctxt->value->user = obj->user;
9093 obj->user = NULL;
9094 obj->boolval = 0;
9095 }
9096 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009097 return(t);
9098}
9099
9100/**
9101 * xmlXPathCompOpEvalFirst:
9102 * @ctxt: the XPath parser context with the compiled expression
9103 * @op: an XPath compiled operation
9104 * @first: the first elem found so far
9105 *
9106 * Evaluate the Precompiled XPath operation searching only the first
9107 * element in document order
9108 *
9109 * Returns the number of examined objects.
9110 */
9111static int
9112xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9113 xmlXPathStepOpPtr op, xmlNodePtr * first)
9114{
9115 int total = 0, cur;
9116 xmlXPathCompExprPtr comp;
9117 xmlXPathObjectPtr arg1, arg2;
9118
Daniel Veillard556c6682001-10-06 09:59:51 +00009119 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009120 comp = ctxt->comp;
9121 switch (op->op) {
9122 case XPATH_OP_END:
9123 return (0);
9124 case XPATH_OP_UNION:
9125 total =
9126 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9127 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009128 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009129 if ((ctxt->value != NULL)
9130 && (ctxt->value->type == XPATH_NODESET)
9131 && (ctxt->value->nodesetval != NULL)
9132 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9133 /*
9134 * limit tree traversing to first node in the result
9135 */
9136 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9137 *first = ctxt->value->nodesetval->nodeTab[0];
9138 }
9139 cur =
9140 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9141 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009142 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009143 CHECK_TYPE0(XPATH_NODESET);
9144 arg2 = valuePop(ctxt);
9145
9146 CHECK_TYPE0(XPATH_NODESET);
9147 arg1 = valuePop(ctxt);
9148
9149 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9150 arg2->nodesetval);
9151 valuePush(ctxt, arg1);
9152 xmlXPathFreeObject(arg2);
9153 /* optimizer */
9154 if (total > cur)
9155 xmlXPathCompSwap(op);
9156 return (total + cur);
9157 case XPATH_OP_ROOT:
9158 xmlXPathRoot(ctxt);
9159 return (0);
9160 case XPATH_OP_NODE:
9161 if (op->ch1 != -1)
9162 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009163 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009164 if (op->ch2 != -1)
9165 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009166 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009167 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9168 return (total);
9169 case XPATH_OP_RESET:
9170 if (op->ch1 != -1)
9171 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009172 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009173 if (op->ch2 != -1)
9174 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009175 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009176 ctxt->context->node = NULL;
9177 return (total);
9178 case XPATH_OP_COLLECT:{
9179 if (op->ch1 == -1)
9180 return (total);
9181
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
9185 /*
9186 * Optimization for [n] selection where n is a number
9187 */
9188 if ((op->ch2 != -1) &&
9189 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9190 (comp->steps[op->ch2].ch1 == -1) &&
9191 (comp->steps[op->ch2].ch2 != -1) &&
9192 (comp->steps[comp->steps[op->ch2].ch2].op ==
9193 XPATH_OP_VALUE)) {
9194 xmlXPathObjectPtr val;
9195
9196 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9197 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9198 int indx = (int) val->floatval;
9199
9200 if (val->floatval == (float) indx) {
9201 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9202 first, NULL);
9203 return (total);
9204 }
9205 }
9206 }
9207 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9208 return (total);
9209 }
9210 case XPATH_OP_VALUE:
9211 valuePush(ctxt,
9212 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9213 return (0);
9214 case XPATH_OP_SORT:
9215 if (op->ch1 != -1)
9216 total +=
9217 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9218 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009219 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009220 if ((ctxt->value != NULL)
9221 && (ctxt->value->type == XPATH_NODESET)
9222 && (ctxt->value->nodesetval != NULL))
9223 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9224 return (total);
9225 default:
9226 return (xmlXPathCompOpEval(ctxt, op));
9227 }
9228}
9229
9230/**
9231 * xmlXPathCompOpEvalLast:
9232 * @ctxt: the XPath parser context with the compiled expression
9233 * @op: an XPath compiled operation
9234 * @last: the last elem found so far
9235 *
9236 * Evaluate the Precompiled XPath operation searching only the last
9237 * element in document order
9238 *
9239 * Returns the number of node traversed
9240 */
9241static int
9242xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9243 xmlNodePtr * last)
9244{
9245 int total = 0, cur;
9246 xmlXPathCompExprPtr comp;
9247 xmlXPathObjectPtr arg1, arg2;
9248
Daniel Veillard556c6682001-10-06 09:59:51 +00009249 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009250 comp = ctxt->comp;
9251 switch (op->op) {
9252 case XPATH_OP_END:
9253 return (0);
9254 case XPATH_OP_UNION:
9255 total =
9256 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009257 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009258 if ((ctxt->value != NULL)
9259 && (ctxt->value->type == XPATH_NODESET)
9260 && (ctxt->value->nodesetval != NULL)
9261 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9262 /*
9263 * limit tree traversing to first node in the result
9264 */
9265 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9266 *last =
9267 ctxt->value->nodesetval->nodeTab[ctxt->value->
9268 nodesetval->nodeNr -
9269 1];
9270 }
9271 cur =
9272 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009273 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009274 if ((ctxt->value != NULL)
9275 && (ctxt->value->type == XPATH_NODESET)
9276 && (ctxt->value->nodesetval != NULL)
9277 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9278 }
9279 CHECK_TYPE0(XPATH_NODESET);
9280 arg2 = valuePop(ctxt);
9281
9282 CHECK_TYPE0(XPATH_NODESET);
9283 arg1 = valuePop(ctxt);
9284
9285 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9286 arg2->nodesetval);
9287 valuePush(ctxt, arg1);
9288 xmlXPathFreeObject(arg2);
9289 /* optimizer */
9290 if (total > cur)
9291 xmlXPathCompSwap(op);
9292 return (total + cur);
9293 case XPATH_OP_ROOT:
9294 xmlXPathRoot(ctxt);
9295 return (0);
9296 case XPATH_OP_NODE:
9297 if (op->ch1 != -1)
9298 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009299 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009300 if (op->ch2 != -1)
9301 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009302 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009303 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9304 return (total);
9305 case XPATH_OP_RESET:
9306 if (op->ch1 != -1)
9307 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009308 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009309 if (op->ch2 != -1)
9310 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009311 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009312 ctxt->context->node = NULL;
9313 return (total);
9314 case XPATH_OP_COLLECT:{
9315 if (op->ch1 == -1)
9316 return (0);
9317
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
9321 /*
9322 * Optimization for [n] selection where n is a number
9323 */
9324 if ((op->ch2 != -1) &&
9325 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9326 (comp->steps[op->ch2].ch1 == -1) &&
9327 (comp->steps[op->ch2].ch2 != -1) &&
9328 (comp->steps[comp->steps[op->ch2].ch2].op ==
9329 XPATH_OP_VALUE)) {
9330 xmlXPathObjectPtr val;
9331
9332 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9333 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9334 int indx = (int) val->floatval;
9335
9336 if (val->floatval == (float) indx) {
9337 total +=
9338 xmlXPathNodeCollectAndTestNth(ctxt, op,
9339 indx, NULL,
9340 last);
9341 return (total);
9342 }
9343 }
9344 }
9345 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9346 return (total);
9347 }
9348 case XPATH_OP_VALUE:
9349 valuePush(ctxt,
9350 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9351 return (0);
9352 case XPATH_OP_SORT:
9353 if (op->ch1 != -1)
9354 total +=
9355 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9356 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009357 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009358 if ((ctxt->value != NULL)
9359 && (ctxt->value->type == XPATH_NODESET)
9360 && (ctxt->value->nodesetval != NULL))
9361 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9362 return (total);
9363 default:
9364 return (xmlXPathCompOpEval(ctxt, op));
9365 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009366}
9367
Owen Taylor3473f882001-02-23 17:55:21 +00009368/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009369 * xmlXPathCompOpEval:
9370 * @ctxt: the XPath parser context with the compiled expression
9371 * @op: an XPath compiled operation
9372 *
9373 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009374 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009375 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009376static int
9377xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9378{
9379 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009380 int equal, ret;
9381 xmlXPathCompExprPtr comp;
9382 xmlXPathObjectPtr arg1, arg2;
9383
Daniel Veillard556c6682001-10-06 09:59:51 +00009384 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009385 comp = ctxt->comp;
9386 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009387 case XPATH_OP_END:
9388 return (0);
9389 case XPATH_OP_AND:
9390 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009391 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009392 xmlXPathBooleanFunction(ctxt, 1);
9393 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9394 return (total);
9395 arg2 = valuePop(ctxt);
9396 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009397 if (ctxt->error) {
9398 xmlXPathFreeObject(arg2);
9399 return(0);
9400 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009401 xmlXPathBooleanFunction(ctxt, 1);
9402 arg1 = valuePop(ctxt);
9403 arg1->boolval &= arg2->boolval;
9404 valuePush(ctxt, arg1);
9405 xmlXPathFreeObject(arg2);
9406 return (total);
9407 case XPATH_OP_OR:
9408 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009409 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009410 xmlXPathBooleanFunction(ctxt, 1);
9411 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9412 return (total);
9413 arg2 = valuePop(ctxt);
9414 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009415 if (ctxt->error) {
9416 xmlXPathFreeObject(arg2);
9417 return(0);
9418 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009419 xmlXPathBooleanFunction(ctxt, 1);
9420 arg1 = valuePop(ctxt);
9421 arg1->boolval |= arg2->boolval;
9422 valuePush(ctxt, arg1);
9423 xmlXPathFreeObject(arg2);
9424 return (total);
9425 case XPATH_OP_EQUAL:
9426 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009427 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009428 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009429 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009430 equal = xmlXPathEqualValues(ctxt);
9431 if (op->value)
9432 valuePush(ctxt, xmlXPathNewBoolean(equal));
9433 else
9434 valuePush(ctxt, xmlXPathNewBoolean(!equal));
9435 return (total);
9436 case XPATH_OP_CMP:
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 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9442 valuePush(ctxt, xmlXPathNewBoolean(ret));
9443 return (total);
9444 case XPATH_OP_PLUS:
9445 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009446 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009447 if (op->ch2 != -1)
9448 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009449 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009450 if (op->value == 0)
9451 xmlXPathSubValues(ctxt);
9452 else if (op->value == 1)
9453 xmlXPathAddValues(ctxt);
9454 else if (op->value == 2)
9455 xmlXPathValueFlipSign(ctxt);
9456 else if (op->value == 3) {
9457 CAST_TO_NUMBER;
9458 CHECK_TYPE0(XPATH_NUMBER);
9459 }
9460 return (total);
9461 case XPATH_OP_MULT:
9462 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009463 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009464 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009465 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009466 if (op->value == 0)
9467 xmlXPathMultValues(ctxt);
9468 else if (op->value == 1)
9469 xmlXPathDivValues(ctxt);
9470 else if (op->value == 2)
9471 xmlXPathModValues(ctxt);
9472 return (total);
9473 case XPATH_OP_UNION:
9474 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009475 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009476 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009477 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009478 CHECK_TYPE0(XPATH_NODESET);
9479 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009480
Daniel Veillardf06307e2001-07-03 10:35:50 +00009481 CHECK_TYPE0(XPATH_NODESET);
9482 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009483
Daniel Veillardf06307e2001-07-03 10:35:50 +00009484 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9485 arg2->nodesetval);
9486 valuePush(ctxt, arg1);
9487 xmlXPathFreeObject(arg2);
9488 return (total);
9489 case XPATH_OP_ROOT:
9490 xmlXPathRoot(ctxt);
9491 return (total);
9492 case XPATH_OP_NODE:
9493 if (op->ch1 != -1)
9494 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009495 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009496 if (op->ch2 != -1)
9497 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009498 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009499 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9500 return (total);
9501 case XPATH_OP_RESET:
9502 if (op->ch1 != -1)
9503 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009504 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009505 if (op->ch2 != -1)
9506 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009507 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009508 ctxt->context->node = NULL;
9509 return (total);
9510 case XPATH_OP_COLLECT:{
9511 if (op->ch1 == -1)
9512 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009513
Daniel Veillardf06307e2001-07-03 10:35:50 +00009514 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009515 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009516
Daniel Veillardf06307e2001-07-03 10:35:50 +00009517 /*
9518 * Optimization for [n] selection where n is a number
9519 */
9520 if ((op->ch2 != -1) &&
9521 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9522 (comp->steps[op->ch2].ch1 == -1) &&
9523 (comp->steps[op->ch2].ch2 != -1) &&
9524 (comp->steps[comp->steps[op->ch2].ch2].op ==
9525 XPATH_OP_VALUE)) {
9526 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00009527
Daniel Veillardf06307e2001-07-03 10:35:50 +00009528 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9529 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9530 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009531
Daniel Veillardf06307e2001-07-03 10:35:50 +00009532 if (val->floatval == (float) indx) {
9533 total +=
9534 xmlXPathNodeCollectAndTestNth(ctxt, op,
9535 indx, NULL,
9536 NULL);
9537 return (total);
9538 }
9539 }
9540 }
9541 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
9542 return (total);
9543 }
9544 case XPATH_OP_VALUE:
9545 valuePush(ctxt,
9546 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9547 return (total);
9548 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +00009549 xmlXPathObjectPtr val;
9550
Daniel Veillardf06307e2001-07-03 10:35:50 +00009551 if (op->ch1 != -1)
9552 total +=
9553 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009554 if (op->value5 == NULL) {
9555 val = xmlXPathVariableLookup(ctxt->context, op->value4);
9556 if (val == NULL) {
9557 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9558 return(0);
9559 }
9560 valuePush(ctxt, val);
9561 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009562 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009563
Daniel Veillardf06307e2001-07-03 10:35:50 +00009564 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9565 if (URI == NULL) {
9566 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009567 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009568 op->value4, op->value5);
9569 return (total);
9570 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009571 val = xmlXPathVariableLookupNS(ctxt->context,
9572 op->value4, URI);
9573 if (val == NULL) {
9574 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9575 return(0);
9576 }
9577 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009578 }
9579 return (total);
9580 }
9581 case XPATH_OP_FUNCTION:{
9582 xmlXPathFunction func;
9583 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +00009584 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009585
9586 if (op->ch1 != -1)
9587 total +=
9588 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009589 if (ctxt->valueNr < op->value) {
9590 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009591 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +00009592 ctxt->error = XPATH_INVALID_OPERAND;
9593 return (total);
9594 }
9595 for (i = 0; i < op->value; i++)
9596 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
9597 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009598 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +00009599 ctxt->error = XPATH_INVALID_OPERAND;
9600 return (total);
9601 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009602 if (op->cache != NULL)
9603 func = (xmlXPathFunction) op->cache;
9604 else {
9605 const xmlChar *URI = NULL;
9606
9607 if (op->value5 == NULL)
9608 func =
9609 xmlXPathFunctionLookup(ctxt->context,
9610 op->value4);
9611 else {
9612 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9613 if (URI == NULL) {
9614 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009615 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009616 op->value4, op->value5);
9617 return (total);
9618 }
9619 func = xmlXPathFunctionLookupNS(ctxt->context,
9620 op->value4, URI);
9621 }
9622 if (func == NULL) {
9623 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009624 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009625 op->value4);
9626 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009627 }
9628 op->cache = (void *) func;
9629 op->cacheURI = (void *) URI;
9630 }
9631 oldFunc = ctxt->context->function;
9632 oldFuncURI = ctxt->context->functionURI;
9633 ctxt->context->function = op->value4;
9634 ctxt->context->functionURI = op->cacheURI;
9635 func(ctxt, op->value);
9636 ctxt->context->function = oldFunc;
9637 ctxt->context->functionURI = oldFuncURI;
9638 return (total);
9639 }
9640 case XPATH_OP_ARG:
9641 if (op->ch1 != -1)
9642 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009643 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009644 if (op->ch2 != -1)
9645 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009646 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009647 return (total);
9648 case XPATH_OP_PREDICATE:
9649 case XPATH_OP_FILTER:{
9650 xmlXPathObjectPtr res;
9651 xmlXPathObjectPtr obj, tmp;
9652 xmlNodeSetPtr newset = NULL;
9653 xmlNodeSetPtr oldset;
9654 xmlNodePtr oldnode;
9655 int i;
9656
9657 /*
9658 * Optimization for ()[1] selection i.e. the first elem
9659 */
9660 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9661 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9662 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
9663 xmlXPathObjectPtr val;
9664
9665 val = comp->steps[op->ch2].value4;
9666 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
9667 (val->floatval == 1.0)) {
9668 xmlNodePtr first = NULL;
9669
9670 total +=
9671 xmlXPathCompOpEvalFirst(ctxt,
9672 &comp->steps[op->ch1],
9673 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009674 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009675 /*
9676 * The nodeset should be in document order,
9677 * Keep only the first value
9678 */
9679 if ((ctxt->value != NULL) &&
9680 (ctxt->value->type == XPATH_NODESET) &&
9681 (ctxt->value->nodesetval != NULL) &&
9682 (ctxt->value->nodesetval->nodeNr > 1))
9683 ctxt->value->nodesetval->nodeNr = 1;
9684 return (total);
9685 }
9686 }
9687 /*
9688 * Optimization for ()[last()] selection i.e. the last elem
9689 */
9690 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9691 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9692 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
9693 int f = comp->steps[op->ch2].ch1;
9694
9695 if ((f != -1) &&
9696 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
9697 (comp->steps[f].value5 == NULL) &&
9698 (comp->steps[f].value == 0) &&
9699 (comp->steps[f].value4 != NULL) &&
9700 (xmlStrEqual
9701 (comp->steps[f].value4, BAD_CAST "last"))) {
9702 xmlNodePtr last = NULL;
9703
9704 total +=
9705 xmlXPathCompOpEvalLast(ctxt,
9706 &comp->steps[op->ch1],
9707 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009708 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009709 /*
9710 * The nodeset should be in document order,
9711 * Keep only the last value
9712 */
9713 if ((ctxt->value != NULL) &&
9714 (ctxt->value->type == XPATH_NODESET) &&
9715 (ctxt->value->nodesetval != NULL) &&
9716 (ctxt->value->nodesetval->nodeTab != NULL) &&
9717 (ctxt->value->nodesetval->nodeNr > 1)) {
9718 ctxt->value->nodesetval->nodeTab[0] =
9719 ctxt->value->nodesetval->nodeTab[ctxt->
9720 value->
9721 nodesetval->
9722 nodeNr -
9723 1];
9724 ctxt->value->nodesetval->nodeNr = 1;
9725 }
9726 return (total);
9727 }
9728 }
9729
9730 if (op->ch1 != -1)
9731 total +=
9732 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009733 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009734 if (op->ch2 == -1)
9735 return (total);
9736 if (ctxt->value == NULL)
9737 return (total);
9738
9739 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009740
9741#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009742 /*
9743 * Hum are we filtering the result of an XPointer expression
9744 */
9745 if (ctxt->value->type == XPATH_LOCATIONSET) {
9746 xmlLocationSetPtr newlocset = NULL;
9747 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009748
Daniel Veillardf06307e2001-07-03 10:35:50 +00009749 /*
9750 * Extract the old locset, and then evaluate the result of the
9751 * expression for all the element in the locset. use it to grow
9752 * up a new locset.
9753 */
9754 CHECK_TYPE0(XPATH_LOCATIONSET);
9755 obj = valuePop(ctxt);
9756 oldlocset = obj->user;
9757 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009758
Daniel Veillardf06307e2001-07-03 10:35:50 +00009759 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
9760 ctxt->context->contextSize = 0;
9761 ctxt->context->proximityPosition = 0;
9762 if (op->ch2 != -1)
9763 total +=
9764 xmlXPathCompOpEval(ctxt,
9765 &comp->steps[op->ch2]);
9766 res = valuePop(ctxt);
9767 if (res != NULL)
9768 xmlXPathFreeObject(res);
9769 valuePush(ctxt, obj);
9770 CHECK_ERROR0;
9771 return (total);
9772 }
9773 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009774
Daniel Veillardf06307e2001-07-03 10:35:50 +00009775 for (i = 0; i < oldlocset->locNr; i++) {
9776 /*
9777 * Run the evaluation with a node list made of a
9778 * single item in the nodelocset.
9779 */
9780 ctxt->context->node = oldlocset->locTab[i]->user;
9781 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9782 valuePush(ctxt, tmp);
9783 ctxt->context->contextSize = oldlocset->locNr;
9784 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009785
Daniel Veillardf06307e2001-07-03 10:35:50 +00009786 if (op->ch2 != -1)
9787 total +=
9788 xmlXPathCompOpEval(ctxt,
9789 &comp->steps[op->ch2]);
9790 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009791
Daniel Veillardf06307e2001-07-03 10:35:50 +00009792 /*
9793 * The result of the evaluation need to be tested to
9794 * decided whether the filter succeeded or not
9795 */
9796 res = valuePop(ctxt);
9797 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9798 xmlXPtrLocationSetAdd(newlocset,
9799 xmlXPathObjectCopy
9800 (oldlocset->locTab[i]));
9801 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009802
Daniel Veillardf06307e2001-07-03 10:35:50 +00009803 /*
9804 * Cleanup
9805 */
9806 if (res != NULL)
9807 xmlXPathFreeObject(res);
9808 if (ctxt->value == tmp) {
9809 res = valuePop(ctxt);
9810 xmlXPathFreeObject(res);
9811 }
9812
9813 ctxt->context->node = NULL;
9814 }
9815
9816 /*
9817 * The result is used as the new evaluation locset.
9818 */
9819 xmlXPathFreeObject(obj);
9820 ctxt->context->node = NULL;
9821 ctxt->context->contextSize = -1;
9822 ctxt->context->proximityPosition = -1;
9823 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
9824 ctxt->context->node = oldnode;
9825 return (total);
9826 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009827#endif /* LIBXML_XPTR_ENABLED */
9828
Daniel Veillardf06307e2001-07-03 10:35:50 +00009829 /*
9830 * Extract the old set, and then evaluate the result of the
9831 * expression for all the element in the set. use it to grow
9832 * up a new set.
9833 */
9834 CHECK_TYPE0(XPATH_NODESET);
9835 obj = valuePop(ctxt);
9836 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00009837
Daniel Veillardf06307e2001-07-03 10:35:50 +00009838 oldnode = ctxt->context->node;
9839 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009840
Daniel Veillardf06307e2001-07-03 10:35:50 +00009841 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
9842 ctxt->context->contextSize = 0;
9843 ctxt->context->proximityPosition = 0;
9844 if (op->ch2 != -1)
9845 total +=
9846 xmlXPathCompOpEval(ctxt,
9847 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009848 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009849 res = valuePop(ctxt);
9850 if (res != NULL)
9851 xmlXPathFreeObject(res);
9852 valuePush(ctxt, obj);
9853 ctxt->context->node = oldnode;
9854 CHECK_ERROR0;
9855 } else {
9856 /*
9857 * Initialize the new set.
9858 */
9859 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009860
Daniel Veillardf06307e2001-07-03 10:35:50 +00009861 for (i = 0; i < oldset->nodeNr; i++) {
9862 /*
9863 * Run the evaluation with a node list made of
9864 * a single item in the nodeset.
9865 */
9866 ctxt->context->node = oldset->nodeTab[i];
9867 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9868 valuePush(ctxt, tmp);
9869 ctxt->context->contextSize = oldset->nodeNr;
9870 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009871
Daniel Veillardf06307e2001-07-03 10:35:50 +00009872 if (op->ch2 != -1)
9873 total +=
9874 xmlXPathCompOpEval(ctxt,
9875 &comp->steps[op->ch2]);
9876 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009877
Daniel Veillardf06307e2001-07-03 10:35:50 +00009878 /*
9879 * The result of the evaluation need to be tested to
9880 * decided whether the filter succeeded or not
9881 */
9882 res = valuePop(ctxt);
9883 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9884 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
9885 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009886
Daniel Veillardf06307e2001-07-03 10:35:50 +00009887 /*
9888 * Cleanup
9889 */
9890 if (res != NULL)
9891 xmlXPathFreeObject(res);
9892 if (ctxt->value == tmp) {
9893 res = valuePop(ctxt);
9894 xmlXPathFreeObject(res);
9895 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009896
Daniel Veillardf06307e2001-07-03 10:35:50 +00009897 ctxt->context->node = NULL;
9898 }
9899
9900 /*
9901 * The result is used as the new evaluation set.
9902 */
9903 xmlXPathFreeObject(obj);
9904 ctxt->context->node = NULL;
9905 ctxt->context->contextSize = -1;
9906 ctxt->context->proximityPosition = -1;
9907 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
9908 }
9909 ctxt->context->node = oldnode;
9910 return (total);
9911 }
9912 case XPATH_OP_SORT:
9913 if (op->ch1 != -1)
9914 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009915 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009916 if ((ctxt->value != NULL) &&
9917 (ctxt->value->type == XPATH_NODESET) &&
9918 (ctxt->value->nodesetval != NULL))
9919 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9920 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009921#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009922 case XPATH_OP_RANGETO:{
9923 xmlXPathObjectPtr range;
9924 xmlXPathObjectPtr res, obj;
9925 xmlXPathObjectPtr tmp;
9926 xmlLocationSetPtr newset = NULL;
9927 xmlNodeSetPtr oldset;
9928 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009929
Daniel Veillardf06307e2001-07-03 10:35:50 +00009930 if (op->ch1 != -1)
9931 total +=
9932 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9933 if (op->ch2 == -1)
9934 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009935
Daniel Veillardf06307e2001-07-03 10:35:50 +00009936 CHECK_TYPE0(XPATH_NODESET);
9937 obj = valuePop(ctxt);
9938 oldset = obj->nodesetval;
9939 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009940
Daniel Veillardf06307e2001-07-03 10:35:50 +00009941 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009942
Daniel Veillardf06307e2001-07-03 10:35:50 +00009943 if (oldset != NULL) {
9944 for (i = 0; i < oldset->nodeNr; i++) {
9945 /*
9946 * Run the evaluation with a node list made of a single item
9947 * in the nodeset.
9948 */
9949 ctxt->context->node = oldset->nodeTab[i];
9950 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9951 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009952
Daniel Veillardf06307e2001-07-03 10:35:50 +00009953 if (op->ch2 != -1)
9954 total +=
9955 xmlXPathCompOpEval(ctxt,
9956 &comp->steps[op->ch2]);
9957 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009958
Daniel Veillardf06307e2001-07-03 10:35:50 +00009959 /*
9960 * The result of the evaluation need to be tested to
9961 * decided whether the filter succeeded or not
9962 */
9963 res = valuePop(ctxt);
9964 range =
9965 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
9966 res);
9967 if (range != NULL) {
9968 xmlXPtrLocationSetAdd(newset, range);
9969 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009970
Daniel Veillardf06307e2001-07-03 10:35:50 +00009971 /*
9972 * Cleanup
9973 */
9974 if (res != NULL)
9975 xmlXPathFreeObject(res);
9976 if (ctxt->value == tmp) {
9977 res = valuePop(ctxt);
9978 xmlXPathFreeObject(res);
9979 }
9980
9981 ctxt->context->node = NULL;
9982 }
9983 }
9984
9985 /*
9986 * The result is used as the new evaluation set.
9987 */
9988 xmlXPathFreeObject(obj);
9989 ctxt->context->node = NULL;
9990 ctxt->context->contextSize = -1;
9991 ctxt->context->proximityPosition = -1;
9992 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
9993 return (total);
9994 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009995#endif /* LIBXML_XPTR_ENABLED */
9996 }
9997 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009998 "XPath: unknown precompiled operation %d\n", op->op);
9999 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010000}
10001
10002/**
10003 * xmlXPathRunEval:
10004 * @ctxt: the XPath parser context with the compiled expression
10005 *
10006 * Evaluate the Precompiled XPath expression in the given context.
10007 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010008static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010009xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10010 xmlXPathCompExprPtr comp;
10011
10012 if ((ctxt == NULL) || (ctxt->comp == NULL))
10013 return;
10014
10015 if (ctxt->valueTab == NULL) {
10016 /* Allocate the value stack */
10017 ctxt->valueTab = (xmlXPathObjectPtr *)
10018 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10019 if (ctxt->valueTab == NULL) {
10020 xmlFree(ctxt);
10021 xmlGenericError(xmlGenericErrorContext,
10022 "xmlXPathRunEval: out of memory\n");
10023 return;
10024 }
10025 ctxt->valueNr = 0;
10026 ctxt->valueMax = 10;
10027 ctxt->value = NULL;
10028 }
10029 comp = ctxt->comp;
10030 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10031}
10032
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010033/************************************************************************
10034 * *
10035 * Public interfaces *
10036 * *
10037 ************************************************************************/
10038
10039/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010040 * xmlXPathEvalPredicate:
10041 * @ctxt: the XPath context
10042 * @res: the Predicate Expression evaluation result
10043 *
10044 * Evaluate a predicate result for the current node.
10045 * A PredicateExpr is evaluated by evaluating the Expr and converting
10046 * the result to a boolean. If the result is a number, the result will
10047 * be converted to true if the number is equal to the position of the
10048 * context node in the context node list (as returned by the position
10049 * function) and will be converted to false otherwise; if the result
10050 * is not a number, then the result will be converted as if by a call
10051 * to the boolean function.
10052 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010053 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010054 */
10055int
10056xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10057 if (res == NULL) return(0);
10058 switch (res->type) {
10059 case XPATH_BOOLEAN:
10060 return(res->boolval);
10061 case XPATH_NUMBER:
10062 return(res->floatval == ctxt->proximityPosition);
10063 case XPATH_NODESET:
10064 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010065 if (res->nodesetval == NULL)
10066 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010067 return(res->nodesetval->nodeNr != 0);
10068 case XPATH_STRING:
10069 return((res->stringval != NULL) &&
10070 (xmlStrlen(res->stringval) != 0));
10071 default:
10072 STRANGE
10073 }
10074 return(0);
10075}
10076
10077/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010078 * xmlXPathEvaluatePredicateResult:
10079 * @ctxt: the XPath Parser context
10080 * @res: the Predicate Expression evaluation result
10081 *
10082 * Evaluate a predicate result for the current node.
10083 * A PredicateExpr is evaluated by evaluating the Expr and converting
10084 * the result to a boolean. If the result is a number, the result will
10085 * be converted to true if the number is equal to the position of the
10086 * context node in the context node list (as returned by the position
10087 * function) and will be converted to false otherwise; if the result
10088 * is not a number, then the result will be converted as if by a call
10089 * to the boolean function.
10090 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010091 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010092 */
10093int
10094xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10095 xmlXPathObjectPtr res) {
10096 if (res == NULL) return(0);
10097 switch (res->type) {
10098 case XPATH_BOOLEAN:
10099 return(res->boolval);
10100 case XPATH_NUMBER:
10101 return(res->floatval == ctxt->context->proximityPosition);
10102 case XPATH_NODESET:
10103 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010104 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010105 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010106 return(res->nodesetval->nodeNr != 0);
10107 case XPATH_STRING:
10108 return((res->stringval != NULL) &&
10109 (xmlStrlen(res->stringval) != 0));
10110 default:
10111 STRANGE
10112 }
10113 return(0);
10114}
10115
10116/**
10117 * xmlXPathCompile:
10118 * @str: the XPath expression
10119 *
10120 * Compile an XPath expression
10121 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010122 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010123 * the caller has to free the object.
10124 */
10125xmlXPathCompExprPtr
10126xmlXPathCompile(const xmlChar *str) {
10127 xmlXPathParserContextPtr ctxt;
10128 xmlXPathCompExprPtr comp;
10129
10130 xmlXPathInit();
10131
10132 ctxt = xmlXPathNewParserContext(str, NULL);
10133 xmlXPathCompileExpr(ctxt);
10134
Daniel Veillard40af6492001-04-22 08:50:55 +000010135 if (*ctxt->cur != 0) {
10136 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10137 comp = NULL;
10138 } else {
10139 comp = ctxt->comp;
10140 ctxt->comp = NULL;
10141 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010142 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010143#ifdef DEBUG_EVAL_COUNTS
10144 if (comp != NULL) {
10145 comp->string = xmlStrdup(str);
10146 comp->nb = 0;
10147 }
10148#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010149 return(comp);
10150}
10151
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010152/**
10153 * xmlXPathCompiledEval:
10154 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010155 * @ctx: the XPath context
10156 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010157 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010158 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010159 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010160 * the caller has to free the object.
10161 */
10162xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010163xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010164 xmlXPathParserContextPtr ctxt;
10165 xmlXPathObjectPtr res, tmp, init = NULL;
10166 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010167#ifndef LIBXML_THREAD_ENABLED
10168 static int reentance = 0;
10169#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010170
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010171 if ((comp == NULL) || (ctx == NULL))
10172 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010173 xmlXPathInit();
10174
10175 CHECK_CONTEXT(ctx)
10176
Daniel Veillard81463942001-10-16 12:34:39 +000010177#ifndef LIBXML_THREAD_ENABLED
10178 reentance++;
10179 if (reentance > 1)
10180 xmlXPathDisableOptimizer = 1;
10181#endif
10182
Daniel Veillardf06307e2001-07-03 10:35:50 +000010183#ifdef DEBUG_EVAL_COUNTS
10184 comp->nb++;
10185 if ((comp->string != NULL) && (comp->nb > 100)) {
10186 fprintf(stderr, "100 x %s\n", comp->string);
10187 comp->nb = 0;
10188 }
10189#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010190 ctxt = xmlXPathCompParserContext(comp, ctx);
10191 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010192
10193 if (ctxt->value == NULL) {
10194 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010195 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010196 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010197 } else {
10198 res = valuePop(ctxt);
10199 }
10200
Daniel Veillardf06307e2001-07-03 10:35:50 +000010201
Owen Taylor3473f882001-02-23 17:55:21 +000010202 do {
10203 tmp = valuePop(ctxt);
10204 if (tmp != NULL) {
10205 if (tmp != init)
10206 stack++;
10207 xmlXPathFreeObject(tmp);
10208 }
10209 } while (tmp != NULL);
10210 if ((stack != 0) && (res != NULL)) {
10211 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010212 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010213 stack);
10214 }
10215 if (ctxt->error != XPATH_EXPRESSION_OK) {
10216 xmlXPathFreeObject(res);
10217 res = NULL;
10218 }
10219
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010220
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010221 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010222 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010223#ifndef LIBXML_THREAD_ENABLED
10224 reentance--;
10225#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010226 return(res);
10227}
10228
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010229/**
10230 * xmlXPathEvalExpr:
10231 * @ctxt: the XPath Parser context
10232 *
10233 * Parse and evaluate an XPath expression in the given context,
10234 * then push the result on the context stack
10235 */
10236void
10237xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10238 xmlXPathCompileExpr(ctxt);
10239 xmlXPathRunEval(ctxt);
10240}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010241
10242/**
10243 * xmlXPathEval:
10244 * @str: the XPath expression
10245 * @ctx: the XPath context
10246 *
10247 * Evaluate the XPath Location Path in the given context.
10248 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010249 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010250 * the caller has to free the object.
10251 */
10252xmlXPathObjectPtr
10253xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10254 xmlXPathParserContextPtr ctxt;
10255 xmlXPathObjectPtr res, tmp, init = NULL;
10256 int stack = 0;
10257
10258 xmlXPathInit();
10259
10260 CHECK_CONTEXT(ctx)
10261
10262 ctxt = xmlXPathNewParserContext(str, ctx);
10263 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010264
10265 if (ctxt->value == NULL) {
10266 xmlGenericError(xmlGenericErrorContext,
10267 "xmlXPathEval: evaluation failed\n");
10268 res = NULL;
10269 } else if (*ctxt->cur != 0) {
10270 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10271 res = NULL;
10272 } else {
10273 res = valuePop(ctxt);
10274 }
10275
10276 do {
10277 tmp = valuePop(ctxt);
10278 if (tmp != NULL) {
10279 if (tmp != init)
10280 stack++;
10281 xmlXPathFreeObject(tmp);
10282 }
10283 } while (tmp != NULL);
10284 if ((stack != 0) && (res != NULL)) {
10285 xmlGenericError(xmlGenericErrorContext,
10286 "xmlXPathEval: %d object left on the stack\n",
10287 stack);
10288 }
10289 if (ctxt->error != XPATH_EXPRESSION_OK) {
10290 xmlXPathFreeObject(res);
10291 res = NULL;
10292 }
10293
Owen Taylor3473f882001-02-23 17:55:21 +000010294 xmlXPathFreeParserContext(ctxt);
10295 return(res);
10296}
10297
10298/**
10299 * xmlXPathEvalExpression:
10300 * @str: the XPath expression
10301 * @ctxt: the XPath context
10302 *
10303 * Evaluate the XPath expression in the given context.
10304 *
10305 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10306 * the caller has to free the object.
10307 */
10308xmlXPathObjectPtr
10309xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10310 xmlXPathParserContextPtr pctxt;
10311 xmlXPathObjectPtr res, tmp;
10312 int stack = 0;
10313
10314 xmlXPathInit();
10315
10316 CHECK_CONTEXT(ctxt)
10317
10318 pctxt = xmlXPathNewParserContext(str, ctxt);
10319 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010320
10321 if (*pctxt->cur != 0) {
10322 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10323 res = NULL;
10324 } else {
10325 res = valuePop(pctxt);
10326 }
10327 do {
10328 tmp = valuePop(pctxt);
10329 if (tmp != NULL) {
10330 xmlXPathFreeObject(tmp);
10331 stack++;
10332 }
10333 } while (tmp != NULL);
10334 if ((stack != 0) && (res != NULL)) {
10335 xmlGenericError(xmlGenericErrorContext,
10336 "xmlXPathEvalExpression: %d object left on the stack\n",
10337 stack);
10338 }
10339 xmlXPathFreeParserContext(pctxt);
10340 return(res);
10341}
10342
10343/**
10344 * xmlXPathRegisterAllFunctions:
10345 * @ctxt: the XPath context
10346 *
10347 * Registers all default XPath functions in this context
10348 */
10349void
10350xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
10351{
10352 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
10353 xmlXPathBooleanFunction);
10354 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
10355 xmlXPathCeilingFunction);
10356 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
10357 xmlXPathCountFunction);
10358 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
10359 xmlXPathConcatFunction);
10360 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
10361 xmlXPathContainsFunction);
10362 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
10363 xmlXPathIdFunction);
10364 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
10365 xmlXPathFalseFunction);
10366 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
10367 xmlXPathFloorFunction);
10368 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
10369 xmlXPathLastFunction);
10370 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
10371 xmlXPathLangFunction);
10372 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
10373 xmlXPathLocalNameFunction);
10374 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
10375 xmlXPathNotFunction);
10376 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
10377 xmlXPathNameFunction);
10378 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
10379 xmlXPathNamespaceURIFunction);
10380 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
10381 xmlXPathNormalizeFunction);
10382 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
10383 xmlXPathNumberFunction);
10384 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
10385 xmlXPathPositionFunction);
10386 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
10387 xmlXPathRoundFunction);
10388 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
10389 xmlXPathStringFunction);
10390 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
10391 xmlXPathStringLengthFunction);
10392 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
10393 xmlXPathStartsWithFunction);
10394 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
10395 xmlXPathSubstringFunction);
10396 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
10397 xmlXPathSubstringBeforeFunction);
10398 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
10399 xmlXPathSubstringAfterFunction);
10400 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
10401 xmlXPathSumFunction);
10402 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
10403 xmlXPathTrueFunction);
10404 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
10405 xmlXPathTranslateFunction);
10406}
10407
10408#endif /* LIBXML_XPATH_ENABLED */