blob: f8966d133e1a358771574fa7a5e5547c40add336 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
5 *
6 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
11 * See COPYRIGHT for the status of this software
12 *
Daniel Veillardc5d64342001-06-24 12:13:24 +000013 * Author: daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000014 *
15 * 14 Nov 2000 ht - truncated declaration of xmlXPathEvalRelativeLocationPath
16 * for VMS
17 */
18
Bjorn Reese70a9da52001-04-21 16:57:29 +000019#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000020#ifdef LIBXML_XPATH_ENABLED
21
Owen Taylor3473f882001-02-23 17:55:21 +000022#include <string.h>
23
24#ifdef HAVE_SYS_TYPES_H
25#include <sys/types.h>
26#endif
27#ifdef HAVE_MATH_H
28#include <math.h>
29#endif
30#ifdef HAVE_FLOAT_H
31#include <float.h>
32#endif
Owen Taylor3473f882001-02-23 17:55:21 +000033#ifdef HAVE_CTYPE_H
34#include <ctype.h>
35#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000036#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000037#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000038#endif
Owen Taylor3473f882001-02-23 17:55:21 +000039
40#include <libxml/xmlmemory.h>
41#include <libxml/tree.h>
42#include <libxml/valid.h>
43#include <libxml/xpath.h>
44#include <libxml/xpathInternals.h>
45#include <libxml/parserInternals.h>
46#include <libxml/hash.h>
47#ifdef LIBXML_XPTR_ENABLED
48#include <libxml/xpointer.h>
49#endif
50#ifdef LIBXML_DEBUG_ENABLED
51#include <libxml/debugXML.h>
52#endif
53#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000054#include <libxml/threads.h>
Owen Taylor3473f882001-02-23 17:55:21 +000055
56/* #define DEBUG */
57/* #define DEBUG_STEP */
Daniel Veillardf06307e2001-07-03 10:35:50 +000058/* #define DEBUG_STEP_NTH */
Owen Taylor3473f882001-02-23 17:55:21 +000059/* #define DEBUG_EXPR */
Daniel Veillardf06307e2001-07-03 10:35:50 +000060/* #define DEBUG_EVAL_COUNTS */
Owen Taylor3473f882001-02-23 17:55:21 +000061
62void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
63double xmlXPathStringEvalNumber(const xmlChar *str);
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)
519void xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth);
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000520static void
521xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000522 int i;
523 char shift[100];
524
525 for (i = 0;((i < depth) && (i < 25));i++)
526 shift[2 * i] = shift[2 * i + 1] = ' ';
527 shift[2 * i] = shift[2 * i + 1] = 0;
528
529 if (cur == NULL) {
530 fprintf(output, shift);
531 fprintf(output, "LocationSet is NULL !\n");
532 return;
533
534 }
535
536 for (i = 0;i < cur->locNr;i++) {
537 fprintf(output, shift);
538 fprintf(output, "%d : ", i + 1);
539 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
540 }
541}
Daniel Veillard017b1082001-06-21 11:20:21 +0000542#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000543
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000544/**
545 * xmlXPathDebugDumpObject:
546 * @output: the FILE * to dump the output
547 * @cur: the object to inspect
548 * @depth: indentation level
549 *
550 * Dump the content of the object for debugging purposes
551 */
552void
553xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000554 int i;
555 char shift[100];
556
557 for (i = 0;((i < depth) && (i < 25));i++)
558 shift[2 * i] = shift[2 * i + 1] = ' ';
559 shift[2 * i] = shift[2 * i + 1] = 0;
560
561 fprintf(output, shift);
562
563 if (cur == NULL) {
564 fprintf(output, "Object is empty (NULL)\n");
565 return;
566 }
567 switch(cur->type) {
568 case XPATH_UNDEFINED:
569 fprintf(output, "Object is uninitialized\n");
570 break;
571 case XPATH_NODESET:
572 fprintf(output, "Object is a Node Set :\n");
573 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
574 break;
575 case XPATH_XSLT_TREE:
576 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000577 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000578 break;
579 case XPATH_BOOLEAN:
580 fprintf(output, "Object is a Boolean : ");
581 if (cur->boolval) fprintf(output, "true\n");
582 else fprintf(output, "false\n");
583 break;
584 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000585 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000586 case 1:
587 fprintf(output, "Object is a number : +Infinity\n");
588 break;
589 case -1:
590 fprintf(output, "Object is a number : -Infinity\n");
591 break;
592 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000593 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000594 fprintf(output, "Object is a number : NaN\n");
595 } else {
596 fprintf(output, "Object is a number : %0g\n", cur->floatval);
597 }
598 }
Owen Taylor3473f882001-02-23 17:55:21 +0000599 break;
600 case XPATH_STRING:
601 fprintf(output, "Object is a string : ");
602 xmlDebugDumpString(output, cur->stringval);
603 fprintf(output, "\n");
604 break;
605 case XPATH_POINT:
606 fprintf(output, "Object is a point : index %d in node", cur->index);
607 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
608 fprintf(output, "\n");
609 break;
610 case XPATH_RANGE:
611 if ((cur->user2 == NULL) ||
612 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
613 fprintf(output, "Object is a collapsed range :\n");
614 fprintf(output, shift);
615 if (cur->index >= 0)
616 fprintf(output, "index %d in ", cur->index);
617 fprintf(output, "node\n");
618 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
619 depth + 1);
620 } else {
621 fprintf(output, "Object is a range :\n");
622 fprintf(output, shift);
623 fprintf(output, "From ");
624 if (cur->index >= 0)
625 fprintf(output, "index %d in ", cur->index);
626 fprintf(output, "node\n");
627 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
628 depth + 1);
629 fprintf(output, shift);
630 fprintf(output, "To ");
631 if (cur->index2 >= 0)
632 fprintf(output, "index %d in ", cur->index2);
633 fprintf(output, "node\n");
634 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
635 depth + 1);
636 fprintf(output, "\n");
637 }
638 break;
639 case XPATH_LOCATIONSET:
640#if defined(LIBXML_XPTR_ENABLED)
641 fprintf(output, "Object is a Location Set:\n");
642 xmlXPathDebugDumpLocationSet(output,
643 (xmlLocationSetPtr) cur->user, depth);
644#endif
645 break;
646 case XPATH_USERS:
647 fprintf(output, "Object is user defined\n");
648 break;
649 }
650}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000651
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000652static void
653xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000654 xmlXPathStepOpPtr op, int depth) {
655 int i;
656 char shift[100];
657
658 for (i = 0;((i < depth) && (i < 25));i++)
659 shift[2 * i] = shift[2 * i + 1] = ' ';
660 shift[2 * i] = shift[2 * i + 1] = 0;
661
662 fprintf(output, shift);
663 if (op == NULL) {
664 fprintf(output, "Step is NULL\n");
665 return;
666 }
667 switch (op->op) {
668 case XPATH_OP_END:
669 fprintf(output, "END"); break;
670 case XPATH_OP_AND:
671 fprintf(output, "AND"); break;
672 case XPATH_OP_OR:
673 fprintf(output, "OR"); break;
674 case XPATH_OP_EQUAL:
675 if (op->value)
676 fprintf(output, "EQUAL =");
677 else
678 fprintf(output, "EQUAL !=");
679 break;
680 case XPATH_OP_CMP:
681 if (op->value)
682 fprintf(output, "CMP <");
683 else
684 fprintf(output, "CMP >");
685 if (!op->value2)
686 fprintf(output, "=");
687 break;
688 case XPATH_OP_PLUS:
689 if (op->value == 0)
690 fprintf(output, "PLUS -");
691 else if (op->value == 1)
692 fprintf(output, "PLUS +");
693 else if (op->value == 2)
694 fprintf(output, "PLUS unary -");
695 else if (op->value == 3)
696 fprintf(output, "PLUS unary - -");
697 break;
698 case XPATH_OP_MULT:
699 if (op->value == 0)
700 fprintf(output, "MULT *");
701 else if (op->value == 1)
702 fprintf(output, "MULT div");
703 else
704 fprintf(output, "MULT mod");
705 break;
706 case XPATH_OP_UNION:
707 fprintf(output, "UNION"); break;
708 case XPATH_OP_ROOT:
709 fprintf(output, "ROOT"); break;
710 case XPATH_OP_NODE:
711 fprintf(output, "NODE"); break;
712 case XPATH_OP_RESET:
713 fprintf(output, "RESET"); break;
714 case XPATH_OP_SORT:
715 fprintf(output, "SORT"); break;
716 case XPATH_OP_COLLECT: {
717 xmlXPathAxisVal axis = op->value;
718 xmlXPathTestVal test = op->value2;
719 xmlXPathTypeVal type = op->value3;
720 const xmlChar *prefix = op->value4;
721 const xmlChar *name = op->value5;
722
723 fprintf(output, "COLLECT ");
724 switch (axis) {
725 case AXIS_ANCESTOR:
726 fprintf(output, " 'ancestors' "); break;
727 case AXIS_ANCESTOR_OR_SELF:
728 fprintf(output, " 'ancestors-or-self' "); break;
729 case AXIS_ATTRIBUTE:
730 fprintf(output, " 'attributes' "); break;
731 case AXIS_CHILD:
732 fprintf(output, " 'child' "); break;
733 case AXIS_DESCENDANT:
734 fprintf(output, " 'descendant' "); break;
735 case AXIS_DESCENDANT_OR_SELF:
736 fprintf(output, " 'descendant-or-self' "); break;
737 case AXIS_FOLLOWING:
738 fprintf(output, " 'following' "); break;
739 case AXIS_FOLLOWING_SIBLING:
740 fprintf(output, " 'following-siblings' "); break;
741 case AXIS_NAMESPACE:
742 fprintf(output, " 'namespace' "); break;
743 case AXIS_PARENT:
744 fprintf(output, " 'parent' "); break;
745 case AXIS_PRECEDING:
746 fprintf(output, " 'preceding' "); break;
747 case AXIS_PRECEDING_SIBLING:
748 fprintf(output, " 'preceding-sibling' "); break;
749 case AXIS_SELF:
750 fprintf(output, " 'self' "); break;
751 }
752 switch (test) {
753 case NODE_TEST_NONE:
754 fprintf(output, "'none' "); break;
755 case NODE_TEST_TYPE:
756 fprintf(output, "'type' "); break;
757 case NODE_TEST_PI:
758 fprintf(output, "'PI' "); break;
759 case NODE_TEST_ALL:
760 fprintf(output, "'all' "); break;
761 case NODE_TEST_NS:
762 fprintf(output, "'namespace' "); break;
763 case NODE_TEST_NAME:
764 fprintf(output, "'name' "); break;
765 }
766 switch (type) {
767 case NODE_TYPE_NODE:
768 fprintf(output, "'node' "); break;
769 case NODE_TYPE_COMMENT:
770 fprintf(output, "'comment' "); break;
771 case NODE_TYPE_TEXT:
772 fprintf(output, "'text' "); break;
773 case NODE_TYPE_PI:
774 fprintf(output, "'PI' "); break;
775 }
776 if (prefix != NULL)
777 fprintf(output, "%s:", prefix);
778 if (name != NULL)
779 fprintf(output, "%s", name);
780 break;
781
782 }
783 case XPATH_OP_VALUE: {
784 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
785
786 fprintf(output, "ELEM ");
787 xmlXPathDebugDumpObject(output, object, 0);
788 goto finish;
789 }
790 case XPATH_OP_VARIABLE: {
791 const xmlChar *prefix = op->value5;
792 const xmlChar *name = op->value4;
793
794 if (prefix != NULL)
795 fprintf(output, "VARIABLE %s:%s", prefix, name);
796 else
797 fprintf(output, "VARIABLE %s", name);
798 break;
799 }
800 case XPATH_OP_FUNCTION: {
801 int nbargs = op->value;
802 const xmlChar *prefix = op->value5;
803 const xmlChar *name = op->value4;
804
805 if (prefix != NULL)
806 fprintf(output, "FUNCTION %s:%s(%d args)",
807 prefix, name, nbargs);
808 else
809 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
810 break;
811 }
812 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
813 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000814 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +0000815#ifdef LIBXML_XPTR_ENABLED
816 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
817#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000818 default:
819 fprintf(output, "UNKNOWN %d\n", op->op); return;
820 }
821 fprintf(output, "\n");
822finish:
823 if (op->ch1 >= 0)
824 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
825 if (op->ch2 >= 0)
826 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
827}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000828
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000829/**
830 * xmlXPathDebugDumpCompExpr:
831 * @output: the FILE * for the output
832 * @comp: the precompiled XPath expression
833 * @depth: the indentation level.
834 *
835 * Dumps the tree of the compiled XPath expression.
836 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000837void
838xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
839 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000840 int i;
841 char shift[100];
842
843 for (i = 0;((i < depth) && (i < 25));i++)
844 shift[2 * i] = shift[2 * i + 1] = ' ';
845 shift[2 * i] = shift[2 * i + 1] = 0;
846
847 fprintf(output, shift);
848
849 if (comp == NULL) {
850 fprintf(output, "Compiled Expression is NULL\n");
851 return;
852 }
853 fprintf(output, "Compiled Expression : %d elements\n",
854 comp->nbStep);
855 i = comp->last;
856 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
857}
Daniel Veillard017b1082001-06-21 11:20:21 +0000858#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000859
860/************************************************************************
861 * *
862 * Parser stacks related functions and macros *
863 * *
864 ************************************************************************/
865
866/*
867 * Generic function for accessing stacks in the Parser Context
868 */
869
870#define PUSH_AND_POP(type, name) \
871extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
872 if (ctxt->name##Nr >= ctxt->name##Max) { \
873 ctxt->name##Max *= 2; \
874 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
875 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
876 if (ctxt->name##Tab == NULL) { \
877 xmlGenericError(xmlGenericErrorContext, \
878 "realloc failed !\n"); \
879 return(0); \
880 } \
881 } \
882 ctxt->name##Tab[ctxt->name##Nr] = value; \
883 ctxt->name = value; \
884 return(ctxt->name##Nr++); \
885} \
886extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
887 type ret; \
888 if (ctxt->name##Nr <= 0) return(0); \
889 ctxt->name##Nr--; \
890 if (ctxt->name##Nr > 0) \
891 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
892 else \
893 ctxt->name = NULL; \
894 ret = ctxt->name##Tab[ctxt->name##Nr]; \
895 ctxt->name##Tab[ctxt->name##Nr] = 0; \
896 return(ret); \
897} \
898
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000899/**
900 * valuePop:
901 * @ctxt: an XPath evaluation context
902 *
903 * Pops the top XPath object from the value stack
904 *
905 * Returns the XPath object just removed
906 */
907/**
908 * valuePush:
909 * @ctxt: an XPath evaluation context
910 * @value: the XPath object
911 *
912 * Pushes a new XPath object on top of the value stack
913 */
Owen Taylor3473f882001-02-23 17:55:21 +0000914PUSH_AND_POP(xmlXPathObjectPtr, value)
915
Thomas Broyerf06a3d82001-07-16 04:52:57 +0000916/**
917 * xmlXPathPopBoolean:
918 * @ctxt: an XPath parser context
919 *
920 * Pops a boolean from the stack, handling conversion if needed.
921 * Check error with #xmlXPathCheckError.
922 *
923 * Returns the boolean
924 */
925int
926xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
927 xmlXPathObjectPtr obj;
928 int ret;
929
930 obj = valuePop(ctxt);
931 if (obj == NULL) {
932 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
933 return(0);
934 }
935 ret = xmlXPathCastToBoolean(obj);
936 xmlXPathFreeObject(obj);
937 return(ret);
938}
939
940/**
941 * xmlXPathPopNumber:
942 * @ctxt: an XPath parser context
943 *
944 * Pops a number from the stack, handling conversion if needed.
945 * Check error with #xmlXPathCheckError.
946 *
947 * Returns the number
948 */
949double
950xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
951 xmlXPathObjectPtr obj;
952 double ret;
953
954 obj = valuePop(ctxt);
955 if (obj == NULL) {
956 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
957 return(0);
958 }
959 ret = xmlXPathCastToNumber(obj);
960 xmlXPathFreeObject(obj);
961 return(ret);
962}
963
964/**
965 * xmlXPathPopString:
966 * @ctxt: an XPath parser context
967 *
968 * Pops a string from the stack, handling conversion if needed.
969 * Check error with #xmlXPathCheckError.
970 *
971 * Returns the string
972 */
973xmlChar *
974xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
975 xmlXPathObjectPtr obj;
976 xmlChar * ret;
977
978 obj = valuePop(ctxt);
979 if (obj == NULL) {
980 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
981 return(NULL);
982 }
983 ret = xmlXPathCastToString(obj);
984 /* TODO: needs refactoring somewhere else */
985 if (obj->stringval == ret)
986 obj->stringval = NULL;
987 xmlXPathFreeObject(obj);
988 return(ret);
989}
990
991/**
992 * xmlXPathPopNodeSet:
993 * @ctxt: an XPath parser context
994 *
995 * Pops a node-set from the stack, handling conversion if needed.
996 * Check error with #xmlXPathCheckError.
997 *
998 * Returns the node-set
999 */
1000xmlNodeSetPtr
1001xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1002 xmlXPathObjectPtr obj;
1003 xmlNodeSetPtr ret;
1004
1005 if (ctxt->value == NULL) {
1006 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1007 return(NULL);
1008 }
1009 if (!xmlXPathStackIsNodeSet(ctxt)) {
1010 xmlXPathSetTypeError(ctxt);
1011 return(NULL);
1012 }
1013 obj = valuePop(ctxt);
1014 ret = obj->nodesetval;
1015 xmlXPathFreeNodeSetList(obj);
1016 return(ret);
1017}
1018
1019/**
1020 * xmlXPathPopExternal:
1021 * @ctxt: an XPath parser context
1022 *
1023 * Pops an external oject from the stack, handling conversion if needed.
1024 * Check error with #xmlXPathCheckError.
1025 *
1026 * Returns the object
1027 */
1028void *
1029xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1030 xmlXPathObjectPtr obj;
1031 void * ret;
1032
1033 if (ctxt->value == NULL) {
1034 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1035 return(NULL);
1036 }
1037 if (ctxt->value->type != XPATH_USERS) {
1038 xmlXPathSetTypeError(ctxt);
1039 return(NULL);
1040 }
1041 obj = valuePop(ctxt);
1042 ret = obj->user;
1043 xmlXPathFreeObject(obj);
1044 return(ret);
1045}
1046
Owen Taylor3473f882001-02-23 17:55:21 +00001047/*
1048 * Macros for accessing the content. Those should be used only by the parser,
1049 * and not exported.
1050 *
1051 * Dirty macros, i.e. one need to make assumption on the context to use them
1052 *
1053 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1054 * CUR returns the current xmlChar value, i.e. a 8 bit value
1055 * in ISO-Latin or UTF-8.
1056 * This should be used internally by the parser
1057 * only to compare to ASCII values otherwise it would break when
1058 * running with UTF-8 encoding.
1059 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1060 * to compare on ASCII based substring.
1061 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1062 * strings within the parser.
1063 * CURRENT Returns the current char value, with the full decoding of
1064 * UTF-8 if we are using this mode. It returns an int.
1065 * NEXT Skip to the next character, this does the proper decoding
1066 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1067 * It returns the pointer to the current xmlChar.
1068 */
1069
1070#define CUR (*ctxt->cur)
1071#define SKIP(val) ctxt->cur += (val)
1072#define NXT(val) ctxt->cur[(val)]
1073#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001074#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1075
1076#define COPY_BUF(l,b,i,v) \
1077 if (l == 1) b[i++] = (xmlChar) v; \
1078 else i += xmlCopyChar(l,&b[i],v)
1079
1080#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001081
1082#define SKIP_BLANKS \
1083 while (IS_BLANK(*(ctxt->cur))) NEXT
1084
1085#define CURRENT (*ctxt->cur)
1086#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1087
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001088
1089#ifndef DBL_DIG
1090#define DBL_DIG 16
1091#endif
1092#ifndef DBL_EPSILON
1093#define DBL_EPSILON 1E-9
1094#endif
1095
1096#define UPPER_DOUBLE 1E9
1097#define LOWER_DOUBLE 1E-5
1098
1099#define INTEGER_DIGITS DBL_DIG
1100#define FRACTION_DIGITS (DBL_DIG + 1)
1101#define EXPONENT_DIGITS (3 + 2)
1102
1103/**
1104 * xmlXPathFormatNumber:
1105 * @number: number to format
1106 * @buffer: output buffer
1107 * @buffersize: size of output buffer
1108 *
1109 * Convert the number into a string representation.
1110 */
1111static void
1112xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1113{
Daniel Veillardcda96922001-08-21 10:56:31 +00001114 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001115 case 1:
1116 if (buffersize > (int)sizeof("+Infinity"))
1117 sprintf(buffer, "+Infinity");
1118 break;
1119 case -1:
1120 if (buffersize > (int)sizeof("-Infinity"))
1121 sprintf(buffer, "-Infinity");
1122 break;
1123 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001124 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001125 if (buffersize > (int)sizeof("NaN"))
1126 sprintf(buffer, "NaN");
1127 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001128 /* 3 is sign, decimal point, and terminating zero */
1129 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1130 int integer_place, fraction_place;
1131 char *ptr;
1132 char *after_fraction;
1133 double absolute_value;
1134 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001135
Bjorn Reese70a9da52001-04-21 16:57:29 +00001136 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001137
Bjorn Reese70a9da52001-04-21 16:57:29 +00001138 /*
1139 * First choose format - scientific or regular floating point.
1140 * In either case, result is in work, and after_fraction points
1141 * just past the fractional part.
1142 */
1143 if ( ((absolute_value > UPPER_DOUBLE) ||
1144 (absolute_value < LOWER_DOUBLE)) &&
1145 (absolute_value != 0.0) ) {
1146 /* Use scientific notation */
1147 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1148 fraction_place = DBL_DIG - 1;
1149 snprintf(work, sizeof(work),"%*.*e",
1150 integer_place, fraction_place, number);
1151 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001152 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001153 else {
1154 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001155 if (absolute_value > 0.0)
1156 integer_place = 1 + (int)log10(absolute_value);
1157 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001158 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001159 fraction_place = (integer_place > 0)
1160 ? DBL_DIG - integer_place
1161 : DBL_DIG;
1162 size = snprintf(work, sizeof(work), "%0.*f",
1163 fraction_place, number);
1164 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001165 }
1166
Bjorn Reese70a9da52001-04-21 16:57:29 +00001167 /* Remove fractional trailing zeroes */
1168 ptr = after_fraction;
1169 while (*(--ptr) == '0')
1170 ;
1171 if (*ptr != '.')
1172 ptr++;
1173 strcpy(ptr, after_fraction);
1174
1175 /* Finally copy result back to caller */
1176 size = strlen(work) + 1;
1177 if (size > buffersize) {
1178 work[buffersize - 1] = 0;
1179 size = buffersize;
1180 }
1181 memcpy(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001182 }
1183 break;
1184 }
1185}
1186
Owen Taylor3473f882001-02-23 17:55:21 +00001187/************************************************************************
1188 * *
1189 * Error handling routines *
1190 * *
1191 ************************************************************************/
1192
1193
Daniel Veillardb44025c2001-10-11 22:55:55 +00001194static const char *xmlXPathErrorMessages[] = {
Owen Taylor3473f882001-02-23 17:55:21 +00001195 "Ok",
1196 "Number encoding",
1197 "Unfinished litteral",
1198 "Start of litteral",
1199 "Expected $ for variable reference",
1200 "Undefined variable",
1201 "Invalid predicate",
1202 "Invalid expression",
1203 "Missing closing curly brace",
1204 "Unregistered function",
1205 "Invalid operand",
1206 "Invalid type",
1207 "Invalid number of arguments",
1208 "Invalid context size",
1209 "Invalid context position",
1210 "Memory allocation error",
1211 "Syntax error",
1212 "Resource error",
1213 "Sub resource error",
Daniel Veillard61d80a22001-04-27 17:13:01 +00001214 "Undefined namespace prefix",
1215 "Encoding error",
1216 "Char out of XML range"
Owen Taylor3473f882001-02-23 17:55:21 +00001217};
1218
1219/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001220 * xmlXPatherror:
Owen Taylor3473f882001-02-23 17:55:21 +00001221 * @ctxt: the XPath Parser context
1222 * @file: the file name
1223 * @line: the line number
1224 * @no: the error number
1225 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001226 * Formats an error message.
Owen Taylor3473f882001-02-23 17:55:21 +00001227 */
1228void
1229xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
1230 int line, int no) {
1231 int n;
1232 const xmlChar *cur;
1233 const xmlChar *base;
1234
1235 xmlGenericError(xmlGenericErrorContext,
1236 "Error %s:%d: %s\n", file, line,
1237 xmlXPathErrorMessages[no]);
1238
1239 cur = ctxt->cur;
1240 base = ctxt->base;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001241 if ((cur == NULL) || (base == NULL))
1242 return;
1243
Owen Taylor3473f882001-02-23 17:55:21 +00001244 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
1245 cur--;
1246 }
1247 n = 0;
1248 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
1249 cur--;
1250 if ((*cur == '\n') || (*cur == '\r')) cur++;
1251 base = cur;
1252 n = 0;
1253 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1254 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
1255 n++;
1256 }
1257 xmlGenericError(xmlGenericErrorContext, "\n");
1258 cur = ctxt->cur;
1259 while ((*cur == '\n') || (*cur == '\r'))
1260 cur--;
1261 n = 0;
1262 while ((cur != base) && (n++ < 80)) {
1263 xmlGenericError(xmlGenericErrorContext, " ");
1264 base++;
1265 }
1266 xmlGenericError(xmlGenericErrorContext,"^\n");
1267}
1268
1269
1270/************************************************************************
1271 * *
1272 * Routines to handle NodeSets *
1273 * *
1274 ************************************************************************/
1275
1276/**
1277 * xmlXPathCmpNodes:
1278 * @node1: the first node
1279 * @node2: the second node
1280 *
1281 * Compare two nodes w.r.t document order
1282 *
1283 * Returns -2 in case of error 1 if first point < second point, 0 if
1284 * that's the same node, -1 otherwise
1285 */
1286int
1287xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1288 int depth1, depth2;
1289 xmlNodePtr cur, root;
1290
1291 if ((node1 == NULL) || (node2 == NULL))
1292 return(-2);
1293 /*
1294 * a couple of optimizations which will avoid computations in most cases
1295 */
1296 if (node1 == node2)
1297 return(0);
Daniel Veillardb33c2012001-04-25 12:59:04 +00001298 if ((node1->type == XML_NAMESPACE_DECL) ||
1299 (node2->type == XML_NAMESPACE_DECL))
1300 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001301 if (node1 == node2->prev)
1302 return(1);
1303 if (node1 == node2->next)
1304 return(-1);
1305
1306 /*
1307 * compute depth to root
1308 */
1309 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1310 if (cur == node1)
1311 return(1);
1312 depth2++;
1313 }
1314 root = cur;
1315 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1316 if (cur == node2)
1317 return(-1);
1318 depth1++;
1319 }
1320 /*
1321 * Distinct document (or distinct entities :-( ) case.
1322 */
1323 if (root != cur) {
1324 return(-2);
1325 }
1326 /*
1327 * get the nearest common ancestor.
1328 */
1329 while (depth1 > depth2) {
1330 depth1--;
1331 node1 = node1->parent;
1332 }
1333 while (depth2 > depth1) {
1334 depth2--;
1335 node2 = node2->parent;
1336 }
1337 while (node1->parent != node2->parent) {
1338 node1 = node1->parent;
1339 node2 = node2->parent;
1340 /* should not happen but just in case ... */
1341 if ((node1 == NULL) || (node2 == NULL))
1342 return(-2);
1343 }
1344 /*
1345 * Find who's first.
1346 */
1347 if (node1 == node2->next)
1348 return(-1);
1349 for (cur = node1->next;cur != NULL;cur = cur->next)
1350 if (cur == node2)
1351 return(1);
1352 return(-1); /* assume there is no sibling list corruption */
1353}
1354
1355/**
1356 * xmlXPathNodeSetSort:
1357 * @set: the node set
1358 *
1359 * Sort the node set in document order
1360 */
1361void
1362xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001363 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001364 xmlNodePtr tmp;
1365
1366 if (set == NULL)
1367 return;
1368
1369 /* Use Shell's sort to sort the node-set */
1370 len = set->nodeNr;
1371 for (incr = len / 2; incr > 0; incr /= 2) {
1372 for (i = incr; i < len; i++) {
1373 j = i - incr;
1374 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001375 if (xmlXPathCmpNodes(set->nodeTab[j],
1376 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001377 tmp = set->nodeTab[j];
1378 set->nodeTab[j] = set->nodeTab[j + incr];
1379 set->nodeTab[j + incr] = tmp;
1380 j -= incr;
1381 } else
1382 break;
1383 }
1384 }
1385 }
1386}
1387
1388#define XML_NODESET_DEFAULT 10
1389/**
1390 * xmlXPathNodeSetCreate:
1391 * @val: an initial xmlNodePtr, or NULL
1392 *
1393 * Create a new xmlNodeSetPtr of type double and of value @val
1394 *
1395 * Returns the newly created object.
1396 */
1397xmlNodeSetPtr
1398xmlXPathNodeSetCreate(xmlNodePtr val) {
1399 xmlNodeSetPtr ret;
1400
1401 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1402 if (ret == NULL) {
1403 xmlGenericError(xmlGenericErrorContext,
1404 "xmlXPathNewNodeSet: out of memory\n");
1405 return(NULL);
1406 }
1407 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1408 if (val != NULL) {
1409 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1410 sizeof(xmlNodePtr));
1411 if (ret->nodeTab == NULL) {
1412 xmlGenericError(xmlGenericErrorContext,
1413 "xmlXPathNewNodeSet: out of memory\n");
1414 return(NULL);
1415 }
1416 memset(ret->nodeTab, 0 ,
1417 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1418 ret->nodeMax = XML_NODESET_DEFAULT;
1419 ret->nodeTab[ret->nodeNr++] = val;
1420 }
1421 return(ret);
1422}
1423
1424/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001425 * xmlXPathNodeSetContains:
1426 * @cur: the node-set
1427 * @val: the node
1428 *
1429 * checks whether @cur contains @val
1430 *
1431 * Returns true (1) if @cur contains @val, false (0) otherwise
1432 */
1433int
1434xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1435 int i;
1436
1437 for (i = 0; i < cur->nodeNr; i++) {
1438 if (cur->nodeTab[i] == val)
1439 return(1);
1440 }
1441 return(0);
1442}
1443
1444/**
Owen Taylor3473f882001-02-23 17:55:21 +00001445 * xmlXPathNodeSetAdd:
1446 * @cur: the initial node set
1447 * @val: a new xmlNodePtr
1448 *
1449 * add a new xmlNodePtr ot an existing NodeSet
1450 */
1451void
1452xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1453 int i;
1454
1455 if (val == NULL) return;
1456
1457 /*
1458 * check against doublons
1459 */
1460 for (i = 0;i < cur->nodeNr;i++)
1461 if (cur->nodeTab[i] == val) return;
1462
1463 /*
1464 * grow the nodeTab if needed
1465 */
1466 if (cur->nodeMax == 0) {
1467 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1468 sizeof(xmlNodePtr));
1469 if (cur->nodeTab == NULL) {
1470 xmlGenericError(xmlGenericErrorContext,
1471 "xmlXPathNodeSetAdd: out of memory\n");
1472 return;
1473 }
1474 memset(cur->nodeTab, 0 ,
1475 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1476 cur->nodeMax = XML_NODESET_DEFAULT;
1477 } else if (cur->nodeNr == cur->nodeMax) {
1478 xmlNodePtr *temp;
1479
1480 cur->nodeMax *= 2;
1481 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1482 sizeof(xmlNodePtr));
1483 if (temp == NULL) {
1484 xmlGenericError(xmlGenericErrorContext,
1485 "xmlXPathNodeSetAdd: out of memory\n");
1486 return;
1487 }
1488 cur->nodeTab = temp;
1489 }
1490 cur->nodeTab[cur->nodeNr++] = val;
1491}
1492
1493/**
1494 * xmlXPathNodeSetAddUnique:
1495 * @cur: the initial node set
1496 * @val: a new xmlNodePtr
1497 *
1498 * add a new xmlNodePtr ot an existing NodeSet, optimized version
1499 * when we are sure the node is not already in the set.
1500 */
1501void
1502xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1503 if (val == NULL) return;
1504
1505 /*
1506 * grow the nodeTab if needed
1507 */
1508 if (cur->nodeMax == 0) {
1509 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1510 sizeof(xmlNodePtr));
1511 if (cur->nodeTab == NULL) {
1512 xmlGenericError(xmlGenericErrorContext,
1513 "xmlXPathNodeSetAddUnique: out of memory\n");
1514 return;
1515 }
1516 memset(cur->nodeTab, 0 ,
1517 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1518 cur->nodeMax = XML_NODESET_DEFAULT;
1519 } else if (cur->nodeNr == cur->nodeMax) {
1520 xmlNodePtr *temp;
1521
1522 cur->nodeMax *= 2;
1523 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1524 sizeof(xmlNodePtr));
1525 if (temp == NULL) {
1526 xmlGenericError(xmlGenericErrorContext,
1527 "xmlXPathNodeSetAddUnique: out of memory\n");
1528 return;
1529 }
1530 cur->nodeTab = temp;
1531 }
1532 cur->nodeTab[cur->nodeNr++] = val;
1533}
1534
1535/**
1536 * xmlXPathNodeSetMerge:
1537 * @val1: the first NodeSet or NULL
1538 * @val2: the second NodeSet
1539 *
1540 * Merges two nodesets, all nodes from @val2 are added to @val1
1541 * if @val1 is NULL, a new set is created and copied from @val2
1542 *
1543 * Returns val1 once extended or NULL in case of error.
1544 */
1545xmlNodeSetPtr
1546xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001547 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001548
1549 if (val2 == NULL) return(val1);
1550 if (val1 == NULL) {
1551 val1 = xmlXPathNodeSetCreate(NULL);
1552 }
1553
1554 initNr = val1->nodeNr;
1555
1556 for (i = 0;i < val2->nodeNr;i++) {
1557 /*
1558 * check against doublons
1559 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001560 skip = 0;
1561 for (j = 0; j < initNr; j++) {
1562 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1563 skip = 1;
1564 break;
1565 }
1566 }
1567 if (skip)
1568 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001569
1570 /*
1571 * grow the nodeTab if needed
1572 */
1573 if (val1->nodeMax == 0) {
1574 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1575 sizeof(xmlNodePtr));
1576 if (val1->nodeTab == NULL) {
1577 xmlGenericError(xmlGenericErrorContext,
1578 "xmlXPathNodeSetMerge: out of memory\n");
1579 return(NULL);
1580 }
1581 memset(val1->nodeTab, 0 ,
1582 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1583 val1->nodeMax = XML_NODESET_DEFAULT;
1584 } else if (val1->nodeNr == val1->nodeMax) {
1585 xmlNodePtr *temp;
1586
1587 val1->nodeMax *= 2;
1588 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1589 sizeof(xmlNodePtr));
1590 if (temp == NULL) {
1591 xmlGenericError(xmlGenericErrorContext,
1592 "xmlXPathNodeSetMerge: out of memory\n");
1593 return(NULL);
1594 }
1595 val1->nodeTab = temp;
1596 }
1597 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1598 }
1599
1600 return(val1);
1601}
1602
1603/**
1604 * xmlXPathNodeSetDel:
1605 * @cur: the initial node set
1606 * @val: an xmlNodePtr
1607 *
1608 * Removes an xmlNodePtr from an existing NodeSet
1609 */
1610void
1611xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
1612 int i;
1613
1614 if (cur == NULL) return;
1615 if (val == NULL) return;
1616
1617 /*
1618 * check against doublons
1619 */
1620 for (i = 0;i < cur->nodeNr;i++)
1621 if (cur->nodeTab[i] == val) break;
1622
1623 if (i >= cur->nodeNr) {
1624#ifdef DEBUG
1625 xmlGenericError(xmlGenericErrorContext,
1626 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
1627 val->name);
1628#endif
1629 return;
1630 }
1631 cur->nodeNr--;
1632 for (;i < cur->nodeNr;i++)
1633 cur->nodeTab[i] = cur->nodeTab[i + 1];
1634 cur->nodeTab[cur->nodeNr] = NULL;
1635}
1636
1637/**
1638 * xmlXPathNodeSetRemove:
1639 * @cur: the initial node set
1640 * @val: the index to remove
1641 *
1642 * Removes an entry from an existing NodeSet list.
1643 */
1644void
1645xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
1646 if (cur == NULL) return;
1647 if (val >= cur->nodeNr) return;
1648 cur->nodeNr--;
1649 for (;val < cur->nodeNr;val++)
1650 cur->nodeTab[val] = cur->nodeTab[val + 1];
1651 cur->nodeTab[cur->nodeNr] = NULL;
1652}
1653
1654/**
1655 * xmlXPathFreeNodeSet:
1656 * @obj: the xmlNodeSetPtr to free
1657 *
1658 * Free the NodeSet compound (not the actual nodes !).
1659 */
1660void
1661xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
1662 if (obj == NULL) return;
1663 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001664 xmlFree(obj->nodeTab);
1665 }
Owen Taylor3473f882001-02-23 17:55:21 +00001666 xmlFree(obj);
1667}
1668
1669/**
1670 * xmlXPathFreeValueTree:
1671 * @obj: the xmlNodeSetPtr to free
1672 *
1673 * Free the NodeSet compound and the actual tree, this is different
1674 * from xmlXPathFreeNodeSet()
1675 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001676static void
Owen Taylor3473f882001-02-23 17:55:21 +00001677xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
1678 int i;
1679
1680 if (obj == NULL) return;
1681 for (i = 0;i < obj->nodeNr;i++)
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00001682 if (obj->nodeTab[i] != NULL)
Daniel Veillardbbd51d52001-02-24 03:07:03 +00001683 xmlFreeNodeList(obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001684
1685 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001686 xmlFree(obj->nodeTab);
1687 }
Owen Taylor3473f882001-02-23 17:55:21 +00001688 xmlFree(obj);
1689}
1690
1691#if defined(DEBUG) || defined(DEBUG_STEP)
1692/**
1693 * xmlGenericErrorContextNodeSet:
1694 * @output: a FILE * for the output
1695 * @obj: the xmlNodeSetPtr to free
1696 *
1697 * Quick display of a NodeSet
1698 */
1699void
1700xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
1701 int i;
1702
1703 if (output == NULL) output = xmlGenericErrorContext;
1704 if (obj == NULL) {
1705 fprintf(output, "NodeSet == NULL !\n");
1706 return;
1707 }
1708 if (obj->nodeNr == 0) {
1709 fprintf(output, "NodeSet is empty\n");
1710 return;
1711 }
1712 if (obj->nodeTab == NULL) {
1713 fprintf(output, " nodeTab == NULL !\n");
1714 return;
1715 }
1716 for (i = 0; i < obj->nodeNr; i++) {
1717 if (obj->nodeTab[i] == NULL) {
1718 fprintf(output, " NULL !\n");
1719 return;
1720 }
1721 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
1722 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
1723 fprintf(output, " /");
1724 else if (obj->nodeTab[i]->name == NULL)
1725 fprintf(output, " noname!");
1726 else fprintf(output, " %s", obj->nodeTab[i]->name);
1727 }
1728 fprintf(output, "\n");
1729}
1730#endif
1731
1732/**
1733 * xmlXPathNewNodeSet:
1734 * @val: the NodePtr value
1735 *
1736 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1737 * it with the single Node @val
1738 *
1739 * Returns the newly created object.
1740 */
1741xmlXPathObjectPtr
1742xmlXPathNewNodeSet(xmlNodePtr val) {
1743 xmlXPathObjectPtr ret;
1744
1745 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1746 if (ret == NULL) {
1747 xmlGenericError(xmlGenericErrorContext,
1748 "xmlXPathNewNodeSet: out of memory\n");
1749 return(NULL);
1750 }
1751 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1752 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00001753 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001754 ret->nodesetval = xmlXPathNodeSetCreate(val);
1755 return(ret);
1756}
1757
1758/**
1759 * xmlXPathNewValueTree:
1760 * @val: the NodePtr value
1761 *
1762 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
1763 * it with the tree root @val
1764 *
1765 * Returns the newly created object.
1766 */
1767xmlXPathObjectPtr
1768xmlXPathNewValueTree(xmlNodePtr val) {
1769 xmlXPathObjectPtr ret;
1770
1771 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1772 if (ret == NULL) {
1773 xmlGenericError(xmlGenericErrorContext,
1774 "xmlXPathNewNodeSet: out of memory\n");
1775 return(NULL);
1776 }
1777 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1778 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00001779 ret->boolval = 1;
1780 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00001781 ret->nodesetval = xmlXPathNodeSetCreate(val);
1782 return(ret);
1783}
1784
1785/**
1786 * xmlXPathNewNodeSetList:
1787 * @val: an existing NodeSet
1788 *
1789 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1790 * it with the Nodeset @val
1791 *
1792 * Returns the newly created object.
1793 */
1794xmlXPathObjectPtr
1795xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
1796 xmlXPathObjectPtr ret;
1797 int i;
1798
1799 if (val == NULL)
1800 ret = NULL;
1801 else if (val->nodeTab == NULL)
1802 ret = xmlXPathNewNodeSet(NULL);
1803 else
1804 {
1805 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
1806 for (i = 1; i < val->nodeNr; ++i)
1807 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
1808 }
1809
1810 return(ret);
1811}
1812
1813/**
1814 * xmlXPathWrapNodeSet:
1815 * @val: the NodePtr value
1816 *
1817 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1818 *
1819 * Returns the newly created object.
1820 */
1821xmlXPathObjectPtr
1822xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
1823 xmlXPathObjectPtr ret;
1824
1825 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1826 if (ret == NULL) {
1827 xmlGenericError(xmlGenericErrorContext,
1828 "xmlXPathWrapNodeSet: out of memory\n");
1829 return(NULL);
1830 }
1831 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1832 ret->type = XPATH_NODESET;
1833 ret->nodesetval = val;
1834 return(ret);
1835}
1836
1837/**
1838 * xmlXPathFreeNodeSetList:
1839 * @obj: an existing NodeSetList object
1840 *
1841 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
1842 * the list contrary to xmlXPathFreeObject().
1843 */
1844void
1845xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
1846 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001847 xmlFree(obj);
1848}
1849
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001850/**
1851 * xmlXPathDifference:
1852 * @nodes1: a node-set
1853 * @nodes2: a node-set
1854 *
1855 * Implements the EXSLT - Sets difference() function:
1856 * node-set set:difference (node-set, node-set)
1857 *
1858 * Returns the difference between the two node sets, or nodes1 if
1859 * nodes2 is empty
1860 */
1861xmlNodeSetPtr
1862xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
1863 xmlNodeSetPtr ret;
1864 int i, l1;
1865 xmlNodePtr cur;
1866
1867 if (xmlXPathNodeSetIsEmpty(nodes2))
1868 return(nodes1);
1869
1870 ret = xmlXPathNodeSetCreate(NULL);
1871 if (xmlXPathNodeSetIsEmpty(nodes1))
1872 return(ret);
1873
1874 l1 = xmlXPathNodeSetGetLength(nodes1);
1875
1876 for (i = 0; i < l1; i++) {
1877 cur = xmlXPathNodeSetItem(nodes1, i);
1878 if (!xmlXPathNodeSetContains(nodes2, cur))
1879 xmlXPathNodeSetAddUnique(ret, cur);
1880 }
1881 return(ret);
1882}
1883
1884/**
1885 * xmlXPathIntersection:
1886 * @nodes1: a node-set
1887 * @nodes2: a node-set
1888 *
1889 * Implements the EXSLT - Sets intersection() function:
1890 * node-set set:intersection (node-set, node-set)
1891 *
1892 * Returns a node set comprising the nodes that are within both the
1893 * node sets passed as arguments
1894 */
1895xmlNodeSetPtr
1896xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
1897 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
1898 int i, l1;
1899 xmlNodePtr cur;
1900
1901 if (xmlXPathNodeSetIsEmpty(nodes1))
1902 return(ret);
1903 if (xmlXPathNodeSetIsEmpty(nodes2))
1904 return(ret);
1905
1906 l1 = xmlXPathNodeSetGetLength(nodes1);
1907
1908 for (i = 0; i < l1; i++) {
1909 cur = xmlXPathNodeSetItem(nodes1, i);
1910 if (xmlXPathNodeSetContains(nodes2, cur))
1911 xmlXPathNodeSetAddUnique(ret, cur);
1912 }
1913 return(ret);
1914}
1915
1916/**
1917 * xmlXPathDistinctSorted:
1918 * @nodes: a node-set, sorted by document order
1919 *
1920 * Implements the EXSLT - Sets distinct() function:
1921 * node-set set:distinct (node-set)
1922 *
1923 * Returns a subset of the nodes contained in @nodes, or @nodes if
1924 * it is empty
1925 */
1926xmlNodeSetPtr
1927xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
1928 xmlNodeSetPtr ret;
1929 xmlHashTablePtr hash;
1930 int i, l;
1931 xmlChar * strval;
1932 xmlNodePtr cur;
1933
1934 if (xmlXPathNodeSetIsEmpty(nodes))
1935 return(nodes);
1936
1937 ret = xmlXPathNodeSetCreate(NULL);
1938 l = xmlXPathNodeSetGetLength(nodes);
1939 hash = xmlHashCreate (l);
1940 for (i = 0; i < l; i++) {
1941 cur = xmlXPathNodeSetItem(nodes, i);
1942 strval = xmlXPathCastNodeToString(cur);
1943 if (xmlHashLookup(hash, strval) == NULL) {
1944 xmlHashAddEntry(hash, strval, strval);
1945 xmlXPathNodeSetAddUnique(ret, cur);
1946 } else {
1947 xmlFree(strval);
1948 }
1949 }
1950 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
1951 return(ret);
1952}
1953
1954/**
1955 * xmlXPathDistinct:
1956 * @nodes: a node-set
1957 *
1958 * Implements the EXSLT - Sets distinct() function:
1959 * node-set set:distinct (node-set)
1960 * @nodes is sorted by document order, then #exslSetsDistinctSorted
1961 * is called with the sorted node-set
1962 *
1963 * Returns a subset of the nodes contained in @nodes, or @nodes if
1964 * it is empty
1965 */
1966xmlNodeSetPtr
1967xmlXPathDistinct (xmlNodeSetPtr nodes) {
1968 if (xmlXPathNodeSetIsEmpty(nodes))
1969 return(nodes);
1970
1971 xmlXPathNodeSetSort(nodes);
1972 return(xmlXPathDistinctSorted(nodes));
1973}
1974
1975/**
1976 * xmlXPathHasSameNodes:
1977 * @nodes1: a node-set
1978 * @nodes2: a node-set
1979 *
1980 * Implements the EXSLT - Sets has-same-nodes function:
1981 * boolean set:has-same-node(node-set, node-set)
1982 *
1983 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
1984 * otherwise
1985 */
1986int
1987xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
1988 int i, l;
1989 xmlNodePtr cur;
1990
1991 if (xmlXPathNodeSetIsEmpty(nodes1) ||
1992 xmlXPathNodeSetIsEmpty(nodes2))
1993 return(0);
1994
1995 l = xmlXPathNodeSetGetLength(nodes1);
1996 for (i = 0; i < l; i++) {
1997 cur = xmlXPathNodeSetItem(nodes1, i);
1998 if (xmlXPathNodeSetContains(nodes2, cur))
1999 return(1);
2000 }
2001 return(0);
2002}
2003
2004/**
2005 * xmlXPathNodeLeadingSorted:
2006 * @nodes: a node-set, sorted by document order
2007 * @node: a node
2008 *
2009 * Implements the EXSLT - Sets leading() function:
2010 * node-set set:leading (node-set, node-set)
2011 *
2012 * Returns the nodes in @nodes that precede @node in document order,
2013 * @nodes if @node is NULL or an empty node-set if @nodes
2014 * doesn't contain @node
2015 */
2016xmlNodeSetPtr
2017xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2018 int i, l;
2019 xmlNodePtr cur;
2020 xmlNodeSetPtr ret;
2021
2022 if (node == NULL)
2023 return(nodes);
2024
2025 ret = xmlXPathNodeSetCreate(NULL);
2026 if (xmlXPathNodeSetIsEmpty(nodes) ||
2027 (!xmlXPathNodeSetContains(nodes, node)))
2028 return(ret);
2029
2030 l = xmlXPathNodeSetGetLength(nodes);
2031 for (i = 0; i < l; i++) {
2032 cur = xmlXPathNodeSetItem(nodes, i);
2033 if (cur == node)
2034 break;
2035 xmlXPathNodeSetAddUnique(ret, cur);
2036 }
2037 return(ret);
2038}
2039
2040/**
2041 * xmlXPathNodeLeading:
2042 * @nodes: a node-set
2043 * @node: a node
2044 *
2045 * Implements the EXSLT - Sets leading() function:
2046 * node-set set:leading (node-set, node-set)
2047 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2048 * is called.
2049 *
2050 * Returns the nodes in @nodes that precede @node in document order,
2051 * @nodes if @node is NULL or an empty node-set if @nodes
2052 * doesn't contain @node
2053 */
2054xmlNodeSetPtr
2055xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2056 xmlXPathNodeSetSort(nodes);
2057 return(xmlXPathNodeLeadingSorted(nodes, node));
2058}
2059
2060/**
2061 * xmlXPathLeadingSorted:
2062 * @nodes1: a node-set, sorted by document order
2063 * @nodes2: a node-set, sorted by document order
2064 *
2065 * Implements the EXSLT - Sets leading() function:
2066 * node-set set:leading (node-set, node-set)
2067 *
2068 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2069 * in document order, @nodes1 if @nodes2 is NULL or empty or
2070 * an empty node-set if @nodes1 doesn't contain @nodes2
2071 */
2072xmlNodeSetPtr
2073xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2074 if (xmlXPathNodeSetIsEmpty(nodes2))
2075 return(nodes1);
2076 return(xmlXPathNodeLeadingSorted(nodes1,
2077 xmlXPathNodeSetItem(nodes2, 1)));
2078}
2079
2080/**
2081 * xmlXPathLeading:
2082 * @nodes1: a node-set
2083 * @nodes2: a node-set
2084 *
2085 * Implements the EXSLT - Sets leading() function:
2086 * node-set set:leading (node-set, node-set)
2087 * @nodes1 and @nodes2 are sorted by document order, then
2088 * #exslSetsLeadingSorted is called.
2089 *
2090 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2091 * in document order, @nodes1 if @nodes2 is NULL or empty or
2092 * an empty node-set if @nodes1 doesn't contain @nodes2
2093 */
2094xmlNodeSetPtr
2095xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2096 if (xmlXPathNodeSetIsEmpty(nodes2))
2097 return(nodes1);
2098 if (xmlXPathNodeSetIsEmpty(nodes1))
2099 return(xmlXPathNodeSetCreate(NULL));
2100 xmlXPathNodeSetSort(nodes1);
2101 xmlXPathNodeSetSort(nodes2);
2102 return(xmlXPathNodeLeadingSorted(nodes1,
2103 xmlXPathNodeSetItem(nodes2, 1)));
2104}
2105
2106/**
2107 * xmlXPathNodeTrailingSorted:
2108 * @nodes: a node-set, sorted by document order
2109 * @node: a node
2110 *
2111 * Implements the EXSLT - Sets trailing() function:
2112 * node-set set:trailing (node-set, node-set)
2113 *
2114 * Returns the nodes in @nodes that follow @node in document order,
2115 * @nodes if @node is NULL or an empty node-set if @nodes
2116 * doesn't contain @node
2117 */
2118xmlNodeSetPtr
2119xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2120 int i, l;
2121 xmlNodePtr cur;
2122 xmlNodeSetPtr ret;
2123
2124 if (node == NULL)
2125 return(nodes);
2126
2127 ret = xmlXPathNodeSetCreate(NULL);
2128 if (xmlXPathNodeSetIsEmpty(nodes) ||
2129 (!xmlXPathNodeSetContains(nodes, node)))
2130 return(ret);
2131
2132 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002133 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002134 cur = xmlXPathNodeSetItem(nodes, i);
2135 if (cur == node)
2136 break;
2137 xmlXPathNodeSetAddUnique(ret, cur);
2138 }
2139 return(ret);
2140}
2141
2142/**
2143 * xmlXPathNodeTrailing:
2144 * @nodes: a node-set
2145 * @node: a node
2146 *
2147 * Implements the EXSLT - Sets trailing() function:
2148 * node-set set:trailing (node-set, node-set)
2149 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2150 * is called.
2151 *
2152 * Returns the nodes in @nodes that follow @node in document order,
2153 * @nodes if @node is NULL or an empty node-set if @nodes
2154 * doesn't contain @node
2155 */
2156xmlNodeSetPtr
2157xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2158 xmlXPathNodeSetSort(nodes);
2159 return(xmlXPathNodeTrailingSorted(nodes, node));
2160}
2161
2162/**
2163 * xmlXPathTrailingSorted:
2164 * @nodes1: a node-set, sorted by document order
2165 * @nodes2: a node-set, sorted by document order
2166 *
2167 * Implements the EXSLT - Sets trailing() function:
2168 * node-set set:trailing (node-set, node-set)
2169 *
2170 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2171 * in document order, @nodes1 if @nodes2 is NULL or empty or
2172 * an empty node-set if @nodes1 doesn't contain @nodes2
2173 */
2174xmlNodeSetPtr
2175xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2176 if (xmlXPathNodeSetIsEmpty(nodes2))
2177 return(nodes1);
2178 return(xmlXPathNodeTrailingSorted(nodes1,
2179 xmlXPathNodeSetItem(nodes2, 0)));
2180}
2181
2182/**
2183 * xmlXPathTrailing:
2184 * @nodes1: a node-set
2185 * @nodes2: a node-set
2186 *
2187 * Implements the EXSLT - Sets trailing() function:
2188 * node-set set:trailing (node-set, node-set)
2189 * @nodes1 and @nodes2 are sorted by document order, then
2190 * #xmlXPathTrailingSorted is called.
2191 *
2192 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2193 * in document order, @nodes1 if @nodes2 is NULL or empty or
2194 * an empty node-set if @nodes1 doesn't contain @nodes2
2195 */
2196xmlNodeSetPtr
2197xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2198 if (xmlXPathNodeSetIsEmpty(nodes2))
2199 return(nodes1);
2200 if (xmlXPathNodeSetIsEmpty(nodes1))
2201 return(xmlXPathNodeSetCreate(NULL));
2202 xmlXPathNodeSetSort(nodes1);
2203 xmlXPathNodeSetSort(nodes2);
2204 return(xmlXPathNodeTrailingSorted(nodes1,
2205 xmlXPathNodeSetItem(nodes2, 0)));
2206}
2207
Owen Taylor3473f882001-02-23 17:55:21 +00002208/************************************************************************
2209 * *
2210 * Routines to handle extra functions *
2211 * *
2212 ************************************************************************/
2213
2214/**
2215 * xmlXPathRegisterFunc:
2216 * @ctxt: the XPath context
2217 * @name: the function name
2218 * @f: the function implementation or NULL
2219 *
2220 * Register a new function. If @f is NULL it unregisters the function
2221 *
2222 * Returns 0 in case of success, -1 in case of error
2223 */
2224int
2225xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2226 xmlXPathFunction f) {
2227 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2228}
2229
2230/**
2231 * xmlXPathRegisterFuncNS:
2232 * @ctxt: the XPath context
2233 * @name: the function name
2234 * @ns_uri: the function namespace URI
2235 * @f: the function implementation or NULL
2236 *
2237 * Register a new function. If @f is NULL it unregisters the function
2238 *
2239 * Returns 0 in case of success, -1 in case of error
2240 */
2241int
2242xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2243 const xmlChar *ns_uri, xmlXPathFunction f) {
2244 if (ctxt == NULL)
2245 return(-1);
2246 if (name == NULL)
2247 return(-1);
2248
2249 if (ctxt->funcHash == NULL)
2250 ctxt->funcHash = xmlHashCreate(0);
2251 if (ctxt->funcHash == NULL)
2252 return(-1);
2253 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2254}
2255
2256/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002257 * xmlXPathRegisterFuncLookup:
2258 * @ctxt: the XPath context
2259 * @f: the lookup function
2260 * @data: the lookup data
2261 *
2262 * Registers an external mecanism to do function lookup.
2263 */
2264void
2265xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2266 xmlXPathFuncLookupFunc f,
2267 void *funcCtxt) {
2268 if (ctxt == NULL)
2269 return;
2270 ctxt->funcLookupFunc = (void *) f;
2271 ctxt->funcLookupData = funcCtxt;
2272}
2273
2274/**
Owen Taylor3473f882001-02-23 17:55:21 +00002275 * xmlXPathFunctionLookup:
2276 * @ctxt: the XPath context
2277 * @name: the function name
2278 *
2279 * Search in the Function array of the context for the given
2280 * function.
2281 *
2282 * Returns the xmlXPathFunction or NULL if not found
2283 */
2284xmlXPathFunction
2285xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002286 if (ctxt == NULL)
2287 return (NULL);
2288
2289 if (ctxt->funcLookupFunc != NULL) {
2290 xmlXPathFunction ret;
2291
2292 ret = ((xmlXPathFuncLookupFunc) ctxt->funcLookupFunc)
2293 (ctxt->funcLookupData, name, NULL);
2294 if (ret != NULL)
2295 return(ret);
2296 }
Owen Taylor3473f882001-02-23 17:55:21 +00002297 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2298}
2299
2300/**
2301 * xmlXPathFunctionLookupNS:
2302 * @ctxt: the XPath context
2303 * @name: the function name
2304 * @ns_uri: the function namespace URI
2305 *
2306 * Search in the Function array of the context for the given
2307 * function.
2308 *
2309 * Returns the xmlXPathFunction or NULL if not found
2310 */
2311xmlXPathFunction
2312xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2313 const xmlChar *ns_uri) {
2314 if (ctxt == NULL)
2315 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002316 if (name == NULL)
2317 return(NULL);
2318
Thomas Broyerba4ad322001-07-26 16:55:21 +00002319 if (ctxt->funcLookupFunc != NULL) {
2320 xmlXPathFunction ret;
2321
2322 ret = ((xmlXPathFuncLookupFunc) ctxt->funcLookupFunc)
2323 (ctxt->funcLookupData, name, ns_uri);
2324 if (ret != NULL)
2325 return(ret);
2326 }
2327
2328 if (ctxt->funcHash == NULL)
2329 return(NULL);
2330
Owen Taylor3473f882001-02-23 17:55:21 +00002331 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2332}
2333
2334/**
2335 * xmlXPathRegisteredFuncsCleanup:
2336 * @ctxt: the XPath context
2337 *
2338 * Cleanup the XPath context data associated to registered functions
2339 */
2340void
2341xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2342 if (ctxt == NULL)
2343 return;
2344
2345 xmlHashFree(ctxt->funcHash, NULL);
2346 ctxt->funcHash = NULL;
2347}
2348
2349/************************************************************************
2350 * *
2351 * Routines to handle Variable *
2352 * *
2353 ************************************************************************/
2354
2355/**
2356 * xmlXPathRegisterVariable:
2357 * @ctxt: the XPath context
2358 * @name: the variable name
2359 * @value: the variable value or NULL
2360 *
2361 * Register a new variable value. If @value is NULL it unregisters
2362 * the variable
2363 *
2364 * Returns 0 in case of success, -1 in case of error
2365 */
2366int
2367xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2368 xmlXPathObjectPtr value) {
2369 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2370}
2371
2372/**
2373 * xmlXPathRegisterVariableNS:
2374 * @ctxt: the XPath context
2375 * @name: the variable name
2376 * @ns_uri: the variable namespace URI
2377 * @value: the variable value or NULL
2378 *
2379 * Register a new variable value. If @value is NULL it unregisters
2380 * the variable
2381 *
2382 * Returns 0 in case of success, -1 in case of error
2383 */
2384int
2385xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2386 const xmlChar *ns_uri,
2387 xmlXPathObjectPtr value) {
2388 if (ctxt == NULL)
2389 return(-1);
2390 if (name == NULL)
2391 return(-1);
2392
2393 if (ctxt->varHash == NULL)
2394 ctxt->varHash = xmlHashCreate(0);
2395 if (ctxt->varHash == NULL)
2396 return(-1);
2397 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2398 (void *) value,
2399 (xmlHashDeallocator)xmlXPathFreeObject));
2400}
2401
2402/**
2403 * xmlXPathRegisterVariableLookup:
2404 * @ctxt: the XPath context
2405 * @f: the lookup function
2406 * @data: the lookup data
2407 *
2408 * register an external mechanism to do variable lookup
2409 */
2410void
2411xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2412 xmlXPathVariableLookupFunc f, void *data) {
2413 if (ctxt == NULL)
2414 return;
2415 ctxt->varLookupFunc = (void *) f;
2416 ctxt->varLookupData = data;
2417}
2418
2419/**
2420 * xmlXPathVariableLookup:
2421 * @ctxt: the XPath context
2422 * @name: the variable name
2423 *
2424 * Search in the Variable array of the context for the given
2425 * variable value.
2426 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002427 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002428 */
2429xmlXPathObjectPtr
2430xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2431 if (ctxt == NULL)
2432 return(NULL);
2433
2434 if (ctxt->varLookupFunc != NULL) {
2435 xmlXPathObjectPtr ret;
2436
2437 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2438 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002439 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002440 }
2441 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2442}
2443
2444/**
2445 * xmlXPathVariableLookupNS:
2446 * @ctxt: the XPath context
2447 * @name: the variable name
2448 * @ns_uri: the variable namespace URI
2449 *
2450 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002451 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002452 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002453 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002454 */
2455xmlXPathObjectPtr
2456xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2457 const xmlChar *ns_uri) {
2458 if (ctxt == NULL)
2459 return(NULL);
2460
2461 if (ctxt->varLookupFunc != NULL) {
2462 xmlXPathObjectPtr ret;
2463
2464 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2465 (ctxt->varLookupData, name, ns_uri);
2466 if (ret != NULL) return(ret);
2467 }
2468
2469 if (ctxt->varHash == NULL)
2470 return(NULL);
2471 if (name == NULL)
2472 return(NULL);
2473
Daniel Veillard8c357d52001-07-03 23:43:33 +00002474 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2475 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002476}
2477
2478/**
2479 * xmlXPathRegisteredVariablesCleanup:
2480 * @ctxt: the XPath context
2481 *
2482 * Cleanup the XPath context data associated to registered variables
2483 */
2484void
2485xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2486 if (ctxt == NULL)
2487 return;
2488
Daniel Veillard76d66f42001-05-16 21:05:17 +00002489 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002490 ctxt->varHash = NULL;
2491}
2492
2493/**
2494 * xmlXPathRegisterNs:
2495 * @ctxt: the XPath context
2496 * @prefix: the namespace prefix
2497 * @ns_uri: the namespace name
2498 *
2499 * Register a new namespace. If @ns_uri is NULL it unregisters
2500 * the namespace
2501 *
2502 * Returns 0 in case of success, -1 in case of error
2503 */
2504int
2505xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2506 const xmlChar *ns_uri) {
2507 if (ctxt == NULL)
2508 return(-1);
2509 if (prefix == NULL)
2510 return(-1);
2511
2512 if (ctxt->nsHash == NULL)
2513 ctxt->nsHash = xmlHashCreate(10);
2514 if (ctxt->nsHash == NULL)
2515 return(-1);
2516 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) ns_uri,
2517 (xmlHashDeallocator)xmlFree));
2518}
2519
2520/**
2521 * xmlXPathNsLookup:
2522 * @ctxt: the XPath context
2523 * @prefix: the namespace prefix value
2524 *
2525 * Search in the namespace declaration array of the context for the given
2526 * namespace name associated to the given prefix
2527 *
2528 * Returns the value or NULL if not found
2529 */
2530const xmlChar *
2531xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2532 if (ctxt == NULL)
2533 return(NULL);
2534 if (prefix == NULL)
2535 return(NULL);
2536
2537#ifdef XML_XML_NAMESPACE
2538 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
2539 return(XML_XML_NAMESPACE);
2540#endif
2541
Daniel Veillardc8f620b2001-04-30 20:31:33 +00002542 if (ctxt->namespaces != NULL) {
2543 int i;
2544
2545 for (i = 0;i < ctxt->nsNr;i++) {
2546 if ((ctxt->namespaces[i] != NULL) &&
2547 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
2548 return(ctxt->namespaces[i]->href);
2549 }
2550 }
Owen Taylor3473f882001-02-23 17:55:21 +00002551
2552 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
2553}
2554
2555/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002556 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00002557 * @ctxt: the XPath context
2558 *
2559 * Cleanup the XPath context data associated to registered variables
2560 */
2561void
2562xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2563 if (ctxt == NULL)
2564 return;
2565
2566 xmlHashFree(ctxt->nsHash, NULL);
2567 ctxt->nsHash = NULL;
2568}
2569
2570/************************************************************************
2571 * *
2572 * Routines to handle Values *
2573 * *
2574 ************************************************************************/
2575
2576/* Allocations are terrible, one need to optimize all this !!! */
2577
2578/**
2579 * xmlXPathNewFloat:
2580 * @val: the double value
2581 *
2582 * Create a new xmlXPathObjectPtr of type double and of value @val
2583 *
2584 * Returns the newly created object.
2585 */
2586xmlXPathObjectPtr
2587xmlXPathNewFloat(double val) {
2588 xmlXPathObjectPtr ret;
2589
2590 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2591 if (ret == NULL) {
2592 xmlGenericError(xmlGenericErrorContext,
2593 "xmlXPathNewFloat: out of memory\n");
2594 return(NULL);
2595 }
2596 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2597 ret->type = XPATH_NUMBER;
2598 ret->floatval = val;
2599 return(ret);
2600}
2601
2602/**
2603 * xmlXPathNewBoolean:
2604 * @val: the boolean value
2605 *
2606 * Create a new xmlXPathObjectPtr of type boolean and of value @val
2607 *
2608 * Returns the newly created object.
2609 */
2610xmlXPathObjectPtr
2611xmlXPathNewBoolean(int val) {
2612 xmlXPathObjectPtr ret;
2613
2614 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2615 if (ret == NULL) {
2616 xmlGenericError(xmlGenericErrorContext,
2617 "xmlXPathNewBoolean: out of memory\n");
2618 return(NULL);
2619 }
2620 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2621 ret->type = XPATH_BOOLEAN;
2622 ret->boolval = (val != 0);
2623 return(ret);
2624}
2625
2626/**
2627 * xmlXPathNewString:
2628 * @val: the xmlChar * value
2629 *
2630 * Create a new xmlXPathObjectPtr of type string and of value @val
2631 *
2632 * Returns the newly created object.
2633 */
2634xmlXPathObjectPtr
2635xmlXPathNewString(const xmlChar *val) {
2636 xmlXPathObjectPtr ret;
2637
2638 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2639 if (ret == NULL) {
2640 xmlGenericError(xmlGenericErrorContext,
2641 "xmlXPathNewString: out of memory\n");
2642 return(NULL);
2643 }
2644 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2645 ret->type = XPATH_STRING;
2646 if (val != NULL)
2647 ret->stringval = xmlStrdup(val);
2648 else
2649 ret->stringval = xmlStrdup((const xmlChar *)"");
2650 return(ret);
2651}
2652
2653/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002654 * xmlXPathWrapString:
2655 * @val: the xmlChar * value
2656 *
2657 * Wraps the @val string into an XPath object.
2658 *
2659 * Returns the newly created object.
2660 */
2661xmlXPathObjectPtr
2662xmlXPathWrapString (xmlChar *val) {
2663 xmlXPathObjectPtr ret;
2664
2665 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2666 if (ret == NULL) {
2667 xmlGenericError(xmlGenericErrorContext,
2668 "xmlXPathWrapString: out of memory\n");
2669 return(NULL);
2670 }
2671 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2672 ret->type = XPATH_STRING;
2673 ret->stringval = val;
2674 return(ret);
2675}
2676
2677/**
Owen Taylor3473f882001-02-23 17:55:21 +00002678 * xmlXPathNewCString:
2679 * @val: the char * value
2680 *
2681 * Create a new xmlXPathObjectPtr of type string and of value @val
2682 *
2683 * Returns the newly created object.
2684 */
2685xmlXPathObjectPtr
2686xmlXPathNewCString(const char *val) {
2687 xmlXPathObjectPtr ret;
2688
2689 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2690 if (ret == NULL) {
2691 xmlGenericError(xmlGenericErrorContext,
2692 "xmlXPathNewCString: out of memory\n");
2693 return(NULL);
2694 }
2695 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2696 ret->type = XPATH_STRING;
2697 ret->stringval = xmlStrdup(BAD_CAST val);
2698 return(ret);
2699}
2700
2701/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002702 * xmlXPathWrapCString:
2703 * @val: the char * value
2704 *
2705 * Wraps a string into an XPath object.
2706 *
2707 * Returns the newly created object.
2708 */
2709xmlXPathObjectPtr
2710xmlXPathWrapCString (char * val) {
2711 return(xmlXPathWrapString((xmlChar *)(val)));
2712}
2713
2714/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002715 * xmlXPathWrapExternal:
2716 * @val: the user data
2717 *
2718 * Wraps the @val data into an XPath object.
2719 *
2720 * Returns the newly created object.
2721 */
2722xmlXPathObjectPtr
2723xmlXPathWrapExternal (void *val) {
2724 xmlXPathObjectPtr ret;
2725
2726 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2727 if (ret == NULL) {
2728 xmlGenericError(xmlGenericErrorContext,
2729 "xmlXPathWrapString: out of memory\n");
2730 return(NULL);
2731 }
2732 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2733 ret->type = XPATH_USERS;
2734 ret->user = val;
2735 return(ret);
2736}
2737
2738/**
Owen Taylor3473f882001-02-23 17:55:21 +00002739 * xmlXPathObjectCopy:
2740 * @val: the original object
2741 *
2742 * allocate a new copy of a given object
2743 *
2744 * Returns the newly created object.
2745 */
2746xmlXPathObjectPtr
2747xmlXPathObjectCopy(xmlXPathObjectPtr val) {
2748 xmlXPathObjectPtr ret;
2749
2750 if (val == NULL)
2751 return(NULL);
2752
2753 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2754 if (ret == NULL) {
2755 xmlGenericError(xmlGenericErrorContext,
2756 "xmlXPathObjectCopy: out of memory\n");
2757 return(NULL);
2758 }
2759 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
2760 switch (val->type) {
2761 case XPATH_BOOLEAN:
2762 case XPATH_NUMBER:
2763 case XPATH_POINT:
2764 case XPATH_RANGE:
2765 break;
2766 case XPATH_STRING:
2767 ret->stringval = xmlStrdup(val->stringval);
2768 break;
2769 case XPATH_XSLT_TREE:
2770 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002771 (val->nodesetval->nodeTab != NULL)) {
2772 ret->boolval = 1;
Daniel Veillard6ab38382001-10-06 13:08:27 +00002773 ret->user = xmlDocCopyNode(val->nodesetval->nodeTab[0],
2774 val->nodesetval->nodeTab[0]->doc, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00002775 ret->nodesetval = xmlXPathNodeSetCreate(
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002776 (xmlNodePtr) ret->user);
2777 } else
Owen Taylor3473f882001-02-23 17:55:21 +00002778 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002779 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00002780 break;
2781 case XPATH_NODESET:
2782 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002783 /* Do not deallocate the copied tree value */
2784 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002785 break;
2786 case XPATH_LOCATIONSET:
2787#ifdef LIBXML_XPTR_ENABLED
2788 {
2789 xmlLocationSetPtr loc = val->user;
2790 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
2791 break;
2792 }
2793#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00002794 case XPATH_USERS:
2795 ret->user = val->user;
2796 break;
2797 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00002798 xmlGenericError(xmlGenericErrorContext,
2799 "xmlXPathObjectCopy: unsupported type %d\n",
2800 val->type);
2801 break;
2802 }
2803 return(ret);
2804}
2805
2806/**
2807 * xmlXPathFreeObject:
2808 * @obj: the object to free
2809 *
2810 * Free up an xmlXPathObjectPtr object.
2811 */
2812void
2813xmlXPathFreeObject(xmlXPathObjectPtr obj) {
2814 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002815 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00002816 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002817 if (obj->user != NULL) {
2818 xmlFreeNodeList((xmlNodePtr) obj->user);
2819 xmlXPathFreeNodeSet(obj->nodesetval);
2820 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00002821 xmlXPathFreeValueTree(obj->nodesetval);
2822 } else {
2823 if (obj->nodesetval != NULL)
2824 xmlXPathFreeNodeSet(obj->nodesetval);
2825 }
Owen Taylor3473f882001-02-23 17:55:21 +00002826#ifdef LIBXML_XPTR_ENABLED
2827 } else if (obj->type == XPATH_LOCATIONSET) {
2828 if (obj->user != NULL)
2829 xmlXPtrFreeLocationSet(obj->user);
2830#endif
2831 } else if (obj->type == XPATH_STRING) {
2832 if (obj->stringval != NULL)
2833 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00002834 }
2835
Owen Taylor3473f882001-02-23 17:55:21 +00002836 xmlFree(obj);
2837}
2838
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002839
2840/************************************************************************
2841 * *
2842 * Type Casting Routines *
2843 * *
2844 ************************************************************************/
2845
2846/**
2847 * xmlXPathCastBooleanToString:
2848 * @val: a boolean
2849 *
2850 * Converts a boolean to its string value.
2851 *
2852 * Returns a newly allocated string.
2853 */
2854xmlChar *
2855xmlXPathCastBooleanToString (int val) {
2856 xmlChar *ret;
2857 if (val)
2858 ret = xmlStrdup((const xmlChar *) "true");
2859 else
2860 ret = xmlStrdup((const xmlChar *) "false");
2861 return(ret);
2862}
2863
2864/**
2865 * xmlXPathCastNumberToString:
2866 * @val: a number
2867 *
2868 * Converts a number to its string value.
2869 *
2870 * Returns a newly allocated string.
2871 */
2872xmlChar *
2873xmlXPathCastNumberToString (double val) {
2874 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00002875 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002876 case 1:
2877 ret = xmlStrdup((const xmlChar *) "+Infinity");
2878 break;
2879 case -1:
2880 ret = xmlStrdup((const xmlChar *) "-Infinity");
2881 break;
2882 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00002883 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002884 ret = xmlStrdup((const xmlChar *) "NaN");
2885 } else {
2886 /* could be improved */
2887 char buf[100];
2888 xmlXPathFormatNumber(val, buf, 100);
2889 ret = xmlStrdup((const xmlChar *) buf);
2890 }
2891 }
2892 return(ret);
2893}
2894
2895/**
2896 * xmlXPathCastNodeToString:
2897 * @node: a node
2898 *
2899 * Converts a node to its string value.
2900 *
2901 * Returns a newly allocated string.
2902 */
2903xmlChar *
2904xmlXPathCastNodeToString (xmlNodePtr node) {
2905 return(xmlNodeGetContent(node));
2906}
2907
2908/**
2909 * xmlXPathCastNodeSetToString:
2910 * @ns: a node-set
2911 *
2912 * Converts a node-set to its string value.
2913 *
2914 * Returns a newly allocated string.
2915 */
2916xmlChar *
2917xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
2918 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
2919 return(xmlStrdup((const xmlChar *) ""));
2920
2921 xmlXPathNodeSetSort(ns);
2922 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
2923}
2924
2925/**
2926 * xmlXPathCastToString:
2927 * @val: an XPath object
2928 *
2929 * Converts an existing object to its string() equivalent
2930 *
2931 * Returns the string value of the object, NULL in case of error.
2932 * A new string is allocated only if needed (val isn't a
2933 * string object).
2934 */
2935xmlChar *
2936xmlXPathCastToString(xmlXPathObjectPtr val) {
2937 xmlChar *ret = NULL;
2938
2939 if (val == NULL)
2940 return(xmlStrdup((const xmlChar *) ""));
2941 switch (val->type) {
2942 case XPATH_UNDEFINED:
2943#ifdef DEBUG_EXPR
2944 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
2945#endif
2946 ret = xmlStrdup((const xmlChar *) "");
2947 break;
2948 case XPATH_XSLT_TREE:
2949 case XPATH_NODESET:
2950 ret = xmlXPathCastNodeSetToString(val->nodesetval);
2951 break;
2952 case XPATH_STRING:
2953 return(val->stringval);
2954 case XPATH_BOOLEAN:
2955 ret = xmlXPathCastBooleanToString(val->boolval);
2956 break;
2957 case XPATH_NUMBER: {
2958 ret = xmlXPathCastNumberToString(val->floatval);
2959 break;
2960 }
2961 case XPATH_USERS:
2962 case XPATH_POINT:
2963 case XPATH_RANGE:
2964 case XPATH_LOCATIONSET:
2965 TODO
2966 ret = xmlStrdup((const xmlChar *) "");
2967 break;
2968 }
2969 return(ret);
2970}
2971
2972/**
2973 * xmlXPathConvertString:
2974 * @val: an XPath object
2975 *
2976 * Converts an existing object to its string() equivalent
2977 *
2978 * Returns the new object, the old one is freed (or the operation
2979 * is done directly on @val)
2980 */
2981xmlXPathObjectPtr
2982xmlXPathConvertString(xmlXPathObjectPtr val) {
2983 xmlChar *res = NULL;
2984
2985 if (val == NULL)
2986 return(xmlXPathNewCString(""));
2987
2988 switch (val->type) {
2989 case XPATH_UNDEFINED:
2990#ifdef DEBUG_EXPR
2991 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2992#endif
2993 break;
2994 case XPATH_XSLT_TREE:
2995 case XPATH_NODESET:
2996 res = xmlXPathCastNodeSetToString(val->nodesetval);
2997 break;
2998 case XPATH_STRING:
2999 return(val);
3000 case XPATH_BOOLEAN:
3001 res = xmlXPathCastBooleanToString(val->boolval);
3002 break;
3003 case XPATH_NUMBER:
3004 res = xmlXPathCastNumberToString(val->floatval);
3005 break;
3006 case XPATH_USERS:
3007 case XPATH_POINT:
3008 case XPATH_RANGE:
3009 case XPATH_LOCATIONSET:
3010 TODO;
3011 break;
3012 }
3013 xmlXPathFreeObject(val);
3014 if (res == NULL)
3015 return(xmlXPathNewCString(""));
3016 return(xmlXPathWrapString(res));
3017}
3018
3019/**
3020 * xmlXPathCastBooleanToNumber:
3021 * @val: a boolean
3022 *
3023 * Converts a boolean to its number value
3024 *
3025 * Returns the number value
3026 */
3027double
3028xmlXPathCastBooleanToNumber(int val) {
3029 if (val)
3030 return(1.0);
3031 return(0.0);
3032}
3033
3034/**
3035 * xmlXPathCastStringToNumber:
3036 * @val: a string
3037 *
3038 * Converts a string to its number value
3039 *
3040 * Returns the number value
3041 */
3042double
3043xmlXPathCastStringToNumber(const xmlChar * val) {
3044 return(xmlXPathStringEvalNumber(val));
3045}
3046
3047/**
3048 * xmlXPathCastNodeToNumber:
3049 * @node: a node
3050 *
3051 * Converts a node to its number value
3052 *
3053 * Returns the number value
3054 */
3055double
3056xmlXPathCastNodeToNumber (xmlNodePtr node) {
3057 xmlChar *strval;
3058 double ret;
3059
3060 if (node == NULL)
3061 return(xmlXPathNAN);
3062 strval = xmlXPathCastNodeToString(node);
3063 if (strval == NULL)
3064 return(xmlXPathNAN);
3065 ret = xmlXPathCastStringToNumber(strval);
3066 xmlFree(strval);
3067
3068 return(ret);
3069}
3070
3071/**
3072 * xmlXPathCastNodeSetToNumber:
3073 * @ns: a node-set
3074 *
3075 * Converts a node-set to its number value
3076 *
3077 * Returns the number value
3078 */
3079double
3080xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3081 xmlChar *str;
3082 double ret;
3083
3084 if (ns == NULL)
3085 return(xmlXPathNAN);
3086 str = xmlXPathCastNodeSetToString(ns);
3087 ret = xmlXPathCastStringToNumber(str);
3088 xmlFree(str);
3089 return(ret);
3090}
3091
3092/**
3093 * xmlXPathCastToNumber:
3094 * @val: an XPath object
3095 *
3096 * Converts an XPath object to its number value
3097 *
3098 * Returns the number value
3099 */
3100double
3101xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3102 double ret = 0.0;
3103
3104 if (val == NULL)
3105 return(xmlXPathNAN);
3106 switch (val->type) {
3107 case XPATH_UNDEFINED:
3108#ifdef DEGUB_EXPR
3109 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3110#endif
3111 ret = xmlXPathNAN;
3112 break;
3113 case XPATH_XSLT_TREE:
3114 case XPATH_NODESET:
3115 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3116 break;
3117 case XPATH_STRING:
3118 ret = xmlXPathCastStringToNumber(val->stringval);
3119 break;
3120 case XPATH_NUMBER:
3121 ret = val->floatval;
3122 break;
3123 case XPATH_BOOLEAN:
3124 ret = xmlXPathCastBooleanToNumber(val->boolval);
3125 break;
3126 case XPATH_USERS:
3127 case XPATH_POINT:
3128 case XPATH_RANGE:
3129 case XPATH_LOCATIONSET:
3130 TODO;
3131 ret = xmlXPathNAN;
3132 break;
3133 }
3134 return(ret);
3135}
3136
3137/**
3138 * xmlXPathConvertNumber:
3139 * @val: an XPath object
3140 *
3141 * Converts an existing object to its number() equivalent
3142 *
3143 * Returns the new object, the old one is freed (or the operation
3144 * is done directly on @val)
3145 */
3146xmlXPathObjectPtr
3147xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3148 xmlXPathObjectPtr ret;
3149
3150 if (val == NULL)
3151 return(xmlXPathNewFloat(0.0));
3152 if (val->type == XPATH_NUMBER)
3153 return(val);
3154 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3155 xmlXPathFreeObject(val);
3156 return(ret);
3157}
3158
3159/**
3160 * xmlXPathCastNumberToBoolean:
3161 * @val: a number
3162 *
3163 * Converts a number to its boolean value
3164 *
3165 * Returns the boolean value
3166 */
3167int
3168xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003169 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003170 return(0);
3171 return(1);
3172}
3173
3174/**
3175 * xmlXPathCastStringToBoolean:
3176 * @val: a string
3177 *
3178 * Converts a string to its boolean value
3179 *
3180 * Returns the boolean value
3181 */
3182int
3183xmlXPathCastStringToBoolean (const xmlChar *val) {
3184 if ((val == NULL) || (xmlStrlen(val) == 0))
3185 return(0);
3186 return(1);
3187}
3188
3189/**
3190 * xmlXPathCastNodeSetToBoolean:
3191 * @ns: a node-set
3192 *
3193 * Converts a node-set to its boolean value
3194 *
3195 * Returns the boolean value
3196 */
3197int
3198xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3199 if ((ns == NULL) || (ns->nodeNr == 0))
3200 return(0);
3201 return(1);
3202}
3203
3204/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003205 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003206 * @val: an XPath object
3207 *
3208 * Converts an XPath object to its boolean value
3209 *
3210 * Returns the boolean value
3211 */
3212int
3213xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3214 int ret = 0;
3215
3216 if (val == NULL)
3217 return(0);
3218 switch (val->type) {
3219 case XPATH_UNDEFINED:
3220#ifdef DEBUG_EXPR
3221 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3222#endif
3223 ret = 0;
3224 break;
3225 case XPATH_XSLT_TREE:
3226 case XPATH_NODESET:
3227 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3228 break;
3229 case XPATH_STRING:
3230 ret = xmlXPathCastStringToBoolean(val->stringval);
3231 break;
3232 case XPATH_NUMBER:
3233 ret = xmlXPathCastNumberToBoolean(val->floatval);
3234 break;
3235 case XPATH_BOOLEAN:
3236 ret = val->boolval;
3237 break;
3238 case XPATH_USERS:
3239 case XPATH_POINT:
3240 case XPATH_RANGE:
3241 case XPATH_LOCATIONSET:
3242 TODO;
3243 ret = 0;
3244 break;
3245 }
3246 return(ret);
3247}
3248
3249
3250/**
3251 * xmlXPathConvertBoolean:
3252 * @val: an XPath object
3253 *
3254 * Converts an existing object to its boolean() equivalent
3255 *
3256 * Returns the new object, the old one is freed (or the operation
3257 * is done directly on @val)
3258 */
3259xmlXPathObjectPtr
3260xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3261 xmlXPathObjectPtr ret;
3262
3263 if (val == NULL)
3264 return(xmlXPathNewBoolean(0));
3265 if (val->type == XPATH_BOOLEAN)
3266 return(val);
3267 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3268 xmlXPathFreeObject(val);
3269 return(ret);
3270}
3271
Owen Taylor3473f882001-02-23 17:55:21 +00003272/************************************************************************
3273 * *
3274 * Routines to handle XPath contexts *
3275 * *
3276 ************************************************************************/
3277
3278/**
3279 * xmlXPathNewContext:
3280 * @doc: the XML document
3281 *
3282 * Create a new xmlXPathContext
3283 *
3284 * Returns the xmlXPathContext just allocated.
3285 */
3286xmlXPathContextPtr
3287xmlXPathNewContext(xmlDocPtr doc) {
3288 xmlXPathContextPtr ret;
3289
3290 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3291 if (ret == NULL) {
3292 xmlGenericError(xmlGenericErrorContext,
3293 "xmlXPathNewContext: out of memory\n");
3294 return(NULL);
3295 }
3296 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3297 ret->doc = doc;
3298 ret->node = NULL;
3299
3300 ret->varHash = NULL;
3301
3302 ret->nb_types = 0;
3303 ret->max_types = 0;
3304 ret->types = NULL;
3305
3306 ret->funcHash = xmlHashCreate(0);
3307
3308 ret->nb_axis = 0;
3309 ret->max_axis = 0;
3310 ret->axis = NULL;
3311
3312 ret->nsHash = NULL;
3313 ret->user = NULL;
3314
3315 ret->contextSize = -1;
3316 ret->proximityPosition = -1;
3317
3318 xmlXPathRegisterAllFunctions(ret);
3319
3320 return(ret);
3321}
3322
3323/**
3324 * xmlXPathFreeContext:
3325 * @ctxt: the context to free
3326 *
3327 * Free up an xmlXPathContext
3328 */
3329void
3330xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3331 xmlXPathRegisteredNsCleanup(ctxt);
3332 xmlXPathRegisteredFuncsCleanup(ctxt);
3333 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003334 xmlFree(ctxt);
3335}
3336
3337/************************************************************************
3338 * *
3339 * Routines to handle XPath parser contexts *
3340 * *
3341 ************************************************************************/
3342
3343#define CHECK_CTXT(ctxt) \
3344 if (ctxt == NULL) { \
3345 xmlGenericError(xmlGenericErrorContext, \
3346 "%s:%d Internal error: ctxt == NULL\n", \
3347 __FILE__, __LINE__); \
3348 } \
3349
3350
3351#define CHECK_CONTEXT(ctxt) \
3352 if (ctxt == NULL) { \
3353 xmlGenericError(xmlGenericErrorContext, \
3354 "%s:%d Internal error: no context\n", \
3355 __FILE__, __LINE__); \
3356 } \
3357 else if (ctxt->doc == NULL) { \
3358 xmlGenericError(xmlGenericErrorContext, \
3359 "%s:%d Internal error: no document\n", \
3360 __FILE__, __LINE__); \
3361 } \
3362 else if (ctxt->doc->children == NULL) { \
3363 xmlGenericError(xmlGenericErrorContext, \
3364 "%s:%d Internal error: document without root\n", \
3365 __FILE__, __LINE__); \
3366 } \
3367
3368
3369/**
3370 * xmlXPathNewParserContext:
3371 * @str: the XPath expression
3372 * @ctxt: the XPath context
3373 *
3374 * Create a new xmlXPathParserContext
3375 *
3376 * Returns the xmlXPathParserContext just allocated.
3377 */
3378xmlXPathParserContextPtr
3379xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3380 xmlXPathParserContextPtr ret;
3381
3382 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3383 if (ret == NULL) {
3384 xmlGenericError(xmlGenericErrorContext,
3385 "xmlXPathNewParserContext: out of memory\n");
3386 return(NULL);
3387 }
3388 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3389 ret->cur = ret->base = str;
3390 ret->context = ctxt;
3391
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003392 ret->comp = xmlXPathNewCompExpr();
3393 if (ret->comp == NULL) {
3394 xmlFree(ret->valueTab);
3395 xmlFree(ret);
3396 return(NULL);
3397 }
3398
3399 return(ret);
3400}
3401
3402/**
3403 * xmlXPathCompParserContext:
3404 * @comp: the XPath compiled expression
3405 * @ctxt: the XPath context
3406 *
3407 * Create a new xmlXPathParserContext when processing a compiled expression
3408 *
3409 * Returns the xmlXPathParserContext just allocated.
3410 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003411static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003412xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3413 xmlXPathParserContextPtr ret;
3414
3415 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3416 if (ret == NULL) {
3417 xmlGenericError(xmlGenericErrorContext,
3418 "xmlXPathNewParserContext: out of memory\n");
3419 return(NULL);
3420 }
3421 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3422
Owen Taylor3473f882001-02-23 17:55:21 +00003423 /* Allocate the value stack */
3424 ret->valueTab = (xmlXPathObjectPtr *)
3425 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003426 if (ret->valueTab == NULL) {
3427 xmlFree(ret);
3428 xmlGenericError(xmlGenericErrorContext,
3429 "xmlXPathNewParserContext: out of memory\n");
3430 return(NULL);
3431 }
Owen Taylor3473f882001-02-23 17:55:21 +00003432 ret->valueNr = 0;
3433 ret->valueMax = 10;
3434 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003435
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003436 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003437 ret->comp = comp;
3438
Owen Taylor3473f882001-02-23 17:55:21 +00003439 return(ret);
3440}
3441
3442/**
3443 * xmlXPathFreeParserContext:
3444 * @ctxt: the context to free
3445 *
3446 * Free up an xmlXPathParserContext
3447 */
3448void
3449xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3450 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003451 xmlFree(ctxt->valueTab);
3452 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003453 if (ctxt->comp)
3454 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003455 xmlFree(ctxt);
3456}
3457
3458/************************************************************************
3459 * *
3460 * The implicit core function library *
3461 * *
3462 ************************************************************************/
3463
Owen Taylor3473f882001-02-23 17:55:21 +00003464/**
Daniel Veillardf06307e2001-07-03 10:35:50 +00003465 * xmlXPathNodeStringHash:
3466 * @node: a node pointer
3467 *
3468 * Function computing the beginning of the string value of the node,
3469 * used to speed up comparisons
3470 *
3471 * Returns an int usable as a hash
3472 */
3473static unsigned int
3474xmlXPathNodeValHash(xmlNodePtr node) {
3475 int len = 2;
3476 const xmlChar * string = NULL;
3477 xmlNodePtr tmp = NULL;
3478 unsigned int ret = 0;
3479
3480 if (node == NULL)
3481 return(0);
3482
3483
3484 switch (node->type) {
3485 case XML_COMMENT_NODE:
3486 case XML_PI_NODE:
3487 case XML_CDATA_SECTION_NODE:
3488 case XML_TEXT_NODE:
3489 string = node->content;
3490 if (string == NULL)
3491 return(0);
3492 if (string[0] == 0)
3493 return(0);
3494 return(((unsigned int) string[0]) +
3495 (((unsigned int) string[1]) << 8));
3496 case XML_NAMESPACE_DECL:
3497 string = ((xmlNsPtr)node)->href;
3498 if (string == NULL)
3499 return(0);
3500 if (string[0] == 0)
3501 return(0);
3502 return(((unsigned int) string[0]) +
3503 (((unsigned int) string[1]) << 8));
3504 case XML_ATTRIBUTE_NODE:
3505 tmp = ((xmlAttrPtr) node)->children;
3506 break;
3507 case XML_ELEMENT_NODE:
3508 tmp = node->children;
3509 break;
3510 default:
3511 return(0);
3512 }
3513 while (tmp != NULL) {
3514 switch (tmp->type) {
3515 case XML_COMMENT_NODE:
3516 case XML_PI_NODE:
3517 case XML_CDATA_SECTION_NODE:
3518 case XML_TEXT_NODE:
3519 string = tmp->content;
3520 break;
3521 case XML_NAMESPACE_DECL:
3522 string = ((xmlNsPtr)tmp)->href;
3523 break;
3524 default:
3525 break;
3526 }
3527 if ((string != NULL) && (string[0] != 0)) {
3528 if (string[0] == 0)
3529 return(0);
3530 if (len == 1) {
3531 return(ret + (((unsigned int) string[0]) << 8));
3532 }
3533 if (string[1] == 0) {
3534 len = 1;
3535 ret = (unsigned int) string[0];
3536 } else {
3537 return(((unsigned int) string[0]) +
3538 (((unsigned int) string[1]) << 8));
3539 }
3540 }
3541 /*
3542 * Skip to next node
3543 */
3544 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
3545 if (tmp->children->type != XML_ENTITY_DECL) {
3546 tmp = tmp->children;
3547 continue;
3548 }
3549 }
3550 if (tmp == node)
3551 break;
3552
3553 if (tmp->next != NULL) {
3554 tmp = tmp->next;
3555 continue;
3556 }
3557
3558 do {
3559 tmp = tmp->parent;
3560 if (tmp == NULL)
3561 break;
3562 if (tmp == node) {
3563 tmp = NULL;
3564 break;
3565 }
3566 if (tmp->next != NULL) {
3567 tmp = tmp->next;
3568 break;
3569 }
3570 } while (tmp != NULL);
3571 }
3572 return(ret);
3573}
3574
3575/**
3576 * xmlXPathStringHash:
3577 * @string: a string
3578 *
3579 * Function computing the beginning of the string value of the node,
3580 * used to speed up comparisons
3581 *
3582 * Returns an int usable as a hash
3583 */
3584static unsigned int
3585xmlXPathStringHash(const xmlChar * string) {
3586 if (string == NULL)
3587 return((unsigned int) 0);
3588 if (string[0] == 0)
3589 return(0);
3590 return(((unsigned int) string[0]) +
3591 (((unsigned int) string[1]) << 8));
3592}
3593
3594/**
Owen Taylor3473f882001-02-23 17:55:21 +00003595 * xmlXPathCompareNodeSetFloat:
3596 * @ctxt: the XPath Parser context
3597 * @inf: less than (1) or greater than (0)
3598 * @strict: is the comparison strict
3599 * @arg: the node set
3600 * @f: the value
3601 *
3602 * Implement the compare operation between a nodeset and a number
3603 * @ns < @val (1, 1, ...
3604 * @ns <= @val (1, 0, ...
3605 * @ns > @val (0, 1, ...
3606 * @ns >= @val (0, 0, ...
3607 *
3608 * If one object to be compared is a node-set and the other is a number,
3609 * then the comparison will be true if and only if there is a node in the
3610 * node-set such that the result of performing the comparison on the number
3611 * to be compared and on the result of converting the string-value of that
3612 * node to a number using the number function is true.
3613 *
3614 * Returns 0 or 1 depending on the results of the test.
3615 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003616static int
Owen Taylor3473f882001-02-23 17:55:21 +00003617xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
3618 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
3619 int i, ret = 0;
3620 xmlNodeSetPtr ns;
3621 xmlChar *str2;
3622
3623 if ((f == NULL) || (arg == NULL) ||
3624 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3625 xmlXPathFreeObject(arg);
3626 xmlXPathFreeObject(f);
3627 return(0);
3628 }
3629 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003630 if (ns != NULL) {
3631 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003632 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003633 if (str2 != NULL) {
3634 valuePush(ctxt,
3635 xmlXPathNewString(str2));
3636 xmlFree(str2);
3637 xmlXPathNumberFunction(ctxt, 1);
3638 valuePush(ctxt, xmlXPathObjectCopy(f));
3639 ret = xmlXPathCompareValues(ctxt, inf, strict);
3640 if (ret)
3641 break;
3642 }
3643 }
Owen Taylor3473f882001-02-23 17:55:21 +00003644 }
3645 xmlXPathFreeObject(arg);
3646 xmlXPathFreeObject(f);
3647 return(ret);
3648}
3649
3650/**
3651 * xmlXPathCompareNodeSetString:
3652 * @ctxt: the XPath Parser context
3653 * @inf: less than (1) or greater than (0)
3654 * @strict: is the comparison strict
3655 * @arg: the node set
3656 * @s: the value
3657 *
3658 * Implement the compare operation between a nodeset and a string
3659 * @ns < @val (1, 1, ...
3660 * @ns <= @val (1, 0, ...
3661 * @ns > @val (0, 1, ...
3662 * @ns >= @val (0, 0, ...
3663 *
3664 * If one object to be compared is a node-set and the other is a string,
3665 * then the comparison will be true if and only if there is a node in
3666 * the node-set such that the result of performing the comparison on the
3667 * string-value of the node and the other string is true.
3668 *
3669 * Returns 0 or 1 depending on the results of the test.
3670 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003671static int
Owen Taylor3473f882001-02-23 17:55:21 +00003672xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
3673 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
3674 int i, ret = 0;
3675 xmlNodeSetPtr ns;
3676 xmlChar *str2;
3677
3678 if ((s == NULL) || (arg == NULL) ||
3679 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3680 xmlXPathFreeObject(arg);
3681 xmlXPathFreeObject(s);
3682 return(0);
3683 }
3684 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003685 if (ns != NULL) {
3686 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003687 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003688 if (str2 != NULL) {
3689 valuePush(ctxt,
3690 xmlXPathNewString(str2));
3691 xmlFree(str2);
3692 valuePush(ctxt, xmlXPathObjectCopy(s));
3693 ret = xmlXPathCompareValues(ctxt, inf, strict);
3694 if (ret)
3695 break;
3696 }
3697 }
Owen Taylor3473f882001-02-23 17:55:21 +00003698 }
3699 xmlXPathFreeObject(arg);
3700 xmlXPathFreeObject(s);
3701 return(ret);
3702}
3703
3704/**
3705 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003706 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00003707 * @strict: is the comparison strict
3708 * @arg1: the fist node set object
3709 * @arg2: the second node set object
3710 *
3711 * Implement the compare operation on nodesets:
3712 *
3713 * If both objects to be compared are node-sets, then the comparison
3714 * will be true if and only if there is a node in the first node-set
3715 * and a node in the second node-set such that the result of performing
3716 * the comparison on the string-values of the two nodes is true.
3717 * ....
3718 * When neither object to be compared is a node-set and the operator
3719 * is <=, <, >= or >, then the objects are compared by converting both
3720 * objects to numbers and comparing the numbers according to IEEE 754.
3721 * ....
3722 * The number function converts its argument to a number as follows:
3723 * - a string that consists of optional whitespace followed by an
3724 * optional minus sign followed by a Number followed by whitespace
3725 * is converted to the IEEE 754 number that is nearest (according
3726 * to the IEEE 754 round-to-nearest rule) to the mathematical value
3727 * represented by the string; any other string is converted to NaN
3728 *
3729 * Conclusion all nodes need to be converted first to their string value
3730 * and then the comparison must be done when possible
3731 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003732static int
3733xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00003734 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3735 int i, j, init = 0;
3736 double val1;
3737 double *values2;
3738 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003739 xmlNodeSetPtr ns1;
3740 xmlNodeSetPtr ns2;
3741
3742 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003743 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
3744 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003745 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003746 }
Owen Taylor3473f882001-02-23 17:55:21 +00003747 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003748 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
3749 xmlXPathFreeObject(arg1);
3750 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003751 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003752 }
Owen Taylor3473f882001-02-23 17:55:21 +00003753
3754 ns1 = arg1->nodesetval;
3755 ns2 = arg2->nodesetval;
3756
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003757 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003758 xmlXPathFreeObject(arg1);
3759 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003760 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003761 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003762 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003763 xmlXPathFreeObject(arg1);
3764 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003765 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003766 }
Owen Taylor3473f882001-02-23 17:55:21 +00003767
3768 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
3769 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003770 xmlXPathFreeObject(arg1);
3771 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003772 return(0);
3773 }
3774 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003775 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00003776 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00003777 continue;
3778 for (j = 0;j < ns2->nodeNr;j++) {
3779 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003780 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00003781 }
Daniel Veillardcda96922001-08-21 10:56:31 +00003782 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00003783 continue;
3784 if (inf && strict)
3785 ret = (val1 < values2[j]);
3786 else if (inf && !strict)
3787 ret = (val1 <= values2[j]);
3788 else if (!inf && strict)
3789 ret = (val1 > values2[j]);
3790 else if (!inf && !strict)
3791 ret = (val1 >= values2[j]);
3792 if (ret)
3793 break;
3794 }
3795 if (ret)
3796 break;
3797 init = 1;
3798 }
3799 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003800 xmlXPathFreeObject(arg1);
3801 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003802 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003803}
3804
3805/**
3806 * xmlXPathCompareNodeSetValue:
3807 * @ctxt: the XPath Parser context
3808 * @inf: less than (1) or greater than (0)
3809 * @strict: is the comparison strict
3810 * @arg: the node set
3811 * @val: the value
3812 *
3813 * Implement the compare operation between a nodeset and a value
3814 * @ns < @val (1, 1, ...
3815 * @ns <= @val (1, 0, ...
3816 * @ns > @val (0, 1, ...
3817 * @ns >= @val (0, 0, ...
3818 *
3819 * If one object to be compared is a node-set and the other is a boolean,
3820 * then the comparison will be true if and only if the result of performing
3821 * the comparison on the boolean and on the result of converting
3822 * the node-set to a boolean using the boolean function is true.
3823 *
3824 * Returns 0 or 1 depending on the results of the test.
3825 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003826static int
Owen Taylor3473f882001-02-23 17:55:21 +00003827xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
3828 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
3829 if ((val == NULL) || (arg == NULL) ||
3830 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3831 return(0);
3832
3833 switch(val->type) {
3834 case XPATH_NUMBER:
3835 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
3836 case XPATH_NODESET:
3837 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003838 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00003839 case XPATH_STRING:
3840 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
3841 case XPATH_BOOLEAN:
3842 valuePush(ctxt, arg);
3843 xmlXPathBooleanFunction(ctxt, 1);
3844 valuePush(ctxt, val);
3845 return(xmlXPathCompareValues(ctxt, inf, strict));
3846 default:
3847 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00003848 }
3849 return(0);
3850}
3851
3852/**
3853 * xmlXPathEqualNodeSetString
3854 * @arg: the nodeset object argument
3855 * @str: the string to compare to.
3856 *
3857 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3858 * If one object to be compared is a node-set and the other is a string,
3859 * then the comparison will be true if and only if there is a node in
3860 * the node-set such that the result of performing the comparison on the
3861 * string-value of the node and the other string is true.
3862 *
3863 * Returns 0 or 1 depending on the results of the test.
3864 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003865static int
Daniel Veillardf06307e2001-07-03 10:35:50 +00003866xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str)
3867{
Owen Taylor3473f882001-02-23 17:55:21 +00003868 int i;
3869 xmlNodeSetPtr ns;
3870 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003871 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00003872
3873 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00003874 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3875 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00003876 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003877 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003878 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00003879 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00003880 if (ns->nodeNr <= 0) {
3881 if (hash == 0)
3882 return(1);
3883 return(0);
3884 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003885 for (i = 0; i < ns->nodeNr; i++) {
3886 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
3887 str2 = xmlNodeGetContent(ns->nodeTab[i]);
3888 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
3889 xmlFree(str2);
3890 return (1);
3891 }
3892 if (str2 != NULL)
3893 xmlFree(str2);
3894 }
Owen Taylor3473f882001-02-23 17:55:21 +00003895 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003896 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00003897}
3898
3899/**
3900 * xmlXPathEqualNodeSetFloat
3901 * @arg: the nodeset object argument
3902 * @f: the float to compare to
3903 *
3904 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3905 * If one object to be compared is a node-set and the other is a number,
3906 * then the comparison will be true if and only if there is a node in
3907 * the node-set such that the result of performing the comparison on the
3908 * number to be compared and on the result of converting the string-value
3909 * of that node to a number using the number function is true.
3910 *
3911 * Returns 0 or 1 depending on the results of the test.
3912 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003913static int
Owen Taylor3473f882001-02-23 17:55:21 +00003914xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) {
3915 char buf[100] = "";
3916
3917 if ((arg == NULL) ||
3918 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3919 return(0);
3920
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003921 xmlXPathFormatNumber(f, buf, sizeof(buf));
Owen Taylor3473f882001-02-23 17:55:21 +00003922 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
3923}
3924
3925
3926/**
3927 * xmlXPathEqualNodeSets
3928 * @arg1: first nodeset object argument
3929 * @arg2: second nodeset object argument
3930 *
3931 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
3932 * If both objects to be compared are node-sets, then the comparison
3933 * will be true if and only if there is a node in the first node-set and
3934 * a node in the second node-set such that the result of performing the
3935 * comparison on the string-values of the two nodes is true.
3936 *
3937 * (needless to say, this is a costly operation)
3938 *
3939 * Returns 0 or 1 depending on the results of the test.
3940 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003941static int
Owen Taylor3473f882001-02-23 17:55:21 +00003942xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3943 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003944 unsigned int *hashs1;
3945 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00003946 xmlChar **values1;
3947 xmlChar **values2;
3948 int ret = 0;
3949 xmlNodeSetPtr ns1;
3950 xmlNodeSetPtr ns2;
3951
3952 if ((arg1 == NULL) ||
3953 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
3954 return(0);
3955 if ((arg2 == NULL) ||
3956 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
3957 return(0);
3958
3959 ns1 = arg1->nodesetval;
3960 ns2 = arg2->nodesetval;
3961
Daniel Veillard911f49a2001-04-07 15:39:35 +00003962 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00003963 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003964 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00003965 return(0);
3966
3967 /*
3968 * check if there is a node pertaining to both sets
3969 */
3970 for (i = 0;i < ns1->nodeNr;i++)
3971 for (j = 0;j < ns2->nodeNr;j++)
3972 if (ns1->nodeTab[i] == ns2->nodeTab[j])
3973 return(1);
3974
3975 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
3976 if (values1 == NULL)
3977 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00003978 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
3979 if (hashs1 == NULL) {
3980 xmlFree(values1);
3981 return(0);
3982 }
Owen Taylor3473f882001-02-23 17:55:21 +00003983 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
3984 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
3985 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00003986 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00003987 xmlFree(values1);
3988 return(0);
3989 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003990 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
3991 if (hashs2 == NULL) {
3992 xmlFree(hashs1);
3993 xmlFree(values1);
3994 xmlFree(values2);
3995 return(0);
3996 }
Owen Taylor3473f882001-02-23 17:55:21 +00003997 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
3998 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00003999 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004000 for (j = 0;j < ns2->nodeNr;j++) {
4001 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004002 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
4003 if (hashs1[i] == hashs2[j]) {
4004 if (values1[i] == NULL)
4005 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4006 if (values2[j] == NULL)
4007 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
4008 ret = xmlStrEqual(values1[i], values2[j]);
4009 if (ret)
4010 break;
4011 }
Owen Taylor3473f882001-02-23 17:55:21 +00004012 }
4013 if (ret)
4014 break;
4015 }
4016 for (i = 0;i < ns1->nodeNr;i++)
4017 if (values1[i] != NULL)
4018 xmlFree(values1[i]);
4019 for (j = 0;j < ns2->nodeNr;j++)
4020 if (values2[j] != NULL)
4021 xmlFree(values2[j]);
4022 xmlFree(values1);
4023 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004024 xmlFree(hashs1);
4025 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004026 return(ret);
4027}
4028
4029/**
4030 * xmlXPathEqualValues:
4031 * @ctxt: the XPath Parser context
4032 *
4033 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4034 *
4035 * Returns 0 or 1 depending on the results of the test.
4036 */
4037int
4038xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4039 xmlXPathObjectPtr arg1, arg2;
4040 int ret = 0;
4041
4042 arg1 = valuePop(ctxt);
4043 if (arg1 == NULL)
4044 XP_ERROR0(XPATH_INVALID_OPERAND);
4045
4046 arg2 = valuePop(ctxt);
4047 if (arg2 == NULL) {
4048 xmlXPathFreeObject(arg1);
4049 XP_ERROR0(XPATH_INVALID_OPERAND);
4050 }
4051
4052 if (arg1 == arg2) {
4053#ifdef DEBUG_EXPR
4054 xmlGenericError(xmlGenericErrorContext,
4055 "Equal: by pointer\n");
4056#endif
4057 return(1);
4058 }
4059
4060 switch (arg1->type) {
4061 case XPATH_UNDEFINED:
4062#ifdef DEBUG_EXPR
4063 xmlGenericError(xmlGenericErrorContext,
4064 "Equal: undefined\n");
4065#endif
4066 break;
4067 case XPATH_XSLT_TREE:
4068 case XPATH_NODESET:
4069 switch (arg2->type) {
4070 case XPATH_UNDEFINED:
4071#ifdef DEBUG_EXPR
4072 xmlGenericError(xmlGenericErrorContext,
4073 "Equal: undefined\n");
4074#endif
4075 break;
4076 case XPATH_XSLT_TREE:
4077 case XPATH_NODESET:
4078 ret = xmlXPathEqualNodeSets(arg1, arg2);
4079 break;
4080 case XPATH_BOOLEAN:
4081 if ((arg1->nodesetval == NULL) ||
4082 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4083 else
4084 ret = 1;
4085 ret = (ret == arg2->boolval);
4086 break;
4087 case XPATH_NUMBER:
4088 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
4089 break;
4090 case XPATH_STRING:
4091 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
4092 break;
4093 case XPATH_USERS:
4094 case XPATH_POINT:
4095 case XPATH_RANGE:
4096 case XPATH_LOCATIONSET:
4097 TODO
4098 break;
4099 }
4100 break;
4101 case XPATH_BOOLEAN:
4102 switch (arg2->type) {
4103 case XPATH_UNDEFINED:
4104#ifdef DEBUG_EXPR
4105 xmlGenericError(xmlGenericErrorContext,
4106 "Equal: undefined\n");
4107#endif
4108 break;
4109 case XPATH_NODESET:
4110 case XPATH_XSLT_TREE:
4111 if ((arg2->nodesetval == NULL) ||
4112 (arg2->nodesetval->nodeNr == 0)) ret = 0;
4113 else
4114 ret = 1;
4115 break;
4116 case XPATH_BOOLEAN:
4117#ifdef DEBUG_EXPR
4118 xmlGenericError(xmlGenericErrorContext,
4119 "Equal: %d boolean %d \n",
4120 arg1->boolval, arg2->boolval);
4121#endif
4122 ret = (arg1->boolval == arg2->boolval);
4123 break;
4124 case XPATH_NUMBER:
4125 if (arg2->floatval) ret = 1;
4126 else ret = 0;
4127 ret = (arg1->boolval == ret);
4128 break;
4129 case XPATH_STRING:
4130 if ((arg2->stringval == NULL) ||
4131 (arg2->stringval[0] == 0)) ret = 0;
4132 else
4133 ret = 1;
4134 ret = (arg1->boolval == ret);
4135 break;
4136 case XPATH_USERS:
4137 case XPATH_POINT:
4138 case XPATH_RANGE:
4139 case XPATH_LOCATIONSET:
4140 TODO
4141 break;
4142 }
4143 break;
4144 case XPATH_NUMBER:
4145 switch (arg2->type) {
4146 case XPATH_UNDEFINED:
4147#ifdef DEBUG_EXPR
4148 xmlGenericError(xmlGenericErrorContext,
4149 "Equal: undefined\n");
4150#endif
4151 break;
4152 case XPATH_NODESET:
4153 case XPATH_XSLT_TREE:
4154 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
4155 break;
4156 case XPATH_BOOLEAN:
4157 if (arg1->floatval) ret = 1;
4158 else ret = 0;
4159 ret = (arg2->boolval == ret);
4160 break;
4161 case XPATH_STRING:
4162 valuePush(ctxt, arg2);
4163 xmlXPathNumberFunction(ctxt, 1);
4164 arg2 = valuePop(ctxt);
4165 /* no break on purpose */
4166 case XPATH_NUMBER:
4167 ret = (arg1->floatval == arg2->floatval);
4168 break;
4169 case XPATH_USERS:
4170 case XPATH_POINT:
4171 case XPATH_RANGE:
4172 case XPATH_LOCATIONSET:
4173 TODO
4174 break;
4175 }
4176 break;
4177 case XPATH_STRING:
4178 switch (arg2->type) {
4179 case XPATH_UNDEFINED:
4180#ifdef DEBUG_EXPR
4181 xmlGenericError(xmlGenericErrorContext,
4182 "Equal: undefined\n");
4183#endif
4184 break;
4185 case XPATH_NODESET:
4186 case XPATH_XSLT_TREE:
4187 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
4188 break;
4189 case XPATH_BOOLEAN:
4190 if ((arg1->stringval == NULL) ||
4191 (arg1->stringval[0] == 0)) ret = 0;
4192 else
4193 ret = 1;
4194 ret = (arg2->boolval == ret);
4195 break;
4196 case XPATH_STRING:
4197 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4198 break;
4199 case XPATH_NUMBER:
4200 valuePush(ctxt, arg1);
4201 xmlXPathNumberFunction(ctxt, 1);
4202 arg1 = valuePop(ctxt);
4203 ret = (arg1->floatval == arg2->floatval);
4204 break;
4205 case XPATH_USERS:
4206 case XPATH_POINT:
4207 case XPATH_RANGE:
4208 case XPATH_LOCATIONSET:
4209 TODO
4210 break;
4211 }
4212 break;
4213 case XPATH_USERS:
4214 case XPATH_POINT:
4215 case XPATH_RANGE:
4216 case XPATH_LOCATIONSET:
4217 TODO
4218 break;
4219 }
4220 xmlXPathFreeObject(arg1);
4221 xmlXPathFreeObject(arg2);
4222 return(ret);
4223}
4224
4225
4226/**
4227 * xmlXPathCompareValues:
4228 * @ctxt: the XPath Parser context
4229 * @inf: less than (1) or greater than (0)
4230 * @strict: is the comparison strict
4231 *
4232 * Implement the compare operation on XPath objects:
4233 * @arg1 < @arg2 (1, 1, ...
4234 * @arg1 <= @arg2 (1, 0, ...
4235 * @arg1 > @arg2 (0, 1, ...
4236 * @arg1 >= @arg2 (0, 0, ...
4237 *
4238 * When neither object to be compared is a node-set and the operator is
4239 * <=, <, >=, >, then the objects are compared by converted both objects
4240 * to numbers and comparing the numbers according to IEEE 754. The <
4241 * comparison will be true if and only if the first number is less than the
4242 * second number. The <= comparison will be true if and only if the first
4243 * number is less than or equal to the second number. The > comparison
4244 * will be true if and only if the first number is greater than the second
4245 * number. The >= comparison will be true if and only if the first number
4246 * is greater than or equal to the second number.
4247 *
4248 * Returns 1 if the comparaison succeeded, 0 if it failed
4249 */
4250int
4251xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
4252 int ret = 0;
4253 xmlXPathObjectPtr arg1, arg2;
4254
4255 arg2 = valuePop(ctxt);
4256 if (arg2 == NULL) {
4257 XP_ERROR0(XPATH_INVALID_OPERAND);
4258 }
4259
4260 arg1 = valuePop(ctxt);
4261 if (arg1 == NULL) {
4262 xmlXPathFreeObject(arg2);
4263 XP_ERROR0(XPATH_INVALID_OPERAND);
4264 }
4265
4266 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
4267 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004268 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004269 } else {
4270 if (arg1->type == XPATH_NODESET) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004271 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4272 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004273 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004274 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4275 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004276 }
4277 }
4278 return(ret);
4279 }
4280
4281 if (arg1->type != XPATH_NUMBER) {
4282 valuePush(ctxt, arg1);
4283 xmlXPathNumberFunction(ctxt, 1);
4284 arg1 = valuePop(ctxt);
4285 }
4286 if (arg1->type != XPATH_NUMBER) {
4287 xmlXPathFreeObject(arg1);
4288 xmlXPathFreeObject(arg2);
4289 XP_ERROR0(XPATH_INVALID_OPERAND);
4290 }
4291 if (arg2->type != XPATH_NUMBER) {
4292 valuePush(ctxt, arg2);
4293 xmlXPathNumberFunction(ctxt, 1);
4294 arg2 = valuePop(ctxt);
4295 }
4296 if (arg2->type != XPATH_NUMBER) {
4297 xmlXPathFreeObject(arg1);
4298 xmlXPathFreeObject(arg2);
4299 XP_ERROR0(XPATH_INVALID_OPERAND);
4300 }
4301 /*
4302 * Add tests for infinity and nan
4303 * => feedback on 3.4 for Inf and NaN
4304 */
4305 if (inf && strict)
4306 ret = (arg1->floatval < arg2->floatval);
4307 else if (inf && !strict)
4308 ret = (arg1->floatval <= arg2->floatval);
4309 else if (!inf && strict)
4310 ret = (arg1->floatval > arg2->floatval);
4311 else if (!inf && !strict)
4312 ret = (arg1->floatval >= arg2->floatval);
4313 xmlXPathFreeObject(arg1);
4314 xmlXPathFreeObject(arg2);
4315 return(ret);
4316}
4317
4318/**
4319 * xmlXPathValueFlipSign:
4320 * @ctxt: the XPath Parser context
4321 *
4322 * Implement the unary - operation on an XPath object
4323 * The numeric operators convert their operands to numbers as if
4324 * by calling the number function.
4325 */
4326void
4327xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004328 CAST_TO_NUMBER;
4329 CHECK_TYPE(XPATH_NUMBER);
4330 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00004331}
4332
4333/**
4334 * xmlXPathAddValues:
4335 * @ctxt: the XPath Parser context
4336 *
4337 * Implement the add operation on XPath objects:
4338 * The numeric operators convert their operands to numbers as if
4339 * by calling the number function.
4340 */
4341void
4342xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
4343 xmlXPathObjectPtr arg;
4344 double val;
4345
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004346 arg = valuePop(ctxt);
4347 if (arg == NULL)
4348 XP_ERROR(XPATH_INVALID_OPERAND);
4349 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004350 xmlXPathFreeObject(arg);
4351
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004352 CAST_TO_NUMBER;
4353 CHECK_TYPE(XPATH_NUMBER);
4354 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00004355}
4356
4357/**
4358 * xmlXPathSubValues:
4359 * @ctxt: the XPath Parser context
4360 *
4361 * Implement the substraction operation on XPath objects:
4362 * The numeric operators convert their operands to numbers as if
4363 * by calling the number function.
4364 */
4365void
4366xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
4367 xmlXPathObjectPtr arg;
4368 double val;
4369
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004370 arg = valuePop(ctxt);
4371 if (arg == NULL)
4372 XP_ERROR(XPATH_INVALID_OPERAND);
4373 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004374 xmlXPathFreeObject(arg);
4375
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004376 CAST_TO_NUMBER;
4377 CHECK_TYPE(XPATH_NUMBER);
4378 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004379}
4380
4381/**
4382 * xmlXPathMultValues:
4383 * @ctxt: the XPath Parser context
4384 *
4385 * Implement the multiply operation on XPath objects:
4386 * The numeric operators convert their operands to numbers as if
4387 * by calling the number function.
4388 */
4389void
4390xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
4391 xmlXPathObjectPtr arg;
4392 double val;
4393
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004394 arg = valuePop(ctxt);
4395 if (arg == NULL)
4396 XP_ERROR(XPATH_INVALID_OPERAND);
4397 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004398 xmlXPathFreeObject(arg);
4399
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004400 CAST_TO_NUMBER;
4401 CHECK_TYPE(XPATH_NUMBER);
4402 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004403}
4404
4405/**
4406 * xmlXPathDivValues:
4407 * @ctxt: the XPath Parser context
4408 *
4409 * Implement the div operation on XPath objects @arg1 / @arg2:
4410 * The numeric operators convert their operands to numbers as if
4411 * by calling the number function.
4412 */
4413void
4414xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
4415 xmlXPathObjectPtr arg;
4416 double val;
4417
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004418 arg = valuePop(ctxt);
4419 if (arg == NULL)
4420 XP_ERROR(XPATH_INVALID_OPERAND);
4421 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004422 xmlXPathFreeObject(arg);
4423
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004424 CAST_TO_NUMBER;
4425 CHECK_TYPE(XPATH_NUMBER);
4426 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004427}
4428
4429/**
4430 * xmlXPathModValues:
4431 * @ctxt: the XPath Parser context
4432 *
4433 * Implement the mod operation on XPath objects: @arg1 / @arg2
4434 * The numeric operators convert their operands to numbers as if
4435 * by calling the number function.
4436 */
4437void
4438xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
4439 xmlXPathObjectPtr arg;
4440 int arg1, arg2;
4441
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004442 arg = valuePop(ctxt);
4443 if (arg == NULL)
4444 XP_ERROR(XPATH_INVALID_OPERAND);
4445 arg2 = (int) xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004446 xmlXPathFreeObject(arg);
4447
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004448 CAST_TO_NUMBER;
4449 CHECK_TYPE(XPATH_NUMBER);
4450 arg1 = (int) ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00004451 if (arg2 == 0)
4452 ctxt->value->floatval = xmlXPathNAN;
4453 else
4454 ctxt->value->floatval = arg1 % arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00004455}
4456
4457/************************************************************************
4458 * *
4459 * The traversal functions *
4460 * *
4461 ************************************************************************/
4462
Owen Taylor3473f882001-02-23 17:55:21 +00004463/*
4464 * A traversal function enumerates nodes along an axis.
4465 * Initially it must be called with NULL, and it indicates
4466 * termination on the axis by returning NULL.
4467 */
4468typedef xmlNodePtr (*xmlXPathTraversalFunction)
4469 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
4470
4471/**
4472 * xmlXPathNextSelf:
4473 * @ctxt: the XPath Parser context
4474 * @cur: the current node in the traversal
4475 *
4476 * Traversal function for the "self" direction
4477 * The self axis contains just the context node itself
4478 *
4479 * Returns the next element following that axis
4480 */
4481xmlNodePtr
4482xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4483 if (cur == NULL)
4484 return(ctxt->context->node);
4485 return(NULL);
4486}
4487
4488/**
4489 * xmlXPathNextChild:
4490 * @ctxt: the XPath Parser context
4491 * @cur: the current node in the traversal
4492 *
4493 * Traversal function for the "child" direction
4494 * The child axis contains the children of the context node in document order.
4495 *
4496 * Returns the next element following that axis
4497 */
4498xmlNodePtr
4499xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4500 if (cur == NULL) {
4501 if (ctxt->context->node == NULL) return(NULL);
4502 switch (ctxt->context->node->type) {
4503 case XML_ELEMENT_NODE:
4504 case XML_TEXT_NODE:
4505 case XML_CDATA_SECTION_NODE:
4506 case XML_ENTITY_REF_NODE:
4507 case XML_ENTITY_NODE:
4508 case XML_PI_NODE:
4509 case XML_COMMENT_NODE:
4510 case XML_NOTATION_NODE:
4511 case XML_DTD_NODE:
4512 return(ctxt->context->node->children);
4513 case XML_DOCUMENT_NODE:
4514 case XML_DOCUMENT_TYPE_NODE:
4515 case XML_DOCUMENT_FRAG_NODE:
4516 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004517#ifdef LIBXML_DOCB_ENABLED
4518 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004519#endif
4520 return(((xmlDocPtr) ctxt->context->node)->children);
4521 case XML_ELEMENT_DECL:
4522 case XML_ATTRIBUTE_DECL:
4523 case XML_ENTITY_DECL:
4524 case XML_ATTRIBUTE_NODE:
4525 case XML_NAMESPACE_DECL:
4526 case XML_XINCLUDE_START:
4527 case XML_XINCLUDE_END:
4528 return(NULL);
4529 }
4530 return(NULL);
4531 }
4532 if ((cur->type == XML_DOCUMENT_NODE) ||
4533 (cur->type == XML_HTML_DOCUMENT_NODE))
4534 return(NULL);
4535 return(cur->next);
4536}
4537
4538/**
4539 * xmlXPathNextDescendant:
4540 * @ctxt: the XPath Parser context
4541 * @cur: the current node in the traversal
4542 *
4543 * Traversal function for the "descendant" direction
4544 * the descendant axis contains the descendants of the context node in document
4545 * order; a descendant is a child or a child of a child and so on.
4546 *
4547 * Returns the next element following that axis
4548 */
4549xmlNodePtr
4550xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4551 if (cur == NULL) {
4552 if (ctxt->context->node == NULL)
4553 return(NULL);
4554 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4555 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4556 return(NULL);
4557
4558 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
4559 return(ctxt->context->doc->children);
4560 return(ctxt->context->node->children);
4561 }
4562
Daniel Veillard567e1b42001-08-01 15:53:47 +00004563 if (cur->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004564 if (cur->children->type != XML_ENTITY_DECL)
Daniel Veillard567e1b42001-08-01 15:53:47 +00004565 return(cur->children);
4566 }
4567
4568 if (cur == ctxt->context->node) return(NULL);
4569
Owen Taylor3473f882001-02-23 17:55:21 +00004570 if (cur->next != NULL) return(cur->next);
4571
4572 do {
4573 cur = cur->parent;
4574 if (cur == NULL) return(NULL);
4575 if (cur == ctxt->context->node) return(NULL);
4576 if (cur->next != NULL) {
4577 cur = cur->next;
4578 return(cur);
4579 }
4580 } while (cur != NULL);
4581 return(cur);
4582}
4583
4584/**
4585 * xmlXPathNextDescendantOrSelf:
4586 * @ctxt: the XPath Parser context
4587 * @cur: the current node in the traversal
4588 *
4589 * Traversal function for the "descendant-or-self" direction
4590 * the descendant-or-self axis contains the context node and the descendants
4591 * of the context node in document order; thus the context node is the first
4592 * node on the axis, and the first child of the context node is the second node
4593 * on the axis
4594 *
4595 * Returns the next element following that axis
4596 */
4597xmlNodePtr
4598xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4599 if (cur == NULL) {
4600 if (ctxt->context->node == NULL)
4601 return(NULL);
4602 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4603 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4604 return(NULL);
4605 return(ctxt->context->node);
4606 }
4607
4608 return(xmlXPathNextDescendant(ctxt, cur));
4609}
4610
4611/**
4612 * xmlXPathNextParent:
4613 * @ctxt: the XPath Parser context
4614 * @cur: the current node in the traversal
4615 *
4616 * Traversal function for the "parent" direction
4617 * The parent axis contains the parent of the context node, if there is one.
4618 *
4619 * Returns the next element following that axis
4620 */
4621xmlNodePtr
4622xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4623 /*
4624 * the parent of an attribute or namespace node is the element
4625 * to which the attribute or namespace node is attached
4626 * Namespace handling !!!
4627 */
4628 if (cur == NULL) {
4629 if (ctxt->context->node == NULL) return(NULL);
4630 switch (ctxt->context->node->type) {
4631 case XML_ELEMENT_NODE:
4632 case XML_TEXT_NODE:
4633 case XML_CDATA_SECTION_NODE:
4634 case XML_ENTITY_REF_NODE:
4635 case XML_ENTITY_NODE:
4636 case XML_PI_NODE:
4637 case XML_COMMENT_NODE:
4638 case XML_NOTATION_NODE:
4639 case XML_DTD_NODE:
4640 case XML_ELEMENT_DECL:
4641 case XML_ATTRIBUTE_DECL:
4642 case XML_XINCLUDE_START:
4643 case XML_XINCLUDE_END:
4644 case XML_ENTITY_DECL:
4645 if (ctxt->context->node->parent == NULL)
4646 return((xmlNodePtr) ctxt->context->doc);
4647 return(ctxt->context->node->parent);
4648 case XML_ATTRIBUTE_NODE: {
4649 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4650
4651 return(att->parent);
4652 }
4653 case XML_DOCUMENT_NODE:
4654 case XML_DOCUMENT_TYPE_NODE:
4655 case XML_DOCUMENT_FRAG_NODE:
4656 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004657#ifdef LIBXML_DOCB_ENABLED
4658 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004659#endif
4660 return(NULL);
4661 case XML_NAMESPACE_DECL:
4662 /*
4663 * TODO !!! may require extending struct _xmlNs with
4664 * parent field
4665 * C.f. Infoset case...
4666 */
4667 return(NULL);
4668 }
4669 }
4670 return(NULL);
4671}
4672
4673/**
4674 * xmlXPathNextAncestor:
4675 * @ctxt: the XPath Parser context
4676 * @cur: the current node in the traversal
4677 *
4678 * Traversal function for the "ancestor" direction
4679 * the ancestor axis contains the ancestors of the context node; the ancestors
4680 * of the context node consist of the parent of context node and the parent's
4681 * parent and so on; the nodes are ordered in reverse document order; thus the
4682 * parent is the first node on the axis, and the parent's parent is the second
4683 * node on the axis
4684 *
4685 * Returns the next element following that axis
4686 */
4687xmlNodePtr
4688xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4689 /*
4690 * the parent of an attribute or namespace node is the element
4691 * to which the attribute or namespace node is attached
4692 * !!!!!!!!!!!!!
4693 */
4694 if (cur == NULL) {
4695 if (ctxt->context->node == NULL) return(NULL);
4696 switch (ctxt->context->node->type) {
4697 case XML_ELEMENT_NODE:
4698 case XML_TEXT_NODE:
4699 case XML_CDATA_SECTION_NODE:
4700 case XML_ENTITY_REF_NODE:
4701 case XML_ENTITY_NODE:
4702 case XML_PI_NODE:
4703 case XML_COMMENT_NODE:
4704 case XML_DTD_NODE:
4705 case XML_ELEMENT_DECL:
4706 case XML_ATTRIBUTE_DECL:
4707 case XML_ENTITY_DECL:
4708 case XML_NOTATION_NODE:
4709 case XML_XINCLUDE_START:
4710 case XML_XINCLUDE_END:
4711 if (ctxt->context->node->parent == NULL)
4712 return((xmlNodePtr) ctxt->context->doc);
4713 return(ctxt->context->node->parent);
4714 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004715 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00004716
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004717 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00004718 }
4719 case XML_DOCUMENT_NODE:
4720 case XML_DOCUMENT_TYPE_NODE:
4721 case XML_DOCUMENT_FRAG_NODE:
4722 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004723#ifdef LIBXML_DOCB_ENABLED
4724 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004725#endif
4726 return(NULL);
4727 case XML_NAMESPACE_DECL:
4728 /*
4729 * TODO !!! may require extending struct _xmlNs with
4730 * parent field
4731 * C.f. Infoset case...
4732 */
4733 return(NULL);
4734 }
4735 return(NULL);
4736 }
4737 if (cur == ctxt->context->doc->children)
4738 return((xmlNodePtr) ctxt->context->doc);
4739 if (cur == (xmlNodePtr) ctxt->context->doc)
4740 return(NULL);
4741 switch (cur->type) {
4742 case XML_ELEMENT_NODE:
4743 case XML_TEXT_NODE:
4744 case XML_CDATA_SECTION_NODE:
4745 case XML_ENTITY_REF_NODE:
4746 case XML_ENTITY_NODE:
4747 case XML_PI_NODE:
4748 case XML_COMMENT_NODE:
4749 case XML_NOTATION_NODE:
4750 case XML_DTD_NODE:
4751 case XML_ELEMENT_DECL:
4752 case XML_ATTRIBUTE_DECL:
4753 case XML_ENTITY_DECL:
4754 case XML_XINCLUDE_START:
4755 case XML_XINCLUDE_END:
4756 return(cur->parent);
4757 case XML_ATTRIBUTE_NODE: {
4758 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4759
4760 return(att->parent);
4761 }
4762 case XML_DOCUMENT_NODE:
4763 case XML_DOCUMENT_TYPE_NODE:
4764 case XML_DOCUMENT_FRAG_NODE:
4765 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004766#ifdef LIBXML_DOCB_ENABLED
4767 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004768#endif
4769 return(NULL);
4770 case XML_NAMESPACE_DECL:
4771 /*
4772 * TODO !!! may require extending struct _xmlNs with
4773 * parent field
4774 * C.f. Infoset case...
4775 */
4776 return(NULL);
4777 }
4778 return(NULL);
4779}
4780
4781/**
4782 * xmlXPathNextAncestorOrSelf:
4783 * @ctxt: the XPath Parser context
4784 * @cur: the current node in the traversal
4785 *
4786 * Traversal function for the "ancestor-or-self" direction
4787 * he ancestor-or-self axis contains the context node and ancestors of
4788 * the context node in reverse document order; thus the context node is
4789 * the first node on the axis, and the context node's parent the second;
4790 * parent here is defined the same as with the parent axis.
4791 *
4792 * Returns the next element following that axis
4793 */
4794xmlNodePtr
4795xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4796 if (cur == NULL)
4797 return(ctxt->context->node);
4798 return(xmlXPathNextAncestor(ctxt, cur));
4799}
4800
4801/**
4802 * xmlXPathNextFollowingSibling:
4803 * @ctxt: the XPath Parser context
4804 * @cur: the current node in the traversal
4805 *
4806 * Traversal function for the "following-sibling" direction
4807 * The following-sibling axis contains the following siblings of the context
4808 * node in document order.
4809 *
4810 * Returns the next element following that axis
4811 */
4812xmlNodePtr
4813xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4814 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4815 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4816 return(NULL);
4817 if (cur == (xmlNodePtr) ctxt->context->doc)
4818 return(NULL);
4819 if (cur == NULL)
4820 return(ctxt->context->node->next);
4821 return(cur->next);
4822}
4823
4824/**
4825 * xmlXPathNextPrecedingSibling:
4826 * @ctxt: the XPath Parser context
4827 * @cur: the current node in the traversal
4828 *
4829 * Traversal function for the "preceding-sibling" direction
4830 * The preceding-sibling axis contains the preceding siblings of the context
4831 * node in reverse document order; the first preceding sibling is first on the
4832 * axis; the sibling preceding that node is the second on the axis and so on.
4833 *
4834 * Returns the next element following that axis
4835 */
4836xmlNodePtr
4837xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4838 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4839 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4840 return(NULL);
4841 if (cur == (xmlNodePtr) ctxt->context->doc)
4842 return(NULL);
4843 if (cur == NULL)
4844 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004845 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
4846 cur = cur->prev;
4847 if (cur == NULL)
4848 return(ctxt->context->node->prev);
4849 }
Owen Taylor3473f882001-02-23 17:55:21 +00004850 return(cur->prev);
4851}
4852
4853/**
4854 * xmlXPathNextFollowing:
4855 * @ctxt: the XPath Parser context
4856 * @cur: the current node in the traversal
4857 *
4858 * Traversal function for the "following" direction
4859 * The following axis contains all nodes in the same document as the context
4860 * node that are after the context node in document order, excluding any
4861 * descendants and excluding attribute nodes and namespace nodes; the nodes
4862 * are ordered in document order
4863 *
4864 * Returns the next element following that axis
4865 */
4866xmlNodePtr
4867xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4868 if (cur != NULL && cur->children != NULL)
4869 return cur->children ;
4870 if (cur == NULL) cur = ctxt->context->node;
4871 if (cur == NULL) return(NULL) ; /* ERROR */
4872 if (cur->next != NULL) return(cur->next) ;
4873 do {
4874 cur = cur->parent;
4875 if (cur == NULL) return(NULL);
4876 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
4877 if (cur->next != NULL) return(cur->next);
4878 } while (cur != NULL);
4879 return(cur);
4880}
4881
4882/*
4883 * xmlXPathIsAncestor:
4884 * @ancestor: the ancestor node
4885 * @node: the current node
4886 *
4887 * Check that @ancestor is a @node's ancestor
4888 *
4889 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
4890 */
4891static int
4892xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
4893 if ((ancestor == NULL) || (node == NULL)) return(0);
4894 /* nodes need to be in the same document */
4895 if (ancestor->doc != node->doc) return(0);
4896 /* avoid searching if ancestor or node is the root node */
4897 if (ancestor == (xmlNodePtr) node->doc) return(1);
4898 if (node == (xmlNodePtr) ancestor->doc) return(0);
4899 while (node->parent != NULL) {
4900 if (node->parent == ancestor)
4901 return(1);
4902 node = node->parent;
4903 }
4904 return(0);
4905}
4906
4907/**
4908 * xmlXPathNextPreceding:
4909 * @ctxt: the XPath Parser context
4910 * @cur: the current node in the traversal
4911 *
4912 * Traversal function for the "preceding" direction
4913 * the preceding axis contains all nodes in the same document as the context
4914 * node that are before the context node in document order, excluding any
4915 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4916 * ordered in reverse document order
4917 *
4918 * Returns the next element following that axis
4919 */
4920xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00004921xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
4922{
Owen Taylor3473f882001-02-23 17:55:21 +00004923 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004924 cur = ctxt->context->node;
4925 if (cur == NULL)
4926 return (NULL);
4927 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
4928 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00004929 do {
4930 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004931 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
4932 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004933 }
4934
4935 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004936 if (cur == NULL)
4937 return (NULL);
4938 if (cur == ctxt->context->doc->children)
4939 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004940 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00004941 return (cur);
4942}
4943
4944/**
4945 * xmlXPathNextPrecedingInternal:
4946 * @ctxt: the XPath Parser context
4947 * @cur: the current node in the traversal
4948 *
4949 * Traversal function for the "preceding" direction
4950 * the preceding axis contains all nodes in the same document as the context
4951 * node that are before the context node in document order, excluding any
4952 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4953 * ordered in reverse document order
4954 * This is a faster implementation but internal only since it requires a
4955 * state kept in the parser context: ctxt->ancestor.
4956 *
4957 * Returns the next element following that axis
4958 */
4959static xmlNodePtr
4960xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
4961 xmlNodePtr cur)
4962{
4963 if (cur == NULL) {
4964 cur = ctxt->context->node;
4965 if (cur == NULL)
4966 return (NULL);
4967 ctxt->ancestor = cur->parent;
4968 }
4969 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
4970 cur = cur->prev;
4971 while (cur->prev == NULL) {
4972 cur = cur->parent;
4973 if (cur == NULL)
4974 return (NULL);
4975 if (cur == ctxt->context->doc->children)
4976 return (NULL);
4977 if (cur != ctxt->ancestor)
4978 return (cur);
4979 ctxt->ancestor = cur->parent;
4980 }
4981 cur = cur->prev;
4982 while (cur->last != NULL)
4983 cur = cur->last;
4984 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004985}
4986
4987/**
4988 * xmlXPathNextNamespace:
4989 * @ctxt: the XPath Parser context
4990 * @cur: the current attribute in the traversal
4991 *
4992 * Traversal function for the "namespace" direction
4993 * the namespace axis contains the namespace nodes of the context node;
4994 * the order of nodes on this axis is implementation-defined; the axis will
4995 * be empty unless the context node is an element
4996 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00004997 * We keep the XML namespace node at the end of the list.
4998 *
Owen Taylor3473f882001-02-23 17:55:21 +00004999 * Returns the next element following that axis
5000 */
5001xmlNodePtr
5002xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005003 xmlNodePtr ret;
5004
Owen Taylor3473f882001-02-23 17:55:21 +00005005 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005006 if (cur == (xmlNodePtr) xmlXPathXMLNamespace)
5007 return(NULL);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005008 if ((cur == NULL) || (ctxt->context->tmpNsList == NULL)) {
5009 if (ctxt->context->tmpNsList != NULL)
5010 xmlFree(ctxt->context->tmpNsList);
5011 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005012 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005013 if (ctxt->context->tmpNsList == NULL) return(NULL);
5014 ctxt->context->tmpNsNr = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005015 }
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005016 ret = (xmlNodePtr)ctxt->context->tmpNsList[ctxt->context->tmpNsNr++];
5017 if (ret == NULL) {
5018 xmlFree(ctxt->context->tmpNsList);
5019 ctxt->context->tmpNsList = NULL;
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005020 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005021 }
5022 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005023}
5024
5025/**
5026 * xmlXPathNextAttribute:
5027 * @ctxt: the XPath Parser context
5028 * @cur: the current attribute in the traversal
5029 *
5030 * Traversal function for the "attribute" direction
5031 * TODO: support DTD inherited default attributes
5032 *
5033 * Returns the next element following that axis
5034 */
5035xmlNodePtr
5036xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005037 if (ctxt->context->node == NULL)
5038 return(NULL);
5039 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5040 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005041 if (cur == NULL) {
5042 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5043 return(NULL);
5044 return((xmlNodePtr)ctxt->context->node->properties);
5045 }
5046 return((xmlNodePtr)cur->next);
5047}
5048
5049/************************************************************************
5050 * *
5051 * NodeTest Functions *
5052 * *
5053 ************************************************************************/
5054
Owen Taylor3473f882001-02-23 17:55:21 +00005055#define IS_FUNCTION 200
5056
Owen Taylor3473f882001-02-23 17:55:21 +00005057
5058/************************************************************************
5059 * *
5060 * Implicit tree core function library *
5061 * *
5062 ************************************************************************/
5063
5064/**
5065 * xmlXPathRoot:
5066 * @ctxt: the XPath Parser context
5067 *
5068 * Initialize the context to the root of the document
5069 */
5070void
5071xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5072 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5073 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5074}
5075
5076/************************************************************************
5077 * *
5078 * The explicit core function library *
5079 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5080 * *
5081 ************************************************************************/
5082
5083
5084/**
5085 * xmlXPathLastFunction:
5086 * @ctxt: the XPath Parser context
5087 * @nargs: the number of arguments
5088 *
5089 * Implement the last() XPath function
5090 * number last()
5091 * The last function returns the number of nodes in the context node list.
5092 */
5093void
5094xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5095 CHECK_ARITY(0);
5096 if (ctxt->context->contextSize >= 0) {
5097 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5098#ifdef DEBUG_EXPR
5099 xmlGenericError(xmlGenericErrorContext,
5100 "last() : %d\n", ctxt->context->contextSize);
5101#endif
5102 } else {
5103 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5104 }
5105}
5106
5107/**
5108 * xmlXPathPositionFunction:
5109 * @ctxt: the XPath Parser context
5110 * @nargs: the number of arguments
5111 *
5112 * Implement the position() XPath function
5113 * number position()
5114 * The position function returns the position of the context node in the
5115 * context node list. The first position is 1, and so the last positionr
5116 * will be equal to last().
5117 */
5118void
5119xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5120 CHECK_ARITY(0);
5121 if (ctxt->context->proximityPosition >= 0) {
5122 valuePush(ctxt,
5123 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5124#ifdef DEBUG_EXPR
5125 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5126 ctxt->context->proximityPosition);
5127#endif
5128 } else {
5129 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5130 }
5131}
5132
5133/**
5134 * xmlXPathCountFunction:
5135 * @ctxt: the XPath Parser context
5136 * @nargs: the number of arguments
5137 *
5138 * Implement the count() XPath function
5139 * number count(node-set)
5140 */
5141void
5142xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5143 xmlXPathObjectPtr cur;
5144
5145 CHECK_ARITY(1);
5146 if ((ctxt->value == NULL) ||
5147 ((ctxt->value->type != XPATH_NODESET) &&
5148 (ctxt->value->type != XPATH_XSLT_TREE)))
5149 XP_ERROR(XPATH_INVALID_TYPE);
5150 cur = valuePop(ctxt);
5151
Daniel Veillard911f49a2001-04-07 15:39:35 +00005152 if ((cur == NULL) || (cur->nodesetval == NULL))
5153 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00005154 else if (cur->type == XPATH_NODESET) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005155 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005156 } else {
5157 if ((cur->nodesetval->nodeNr != 1) ||
5158 (cur->nodesetval->nodeTab == NULL)) {
5159 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5160 } else {
5161 xmlNodePtr tmp;
5162 int i = 0;
5163
5164 tmp = cur->nodesetval->nodeTab[0];
5165 if (tmp != NULL) {
5166 tmp = tmp->children;
5167 while (tmp != NULL) {
5168 tmp = tmp->next;
5169 i++;
5170 }
5171 }
5172 valuePush(ctxt, xmlXPathNewFloat((double) i));
5173 }
5174 }
Owen Taylor3473f882001-02-23 17:55:21 +00005175 xmlXPathFreeObject(cur);
5176}
5177
5178/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005179 * xmlXPathGetElementsByIds:
5180 * @doc: the document
5181 * @ids: a whitespace separated list of IDs
5182 *
5183 * Selects elements by their unique ID.
5184 *
5185 * Returns a node-set of selected elements.
5186 */
5187static xmlNodeSetPtr
5188xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5189 xmlNodeSetPtr ret;
5190 const xmlChar *cur = ids;
5191 xmlChar *ID;
5192 xmlAttrPtr attr;
5193 xmlNodePtr elem = NULL;
5194
5195 ret = xmlXPathNodeSetCreate(NULL);
5196
5197 while (IS_BLANK(*cur)) cur++;
5198 while (*cur != 0) {
5199 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
5200 (*cur == '.') || (*cur == '-') ||
5201 (*cur == '_') || (*cur == ':') ||
5202 (IS_COMBINING(*cur)) ||
5203 (IS_EXTENDER(*cur)))
5204 cur++;
5205
5206 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
5207
5208 ID = xmlStrndup(ids, cur - ids);
5209 attr = xmlGetID(doc, ID);
5210 if (attr != NULL) {
5211 elem = attr->parent;
5212 xmlXPathNodeSetAdd(ret, elem);
5213 }
5214 if (ID != NULL)
5215 xmlFree(ID);
5216
5217 while (IS_BLANK(*cur)) cur++;
5218 ids = cur;
5219 }
5220 return(ret);
5221}
5222
5223/**
Owen Taylor3473f882001-02-23 17:55:21 +00005224 * xmlXPathIdFunction:
5225 * @ctxt: the XPath Parser context
5226 * @nargs: the number of arguments
5227 *
5228 * Implement the id() XPath function
5229 * node-set id(object)
5230 * The id function selects elements by their unique ID
5231 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5232 * then the result is the union of the result of applying id to the
5233 * string value of each of the nodes in the argument node-set. When the
5234 * argument to id is of any other type, the argument is converted to a
5235 * string as if by a call to the string function; the string is split
5236 * into a whitespace-separated list of tokens (whitespace is any sequence
5237 * of characters matching the production S); the result is a node-set
5238 * containing the elements in the same document as the context node that
5239 * have a unique ID equal to any of the tokens in the list.
5240 */
5241void
5242xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005243 xmlChar *tokens;
5244 xmlNodeSetPtr ret;
5245 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00005246
5247 CHECK_ARITY(1);
5248 obj = valuePop(ctxt);
5249 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
5250 if (obj->type == XPATH_NODESET) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005251 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00005252 int i;
5253
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005254 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005255
Daniel Veillard911f49a2001-04-07 15:39:35 +00005256 if (obj->nodesetval != NULL) {
5257 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005258 tokens =
5259 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
5260 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
5261 ret = xmlXPathNodeSetMerge(ret, ns);
5262 xmlXPathFreeNodeSet(ns);
5263 if (tokens != NULL)
5264 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00005265 }
Owen Taylor3473f882001-02-23 17:55:21 +00005266 }
5267
5268 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005269 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005270 return;
5271 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005272 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00005273
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005274 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
5275 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005276
Owen Taylor3473f882001-02-23 17:55:21 +00005277 xmlXPathFreeObject(obj);
5278 return;
5279}
5280
5281/**
5282 * xmlXPathLocalNameFunction:
5283 * @ctxt: the XPath Parser context
5284 * @nargs: the number of arguments
5285 *
5286 * Implement the local-name() XPath function
5287 * string local-name(node-set?)
5288 * The local-name function returns a string containing the local part
5289 * of the name of the node in the argument node-set that is first in
5290 * document order. If the node-set is empty or the first node has no
5291 * name, an empty string is returned. If the argument is omitted it
5292 * defaults to the context node.
5293 */
5294void
5295xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5296 xmlXPathObjectPtr cur;
5297
5298 if (nargs == 0) {
5299 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5300 nargs = 1;
5301 }
5302
5303 CHECK_ARITY(1);
5304 if ((ctxt->value == NULL) ||
5305 ((ctxt->value->type != XPATH_NODESET) &&
5306 (ctxt->value->type != XPATH_XSLT_TREE)))
5307 XP_ERROR(XPATH_INVALID_TYPE);
5308 cur = valuePop(ctxt);
5309
Daniel Veillard911f49a2001-04-07 15:39:35 +00005310 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005311 valuePush(ctxt, xmlXPathNewCString(""));
5312 } else {
5313 int i = 0; /* Should be first in document order !!!!! */
5314 switch (cur->nodesetval->nodeTab[i]->type) {
5315 case XML_ELEMENT_NODE:
5316 case XML_ATTRIBUTE_NODE:
5317 case XML_PI_NODE:
5318 valuePush(ctxt,
5319 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
5320 break;
5321 case XML_NAMESPACE_DECL:
5322 valuePush(ctxt, xmlXPathNewString(
5323 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
5324 break;
5325 default:
5326 valuePush(ctxt, xmlXPathNewCString(""));
5327 }
5328 }
5329 xmlXPathFreeObject(cur);
5330}
5331
5332/**
5333 * xmlXPathNamespaceURIFunction:
5334 * @ctxt: the XPath Parser context
5335 * @nargs: the number of arguments
5336 *
5337 * Implement the namespace-uri() XPath function
5338 * string namespace-uri(node-set?)
5339 * The namespace-uri function returns a string containing the
5340 * namespace URI of the expanded name of the node in the argument
5341 * node-set that is first in document order. If the node-set is empty,
5342 * the first node has no name, or the expanded name has no namespace
5343 * URI, an empty string is returned. If the argument is omitted it
5344 * defaults to the context node.
5345 */
5346void
5347xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5348 xmlXPathObjectPtr cur;
5349
5350 if (nargs == 0) {
5351 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5352 nargs = 1;
5353 }
5354 CHECK_ARITY(1);
5355 if ((ctxt->value == NULL) ||
5356 ((ctxt->value->type != XPATH_NODESET) &&
5357 (ctxt->value->type != XPATH_XSLT_TREE)))
5358 XP_ERROR(XPATH_INVALID_TYPE);
5359 cur = valuePop(ctxt);
5360
Daniel Veillard911f49a2001-04-07 15:39:35 +00005361 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005362 valuePush(ctxt, xmlXPathNewCString(""));
5363 } else {
5364 int i = 0; /* Should be first in document order !!!!! */
5365 switch (cur->nodesetval->nodeTab[i]->type) {
5366 case XML_ELEMENT_NODE:
5367 case XML_ATTRIBUTE_NODE:
5368 if (cur->nodesetval->nodeTab[i]->ns == NULL)
5369 valuePush(ctxt, xmlXPathNewCString(""));
5370 else
5371 valuePush(ctxt, xmlXPathNewString(
5372 cur->nodesetval->nodeTab[i]->ns->href));
5373 break;
5374 default:
5375 valuePush(ctxt, xmlXPathNewCString(""));
5376 }
5377 }
5378 xmlXPathFreeObject(cur);
5379}
5380
5381/**
5382 * xmlXPathNameFunction:
5383 * @ctxt: the XPath Parser context
5384 * @nargs: the number of arguments
5385 *
5386 * Implement the name() XPath function
5387 * string name(node-set?)
5388 * The name function returns a string containing a QName representing
5389 * the name of the node in the argument node-set that is first in documenti
5390 * order. The QName must represent the name with respect to the namespace
5391 * declarations in effect on the node whose name is being represented.
5392 * Typically, this will be the form in which the name occurred in the XML
5393 * source. This need not be the case if there are namespace declarations
5394 * in effect on the node that associate multiple prefixes with the same
5395 * namespace. However, an implementation may include information about
5396 * the original prefix in its representation of nodes; in this case, an
5397 * implementation can ensure that the returned string is always the same
5398 * as the QName used in the XML source. If the argument it omitted it
5399 * defaults to the context node.
5400 * Libxml keep the original prefix so the "real qualified name" used is
5401 * returned.
5402 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005403static void
Daniel Veillard04383752001-07-08 14:27:15 +00005404xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
5405{
Owen Taylor3473f882001-02-23 17:55:21 +00005406 xmlXPathObjectPtr cur;
5407
5408 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00005409 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5410 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00005411 }
5412
5413 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00005414 if ((ctxt->value == NULL) ||
5415 ((ctxt->value->type != XPATH_NODESET) &&
5416 (ctxt->value->type != XPATH_XSLT_TREE)))
5417 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00005418 cur = valuePop(ctxt);
5419
Daniel Veillard911f49a2001-04-07 15:39:35 +00005420 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00005421 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00005422 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00005423 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005424
Daniel Veillard04383752001-07-08 14:27:15 +00005425 switch (cur->nodesetval->nodeTab[i]->type) {
5426 case XML_ELEMENT_NODE:
5427 case XML_ATTRIBUTE_NODE:
5428 if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
5429 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL))
5430 valuePush(ctxt,
5431 xmlXPathNewString(cur->nodesetval->
5432 nodeTab[i]->name));
5433
5434 else {
5435 char name[2000];
5436
5437 snprintf(name, sizeof(name), "%s:%s",
5438 (char *) cur->nodesetval->nodeTab[i]->ns->
5439 prefix,
5440 (char *) cur->nodesetval->nodeTab[i]->name);
5441 name[sizeof(name) - 1] = 0;
5442 valuePush(ctxt, xmlXPathNewCString(name));
5443 }
5444 break;
5445 default:
5446 valuePush(ctxt,
5447 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
5448 xmlXPathLocalNameFunction(ctxt, 1);
5449 }
Owen Taylor3473f882001-02-23 17:55:21 +00005450 }
5451 xmlXPathFreeObject(cur);
5452}
5453
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005454
5455/**
Owen Taylor3473f882001-02-23 17:55:21 +00005456 * xmlXPathStringFunction:
5457 * @ctxt: the XPath Parser context
5458 * @nargs: the number of arguments
5459 *
5460 * Implement the string() XPath function
5461 * string string(object?)
5462 * he string function converts an object to a string as follows:
5463 * - A node-set is converted to a string by returning the value of
5464 * the node in the node-set that is first in document order.
5465 * If the node-set is empty, an empty string is returned.
5466 * - A number is converted to a string as follows
5467 * + NaN is converted to the string NaN
5468 * + positive zero is converted to the string 0
5469 * + negative zero is converted to the string 0
5470 * + positive infinity is converted to the string Infinity
5471 * + negative infinity is converted to the string -Infinity
5472 * + if the number is an integer, the number is represented in
5473 * decimal form as a Number with no decimal point and no leading
5474 * zeros, preceded by a minus sign (-) if the number is negative
5475 * + otherwise, the number is represented in decimal form as a
5476 * Number including a decimal point with at least one digit
5477 * before the decimal point and at least one digit after the
5478 * decimal point, preceded by a minus sign (-) if the number
5479 * is negative; there must be no leading zeros before the decimal
5480 * point apart possibly from the one required digit immediatelyi
5481 * before the decimal point; beyond the one required digit
5482 * after the decimal point there must be as many, but only as
5483 * many, more digits as are needed to uniquely distinguish the
5484 * number from all other IEEE 754 numeric values.
5485 * - The boolean false value is converted to the string false.
5486 * The boolean true value is converted to the string true.
5487 *
5488 * If the argument is omitted, it defaults to a node-set with the
5489 * context node as its only member.
5490 */
5491void
5492xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5493 xmlXPathObjectPtr cur;
5494
5495 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005496 valuePush(ctxt,
5497 xmlXPathWrapString(
5498 xmlXPathCastNodeToString(ctxt->context->node)));
5499 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005500 }
5501
5502 CHECK_ARITY(1);
5503 cur = valuePop(ctxt);
5504 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005505 cur = xmlXPathConvertString(cur);
5506 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005507}
5508
5509/**
5510 * xmlXPathStringLengthFunction:
5511 * @ctxt: the XPath Parser context
5512 * @nargs: the number of arguments
5513 *
5514 * Implement the string-length() XPath function
5515 * number string-length(string?)
5516 * The string-length returns the number of characters in the string
5517 * (see [3.6 Strings]). If the argument is omitted, it defaults to
5518 * the context node converted to a string, in other words the value
5519 * of the context node.
5520 */
5521void
5522xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5523 xmlXPathObjectPtr cur;
5524
5525 if (nargs == 0) {
5526 if (ctxt->context->node == NULL) {
5527 valuePush(ctxt, xmlXPathNewFloat(0));
5528 } else {
5529 xmlChar *content;
5530
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005531 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005532 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00005533 xmlFree(content);
5534 }
5535 return;
5536 }
5537 CHECK_ARITY(1);
5538 CAST_TO_STRING;
5539 CHECK_TYPE(XPATH_STRING);
5540 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005541 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00005542 xmlXPathFreeObject(cur);
5543}
5544
5545/**
5546 * xmlXPathConcatFunction:
5547 * @ctxt: the XPath Parser context
5548 * @nargs: the number of arguments
5549 *
5550 * Implement the concat() XPath function
5551 * string concat(string, string, string*)
5552 * The concat function returns the concatenation of its arguments.
5553 */
5554void
5555xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5556 xmlXPathObjectPtr cur, newobj;
5557 xmlChar *tmp;
5558
5559 if (nargs < 2) {
5560 CHECK_ARITY(2);
5561 }
5562
5563 CAST_TO_STRING;
5564 cur = valuePop(ctxt);
5565 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
5566 xmlXPathFreeObject(cur);
5567 return;
5568 }
5569 nargs--;
5570
5571 while (nargs > 0) {
5572 CAST_TO_STRING;
5573 newobj = valuePop(ctxt);
5574 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
5575 xmlXPathFreeObject(newobj);
5576 xmlXPathFreeObject(cur);
5577 XP_ERROR(XPATH_INVALID_TYPE);
5578 }
5579 tmp = xmlStrcat(newobj->stringval, cur->stringval);
5580 newobj->stringval = cur->stringval;
5581 cur->stringval = tmp;
5582
5583 xmlXPathFreeObject(newobj);
5584 nargs--;
5585 }
5586 valuePush(ctxt, cur);
5587}
5588
5589/**
5590 * xmlXPathContainsFunction:
5591 * @ctxt: the XPath Parser context
5592 * @nargs: the number of arguments
5593 *
5594 * Implement the contains() XPath function
5595 * boolean contains(string, string)
5596 * The contains function returns true if the first argument string
5597 * contains the second argument string, and otherwise returns false.
5598 */
5599void
5600xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5601 xmlXPathObjectPtr hay, needle;
5602
5603 CHECK_ARITY(2);
5604 CAST_TO_STRING;
5605 CHECK_TYPE(XPATH_STRING);
5606 needle = valuePop(ctxt);
5607 CAST_TO_STRING;
5608 hay = valuePop(ctxt);
5609 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5610 xmlXPathFreeObject(hay);
5611 xmlXPathFreeObject(needle);
5612 XP_ERROR(XPATH_INVALID_TYPE);
5613 }
5614 if (xmlStrstr(hay->stringval, needle->stringval))
5615 valuePush(ctxt, xmlXPathNewBoolean(1));
5616 else
5617 valuePush(ctxt, xmlXPathNewBoolean(0));
5618 xmlXPathFreeObject(hay);
5619 xmlXPathFreeObject(needle);
5620}
5621
5622/**
5623 * xmlXPathStartsWithFunction:
5624 * @ctxt: the XPath Parser context
5625 * @nargs: the number of arguments
5626 *
5627 * Implement the starts-with() XPath function
5628 * boolean starts-with(string, string)
5629 * The starts-with function returns true if the first argument string
5630 * starts with the second argument string, and otherwise returns false.
5631 */
5632void
5633xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5634 xmlXPathObjectPtr hay, needle;
5635 int n;
5636
5637 CHECK_ARITY(2);
5638 CAST_TO_STRING;
5639 CHECK_TYPE(XPATH_STRING);
5640 needle = valuePop(ctxt);
5641 CAST_TO_STRING;
5642 hay = valuePop(ctxt);
5643 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5644 xmlXPathFreeObject(hay);
5645 xmlXPathFreeObject(needle);
5646 XP_ERROR(XPATH_INVALID_TYPE);
5647 }
5648 n = xmlStrlen(needle->stringval);
5649 if (xmlStrncmp(hay->stringval, needle->stringval, n))
5650 valuePush(ctxt, xmlXPathNewBoolean(0));
5651 else
5652 valuePush(ctxt, xmlXPathNewBoolean(1));
5653 xmlXPathFreeObject(hay);
5654 xmlXPathFreeObject(needle);
5655}
5656
5657/**
5658 * xmlXPathSubstringFunction:
5659 * @ctxt: the XPath Parser context
5660 * @nargs: the number of arguments
5661 *
5662 * Implement the substring() XPath function
5663 * string substring(string, number, number?)
5664 * The substring function returns the substring of the first argument
5665 * starting at the position specified in the second argument with
5666 * length specified in the third argument. For example,
5667 * substring("12345",2,3) returns "234". If the third argument is not
5668 * specified, it returns the substring starting at the position specified
5669 * in the second argument and continuing to the end of the string. For
5670 * example, substring("12345",2) returns "2345". More precisely, each
5671 * character in the string (see [3.6 Strings]) is considered to have a
5672 * numeric position: the position of the first character is 1, the position
5673 * of the second character is 2 and so on. The returned substring contains
5674 * those characters for which the position of the character is greater than
5675 * or equal to the second argument and, if the third argument is specified,
5676 * less than the sum of the second and third arguments; the comparisons
5677 * and addition used for the above follow the standard IEEE 754 rules. Thus:
5678 * - substring("12345", 1.5, 2.6) returns "234"
5679 * - substring("12345", 0, 3) returns "12"
5680 * - substring("12345", 0 div 0, 3) returns ""
5681 * - substring("12345", 1, 0 div 0) returns ""
5682 * - substring("12345", -42, 1 div 0) returns "12345"
5683 * - substring("12345", -1 div 0, 1 div 0) returns ""
5684 */
5685void
5686xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5687 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005688 double le=0, in;
5689 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00005690 xmlChar *ret;
5691
Owen Taylor3473f882001-02-23 17:55:21 +00005692 if (nargs < 2) {
5693 CHECK_ARITY(2);
5694 }
5695 if (nargs > 3) {
5696 CHECK_ARITY(3);
5697 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005698 /*
5699 * take care of possible last (position) argument
5700 */
Owen Taylor3473f882001-02-23 17:55:21 +00005701 if (nargs == 3) {
5702 CAST_TO_NUMBER;
5703 CHECK_TYPE(XPATH_NUMBER);
5704 len = valuePop(ctxt);
5705 le = len->floatval;
5706 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00005707 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005708
Owen Taylor3473f882001-02-23 17:55:21 +00005709 CAST_TO_NUMBER;
5710 CHECK_TYPE(XPATH_NUMBER);
5711 start = valuePop(ctxt);
5712 in = start->floatval;
5713 xmlXPathFreeObject(start);
5714 CAST_TO_STRING;
5715 CHECK_TYPE(XPATH_STRING);
5716 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00005717 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005718
Daniel Veillard97ac1312001-05-30 19:14:17 +00005719 /*
5720 * If last pos not present, calculate last position
5721 */
5722 if (nargs != 3)
5723 le = m;
5724
5725 /*
5726 * To meet our requirements, initial index calculations
5727 * must be done before we convert to integer format
5728 *
5729 * First we normalize indices
5730 */
5731 in -= 1.0;
5732 le += in;
5733 if (in < 0.0)
5734 in = 0.0;
5735 if (le > (double)m)
5736 le = (double)m;
5737
5738 /*
5739 * Now we go to integer form, rounding up
5740 */
Owen Taylor3473f882001-02-23 17:55:21 +00005741 i = (int) in;
5742 if (((double)i) != in) i++;
5743
Owen Taylor3473f882001-02-23 17:55:21 +00005744 l = (int) le;
5745 if (((double)l) != le) l++;
5746
Daniel Veillard97ac1312001-05-30 19:14:17 +00005747 if (l > m) l=m;
Owen Taylor3473f882001-02-23 17:55:21 +00005748
5749 /* number of chars to copy */
5750 l -= i;
5751
Daniel Veillard97ac1312001-05-30 19:14:17 +00005752 ret = xmlUTF8Strsub(str->stringval, i, l);
Owen Taylor3473f882001-02-23 17:55:21 +00005753 if (ret == NULL)
5754 valuePush(ctxt, xmlXPathNewCString(""));
5755 else {
5756 valuePush(ctxt, xmlXPathNewString(ret));
5757 xmlFree(ret);
5758 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005759
Owen Taylor3473f882001-02-23 17:55:21 +00005760 xmlXPathFreeObject(str);
5761}
5762
5763/**
5764 * xmlXPathSubstringBeforeFunction:
5765 * @ctxt: the XPath Parser context
5766 * @nargs: the number of arguments
5767 *
5768 * Implement the substring-before() XPath function
5769 * string substring-before(string, string)
5770 * The substring-before function returns the substring of the first
5771 * argument string that precedes the first occurrence of the second
5772 * argument string in the first argument string, or the empty string
5773 * if the first argument string does not contain the second argument
5774 * string. For example, substring-before("1999/04/01","/") returns 1999.
5775 */
5776void
5777xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5778 xmlXPathObjectPtr str;
5779 xmlXPathObjectPtr find;
5780 xmlBufferPtr target;
5781 const xmlChar *point;
5782 int offset;
5783
5784 CHECK_ARITY(2);
5785 CAST_TO_STRING;
5786 find = valuePop(ctxt);
5787 CAST_TO_STRING;
5788 str = valuePop(ctxt);
5789
5790 target = xmlBufferCreate();
5791 if (target) {
5792 point = xmlStrstr(str->stringval, find->stringval);
5793 if (point) {
5794 offset = (int)(point - str->stringval);
5795 xmlBufferAdd(target, str->stringval, offset);
5796 }
5797 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5798 xmlBufferFree(target);
5799 }
5800
5801 xmlXPathFreeObject(str);
5802 xmlXPathFreeObject(find);
5803}
5804
5805/**
5806 * xmlXPathSubstringAfterFunction:
5807 * @ctxt: the XPath Parser context
5808 * @nargs: the number of arguments
5809 *
5810 * Implement the substring-after() XPath function
5811 * string substring-after(string, string)
5812 * The substring-after function returns the substring of the first
5813 * argument string that follows the first occurrence of the second
5814 * argument string in the first argument string, or the empty stringi
5815 * if the first argument string does not contain the second argument
5816 * string. For example, substring-after("1999/04/01","/") returns 04/01,
5817 * and substring-after("1999/04/01","19") returns 99/04/01.
5818 */
5819void
5820xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5821 xmlXPathObjectPtr str;
5822 xmlXPathObjectPtr find;
5823 xmlBufferPtr target;
5824 const xmlChar *point;
5825 int offset;
5826
5827 CHECK_ARITY(2);
5828 CAST_TO_STRING;
5829 find = valuePop(ctxt);
5830 CAST_TO_STRING;
5831 str = valuePop(ctxt);
5832
5833 target = xmlBufferCreate();
5834 if (target) {
5835 point = xmlStrstr(str->stringval, find->stringval);
5836 if (point) {
5837 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
5838 xmlBufferAdd(target, &str->stringval[offset],
5839 xmlStrlen(str->stringval) - offset);
5840 }
5841 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5842 xmlBufferFree(target);
5843 }
5844
5845 xmlXPathFreeObject(str);
5846 xmlXPathFreeObject(find);
5847}
5848
5849/**
5850 * xmlXPathNormalizeFunction:
5851 * @ctxt: the XPath Parser context
5852 * @nargs: the number of arguments
5853 *
5854 * Implement the normalize-space() XPath function
5855 * string normalize-space(string?)
5856 * The normalize-space function returns the argument string with white
5857 * space normalized by stripping leading and trailing whitespace
5858 * and replacing sequences of whitespace characters by a single
5859 * space. Whitespace characters are the same allowed by the S production
5860 * in XML. If the argument is omitted, it defaults to the context
5861 * node converted to a string, in other words the value of the context node.
5862 */
5863void
5864xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5865 xmlXPathObjectPtr obj = NULL;
5866 xmlChar *source = NULL;
5867 xmlBufferPtr target;
5868 xmlChar blank;
5869
5870 if (nargs == 0) {
5871 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005872 valuePush(ctxt,
5873 xmlXPathWrapString(
5874 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00005875 nargs = 1;
5876 }
5877
5878 CHECK_ARITY(1);
5879 CAST_TO_STRING;
5880 CHECK_TYPE(XPATH_STRING);
5881 obj = valuePop(ctxt);
5882 source = obj->stringval;
5883
5884 target = xmlBufferCreate();
5885 if (target && source) {
5886
5887 /* Skip leading whitespaces */
5888 while (IS_BLANK(*source))
5889 source++;
5890
5891 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
5892 blank = 0;
5893 while (*source) {
5894 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005895 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00005896 } else {
5897 if (blank) {
5898 xmlBufferAdd(target, &blank, 1);
5899 blank = 0;
5900 }
5901 xmlBufferAdd(target, source, 1);
5902 }
5903 source++;
5904 }
5905
5906 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5907 xmlBufferFree(target);
5908 }
5909 xmlXPathFreeObject(obj);
5910}
5911
5912/**
5913 * xmlXPathTranslateFunction:
5914 * @ctxt: the XPath Parser context
5915 * @nargs: the number of arguments
5916 *
5917 * Implement the translate() XPath function
5918 * string translate(string, string, string)
5919 * The translate function returns the first argument string with
5920 * occurrences of characters in the second argument string replaced
5921 * by the character at the corresponding position in the third argument
5922 * string. For example, translate("bar","abc","ABC") returns the string
5923 * BAr. If there is a character in the second argument string with no
5924 * character at a corresponding position in the third argument string
5925 * (because the second argument string is longer than the third argument
5926 * string), then occurrences of that character in the first argument
5927 * string are removed. For example, translate("--aaa--","abc-","ABC")
5928 * returns "AAA". If a character occurs more than once in second
5929 * argument string, then the first occurrence determines the replacement
5930 * character. If the third argument string is longer than the second
5931 * argument string, then excess characters are ignored.
5932 */
5933void
5934xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00005935 xmlXPathObjectPtr str;
5936 xmlXPathObjectPtr from;
5937 xmlXPathObjectPtr to;
5938 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005939 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00005940 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005941 xmlChar *point;
5942 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00005943
Daniel Veillarde043ee12001-04-16 14:08:07 +00005944 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00005945
Daniel Veillarde043ee12001-04-16 14:08:07 +00005946 CAST_TO_STRING;
5947 to = valuePop(ctxt);
5948 CAST_TO_STRING;
5949 from = valuePop(ctxt);
5950 CAST_TO_STRING;
5951 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005952
Daniel Veillarde043ee12001-04-16 14:08:07 +00005953 target = xmlBufferCreate();
5954 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005955 max = xmlUTF8Strlen(to->stringval);
5956 for (cptr = str->stringval; (ch=*cptr); ) {
5957 offset = xmlUTF8Strloc(from->stringval, cptr);
5958 if (offset >= 0) {
5959 if (offset < max) {
5960 point = xmlUTF8Strpos(to->stringval, offset);
5961 if (point)
5962 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
5963 }
5964 } else
5965 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
5966
5967 /* Step to next character in input */
5968 cptr++;
5969 if ( ch & 0x80 ) {
5970 /* if not simple ascii, verify proper format */
5971 if ( (ch & 0xc0) != 0xc0 ) {
5972 xmlGenericError(xmlGenericErrorContext,
5973 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5974 break;
5975 }
5976 /* then skip over remaining bytes for this char */
5977 while ( (ch <<= 1) & 0x80 )
5978 if ( (*cptr++ & 0xc0) != 0x80 ) {
5979 xmlGenericError(xmlGenericErrorContext,
5980 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5981 break;
5982 }
5983 if (ch & 0x80) /* must have had error encountered */
5984 break;
5985 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005986 }
Owen Taylor3473f882001-02-23 17:55:21 +00005987 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005988 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5989 xmlBufferFree(target);
5990 xmlXPathFreeObject(str);
5991 xmlXPathFreeObject(from);
5992 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00005993}
5994
5995/**
5996 * xmlXPathBooleanFunction:
5997 * @ctxt: the XPath Parser context
5998 * @nargs: the number of arguments
5999 *
6000 * Implement the boolean() XPath function
6001 * boolean boolean(object)
6002 * he boolean function converts its argument to a boolean as follows:
6003 * - a number is true if and only if it is neither positive or
6004 * negative zero nor NaN
6005 * - a node-set is true if and only if it is non-empty
6006 * - a string is true if and only if its length is non-zero
6007 */
6008void
6009xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6010 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006011
6012 CHECK_ARITY(1);
6013 cur = valuePop(ctxt);
6014 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006015 cur = xmlXPathConvertBoolean(cur);
6016 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006017}
6018
6019/**
6020 * xmlXPathNotFunction:
6021 * @ctxt: the XPath Parser context
6022 * @nargs: the number of arguments
6023 *
6024 * Implement the not() XPath function
6025 * boolean not(boolean)
6026 * The not function returns true if its argument is false,
6027 * and false otherwise.
6028 */
6029void
6030xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6031 CHECK_ARITY(1);
6032 CAST_TO_BOOLEAN;
6033 CHECK_TYPE(XPATH_BOOLEAN);
6034 ctxt->value->boolval = ! ctxt->value->boolval;
6035}
6036
6037/**
6038 * xmlXPathTrueFunction:
6039 * @ctxt: the XPath Parser context
6040 * @nargs: the number of arguments
6041 *
6042 * Implement the true() XPath function
6043 * boolean true()
6044 */
6045void
6046xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6047 CHECK_ARITY(0);
6048 valuePush(ctxt, xmlXPathNewBoolean(1));
6049}
6050
6051/**
6052 * xmlXPathFalseFunction:
6053 * @ctxt: the XPath Parser context
6054 * @nargs: the number of arguments
6055 *
6056 * Implement the false() XPath function
6057 * boolean false()
6058 */
6059void
6060xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6061 CHECK_ARITY(0);
6062 valuePush(ctxt, xmlXPathNewBoolean(0));
6063}
6064
6065/**
6066 * xmlXPathLangFunction:
6067 * @ctxt: the XPath Parser context
6068 * @nargs: the number of arguments
6069 *
6070 * Implement the lang() XPath function
6071 * boolean lang(string)
6072 * The lang function returns true or false depending on whether the
6073 * language of the context node as specified by xml:lang attributes
6074 * is the same as or is a sublanguage of the language specified by
6075 * the argument string. The language of the context node is determined
6076 * by the value of the xml:lang attribute on the context node, or, if
6077 * the context node has no xml:lang attribute, by the value of the
6078 * xml:lang attribute on the nearest ancestor of the context node that
6079 * has an xml:lang attribute. If there is no such attribute, then lang
6080 * returns false. If there is such an attribute, then lang returns
6081 * true if the attribute value is equal to the argument ignoring case,
6082 * or if there is some suffix starting with - such that the attribute
6083 * value is equal to the argument ignoring that suffix of the attribute
6084 * value and ignoring case.
6085 */
6086void
6087xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6088 xmlXPathObjectPtr val;
6089 const xmlChar *theLang;
6090 const xmlChar *lang;
6091 int ret = 0;
6092 int i;
6093
6094 CHECK_ARITY(1);
6095 CAST_TO_STRING;
6096 CHECK_TYPE(XPATH_STRING);
6097 val = valuePop(ctxt);
6098 lang = val->stringval;
6099 theLang = xmlNodeGetLang(ctxt->context->node);
6100 if ((theLang != NULL) && (lang != NULL)) {
6101 for (i = 0;lang[i] != 0;i++)
6102 if (toupper(lang[i]) != toupper(theLang[i]))
6103 goto not_equal;
6104 ret = 1;
6105 }
6106not_equal:
6107 xmlXPathFreeObject(val);
6108 valuePush(ctxt, xmlXPathNewBoolean(ret));
6109}
6110
6111/**
6112 * xmlXPathNumberFunction:
6113 * @ctxt: the XPath Parser context
6114 * @nargs: the number of arguments
6115 *
6116 * Implement the number() XPath function
6117 * number number(object?)
6118 */
6119void
6120xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6121 xmlXPathObjectPtr cur;
6122 double res;
6123
6124 if (nargs == 0) {
6125 if (ctxt->context->node == NULL) {
6126 valuePush(ctxt, xmlXPathNewFloat(0.0));
6127 } else {
6128 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6129
6130 res = xmlXPathStringEvalNumber(content);
6131 valuePush(ctxt, xmlXPathNewFloat(res));
6132 xmlFree(content);
6133 }
6134 return;
6135 }
6136
6137 CHECK_ARITY(1);
6138 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006139 cur = xmlXPathConvertNumber(cur);
6140 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006141}
6142
6143/**
6144 * xmlXPathSumFunction:
6145 * @ctxt: the XPath Parser context
6146 * @nargs: the number of arguments
6147 *
6148 * Implement the sum() XPath function
6149 * number sum(node-set)
6150 * The sum function returns the sum of the values of the nodes in
6151 * the argument node-set.
6152 */
6153void
6154xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6155 xmlXPathObjectPtr cur;
6156 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006157 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006158
6159 CHECK_ARITY(1);
6160 if ((ctxt->value == NULL) ||
6161 ((ctxt->value->type != XPATH_NODESET) &&
6162 (ctxt->value->type != XPATH_XSLT_TREE)))
6163 XP_ERROR(XPATH_INVALID_TYPE);
6164 cur = valuePop(ctxt);
6165
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006166 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006167 valuePush(ctxt, xmlXPathNewFloat(0.0));
6168 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006169 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6170 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006171 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006172 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006173 }
6174 xmlXPathFreeObject(cur);
6175}
6176
6177/**
6178 * xmlXPathFloorFunction:
6179 * @ctxt: the XPath Parser context
6180 * @nargs: the number of arguments
6181 *
6182 * Implement the floor() XPath function
6183 * number floor(number)
6184 * The floor function returns the largest (closest to positive infinity)
6185 * number that is not greater than the argument and that is an integer.
6186 */
6187void
6188xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6189 CHECK_ARITY(1);
6190 CAST_TO_NUMBER;
6191 CHECK_TYPE(XPATH_NUMBER);
6192#if 0
6193 ctxt->value->floatval = floor(ctxt->value->floatval);
6194#else
6195 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
6196 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
6197#endif
6198}
6199
6200/**
6201 * xmlXPathCeilingFunction:
6202 * @ctxt: the XPath Parser context
6203 * @nargs: the number of arguments
6204 *
6205 * Implement the ceiling() XPath function
6206 * number ceiling(number)
6207 * The ceiling function returns the smallest (closest to negative infinity)
6208 * number that is not less than the argument and that is an integer.
6209 */
6210void
6211xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6212 double f;
6213
6214 CHECK_ARITY(1);
6215 CAST_TO_NUMBER;
6216 CHECK_TYPE(XPATH_NUMBER);
6217
6218#if 0
6219 ctxt->value->floatval = ceil(ctxt->value->floatval);
6220#else
6221 f = (double)((int) ctxt->value->floatval);
6222 if (f != ctxt->value->floatval)
6223 ctxt->value->floatval = f + 1;
6224#endif
6225}
6226
6227/**
6228 * xmlXPathRoundFunction:
6229 * @ctxt: the XPath Parser context
6230 * @nargs: the number of arguments
6231 *
6232 * Implement the round() XPath function
6233 * number round(number)
6234 * The round function returns the number that is closest to the
6235 * argument and that is an integer. If there are two such numbers,
6236 * then the one that is even is returned.
6237 */
6238void
6239xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6240 double f;
6241
6242 CHECK_ARITY(1);
6243 CAST_TO_NUMBER;
6244 CHECK_TYPE(XPATH_NUMBER);
6245
Daniel Veillardcda96922001-08-21 10:56:31 +00006246 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
6247 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
6248 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00006249 (ctxt->value->floatval == 0.0))
6250 return;
6251
6252#if 0
6253 f = floor(ctxt->value->floatval);
6254#else
6255 f = (double)((int) ctxt->value->floatval);
6256#endif
6257 if (ctxt->value->floatval < f + 0.5)
6258 ctxt->value->floatval = f;
6259 else
6260 ctxt->value->floatval = f + 1;
6261}
6262
6263/************************************************************************
6264 * *
6265 * The Parser *
6266 * *
6267 ************************************************************************/
6268
6269/*
6270 * a couple of forward declarations since we use a recursive call based
6271 * implementation.
6272 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006273static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006274static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006275static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006276#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006277static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
6278#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006279#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006280static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006281#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00006282static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
6283 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00006284
6285/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00006286 * xmlXPathCurrentChar:
6287 * @ctxt: the XPath parser context
6288 * @cur: pointer to the beginning of the char
6289 * @len: pointer to the length of the char read
6290 *
6291 * The current char value, if using UTF-8 this may actaully span multiple
6292 * bytes in the input buffer.
6293 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006294 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00006295 */
6296
6297static int
6298xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
6299 unsigned char c;
6300 unsigned int val;
6301 const xmlChar *cur;
6302
6303 if (ctxt == NULL)
6304 return(0);
6305 cur = ctxt->cur;
6306
6307 /*
6308 * We are supposed to handle UTF8, check it's valid
6309 * From rfc2044: encoding of the Unicode values on UTF-8:
6310 *
6311 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
6312 * 0000 0000-0000 007F 0xxxxxxx
6313 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
6314 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
6315 *
6316 * Check for the 0x110000 limit too
6317 */
6318 c = *cur;
6319 if (c & 0x80) {
6320 if ((cur[1] & 0xc0) != 0x80)
6321 goto encoding_error;
6322 if ((c & 0xe0) == 0xe0) {
6323
6324 if ((cur[2] & 0xc0) != 0x80)
6325 goto encoding_error;
6326 if ((c & 0xf0) == 0xf0) {
6327 if (((c & 0xf8) != 0xf0) ||
6328 ((cur[3] & 0xc0) != 0x80))
6329 goto encoding_error;
6330 /* 4-byte code */
6331 *len = 4;
6332 val = (cur[0] & 0x7) << 18;
6333 val |= (cur[1] & 0x3f) << 12;
6334 val |= (cur[2] & 0x3f) << 6;
6335 val |= cur[3] & 0x3f;
6336 } else {
6337 /* 3-byte code */
6338 *len = 3;
6339 val = (cur[0] & 0xf) << 12;
6340 val |= (cur[1] & 0x3f) << 6;
6341 val |= cur[2] & 0x3f;
6342 }
6343 } else {
6344 /* 2-byte code */
6345 *len = 2;
6346 val = (cur[0] & 0x1f) << 6;
6347 val |= cur[1] & 0x3f;
6348 }
6349 if (!IS_CHAR(val)) {
6350 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
6351 }
6352 return(val);
6353 } else {
6354 /* 1-byte code */
6355 *len = 1;
6356 return((int) *cur);
6357 }
6358encoding_error:
6359 /*
6360 * If we detect an UTF8 error that probably mean that the
6361 * input encoding didn't get properly advertized in the
6362 * declaration header. Report the error and switch the encoding
6363 * to ISO-Latin-1 (if you don't like this policy, just declare the
6364 * encoding !)
6365 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00006366 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00006367 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006368}
6369
6370/**
Owen Taylor3473f882001-02-23 17:55:21 +00006371 * xmlXPathParseNCName:
6372 * @ctxt: the XPath Parser context
6373 *
6374 * parse an XML namespace non qualified name.
6375 *
6376 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
6377 *
6378 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
6379 * CombiningChar | Extender
6380 *
6381 * Returns the namespace name or NULL
6382 */
6383
6384xmlChar *
6385xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00006386 const xmlChar *in;
6387 xmlChar *ret;
6388 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006389
Daniel Veillard2156a562001-04-28 12:24:34 +00006390 /*
6391 * Accelerator for simple ASCII names
6392 */
6393 in = ctxt->cur;
6394 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6395 ((*in >= 0x41) && (*in <= 0x5A)) ||
6396 (*in == '_')) {
6397 in++;
6398 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6399 ((*in >= 0x41) && (*in <= 0x5A)) ||
6400 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00006401 (*in == '_') || (*in == '.') ||
6402 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00006403 in++;
6404 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
6405 (*in == '[') || (*in == ']') || (*in == ':') ||
6406 (*in == '@') || (*in == '*')) {
6407 count = in - ctxt->cur;
6408 if (count == 0)
6409 return(NULL);
6410 ret = xmlStrndup(ctxt->cur, count);
6411 ctxt->cur = in;
6412 return(ret);
6413 }
6414 }
6415 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00006416}
6417
Daniel Veillard2156a562001-04-28 12:24:34 +00006418
Owen Taylor3473f882001-02-23 17:55:21 +00006419/**
6420 * xmlXPathParseQName:
6421 * @ctxt: the XPath Parser context
6422 * @prefix: a xmlChar **
6423 *
6424 * parse an XML qualified name
6425 *
6426 * [NS 5] QName ::= (Prefix ':')? LocalPart
6427 *
6428 * [NS 6] Prefix ::= NCName
6429 *
6430 * [NS 7] LocalPart ::= NCName
6431 *
6432 * Returns the function returns the local part, and prefix is updated
6433 * to get the Prefix if any.
6434 */
6435
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006436static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006437xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
6438 xmlChar *ret = NULL;
6439
6440 *prefix = NULL;
6441 ret = xmlXPathParseNCName(ctxt);
6442 if (CUR == ':') {
6443 *prefix = ret;
6444 NEXT;
6445 ret = xmlXPathParseNCName(ctxt);
6446 }
6447 return(ret);
6448}
6449
6450/**
6451 * xmlXPathParseName:
6452 * @ctxt: the XPath Parser context
6453 *
6454 * parse an XML name
6455 *
6456 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6457 * CombiningChar | Extender
6458 *
6459 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6460 *
6461 * Returns the namespace name or NULL
6462 */
6463
6464xmlChar *
6465xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006466 const xmlChar *in;
6467 xmlChar *ret;
6468 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006469
Daniel Veillard61d80a22001-04-27 17:13:01 +00006470 /*
6471 * Accelerator for simple ASCII names
6472 */
6473 in = ctxt->cur;
6474 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6475 ((*in >= 0x41) && (*in <= 0x5A)) ||
6476 (*in == '_') || (*in == ':')) {
6477 in++;
6478 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6479 ((*in >= 0x41) && (*in <= 0x5A)) ||
6480 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00006481 (*in == '_') || (*in == '-') ||
6482 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00006483 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00006484 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006485 count = in - ctxt->cur;
6486 ret = xmlStrndup(ctxt->cur, count);
6487 ctxt->cur = in;
6488 return(ret);
6489 }
6490 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006491 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00006492}
6493
Daniel Veillard61d80a22001-04-27 17:13:01 +00006494static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00006495xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006496 xmlChar buf[XML_MAX_NAMELEN + 5];
6497 int len = 0, l;
6498 int c;
6499
6500 /*
6501 * Handler for more complex cases
6502 */
6503 c = CUR_CHAR(l);
6504 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00006505 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
6506 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00006507 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00006508 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006509 return(NULL);
6510 }
6511
6512 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
6513 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
6514 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006515 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006516 (IS_COMBINING(c)) ||
6517 (IS_EXTENDER(c)))) {
6518 COPY_BUF(l,buf,len,c);
6519 NEXTL(l);
6520 c = CUR_CHAR(l);
6521 if (len >= XML_MAX_NAMELEN) {
6522 /*
6523 * Okay someone managed to make a huge name, so he's ready to pay
6524 * for the processing speed.
6525 */
6526 xmlChar *buffer;
6527 int max = len * 2;
6528
6529 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
6530 if (buffer == NULL) {
6531 XP_ERROR0(XPATH_MEMORY_ERROR);
6532 }
6533 memcpy(buffer, buf, len);
6534 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
6535 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006536 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006537 (IS_COMBINING(c)) ||
6538 (IS_EXTENDER(c))) {
6539 if (len + 10 > max) {
6540 max *= 2;
6541 buffer = (xmlChar *) xmlRealloc(buffer,
6542 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00006543 if (buffer == NULL) {
6544 XP_ERROR0(XPATH_MEMORY_ERROR);
6545 }
6546 }
6547 COPY_BUF(l,buffer,len,c);
6548 NEXTL(l);
6549 c = CUR_CHAR(l);
6550 }
6551 buffer[len] = 0;
6552 return(buffer);
6553 }
6554 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006555 if (len == 0)
6556 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006557 return(xmlStrndup(buf, len));
6558}
Owen Taylor3473f882001-02-23 17:55:21 +00006559/**
6560 * xmlXPathStringEvalNumber:
6561 * @str: A string to scan
6562 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00006563 * [30a] Float ::= Number ('e' Digits?)?
6564 *
Owen Taylor3473f882001-02-23 17:55:21 +00006565 * [30] Number ::= Digits ('.' Digits?)?
6566 * | '.' Digits
6567 * [31] Digits ::= [0-9]+
6568 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006569 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00006570 * In complement of the Number expression, this function also handles
6571 * negative values : '-' Number.
6572 *
6573 * Returns the double value.
6574 */
6575double
6576xmlXPathStringEvalNumber(const xmlChar *str) {
6577 const xmlChar *cur = str;
6578 double ret = 0.0;
6579 double mult = 1;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006580 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006581 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006582 int exponent = 0;
6583 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006584#ifdef __GNUC__
6585 unsigned long tmp = 0;
6586#endif
Bjorn Reese70a9da52001-04-21 16:57:29 +00006587
Owen Taylor3473f882001-02-23 17:55:21 +00006588 while (IS_BLANK(*cur)) cur++;
6589 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
6590 return(xmlXPathNAN);
6591 }
6592 if (*cur == '-') {
6593 isneg = 1;
6594 cur++;
6595 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00006596
6597#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006598 /*
Daniel Veillardb06c6142001-08-27 14:26:30 +00006599 * tmp is a workaround against a gcc compiler bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006600 */
Owen Taylor3473f882001-02-23 17:55:21 +00006601 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006602 tmp = tmp * 10 + (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00006603 ok = 1;
6604 cur++;
6605 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006606 ret = (double) tmp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006607#else
6608 while ((*cur >= '0') && (*cur <= '9')) {
6609 ret = ret * 10 + (*cur - '0');
6610 ok = 1;
6611 cur++;
6612 }
6613#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006614
Owen Taylor3473f882001-02-23 17:55:21 +00006615 if (*cur == '.') {
6616 cur++;
6617 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
6618 return(xmlXPathNAN);
6619 }
6620 while ((*cur >= '0') && (*cur <= '9')) {
6621 mult /= 10;
6622 ret = ret + (*cur - '0') * mult;
6623 cur++;
6624 }
6625 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006626 if ((*cur == 'e') || (*cur == 'E')) {
6627 cur++;
6628 if (*cur == '-') {
6629 is_exponent_negative = 1;
6630 cur++;
6631 }
6632 while ((*cur >= '0') && (*cur <= '9')) {
6633 exponent = exponent * 10 + (*cur - '0');
6634 cur++;
6635 }
6636 }
Owen Taylor3473f882001-02-23 17:55:21 +00006637 while (IS_BLANK(*cur)) cur++;
6638 if (*cur != 0) return(xmlXPathNAN);
6639 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006640 if (is_exponent_negative) exponent = -exponent;
6641 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00006642 return(ret);
6643}
6644
6645/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006646 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00006647 * @ctxt: the XPath Parser context
6648 *
6649 * [30] Number ::= Digits ('.' Digits?)?
6650 * | '.' Digits
6651 * [31] Digits ::= [0-9]+
6652 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006653 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00006654 *
6655 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006656static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006657xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
6658{
Owen Taylor3473f882001-02-23 17:55:21 +00006659 double ret = 0.0;
6660 double mult = 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006661 int ok = 0, tmp = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006662 int exponent = 0;
6663 int is_exponent_negative = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006664
6665 CHECK_ERROR;
6666 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
6667 XP_ERROR(XPATH_NUMBER_ERROR);
6668 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006669 /*
6670 * Try to work around a gcc optimizer bug
6671 */
Owen Taylor3473f882001-02-23 17:55:21 +00006672 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006673 tmp = tmp * 10 + (CUR - '0');
6674 ok = 1;
6675 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +00006676 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006677 ret = (double) tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00006678 if (CUR == '.') {
6679 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006680 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
6681 XP_ERROR(XPATH_NUMBER_ERROR);
6682 }
6683 while ((CUR >= '0') && (CUR <= '9')) {
6684 mult /= 10;
6685 ret = ret + (CUR - '0') * mult;
6686 NEXT;
6687 }
Owen Taylor3473f882001-02-23 17:55:21 +00006688 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006689 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006690 NEXT;
6691 if (CUR == '-') {
6692 is_exponent_negative = 1;
6693 NEXT;
6694 }
6695 while ((CUR >= '0') && (CUR <= '9')) {
6696 exponent = exponent * 10 + (CUR - '0');
6697 NEXT;
6698 }
6699 if (is_exponent_negative)
6700 exponent = -exponent;
6701 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006702 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006703 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006704 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006705}
6706
6707/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006708 * xmlXPathParseLiteral:
6709 * @ctxt: the XPath Parser context
6710 *
6711 * Parse a Literal
6712 *
6713 * [29] Literal ::= '"' [^"]* '"'
6714 * | "'" [^']* "'"
6715 *
6716 * Returns the value found or NULL in case of error
6717 */
6718static xmlChar *
6719xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
6720 const xmlChar *q;
6721 xmlChar *ret = NULL;
6722
6723 if (CUR == '"') {
6724 NEXT;
6725 q = CUR_PTR;
6726 while ((IS_CHAR(CUR)) && (CUR != '"'))
6727 NEXT;
6728 if (!IS_CHAR(CUR)) {
6729 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6730 } else {
6731 ret = xmlStrndup(q, CUR_PTR - q);
6732 NEXT;
6733 }
6734 } else if (CUR == '\'') {
6735 NEXT;
6736 q = CUR_PTR;
6737 while ((IS_CHAR(CUR)) && (CUR != '\''))
6738 NEXT;
6739 if (!IS_CHAR(CUR)) {
6740 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6741 } else {
6742 ret = xmlStrndup(q, CUR_PTR - q);
6743 NEXT;
6744 }
6745 } else {
6746 XP_ERROR0(XPATH_START_LITERAL_ERROR);
6747 }
6748 return(ret);
6749}
6750
6751/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006752 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00006753 * @ctxt: the XPath Parser context
6754 *
6755 * Parse a Literal and push it on the stack.
6756 *
6757 * [29] Literal ::= '"' [^"]* '"'
6758 * | "'" [^']* "'"
6759 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006760 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00006761 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006762static void
6763xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006764 const xmlChar *q;
6765 xmlChar *ret = NULL;
6766
6767 if (CUR == '"') {
6768 NEXT;
6769 q = CUR_PTR;
6770 while ((IS_CHAR(CUR)) && (CUR != '"'))
6771 NEXT;
6772 if (!IS_CHAR(CUR)) {
6773 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
6774 } else {
6775 ret = xmlStrndup(q, CUR_PTR - q);
6776 NEXT;
6777 }
6778 } else if (CUR == '\'') {
6779 NEXT;
6780 q = CUR_PTR;
6781 while ((IS_CHAR(CUR)) && (CUR != '\''))
6782 NEXT;
6783 if (!IS_CHAR(CUR)) {
6784 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
6785 } else {
6786 ret = xmlStrndup(q, CUR_PTR - q);
6787 NEXT;
6788 }
6789 } else {
6790 XP_ERROR(XPATH_START_LITERAL_ERROR);
6791 }
6792 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006793 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
6794 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006795 xmlFree(ret);
6796}
6797
6798/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006799 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00006800 * @ctxt: the XPath Parser context
6801 *
6802 * Parse a VariableReference, evaluate it and push it on the stack.
6803 *
6804 * The variable bindings consist of a mapping from variable names
6805 * to variable values. The value of a variable is an object, which
6806 * of any of the types that are possible for the value of an expression,
6807 * and may also be of additional types not specified here.
6808 *
6809 * Early evaluation is possible since:
6810 * The variable bindings [...] used to evaluate a subexpression are
6811 * always the same as those used to evaluate the containing expression.
6812 *
6813 * [36] VariableReference ::= '$' QName
6814 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006815static void
6816xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006817 xmlChar *name;
6818 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006819
6820 SKIP_BLANKS;
6821 if (CUR != '$') {
6822 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
6823 }
6824 NEXT;
6825 name = xmlXPathParseQName(ctxt, &prefix);
6826 if (name == NULL) {
6827 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
6828 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006829 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006830 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
6831 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006832 SKIP_BLANKS;
6833}
6834
6835/**
6836 * xmlXPathIsNodeType:
6837 * @ctxt: the XPath Parser context
6838 * @name: a name string
6839 *
6840 * Is the name given a NodeType one.
6841 *
6842 * [38] NodeType ::= 'comment'
6843 * | 'text'
6844 * | 'processing-instruction'
6845 * | 'node'
6846 *
6847 * Returns 1 if true 0 otherwise
6848 */
6849int
6850xmlXPathIsNodeType(const xmlChar *name) {
6851 if (name == NULL)
6852 return(0);
6853
6854 if (xmlStrEqual(name, BAD_CAST "comment"))
6855 return(1);
6856 if (xmlStrEqual(name, BAD_CAST "text"))
6857 return(1);
6858 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
6859 return(1);
6860 if (xmlStrEqual(name, BAD_CAST "node"))
6861 return(1);
6862 return(0);
6863}
6864
6865/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006866 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00006867 * @ctxt: the XPath Parser context
6868 *
6869 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
6870 * [17] Argument ::= Expr
6871 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006872 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00006873 * pushed on the stack
6874 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006875static void
6876xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006877 xmlChar *name;
6878 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006879 int nbargs = 0;
6880
6881 name = xmlXPathParseQName(ctxt, &prefix);
6882 if (name == NULL) {
6883 XP_ERROR(XPATH_EXPR_ERROR);
6884 }
6885 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006886#ifdef DEBUG_EXPR
6887 if (prefix == NULL)
6888 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
6889 name);
6890 else
6891 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
6892 prefix, name);
6893#endif
6894
Owen Taylor3473f882001-02-23 17:55:21 +00006895 if (CUR != '(') {
6896 XP_ERROR(XPATH_EXPR_ERROR);
6897 }
6898 NEXT;
6899 SKIP_BLANKS;
6900
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006901 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006902 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006903 int op1 = ctxt->comp->last;
6904 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006905 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006906 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006907 nbargs++;
6908 if (CUR == ')') break;
6909 if (CUR != ',') {
6910 XP_ERROR(XPATH_EXPR_ERROR);
6911 }
6912 NEXT;
6913 SKIP_BLANKS;
6914 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006915 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
6916 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006917 NEXT;
6918 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006919}
6920
6921/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006922 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006923 * @ctxt: the XPath Parser context
6924 *
6925 * [15] PrimaryExpr ::= VariableReference
6926 * | '(' Expr ')'
6927 * | Literal
6928 * | Number
6929 * | FunctionCall
6930 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006931 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006932 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006933static void
6934xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006935 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006936 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006937 else if (CUR == '(') {
6938 NEXT;
6939 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006940 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006941 if (CUR != ')') {
6942 XP_ERROR(XPATH_EXPR_ERROR);
6943 }
6944 NEXT;
6945 SKIP_BLANKS;
6946 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006947 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006948 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006949 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006950 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006951 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006952 }
6953 SKIP_BLANKS;
6954}
6955
6956/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006957 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006958 * @ctxt: the XPath Parser context
6959 *
6960 * [20] FilterExpr ::= PrimaryExpr
6961 * | FilterExpr Predicate
6962 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006963 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006964 * Square brackets are used to filter expressions in the same way that
6965 * they are used in location paths. It is an error if the expression to
6966 * be filtered does not evaluate to a node-set. The context node list
6967 * used for evaluating the expression in square brackets is the node-set
6968 * to be filtered listed in document order.
6969 */
6970
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006971static void
6972xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
6973 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006974 CHECK_ERROR;
6975 SKIP_BLANKS;
6976
6977 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006978 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00006979 SKIP_BLANKS;
6980 }
6981
6982
6983}
6984
6985/**
6986 * xmlXPathScanName:
6987 * @ctxt: the XPath Parser context
6988 *
6989 * Trickery: parse an XML name but without consuming the input flow
6990 * Needed to avoid insanity in the parser state.
6991 *
6992 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6993 * CombiningChar | Extender
6994 *
6995 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6996 *
6997 * [6] Names ::= Name (S Name)*
6998 *
6999 * Returns the Name parsed or NULL
7000 */
7001
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007002static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007003xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7004 xmlChar buf[XML_MAX_NAMELEN];
7005 int len = 0;
7006
7007 SKIP_BLANKS;
7008 if (!IS_LETTER(CUR) && (CUR != '_') &&
7009 (CUR != ':')) {
7010 return(NULL);
7011 }
7012
7013 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7014 (NXT(len) == '.') || (NXT(len) == '-') ||
7015 (NXT(len) == '_') || (NXT(len) == ':') ||
7016 (IS_COMBINING(NXT(len))) ||
7017 (IS_EXTENDER(NXT(len)))) {
7018 buf[len] = NXT(len);
7019 len++;
7020 if (len >= XML_MAX_NAMELEN) {
7021 xmlGenericError(xmlGenericErrorContext,
7022 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7023 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7024 (NXT(len) == '.') || (NXT(len) == '-') ||
7025 (NXT(len) == '_') || (NXT(len) == ':') ||
7026 (IS_COMBINING(NXT(len))) ||
7027 (IS_EXTENDER(NXT(len))))
7028 len++;
7029 break;
7030 }
7031 }
7032 return(xmlStrndup(buf, len));
7033}
7034
7035/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007036 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007037 * @ctxt: the XPath Parser context
7038 *
7039 * [19] PathExpr ::= LocationPath
7040 * | FilterExpr
7041 * | FilterExpr '/' RelativeLocationPath
7042 * | FilterExpr '//' RelativeLocationPath
7043 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007044 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007045 * The / operator and // operators combine an arbitrary expression
7046 * and a relative location path. It is an error if the expression
7047 * does not evaluate to a node-set.
7048 * The / operator does composition in the same way as when / is
7049 * used in a location path. As in location paths, // is short for
7050 * /descendant-or-self::node()/.
7051 */
7052
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007053static void
7054xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007055 int lc = 1; /* Should we branch to LocationPath ? */
7056 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7057
7058 SKIP_BLANKS;
7059 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
7060 (CUR == '\'') || (CUR == '"')) {
7061 lc = 0;
7062 } else if (CUR == '*') {
7063 /* relative or absolute location path */
7064 lc = 1;
7065 } else if (CUR == '/') {
7066 /* relative or absolute location path */
7067 lc = 1;
7068 } else if (CUR == '@') {
7069 /* relative abbreviated attribute location path */
7070 lc = 1;
7071 } else if (CUR == '.') {
7072 /* relative abbreviated attribute location path */
7073 lc = 1;
7074 } else {
7075 /*
7076 * Problem is finding if we have a name here whether it's:
7077 * - a nodetype
7078 * - a function call in which case it's followed by '('
7079 * - an axis in which case it's followed by ':'
7080 * - a element name
7081 * We do an a priori analysis here rather than having to
7082 * maintain parsed token content through the recursive function
7083 * calls. This looks uglier but makes the code quite easier to
7084 * read/write/debug.
7085 */
7086 SKIP_BLANKS;
7087 name = xmlXPathScanName(ctxt);
7088 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7089#ifdef DEBUG_STEP
7090 xmlGenericError(xmlGenericErrorContext,
7091 "PathExpr: Axis\n");
7092#endif
7093 lc = 1;
7094 xmlFree(name);
7095 } else if (name != NULL) {
7096 int len =xmlStrlen(name);
7097 int blank = 0;
7098
7099
7100 while (NXT(len) != 0) {
7101 if (NXT(len) == '/') {
7102 /* element name */
7103#ifdef DEBUG_STEP
7104 xmlGenericError(xmlGenericErrorContext,
7105 "PathExpr: AbbrRelLocation\n");
7106#endif
7107 lc = 1;
7108 break;
7109 } else if (IS_BLANK(NXT(len))) {
7110 /* skip to next */
7111 blank = 1;
7112 } else if (NXT(len) == ':') {
7113#ifdef DEBUG_STEP
7114 xmlGenericError(xmlGenericErrorContext,
7115 "PathExpr: AbbrRelLocation\n");
7116#endif
7117 lc = 1;
7118 break;
7119 } else if ((NXT(len) == '(')) {
7120 /* Note Type or Function */
7121 if (xmlXPathIsNodeType(name)) {
7122#ifdef DEBUG_STEP
7123 xmlGenericError(xmlGenericErrorContext,
7124 "PathExpr: Type search\n");
7125#endif
7126 lc = 1;
7127 } else {
7128#ifdef DEBUG_STEP
7129 xmlGenericError(xmlGenericErrorContext,
7130 "PathExpr: function call\n");
7131#endif
7132 lc = 0;
7133 }
7134 break;
7135 } else if ((NXT(len) == '[')) {
7136 /* element name */
7137#ifdef DEBUG_STEP
7138 xmlGenericError(xmlGenericErrorContext,
7139 "PathExpr: AbbrRelLocation\n");
7140#endif
7141 lc = 1;
7142 break;
7143 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7144 (NXT(len) == '=')) {
7145 lc = 1;
7146 break;
7147 } else {
7148 lc = 1;
7149 break;
7150 }
7151 len++;
7152 }
7153 if (NXT(len) == 0) {
7154#ifdef DEBUG_STEP
7155 xmlGenericError(xmlGenericErrorContext,
7156 "PathExpr: AbbrRelLocation\n");
7157#endif
7158 /* element name */
7159 lc = 1;
7160 }
7161 xmlFree(name);
7162 } else {
7163 /* make sure all cases are covered explicitely */
7164 XP_ERROR(XPATH_EXPR_ERROR);
7165 }
7166 }
7167
7168 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007169 if (CUR == '/') {
7170 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7171 } else {
7172 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007173 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007174 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007175 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007176 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007177 CHECK_ERROR;
7178 if ((CUR == '/') && (NXT(1) == '/')) {
7179 SKIP(2);
7180 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007181
7182 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7183 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7184 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7185
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007186 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007187 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007188 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007189 }
7190 }
7191 SKIP_BLANKS;
7192}
7193
7194/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007195 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007196 * @ctxt: the XPath Parser context
7197 *
7198 * [18] UnionExpr ::= PathExpr
7199 * | UnionExpr '|' PathExpr
7200 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007201 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007202 */
7203
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007204static void
7205xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7206 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007207 CHECK_ERROR;
7208 SKIP_BLANKS;
7209 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007210 int op1 = ctxt->comp->last;
7211 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007212
7213 NEXT;
7214 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007215 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007216
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007217 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
7218
Owen Taylor3473f882001-02-23 17:55:21 +00007219 SKIP_BLANKS;
7220 }
Owen Taylor3473f882001-02-23 17:55:21 +00007221}
7222
7223/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007224 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007225 * @ctxt: the XPath Parser context
7226 *
7227 * [27] UnaryExpr ::= UnionExpr
7228 * | '-' UnaryExpr
7229 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007230 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007231 */
7232
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007233static void
7234xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007235 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007236 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007237
7238 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00007239 while (CUR == '-') {
7240 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007241 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007242 NEXT;
7243 SKIP_BLANKS;
7244 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007245
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007246 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007247 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007248 if (found) {
7249 if (minus)
7250 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
7251 else
7252 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007253 }
7254}
7255
7256/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007257 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007258 * @ctxt: the XPath Parser context
7259 *
7260 * [26] MultiplicativeExpr ::= UnaryExpr
7261 * | MultiplicativeExpr MultiplyOperator UnaryExpr
7262 * | MultiplicativeExpr 'div' UnaryExpr
7263 * | MultiplicativeExpr 'mod' UnaryExpr
7264 * [34] MultiplyOperator ::= '*'
7265 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007266 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007267 */
7268
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007269static void
7270xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
7271 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007272 CHECK_ERROR;
7273 SKIP_BLANKS;
7274 while ((CUR == '*') ||
7275 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
7276 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
7277 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007278 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007279
7280 if (CUR == '*') {
7281 op = 0;
7282 NEXT;
7283 } else if (CUR == 'd') {
7284 op = 1;
7285 SKIP(3);
7286 } else if (CUR == 'm') {
7287 op = 2;
7288 SKIP(3);
7289 }
7290 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007291 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007292 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007293 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007294 SKIP_BLANKS;
7295 }
7296}
7297
7298/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007299 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007300 * @ctxt: the XPath Parser context
7301 *
7302 * [25] AdditiveExpr ::= MultiplicativeExpr
7303 * | AdditiveExpr '+' MultiplicativeExpr
7304 * | AdditiveExpr '-' MultiplicativeExpr
7305 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007306 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007307 */
7308
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007309static void
7310xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007311
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007312 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007313 CHECK_ERROR;
7314 SKIP_BLANKS;
7315 while ((CUR == '+') || (CUR == '-')) {
7316 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007317 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007318
7319 if (CUR == '+') plus = 1;
7320 else plus = 0;
7321 NEXT;
7322 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007323 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007324 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007325 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007326 SKIP_BLANKS;
7327 }
7328}
7329
7330/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007331 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007332 * @ctxt: the XPath Parser context
7333 *
7334 * [24] RelationalExpr ::= AdditiveExpr
7335 * | RelationalExpr '<' AdditiveExpr
7336 * | RelationalExpr '>' AdditiveExpr
7337 * | RelationalExpr '<=' AdditiveExpr
7338 * | RelationalExpr '>=' AdditiveExpr
7339 *
7340 * A <= B > C is allowed ? Answer from James, yes with
7341 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
7342 * which is basically what got implemented.
7343 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007344 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00007345 * on the stack
7346 */
7347
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007348static void
7349xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
7350 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007351 CHECK_ERROR;
7352 SKIP_BLANKS;
7353 while ((CUR == '<') ||
7354 (CUR == '>') ||
7355 ((CUR == '<') && (NXT(1) == '=')) ||
7356 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007357 int inf, strict;
7358 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007359
7360 if (CUR == '<') inf = 1;
7361 else inf = 0;
7362 if (NXT(1) == '=') strict = 0;
7363 else strict = 1;
7364 NEXT;
7365 if (!strict) NEXT;
7366 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007367 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007368 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007369 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00007370 SKIP_BLANKS;
7371 }
7372}
7373
7374/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007375 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007376 * @ctxt: the XPath Parser context
7377 *
7378 * [23] EqualityExpr ::= RelationalExpr
7379 * | EqualityExpr '=' RelationalExpr
7380 * | EqualityExpr '!=' RelationalExpr
7381 *
7382 * A != B != C is allowed ? Answer from James, yes with
7383 * (RelationalExpr = RelationalExpr) = RelationalExpr
7384 * (RelationalExpr != RelationalExpr) != RelationalExpr
7385 * which is basically what got implemented.
7386 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007387 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007388 *
7389 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007390static void
7391xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
7392 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007393 CHECK_ERROR;
7394 SKIP_BLANKS;
7395 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007396 int eq;
7397 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007398
7399 if (CUR == '=') eq = 1;
7400 else eq = 0;
7401 NEXT;
7402 if (!eq) NEXT;
7403 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007404 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007405 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007406 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007407 SKIP_BLANKS;
7408 }
7409}
7410
7411/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007412 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007413 * @ctxt: the XPath Parser context
7414 *
7415 * [22] AndExpr ::= EqualityExpr
7416 * | AndExpr 'and' EqualityExpr
7417 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007418 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007419 *
7420 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007421static void
7422xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
7423 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007424 CHECK_ERROR;
7425 SKIP_BLANKS;
7426 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007427 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007428 SKIP(3);
7429 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007430 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007431 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007432 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007433 SKIP_BLANKS;
7434 }
7435}
7436
7437/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007438 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007439 * @ctxt: the XPath Parser context
7440 *
7441 * [14] Expr ::= OrExpr
7442 * [21] OrExpr ::= AndExpr
7443 * | OrExpr 'or' AndExpr
7444 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007445 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00007446 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007447static void
7448xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
7449 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007450 CHECK_ERROR;
7451 SKIP_BLANKS;
7452 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007453 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007454 SKIP(2);
7455 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007456 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007457 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007458 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
7459 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00007460 SKIP_BLANKS;
7461 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007462 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
7463 /* more ops could be optimized too */
7464 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
7465 }
Owen Taylor3473f882001-02-23 17:55:21 +00007466}
7467
7468/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007469 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00007470 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007471 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00007472 *
7473 * [8] Predicate ::= '[' PredicateExpr ']'
7474 * [9] PredicateExpr ::= Expr
7475 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007476 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00007477 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007478static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007479xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007480 int op1 = ctxt->comp->last;
7481
7482 SKIP_BLANKS;
7483 if (CUR != '[') {
7484 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7485 }
7486 NEXT;
7487 SKIP_BLANKS;
7488
7489 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007490 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007491 CHECK_ERROR;
7492
7493 if (CUR != ']') {
7494 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7495 }
7496
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007497 if (filter)
7498 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
7499 else
7500 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007501
7502 NEXT;
7503 SKIP_BLANKS;
7504}
7505
7506/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007507 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00007508 * @ctxt: the XPath Parser context
7509 * @test: pointer to a xmlXPathTestVal
7510 * @type: pointer to a xmlXPathTypeVal
7511 * @prefix: placeholder for a possible name prefix
7512 *
7513 * [7] NodeTest ::= NameTest
7514 * | NodeType '(' ')'
7515 * | 'processing-instruction' '(' Literal ')'
7516 *
7517 * [37] NameTest ::= '*'
7518 * | NCName ':' '*'
7519 * | QName
7520 * [38] NodeType ::= 'comment'
7521 * | 'text'
7522 * | 'processing-instruction'
7523 * | 'node'
7524 *
7525 * Returns the name found and update @test, @type and @prefix appropriately
7526 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007527static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007528xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
7529 xmlXPathTypeVal *type, const xmlChar **prefix,
7530 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00007531 int blanks;
7532
7533 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
7534 STRANGE;
7535 return(NULL);
7536 }
7537 *type = 0;
7538 *test = 0;
7539 *prefix = NULL;
7540 SKIP_BLANKS;
7541
7542 if ((name == NULL) && (CUR == '*')) {
7543 /*
7544 * All elements
7545 */
7546 NEXT;
7547 *test = NODE_TEST_ALL;
7548 return(NULL);
7549 }
7550
7551 if (name == NULL)
7552 name = xmlXPathParseNCName(ctxt);
7553 if (name == NULL) {
7554 XP_ERROR0(XPATH_EXPR_ERROR);
7555 }
7556
7557 blanks = IS_BLANK(CUR);
7558 SKIP_BLANKS;
7559 if (CUR == '(') {
7560 NEXT;
7561 /*
7562 * NodeType or PI search
7563 */
7564 if (xmlStrEqual(name, BAD_CAST "comment"))
7565 *type = NODE_TYPE_COMMENT;
7566 else if (xmlStrEqual(name, BAD_CAST "node"))
7567 *type = NODE_TYPE_NODE;
7568 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
7569 *type = NODE_TYPE_PI;
7570 else if (xmlStrEqual(name, BAD_CAST "text"))
7571 *type = NODE_TYPE_TEXT;
7572 else {
7573 if (name != NULL)
7574 xmlFree(name);
7575 XP_ERROR0(XPATH_EXPR_ERROR);
7576 }
7577
7578 *test = NODE_TEST_TYPE;
7579
7580 SKIP_BLANKS;
7581 if (*type == NODE_TYPE_PI) {
7582 /*
7583 * Specific case: search a PI by name.
7584 */
Owen Taylor3473f882001-02-23 17:55:21 +00007585 if (name != NULL)
7586 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00007587 name = NULL;
7588 if (CUR != ')') {
7589 name = xmlXPathParseLiteral(ctxt);
7590 CHECK_ERROR 0;
7591 SKIP_BLANKS;
7592 }
Owen Taylor3473f882001-02-23 17:55:21 +00007593 }
7594 if (CUR != ')') {
7595 if (name != NULL)
7596 xmlFree(name);
7597 XP_ERROR0(XPATH_UNCLOSED_ERROR);
7598 }
7599 NEXT;
7600 return(name);
7601 }
7602 *test = NODE_TEST_NAME;
7603 if ((!blanks) && (CUR == ':')) {
7604 NEXT;
7605
7606 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007607 * Since currently the parser context don't have a
7608 * namespace list associated:
7609 * The namespace name for this prefix can be computed
7610 * only at evaluation time. The compilation is done
7611 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00007612 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007613#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00007614 *prefix = xmlXPathNsLookup(ctxt->context, name);
7615 if (name != NULL)
7616 xmlFree(name);
7617 if (*prefix == NULL) {
7618 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
7619 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007620#else
7621 *prefix = name;
7622#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007623
7624 if (CUR == '*') {
7625 /*
7626 * All elements
7627 */
7628 NEXT;
7629 *test = NODE_TEST_ALL;
7630 return(NULL);
7631 }
7632
7633 name = xmlXPathParseNCName(ctxt);
7634 if (name == NULL) {
7635 XP_ERROR0(XPATH_EXPR_ERROR);
7636 }
7637 }
7638 return(name);
7639}
7640
7641/**
7642 * xmlXPathIsAxisName:
7643 * @name: a preparsed name token
7644 *
7645 * [6] AxisName ::= 'ancestor'
7646 * | 'ancestor-or-self'
7647 * | 'attribute'
7648 * | 'child'
7649 * | 'descendant'
7650 * | 'descendant-or-self'
7651 * | 'following'
7652 * | 'following-sibling'
7653 * | 'namespace'
7654 * | 'parent'
7655 * | 'preceding'
7656 * | 'preceding-sibling'
7657 * | 'self'
7658 *
7659 * Returns the axis or 0
7660 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007661static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00007662xmlXPathIsAxisName(const xmlChar *name) {
7663 xmlXPathAxisVal ret = 0;
7664 switch (name[0]) {
7665 case 'a':
7666 if (xmlStrEqual(name, BAD_CAST "ancestor"))
7667 ret = AXIS_ANCESTOR;
7668 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
7669 ret = AXIS_ANCESTOR_OR_SELF;
7670 if (xmlStrEqual(name, BAD_CAST "attribute"))
7671 ret = AXIS_ATTRIBUTE;
7672 break;
7673 case 'c':
7674 if (xmlStrEqual(name, BAD_CAST "child"))
7675 ret = AXIS_CHILD;
7676 break;
7677 case 'd':
7678 if (xmlStrEqual(name, BAD_CAST "descendant"))
7679 ret = AXIS_DESCENDANT;
7680 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
7681 ret = AXIS_DESCENDANT_OR_SELF;
7682 break;
7683 case 'f':
7684 if (xmlStrEqual(name, BAD_CAST "following"))
7685 ret = AXIS_FOLLOWING;
7686 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
7687 ret = AXIS_FOLLOWING_SIBLING;
7688 break;
7689 case 'n':
7690 if (xmlStrEqual(name, BAD_CAST "namespace"))
7691 ret = AXIS_NAMESPACE;
7692 break;
7693 case 'p':
7694 if (xmlStrEqual(name, BAD_CAST "parent"))
7695 ret = AXIS_PARENT;
7696 if (xmlStrEqual(name, BAD_CAST "preceding"))
7697 ret = AXIS_PRECEDING;
7698 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
7699 ret = AXIS_PRECEDING_SIBLING;
7700 break;
7701 case 's':
7702 if (xmlStrEqual(name, BAD_CAST "self"))
7703 ret = AXIS_SELF;
7704 break;
7705 }
7706 return(ret);
7707}
7708
7709/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007710 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00007711 * @ctxt: the XPath Parser context
7712 *
7713 * [4] Step ::= AxisSpecifier NodeTest Predicate*
7714 * | AbbreviatedStep
7715 *
7716 * [12] AbbreviatedStep ::= '.' | '..'
7717 *
7718 * [5] AxisSpecifier ::= AxisName '::'
7719 * | AbbreviatedAxisSpecifier
7720 *
7721 * [13] AbbreviatedAxisSpecifier ::= '@'?
7722 *
7723 * Modified for XPtr range support as:
7724 *
7725 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
7726 * | AbbreviatedStep
7727 * | 'range-to' '(' Expr ')' Predicate*
7728 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007729 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00007730 * A location step of . is short for self::node(). This is
7731 * particularly useful in conjunction with //. For example, the
7732 * location path .//para is short for
7733 * self::node()/descendant-or-self::node()/child::para
7734 * and so will select all para descendant elements of the context
7735 * node.
7736 * Similarly, a location step of .. is short for parent::node().
7737 * For example, ../title is short for parent::node()/child::title
7738 * and so will select the title children of the parent of the context
7739 * node.
7740 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007741static void
7742xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007743#ifdef LIBXML_XPTR_ENABLED
7744 int rangeto = 0;
7745 int op2 = -1;
7746#endif
7747
Owen Taylor3473f882001-02-23 17:55:21 +00007748 SKIP_BLANKS;
7749 if ((CUR == '.') && (NXT(1) == '.')) {
7750 SKIP(2);
7751 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007752 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
7753 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007754 } else if (CUR == '.') {
7755 NEXT;
7756 SKIP_BLANKS;
7757 } else {
7758 xmlChar *name = NULL;
7759 const xmlChar *prefix = NULL;
7760 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007761 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007762 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007763 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00007764
7765 /*
7766 * The modification needed for XPointer change to the production
7767 */
7768#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007769 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00007770 name = xmlXPathParseNCName(ctxt);
7771 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007772 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007773 xmlFree(name);
7774 SKIP_BLANKS;
7775 if (CUR != '(') {
7776 XP_ERROR(XPATH_EXPR_ERROR);
7777 }
7778 NEXT;
7779 SKIP_BLANKS;
7780
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007781 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007782 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00007783 CHECK_ERROR;
7784
7785 SKIP_BLANKS;
7786 if (CUR != ')') {
7787 XP_ERROR(XPATH_EXPR_ERROR);
7788 }
7789 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007790 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007791 goto eval_predicates;
7792 }
7793 }
7794#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00007795 if (CUR == '*') {
7796 axis = AXIS_CHILD;
7797 } else {
7798 if (name == NULL)
7799 name = xmlXPathParseNCName(ctxt);
7800 if (name != NULL) {
7801 axis = xmlXPathIsAxisName(name);
7802 if (axis != 0) {
7803 SKIP_BLANKS;
7804 if ((CUR == ':') && (NXT(1) == ':')) {
7805 SKIP(2);
7806 xmlFree(name);
7807 name = NULL;
7808 } else {
7809 /* an element name can conflict with an axis one :-\ */
7810 axis = AXIS_CHILD;
7811 }
Owen Taylor3473f882001-02-23 17:55:21 +00007812 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00007813 axis = AXIS_CHILD;
7814 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007815 } else if (CUR == '@') {
7816 NEXT;
7817 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00007818 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00007819 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00007820 }
Owen Taylor3473f882001-02-23 17:55:21 +00007821 }
7822
7823 CHECK_ERROR;
7824
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007825 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00007826 if (test == 0)
7827 return;
7828
7829#ifdef DEBUG_STEP
7830 xmlGenericError(xmlGenericErrorContext,
7831 "Basis : computing new set\n");
7832#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007833
Owen Taylor3473f882001-02-23 17:55:21 +00007834#ifdef DEBUG_STEP
7835 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007836 if (ctxt->value == NULL)
7837 xmlGenericError(xmlGenericErrorContext, "no value\n");
7838 else if (ctxt->value->nodesetval == NULL)
7839 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7840 else
7841 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007842#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007843
7844eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007845 op1 = ctxt->comp->last;
7846 ctxt->comp->last = -1;
7847
Owen Taylor3473f882001-02-23 17:55:21 +00007848 SKIP_BLANKS;
7849 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007850 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007851 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007852
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007853#ifdef LIBXML_XPTR_ENABLED
7854 if (rangeto) {
7855 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
7856 } else
7857#endif
7858 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
7859 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007860
Owen Taylor3473f882001-02-23 17:55:21 +00007861 }
7862#ifdef DEBUG_STEP
7863 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007864 if (ctxt->value == NULL)
7865 xmlGenericError(xmlGenericErrorContext, "no value\n");
7866 else if (ctxt->value->nodesetval == NULL)
7867 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7868 else
7869 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
7870 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007871#endif
7872}
7873
7874/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007875 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007876 * @ctxt: the XPath Parser context
7877 *
7878 * [3] RelativeLocationPath ::= Step
7879 * | RelativeLocationPath '/' Step
7880 * | AbbreviatedRelativeLocationPath
7881 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
7882 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007883 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00007884 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007885static void
Owen Taylor3473f882001-02-23 17:55:21 +00007886#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007887xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007888#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007889xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007890#endif
7891(xmlXPathParserContextPtr ctxt) {
7892 SKIP_BLANKS;
7893 if ((CUR == '/') && (NXT(1) == '/')) {
7894 SKIP(2);
7895 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007896 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7897 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007898 } else if (CUR == '/') {
7899 NEXT;
7900 SKIP_BLANKS;
7901 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007902 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007903 SKIP_BLANKS;
7904 while (CUR == '/') {
7905 if ((CUR == '/') && (NXT(1) == '/')) {
7906 SKIP(2);
7907 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007908 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00007909 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007910 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007911 } else if (CUR == '/') {
7912 NEXT;
7913 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007914 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007915 }
7916 SKIP_BLANKS;
7917 }
7918}
7919
7920/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007921 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007922 * @ctxt: the XPath Parser context
7923 *
7924 * [1] LocationPath ::= RelativeLocationPath
7925 * | AbsoluteLocationPath
7926 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
7927 * | AbbreviatedAbsoluteLocationPath
7928 * [10] AbbreviatedAbsoluteLocationPath ::=
7929 * '//' RelativeLocationPath
7930 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007931 * Compile a location path
7932 *
Owen Taylor3473f882001-02-23 17:55:21 +00007933 * // is short for /descendant-or-self::node()/. For example,
7934 * //para is short for /descendant-or-self::node()/child::para and
7935 * so will select any para element in the document (even a para element
7936 * that is a document element will be selected by //para since the
7937 * document element node is a child of the root node); div//para is
7938 * short for div/descendant-or-self::node()/child::para and so will
7939 * select all para descendants of div children.
7940 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007941static void
7942xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007943 SKIP_BLANKS;
7944 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007945 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007946 } else {
7947 while (CUR == '/') {
7948 if ((CUR == '/') && (NXT(1) == '/')) {
7949 SKIP(2);
7950 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007951 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7952 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007953 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007954 } else if (CUR == '/') {
7955 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00007956 SKIP_BLANKS;
7957 if ((CUR != 0 ) &&
7958 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
7959 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007960 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007961 }
7962 }
7963 }
7964}
7965
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007966/************************************************************************
7967 * *
7968 * XPath precompiled expression evaluation *
7969 * *
7970 ************************************************************************/
7971
Daniel Veillardf06307e2001-07-03 10:35:50 +00007972static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007973xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
7974
7975/**
7976 * xmlXPathNodeCollectAndTest:
7977 * @ctxt: the XPath Parser context
7978 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00007979 * @first: pointer to the first element in document order
7980 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007981 *
7982 * This is the function implementing a step: based on the current list
7983 * of nodes, it builds up a new list, looking at all nodes under that
7984 * axis and selecting them it also do the predicate filtering
7985 *
7986 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00007987 *
7988 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007989 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00007990static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007991xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00007992 xmlXPathStepOpPtr op,
7993 xmlNodePtr * first, xmlNodePtr * last)
7994{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007995 xmlXPathAxisVal axis = op->value;
7996 xmlXPathTestVal test = op->value2;
7997 xmlXPathTypeVal type = op->value3;
7998 const xmlChar *prefix = op->value4;
7999 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008000 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008001
8002#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008003 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008004#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008005 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008006 xmlNodeSetPtr ret, list;
8007 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008008 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008009 xmlNodePtr cur = NULL;
8010 xmlXPathObjectPtr obj;
8011 xmlNodeSetPtr nodelist;
8012 xmlNodePtr tmp;
8013
Daniel Veillardf06307e2001-07-03 10:35:50 +00008014 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008015 obj = valuePop(ctxt);
8016 addNode = xmlXPathNodeSetAdd;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008017 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008018 URI = xmlXPathNsLookup(ctxt->context, prefix);
8019 if (URI == NULL)
8020 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008021 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008022#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008023 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008024#endif
8025 switch (axis) {
8026 case AXIS_ANCESTOR:
8027#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008028 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008029#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008030 first = NULL;
8031 next = xmlXPathNextAncestor;
8032 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008033 case AXIS_ANCESTOR_OR_SELF:
8034#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008035 xmlGenericError(xmlGenericErrorContext,
8036 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008037#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008038 first = NULL;
8039 next = xmlXPathNextAncestorOrSelf;
8040 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008041 case AXIS_ATTRIBUTE:
8042#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008043 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008044#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008045 first = NULL;
8046 last = NULL;
8047 next = xmlXPathNextAttribute;
8048 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008049 case AXIS_CHILD:
8050#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008051 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008052#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008053 last = NULL;
8054 next = xmlXPathNextChild;
8055 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008056 case AXIS_DESCENDANT:
8057#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008058 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008059#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008060 last = NULL;
8061 next = xmlXPathNextDescendant;
8062 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008063 case AXIS_DESCENDANT_OR_SELF:
8064#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008065 xmlGenericError(xmlGenericErrorContext,
8066 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008067#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008068 last = NULL;
8069 next = xmlXPathNextDescendantOrSelf;
8070 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008071 case AXIS_FOLLOWING:
8072#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008073 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008074#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008075 last = NULL;
8076 next = xmlXPathNextFollowing;
8077 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008078 case AXIS_FOLLOWING_SIBLING:
8079#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008080 xmlGenericError(xmlGenericErrorContext,
8081 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008082#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008083 last = NULL;
8084 next = xmlXPathNextFollowingSibling;
8085 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008086 case AXIS_NAMESPACE:
8087#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008088 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008089#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008090 first = NULL;
8091 last = NULL;
8092 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8093 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008094 case AXIS_PARENT:
8095#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008096 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008097#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008098 first = NULL;
8099 next = xmlXPathNextParent;
8100 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008101 case AXIS_PRECEDING:
8102#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008103 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008104#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008105 first = NULL;
8106 next = xmlXPathNextPrecedingInternal;
8107 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008108 case AXIS_PRECEDING_SIBLING:
8109#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008110 xmlGenericError(xmlGenericErrorContext,
8111 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008112#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008113 first = NULL;
8114 next = xmlXPathNextPrecedingSibling;
8115 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008116 case AXIS_SELF:
8117#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008118 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008119#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008120 first = NULL;
8121 last = NULL;
8122 next = xmlXPathNextSelf;
8123 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008124 }
8125 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008126 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008127
8128 nodelist = obj->nodesetval;
8129 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008130 xmlXPathFreeObject(obj);
8131 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8132 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008133 }
8134 addNode = xmlXPathNodeSetAddUnique;
8135 ret = NULL;
8136#ifdef DEBUG_STEP
8137 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008138 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008139 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008140 case NODE_TEST_NONE:
8141 xmlGenericError(xmlGenericErrorContext,
8142 " searching for none !!!\n");
8143 break;
8144 case NODE_TEST_TYPE:
8145 xmlGenericError(xmlGenericErrorContext,
8146 " searching for type %d\n", type);
8147 break;
8148 case NODE_TEST_PI:
8149 xmlGenericError(xmlGenericErrorContext,
8150 " searching for PI !!!\n");
8151 break;
8152 case NODE_TEST_ALL:
8153 xmlGenericError(xmlGenericErrorContext,
8154 " searching for *\n");
8155 break;
8156 case NODE_TEST_NS:
8157 xmlGenericError(xmlGenericErrorContext,
8158 " searching for namespace %s\n",
8159 prefix);
8160 break;
8161 case NODE_TEST_NAME:
8162 xmlGenericError(xmlGenericErrorContext,
8163 " searching for name %s\n", name);
8164 if (prefix != NULL)
8165 xmlGenericError(xmlGenericErrorContext,
8166 " with namespace %s\n", prefix);
8167 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008168 }
8169 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8170#endif
8171 /*
8172 * 2.3 Node Tests
8173 * - For the attribute axis, the principal node type is attribute.
8174 * - For the namespace axis, the principal node type is namespace.
8175 * - For other axes, the principal node type is element.
8176 *
8177 * A node test * is true for any node of the
8178 * principal node type. For example, child::* willi
8179 * select all element children of the context node
8180 */
8181 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008182 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008183 ctxt->context->node = nodelist->nodeTab[i];
8184
Daniel Veillardf06307e2001-07-03 10:35:50 +00008185 cur = NULL;
8186 list = xmlXPathNodeSetCreate(NULL);
8187 do {
8188 cur = next(ctxt, cur);
8189 if (cur == NULL)
8190 break;
8191 if ((first != NULL) && (*first == cur))
8192 break;
8193 if (((t % 256) == 0) &&
8194 (first != NULL) && (*first != NULL) &&
8195 (xmlXPathCmpNodes(*first, cur) >= 0))
8196 break;
8197 if ((last != NULL) && (*last == cur))
8198 break;
8199 if (((t % 256) == 0) &&
8200 (last != NULL) && (*last != NULL) &&
8201 (xmlXPathCmpNodes(cur, *last) >= 0))
8202 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008203 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008204#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008205 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8206#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008207 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008208 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008209 ctxt->context->node = tmp;
8210 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008211 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008212 if ((cur->type == type) ||
8213 ((type == NODE_TYPE_NODE) &&
8214 ((cur->type == XML_DOCUMENT_NODE) ||
8215 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8216 (cur->type == XML_ELEMENT_NODE) ||
8217 (cur->type == XML_PI_NODE) ||
8218 (cur->type == XML_COMMENT_NODE) ||
8219 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00008220 (cur->type == XML_TEXT_NODE))) ||
8221 ((type == NODE_TYPE_TEXT) &&
8222 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008223#ifdef DEBUG_STEP
8224 n++;
8225#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008226 addNode(list, cur);
8227 }
8228 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008229 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008230 if (cur->type == XML_PI_NODE) {
8231 if ((name != NULL) &&
8232 (!xmlStrEqual(name, cur->name)))
8233 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008234#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008235 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008236#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008237 addNode(list, cur);
8238 }
8239 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008240 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008241 if (axis == AXIS_ATTRIBUTE) {
8242 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008243#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008244 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008245#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008246 addNode(list, cur);
8247 }
8248 } else if (axis == AXIS_NAMESPACE) {
8249 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008250#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008251 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008252#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008253 addNode(list, cur);
8254 }
8255 } else {
8256 if (cur->type == XML_ELEMENT_NODE) {
8257 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008258#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008259 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008260#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008261 addNode(list, cur);
8262 } else if ((cur->ns != NULL) &&
8263 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008264#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008265 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008266#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008267 addNode(list, cur);
8268 }
8269 }
8270 }
8271 break;
8272 case NODE_TEST_NS:{
8273 TODO;
8274 break;
8275 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008276 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008277 switch (cur->type) {
8278 case XML_ELEMENT_NODE:
8279 if (xmlStrEqual(name, cur->name)) {
8280 if (prefix == NULL) {
8281 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008282#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008283 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008284#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008285 addNode(list, cur);
8286 }
8287 } else {
8288 if ((cur->ns != NULL) &&
8289 (xmlStrEqual(URI,
8290 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008291#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008292 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008293#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008294 addNode(list, cur);
8295 }
8296 }
8297 }
8298 break;
8299 case XML_ATTRIBUTE_NODE:{
8300 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008301
Daniel Veillardf06307e2001-07-03 10:35:50 +00008302 if (xmlStrEqual(name, attr->name)) {
8303 if (prefix == NULL) {
8304 if ((attr->ns == NULL) ||
8305 (attr->ns->prefix == NULL)) {
8306#ifdef DEBUG_STEP
8307 n++;
8308#endif
8309 addNode(list,
8310 (xmlNodePtr) attr);
8311 }
8312 } else {
8313 if ((attr->ns != NULL) &&
8314 (xmlStrEqual(URI,
8315 attr->ns->
8316 href))) {
8317#ifdef DEBUG_STEP
8318 n++;
8319#endif
8320 addNode(list,
8321 (xmlNodePtr) attr);
8322 }
8323 }
8324 }
8325 break;
8326 }
8327 case XML_NAMESPACE_DECL:
8328 if (cur->type == XML_NAMESPACE_DECL) {
8329 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008330
Daniel Veillardf06307e2001-07-03 10:35:50 +00008331 if ((ns->prefix != NULL) && (name != NULL)
8332 && (xmlStrEqual(ns->prefix, name))) {
8333#ifdef DEBUG_STEP
8334 n++;
8335#endif
8336 addNode(list, cur);
8337 }
8338 }
8339 break;
8340 default:
8341 break;
8342 }
8343 break;
8344 break;
8345 }
8346 } while (cur != NULL);
8347
8348 /*
8349 * If there is some predicate filtering do it now
8350 */
8351 if (op->ch2 != -1) {
8352 xmlXPathObjectPtr obj2;
8353
8354 valuePush(ctxt, xmlXPathWrapNodeSet(list));
8355 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
8356 CHECK_TYPE0(XPATH_NODESET);
8357 obj2 = valuePop(ctxt);
8358 list = obj2->nodesetval;
8359 obj2->nodesetval = NULL;
8360 xmlXPathFreeObject(obj2);
8361 }
8362 if (ret == NULL) {
8363 ret = list;
8364 } else {
8365 ret = xmlXPathNodeSetMerge(ret, list);
8366 xmlXPathFreeNodeSet(list);
8367 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008368 }
8369 ctxt->context->node = tmp;
8370#ifdef DEBUG_STEP
8371 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008372 "\nExamined %d nodes, found %d nodes at that step\n",
8373 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008374#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008375 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00008376 if ((obj->boolval) && (obj->user != NULL)) {
8377 ctxt->value->boolval = 1;
8378 ctxt->value->user = obj->user;
8379 obj->user = NULL;
8380 obj->boolval = 0;
8381 }
8382 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008383 return(t);
8384}
8385
8386/**
8387 * xmlXPathNodeCollectAndTestNth:
8388 * @ctxt: the XPath Parser context
8389 * @op: the XPath precompiled step operation
8390 * @indx: the index to collect
8391 * @first: pointer to the first element in document order
8392 * @last: pointer to the last element in document order
8393 *
8394 * This is the function implementing a step: based on the current list
8395 * of nodes, it builds up a new list, looking at all nodes under that
8396 * axis and selecting them it also do the predicate filtering
8397 *
8398 * Pushes the new NodeSet resulting from the search.
8399 * Returns the number of node traversed
8400 */
8401static int
8402xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
8403 xmlXPathStepOpPtr op, int indx,
8404 xmlNodePtr * first, xmlNodePtr * last)
8405{
8406 xmlXPathAxisVal axis = op->value;
8407 xmlXPathTestVal test = op->value2;
8408 xmlXPathTypeVal type = op->value3;
8409 const xmlChar *prefix = op->value4;
8410 const xmlChar *name = op->value5;
8411 const xmlChar *URI = NULL;
8412 int n = 0, t = 0;
8413
8414 int i;
8415 xmlNodeSetPtr list;
8416 xmlXPathTraversalFunction next = NULL;
8417 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
8418 xmlNodePtr cur = NULL;
8419 xmlXPathObjectPtr obj;
8420 xmlNodeSetPtr nodelist;
8421 xmlNodePtr tmp;
8422
8423 CHECK_TYPE0(XPATH_NODESET);
8424 obj = valuePop(ctxt);
8425 addNode = xmlXPathNodeSetAdd;
8426 if (prefix != NULL) {
8427 URI = xmlXPathNsLookup(ctxt->context, prefix);
8428 if (URI == NULL)
8429 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8430 }
8431#ifdef DEBUG_STEP_NTH
8432 xmlGenericError(xmlGenericErrorContext, "new step : ");
8433 if (first != NULL) {
8434 if (*first != NULL)
8435 xmlGenericError(xmlGenericErrorContext, "first = %s ",
8436 (*first)->name);
8437 else
8438 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
8439 }
8440 if (last != NULL) {
8441 if (*last != NULL)
8442 xmlGenericError(xmlGenericErrorContext, "last = %s ",
8443 (*last)->name);
8444 else
8445 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
8446 }
8447#endif
8448 switch (axis) {
8449 case AXIS_ANCESTOR:
8450#ifdef DEBUG_STEP_NTH
8451 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
8452#endif
8453 first = NULL;
8454 next = xmlXPathNextAncestor;
8455 break;
8456 case AXIS_ANCESTOR_OR_SELF:
8457#ifdef DEBUG_STEP_NTH
8458 xmlGenericError(xmlGenericErrorContext,
8459 "axis 'ancestors-or-self' ");
8460#endif
8461 first = NULL;
8462 next = xmlXPathNextAncestorOrSelf;
8463 break;
8464 case AXIS_ATTRIBUTE:
8465#ifdef DEBUG_STEP_NTH
8466 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
8467#endif
8468 first = NULL;
8469 last = NULL;
8470 next = xmlXPathNextAttribute;
8471 break;
8472 case AXIS_CHILD:
8473#ifdef DEBUG_STEP_NTH
8474 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
8475#endif
8476 last = NULL;
8477 next = xmlXPathNextChild;
8478 break;
8479 case AXIS_DESCENDANT:
8480#ifdef DEBUG_STEP_NTH
8481 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
8482#endif
8483 last = NULL;
8484 next = xmlXPathNextDescendant;
8485 break;
8486 case AXIS_DESCENDANT_OR_SELF:
8487#ifdef DEBUG_STEP_NTH
8488 xmlGenericError(xmlGenericErrorContext,
8489 "axis 'descendant-or-self' ");
8490#endif
8491 last = NULL;
8492 next = xmlXPathNextDescendantOrSelf;
8493 break;
8494 case AXIS_FOLLOWING:
8495#ifdef DEBUG_STEP_NTH
8496 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
8497#endif
8498 last = NULL;
8499 next = xmlXPathNextFollowing;
8500 break;
8501 case AXIS_FOLLOWING_SIBLING:
8502#ifdef DEBUG_STEP_NTH
8503 xmlGenericError(xmlGenericErrorContext,
8504 "axis 'following-siblings' ");
8505#endif
8506 last = NULL;
8507 next = xmlXPathNextFollowingSibling;
8508 break;
8509 case AXIS_NAMESPACE:
8510#ifdef DEBUG_STEP_NTH
8511 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
8512#endif
8513 last = NULL;
8514 first = NULL;
8515 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8516 break;
8517 case AXIS_PARENT:
8518#ifdef DEBUG_STEP_NTH
8519 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
8520#endif
8521 first = NULL;
8522 next = xmlXPathNextParent;
8523 break;
8524 case AXIS_PRECEDING:
8525#ifdef DEBUG_STEP_NTH
8526 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
8527#endif
8528 first = NULL;
8529 next = xmlXPathNextPrecedingInternal;
8530 break;
8531 case AXIS_PRECEDING_SIBLING:
8532#ifdef DEBUG_STEP_NTH
8533 xmlGenericError(xmlGenericErrorContext,
8534 "axis 'preceding-sibling' ");
8535#endif
8536 first = NULL;
8537 next = xmlXPathNextPrecedingSibling;
8538 break;
8539 case AXIS_SELF:
8540#ifdef DEBUG_STEP_NTH
8541 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
8542#endif
8543 first = NULL;
8544 last = NULL;
8545 next = xmlXPathNextSelf;
8546 break;
8547 }
8548 if (next == NULL)
8549 return(0);
8550
8551 nodelist = obj->nodesetval;
8552 if (nodelist == NULL) {
8553 xmlXPathFreeObject(obj);
8554 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8555 return(0);
8556 }
8557 addNode = xmlXPathNodeSetAddUnique;
8558#ifdef DEBUG_STEP_NTH
8559 xmlGenericError(xmlGenericErrorContext,
8560 " context contains %d nodes\n", nodelist->nodeNr);
8561 switch (test) {
8562 case NODE_TEST_NONE:
8563 xmlGenericError(xmlGenericErrorContext,
8564 " searching for none !!!\n");
8565 break;
8566 case NODE_TEST_TYPE:
8567 xmlGenericError(xmlGenericErrorContext,
8568 " searching for type %d\n", type);
8569 break;
8570 case NODE_TEST_PI:
8571 xmlGenericError(xmlGenericErrorContext,
8572 " searching for PI !!!\n");
8573 break;
8574 case NODE_TEST_ALL:
8575 xmlGenericError(xmlGenericErrorContext,
8576 " searching for *\n");
8577 break;
8578 case NODE_TEST_NS:
8579 xmlGenericError(xmlGenericErrorContext,
8580 " searching for namespace %s\n",
8581 prefix);
8582 break;
8583 case NODE_TEST_NAME:
8584 xmlGenericError(xmlGenericErrorContext,
8585 " searching for name %s\n", name);
8586 if (prefix != NULL)
8587 xmlGenericError(xmlGenericErrorContext,
8588 " with namespace %s\n", prefix);
8589 break;
8590 }
8591 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8592#endif
8593 /*
8594 * 2.3 Node Tests
8595 * - For the attribute axis, the principal node type is attribute.
8596 * - For the namespace axis, the principal node type is namespace.
8597 * - For other axes, the principal node type is element.
8598 *
8599 * A node test * is true for any node of the
8600 * principal node type. For example, child::* willi
8601 * select all element children of the context node
8602 */
8603 tmp = ctxt->context->node;
8604 list = xmlXPathNodeSetCreate(NULL);
8605 for (i = 0; i < nodelist->nodeNr; i++) {
8606 ctxt->context->node = nodelist->nodeTab[i];
8607
8608 cur = NULL;
8609 n = 0;
8610 do {
8611 cur = next(ctxt, cur);
8612 if (cur == NULL)
8613 break;
8614 if ((first != NULL) && (*first == cur))
8615 break;
8616 if (((t % 256) == 0) &&
8617 (first != NULL) && (*first != NULL) &&
8618 (xmlXPathCmpNodes(*first, cur) >= 0))
8619 break;
8620 if ((last != NULL) && (*last == cur))
8621 break;
8622 if (((t % 256) == 0) &&
8623 (last != NULL) && (*last != NULL) &&
8624 (xmlXPathCmpNodes(cur, *last) >= 0))
8625 break;
8626 t++;
8627 switch (test) {
8628 case NODE_TEST_NONE:
8629 ctxt->context->node = tmp;
8630 STRANGE return(0);
8631 case NODE_TEST_TYPE:
8632 if ((cur->type == type) ||
8633 ((type == NODE_TYPE_NODE) &&
8634 ((cur->type == XML_DOCUMENT_NODE) ||
8635 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8636 (cur->type == XML_ELEMENT_NODE) ||
8637 (cur->type == XML_PI_NODE) ||
8638 (cur->type == XML_COMMENT_NODE) ||
8639 (cur->type == XML_CDATA_SECTION_NODE) ||
8640 (cur->type == XML_TEXT_NODE)))) {
8641 n++;
8642 if (n == indx)
8643 addNode(list, cur);
8644 }
8645 break;
8646 case NODE_TEST_PI:
8647 if (cur->type == XML_PI_NODE) {
8648 if ((name != NULL) &&
8649 (!xmlStrEqual(name, cur->name)))
8650 break;
8651 n++;
8652 if (n == indx)
8653 addNode(list, cur);
8654 }
8655 break;
8656 case NODE_TEST_ALL:
8657 if (axis == AXIS_ATTRIBUTE) {
8658 if (cur->type == XML_ATTRIBUTE_NODE) {
8659 n++;
8660 if (n == indx)
8661 addNode(list, cur);
8662 }
8663 } else if (axis == AXIS_NAMESPACE) {
8664 if (cur->type == XML_NAMESPACE_DECL) {
8665 n++;
8666 if (n == indx)
8667 addNode(list, cur);
8668 }
8669 } else {
8670 if (cur->type == XML_ELEMENT_NODE) {
8671 if (prefix == NULL) {
8672 n++;
8673 if (n == indx)
8674 addNode(list, cur);
8675 } else if ((cur->ns != NULL) &&
8676 (xmlStrEqual(URI, cur->ns->href))) {
8677 n++;
8678 if (n == indx)
8679 addNode(list, cur);
8680 }
8681 }
8682 }
8683 break;
8684 case NODE_TEST_NS:{
8685 TODO;
8686 break;
8687 }
8688 case NODE_TEST_NAME:
8689 switch (cur->type) {
8690 case XML_ELEMENT_NODE:
8691 if (xmlStrEqual(name, cur->name)) {
8692 if (prefix == NULL) {
8693 if (cur->ns == NULL) {
8694 n++;
8695 if (n == indx)
8696 addNode(list, cur);
8697 }
8698 } else {
8699 if ((cur->ns != NULL) &&
8700 (xmlStrEqual(URI,
8701 cur->ns->href))) {
8702 n++;
8703 if (n == indx)
8704 addNode(list, cur);
8705 }
8706 }
8707 }
8708 break;
8709 case XML_ATTRIBUTE_NODE:{
8710 xmlAttrPtr attr = (xmlAttrPtr) cur;
8711
8712 if (xmlStrEqual(name, attr->name)) {
8713 if (prefix == NULL) {
8714 if ((attr->ns == NULL) ||
8715 (attr->ns->prefix == NULL)) {
8716 n++;
8717 if (n == indx)
8718 addNode(list, cur);
8719 }
8720 } else {
8721 if ((attr->ns != NULL) &&
8722 (xmlStrEqual(URI,
8723 attr->ns->
8724 href))) {
8725 n++;
8726 if (n == indx)
8727 addNode(list, cur);
8728 }
8729 }
8730 }
8731 break;
8732 }
8733 case XML_NAMESPACE_DECL:
8734 if (cur->type == XML_NAMESPACE_DECL) {
8735 xmlNsPtr ns = (xmlNsPtr) cur;
8736
8737 if ((ns->prefix != NULL) && (name != NULL)
8738 && (xmlStrEqual(ns->prefix, name))) {
8739 n++;
8740 if (n == indx)
8741 addNode(list, cur);
8742 }
8743 }
8744 break;
8745 default:
8746 break;
8747 }
8748 break;
8749 break;
8750 }
8751 } while (n < indx);
8752 }
8753 ctxt->context->node = tmp;
8754#ifdef DEBUG_STEP_NTH
8755 xmlGenericError(xmlGenericErrorContext,
8756 "\nExamined %d nodes, found %d nodes at that step\n",
8757 t, list->nodeNr);
8758#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008759 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00008760 if ((obj->boolval) && (obj->user != NULL)) {
8761 ctxt->value->boolval = 1;
8762 ctxt->value->user = obj->user;
8763 obj->user = NULL;
8764 obj->boolval = 0;
8765 }
8766 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008767 return(t);
8768}
8769
8770/**
8771 * xmlXPathCompOpEvalFirst:
8772 * @ctxt: the XPath parser context with the compiled expression
8773 * @op: an XPath compiled operation
8774 * @first: the first elem found so far
8775 *
8776 * Evaluate the Precompiled XPath operation searching only the first
8777 * element in document order
8778 *
8779 * Returns the number of examined objects.
8780 */
8781static int
8782xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
8783 xmlXPathStepOpPtr op, xmlNodePtr * first)
8784{
8785 int total = 0, cur;
8786 xmlXPathCompExprPtr comp;
8787 xmlXPathObjectPtr arg1, arg2;
8788
Daniel Veillard556c6682001-10-06 09:59:51 +00008789 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008790 comp = ctxt->comp;
8791 switch (op->op) {
8792 case XPATH_OP_END:
8793 return (0);
8794 case XPATH_OP_UNION:
8795 total =
8796 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
8797 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00008798 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008799 if ((ctxt->value != NULL)
8800 && (ctxt->value->type == XPATH_NODESET)
8801 && (ctxt->value->nodesetval != NULL)
8802 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8803 /*
8804 * limit tree traversing to first node in the result
8805 */
8806 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8807 *first = ctxt->value->nodesetval->nodeTab[0];
8808 }
8809 cur =
8810 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
8811 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00008812 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008813 CHECK_TYPE0(XPATH_NODESET);
8814 arg2 = valuePop(ctxt);
8815
8816 CHECK_TYPE0(XPATH_NODESET);
8817 arg1 = valuePop(ctxt);
8818
8819 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8820 arg2->nodesetval);
8821 valuePush(ctxt, arg1);
8822 xmlXPathFreeObject(arg2);
8823 /* optimizer */
8824 if (total > cur)
8825 xmlXPathCompSwap(op);
8826 return (total + cur);
8827 case XPATH_OP_ROOT:
8828 xmlXPathRoot(ctxt);
8829 return (0);
8830 case XPATH_OP_NODE:
8831 if (op->ch1 != -1)
8832 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008833 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008834 if (op->ch2 != -1)
8835 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008836 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008837 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8838 return (total);
8839 case XPATH_OP_RESET:
8840 if (op->ch1 != -1)
8841 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008842 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008843 if (op->ch2 != -1)
8844 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008845 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008846 ctxt->context->node = NULL;
8847 return (total);
8848 case XPATH_OP_COLLECT:{
8849 if (op->ch1 == -1)
8850 return (total);
8851
8852 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008853 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008854
8855 /*
8856 * Optimization for [n] selection where n is a number
8857 */
8858 if ((op->ch2 != -1) &&
8859 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8860 (comp->steps[op->ch2].ch1 == -1) &&
8861 (comp->steps[op->ch2].ch2 != -1) &&
8862 (comp->steps[comp->steps[op->ch2].ch2].op ==
8863 XPATH_OP_VALUE)) {
8864 xmlXPathObjectPtr val;
8865
8866 val = comp->steps[comp->steps[op->ch2].ch2].value4;
8867 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
8868 int indx = (int) val->floatval;
8869
8870 if (val->floatval == (float) indx) {
8871 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
8872 first, NULL);
8873 return (total);
8874 }
8875 }
8876 }
8877 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
8878 return (total);
8879 }
8880 case XPATH_OP_VALUE:
8881 valuePush(ctxt,
8882 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
8883 return (0);
8884 case XPATH_OP_SORT:
8885 if (op->ch1 != -1)
8886 total +=
8887 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
8888 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00008889 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008890 if ((ctxt->value != NULL)
8891 && (ctxt->value->type == XPATH_NODESET)
8892 && (ctxt->value->nodesetval != NULL))
8893 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8894 return (total);
8895 default:
8896 return (xmlXPathCompOpEval(ctxt, op));
8897 }
8898}
8899
8900/**
8901 * xmlXPathCompOpEvalLast:
8902 * @ctxt: the XPath parser context with the compiled expression
8903 * @op: an XPath compiled operation
8904 * @last: the last elem found so far
8905 *
8906 * Evaluate the Precompiled XPath operation searching only the last
8907 * element in document order
8908 *
8909 * Returns the number of node traversed
8910 */
8911static int
8912xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
8913 xmlNodePtr * last)
8914{
8915 int total = 0, cur;
8916 xmlXPathCompExprPtr comp;
8917 xmlXPathObjectPtr arg1, arg2;
8918
Daniel Veillard556c6682001-10-06 09:59:51 +00008919 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008920 comp = ctxt->comp;
8921 switch (op->op) {
8922 case XPATH_OP_END:
8923 return (0);
8924 case XPATH_OP_UNION:
8925 total =
8926 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00008927 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008928 if ((ctxt->value != NULL)
8929 && (ctxt->value->type == XPATH_NODESET)
8930 && (ctxt->value->nodesetval != NULL)
8931 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8932 /*
8933 * limit tree traversing to first node in the result
8934 */
8935 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8936 *last =
8937 ctxt->value->nodesetval->nodeTab[ctxt->value->
8938 nodesetval->nodeNr -
8939 1];
8940 }
8941 cur =
8942 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00008943 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008944 if ((ctxt->value != NULL)
8945 && (ctxt->value->type == XPATH_NODESET)
8946 && (ctxt->value->nodesetval != NULL)
8947 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8948 }
8949 CHECK_TYPE0(XPATH_NODESET);
8950 arg2 = valuePop(ctxt);
8951
8952 CHECK_TYPE0(XPATH_NODESET);
8953 arg1 = valuePop(ctxt);
8954
8955 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8956 arg2->nodesetval);
8957 valuePush(ctxt, arg1);
8958 xmlXPathFreeObject(arg2);
8959 /* optimizer */
8960 if (total > cur)
8961 xmlXPathCompSwap(op);
8962 return (total + cur);
8963 case XPATH_OP_ROOT:
8964 xmlXPathRoot(ctxt);
8965 return (0);
8966 case XPATH_OP_NODE:
8967 if (op->ch1 != -1)
8968 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008969 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008970 if (op->ch2 != -1)
8971 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008972 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008973 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8974 return (total);
8975 case XPATH_OP_RESET:
8976 if (op->ch1 != -1)
8977 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008978 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008979 if (op->ch2 != -1)
8980 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008981 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008982 ctxt->context->node = NULL;
8983 return (total);
8984 case XPATH_OP_COLLECT:{
8985 if (op->ch1 == -1)
8986 return (0);
8987
8988 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008989 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008990
8991 /*
8992 * Optimization for [n] selection where n is a number
8993 */
8994 if ((op->ch2 != -1) &&
8995 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8996 (comp->steps[op->ch2].ch1 == -1) &&
8997 (comp->steps[op->ch2].ch2 != -1) &&
8998 (comp->steps[comp->steps[op->ch2].ch2].op ==
8999 XPATH_OP_VALUE)) {
9000 xmlXPathObjectPtr val;
9001
9002 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9003 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9004 int indx = (int) val->floatval;
9005
9006 if (val->floatval == (float) indx) {
9007 total +=
9008 xmlXPathNodeCollectAndTestNth(ctxt, op,
9009 indx, NULL,
9010 last);
9011 return (total);
9012 }
9013 }
9014 }
9015 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9016 return (total);
9017 }
9018 case XPATH_OP_VALUE:
9019 valuePush(ctxt,
9020 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9021 return (0);
9022 case XPATH_OP_SORT:
9023 if (op->ch1 != -1)
9024 total +=
9025 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9026 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009027 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009028 if ((ctxt->value != NULL)
9029 && (ctxt->value->type == XPATH_NODESET)
9030 && (ctxt->value->nodesetval != NULL))
9031 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9032 return (total);
9033 default:
9034 return (xmlXPathCompOpEval(ctxt, op));
9035 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009036}
9037
Owen Taylor3473f882001-02-23 17:55:21 +00009038/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009039 * xmlXPathCompOpEval:
9040 * @ctxt: the XPath parser context with the compiled expression
9041 * @op: an XPath compiled operation
9042 *
9043 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009044 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009045 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009046static int
9047xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9048{
9049 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009050 int equal, ret;
9051 xmlXPathCompExprPtr comp;
9052 xmlXPathObjectPtr arg1, arg2;
9053
Daniel Veillard556c6682001-10-06 09:59:51 +00009054 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009055 comp = ctxt->comp;
9056 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009057 case XPATH_OP_END:
9058 return (0);
9059 case XPATH_OP_AND:
9060 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009061 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009062 xmlXPathBooleanFunction(ctxt, 1);
9063 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9064 return (total);
9065 arg2 = valuePop(ctxt);
9066 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009067 if (ctxt->error) {
9068 xmlXPathFreeObject(arg2);
9069 return(0);
9070 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009071 xmlXPathBooleanFunction(ctxt, 1);
9072 arg1 = valuePop(ctxt);
9073 arg1->boolval &= arg2->boolval;
9074 valuePush(ctxt, arg1);
9075 xmlXPathFreeObject(arg2);
9076 return (total);
9077 case XPATH_OP_OR:
9078 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009079 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009080 xmlXPathBooleanFunction(ctxt, 1);
9081 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9082 return (total);
9083 arg2 = valuePop(ctxt);
9084 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009085 if (ctxt->error) {
9086 xmlXPathFreeObject(arg2);
9087 return(0);
9088 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009089 xmlXPathBooleanFunction(ctxt, 1);
9090 arg1 = valuePop(ctxt);
9091 arg1->boolval |= arg2->boolval;
9092 valuePush(ctxt, arg1);
9093 xmlXPathFreeObject(arg2);
9094 return (total);
9095 case XPATH_OP_EQUAL:
9096 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009097 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009098 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009099 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009100 equal = xmlXPathEqualValues(ctxt);
9101 if (op->value)
9102 valuePush(ctxt, xmlXPathNewBoolean(equal));
9103 else
9104 valuePush(ctxt, xmlXPathNewBoolean(!equal));
9105 return (total);
9106 case XPATH_OP_CMP:
9107 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009108 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009109 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009110 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009111 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9112 valuePush(ctxt, xmlXPathNewBoolean(ret));
9113 return (total);
9114 case XPATH_OP_PLUS:
9115 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009116 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009117 if (op->ch2 != -1)
9118 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009119 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009120 if (op->value == 0)
9121 xmlXPathSubValues(ctxt);
9122 else if (op->value == 1)
9123 xmlXPathAddValues(ctxt);
9124 else if (op->value == 2)
9125 xmlXPathValueFlipSign(ctxt);
9126 else if (op->value == 3) {
9127 CAST_TO_NUMBER;
9128 CHECK_TYPE0(XPATH_NUMBER);
9129 }
9130 return (total);
9131 case XPATH_OP_MULT:
9132 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009133 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009134 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009135 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009136 if (op->value == 0)
9137 xmlXPathMultValues(ctxt);
9138 else if (op->value == 1)
9139 xmlXPathDivValues(ctxt);
9140 else if (op->value == 2)
9141 xmlXPathModValues(ctxt);
9142 return (total);
9143 case XPATH_OP_UNION:
9144 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009145 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009146 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009147 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009148 CHECK_TYPE0(XPATH_NODESET);
9149 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009150
Daniel Veillardf06307e2001-07-03 10:35:50 +00009151 CHECK_TYPE0(XPATH_NODESET);
9152 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009153
Daniel Veillardf06307e2001-07-03 10:35:50 +00009154 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9155 arg2->nodesetval);
9156 valuePush(ctxt, arg1);
9157 xmlXPathFreeObject(arg2);
9158 return (total);
9159 case XPATH_OP_ROOT:
9160 xmlXPathRoot(ctxt);
9161 return (total);
9162 case XPATH_OP_NODE:
9163 if (op->ch1 != -1)
9164 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009165 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009166 if (op->ch2 != -1)
9167 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009168 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009169 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9170 return (total);
9171 case XPATH_OP_RESET:
9172 if (op->ch1 != -1)
9173 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009174 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009175 if (op->ch2 != -1)
9176 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009177 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009178 ctxt->context->node = NULL;
9179 return (total);
9180 case XPATH_OP_COLLECT:{
9181 if (op->ch1 == -1)
9182 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009183
Daniel Veillardf06307e2001-07-03 10:35:50 +00009184 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009185 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009186
Daniel Veillardf06307e2001-07-03 10:35:50 +00009187 /*
9188 * Optimization for [n] selection where n is a number
9189 */
9190 if ((op->ch2 != -1) &&
9191 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9192 (comp->steps[op->ch2].ch1 == -1) &&
9193 (comp->steps[op->ch2].ch2 != -1) &&
9194 (comp->steps[comp->steps[op->ch2].ch2].op ==
9195 XPATH_OP_VALUE)) {
9196 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00009197
Daniel Veillardf06307e2001-07-03 10:35:50 +00009198 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9199 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9200 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009201
Daniel Veillardf06307e2001-07-03 10:35:50 +00009202 if (val->floatval == (float) indx) {
9203 total +=
9204 xmlXPathNodeCollectAndTestNth(ctxt, op,
9205 indx, NULL,
9206 NULL);
9207 return (total);
9208 }
9209 }
9210 }
9211 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
9212 return (total);
9213 }
9214 case XPATH_OP_VALUE:
9215 valuePush(ctxt,
9216 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9217 return (total);
9218 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +00009219 xmlXPathObjectPtr val;
9220
Daniel Veillardf06307e2001-07-03 10:35:50 +00009221 if (op->ch1 != -1)
9222 total +=
9223 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009224 if (op->value5 == NULL) {
9225 val = xmlXPathVariableLookup(ctxt->context, op->value4);
9226 if (val == NULL) {
9227 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9228 return(0);
9229 }
9230 valuePush(ctxt, val);
9231 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009232 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009233
Daniel Veillardf06307e2001-07-03 10:35:50 +00009234 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9235 if (URI == NULL) {
9236 xmlGenericError(xmlGenericErrorContext,
9237 "xmlXPathRunEval: variable %s bound to undefined prefix %s\n",
9238 op->value4, op->value5);
9239 return (total);
9240 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009241 val = xmlXPathVariableLookupNS(ctxt->context,
9242 op->value4, URI);
9243 if (val == NULL) {
9244 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9245 return(0);
9246 }
9247 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009248 }
9249 return (total);
9250 }
9251 case XPATH_OP_FUNCTION:{
9252 xmlXPathFunction func;
9253 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +00009254 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009255
9256 if (op->ch1 != -1)
9257 total +=
9258 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009259 if (ctxt->valueNr < op->value) {
9260 xmlGenericError(xmlGenericErrorContext,
9261 "xmlXPathRunEval: parameter error\n");
9262 ctxt->error = XPATH_INVALID_OPERAND;
9263 return (total);
9264 }
9265 for (i = 0; i < op->value; i++)
9266 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
9267 xmlGenericError(xmlGenericErrorContext,
9268 "xmlXPathRunEval: parameter error\n");
9269 ctxt->error = XPATH_INVALID_OPERAND;
9270 return (total);
9271 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009272 if (op->cache != NULL)
9273 func = (xmlXPathFunction) op->cache;
9274 else {
9275 const xmlChar *URI = NULL;
9276
9277 if (op->value5 == NULL)
9278 func =
9279 xmlXPathFunctionLookup(ctxt->context,
9280 op->value4);
9281 else {
9282 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9283 if (URI == NULL) {
9284 xmlGenericError(xmlGenericErrorContext,
9285 "xmlXPathRunEval: function %s bound to undefined prefix %s\n",
9286 op->value4, op->value5);
9287 return (total);
9288 }
9289 func = xmlXPathFunctionLookupNS(ctxt->context,
9290 op->value4, URI);
9291 }
9292 if (func == NULL) {
9293 xmlGenericError(xmlGenericErrorContext,
9294 "xmlXPathRunEval: function %s not found\n",
9295 op->value4);
9296 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009297 }
9298 op->cache = (void *) func;
9299 op->cacheURI = (void *) URI;
9300 }
9301 oldFunc = ctxt->context->function;
9302 oldFuncURI = ctxt->context->functionURI;
9303 ctxt->context->function = op->value4;
9304 ctxt->context->functionURI = op->cacheURI;
9305 func(ctxt, op->value);
9306 ctxt->context->function = oldFunc;
9307 ctxt->context->functionURI = oldFuncURI;
9308 return (total);
9309 }
9310 case XPATH_OP_ARG:
9311 if (op->ch1 != -1)
9312 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009313 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009314 if (op->ch2 != -1)
9315 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009316 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009317 return (total);
9318 case XPATH_OP_PREDICATE:
9319 case XPATH_OP_FILTER:{
9320 xmlXPathObjectPtr res;
9321 xmlXPathObjectPtr obj, tmp;
9322 xmlNodeSetPtr newset = NULL;
9323 xmlNodeSetPtr oldset;
9324 xmlNodePtr oldnode;
9325 int i;
9326
9327 /*
9328 * Optimization for ()[1] selection i.e. the first elem
9329 */
9330 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9331 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9332 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
9333 xmlXPathObjectPtr val;
9334
9335 val = comp->steps[op->ch2].value4;
9336 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
9337 (val->floatval == 1.0)) {
9338 xmlNodePtr first = NULL;
9339
9340 total +=
9341 xmlXPathCompOpEvalFirst(ctxt,
9342 &comp->steps[op->ch1],
9343 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009344 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009345 /*
9346 * The nodeset should be in document order,
9347 * Keep only the first value
9348 */
9349 if ((ctxt->value != NULL) &&
9350 (ctxt->value->type == XPATH_NODESET) &&
9351 (ctxt->value->nodesetval != NULL) &&
9352 (ctxt->value->nodesetval->nodeNr > 1))
9353 ctxt->value->nodesetval->nodeNr = 1;
9354 return (total);
9355 }
9356 }
9357 /*
9358 * Optimization for ()[last()] selection i.e. the last elem
9359 */
9360 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9361 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9362 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
9363 int f = comp->steps[op->ch2].ch1;
9364
9365 if ((f != -1) &&
9366 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
9367 (comp->steps[f].value5 == NULL) &&
9368 (comp->steps[f].value == 0) &&
9369 (comp->steps[f].value4 != NULL) &&
9370 (xmlStrEqual
9371 (comp->steps[f].value4, BAD_CAST "last"))) {
9372 xmlNodePtr last = NULL;
9373
9374 total +=
9375 xmlXPathCompOpEvalLast(ctxt,
9376 &comp->steps[op->ch1],
9377 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009378 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009379 /*
9380 * The nodeset should be in document order,
9381 * Keep only the last value
9382 */
9383 if ((ctxt->value != NULL) &&
9384 (ctxt->value->type == XPATH_NODESET) &&
9385 (ctxt->value->nodesetval != NULL) &&
9386 (ctxt->value->nodesetval->nodeTab != NULL) &&
9387 (ctxt->value->nodesetval->nodeNr > 1)) {
9388 ctxt->value->nodesetval->nodeTab[0] =
9389 ctxt->value->nodesetval->nodeTab[ctxt->
9390 value->
9391 nodesetval->
9392 nodeNr -
9393 1];
9394 ctxt->value->nodesetval->nodeNr = 1;
9395 }
9396 return (total);
9397 }
9398 }
9399
9400 if (op->ch1 != -1)
9401 total +=
9402 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009403 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009404 if (op->ch2 == -1)
9405 return (total);
9406 if (ctxt->value == NULL)
9407 return (total);
9408
9409 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009410
9411#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009412 /*
9413 * Hum are we filtering the result of an XPointer expression
9414 */
9415 if (ctxt->value->type == XPATH_LOCATIONSET) {
9416 xmlLocationSetPtr newlocset = NULL;
9417 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009418
Daniel Veillardf06307e2001-07-03 10:35:50 +00009419 /*
9420 * Extract the old locset, and then evaluate the result of the
9421 * expression for all the element in the locset. use it to grow
9422 * up a new locset.
9423 */
9424 CHECK_TYPE0(XPATH_LOCATIONSET);
9425 obj = valuePop(ctxt);
9426 oldlocset = obj->user;
9427 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009428
Daniel Veillardf06307e2001-07-03 10:35:50 +00009429 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
9430 ctxt->context->contextSize = 0;
9431 ctxt->context->proximityPosition = 0;
9432 if (op->ch2 != -1)
9433 total +=
9434 xmlXPathCompOpEval(ctxt,
9435 &comp->steps[op->ch2]);
9436 res = valuePop(ctxt);
9437 if (res != NULL)
9438 xmlXPathFreeObject(res);
9439 valuePush(ctxt, obj);
9440 CHECK_ERROR0;
9441 return (total);
9442 }
9443 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009444
Daniel Veillardf06307e2001-07-03 10:35:50 +00009445 for (i = 0; i < oldlocset->locNr; i++) {
9446 /*
9447 * Run the evaluation with a node list made of a
9448 * single item in the nodelocset.
9449 */
9450 ctxt->context->node = oldlocset->locTab[i]->user;
9451 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9452 valuePush(ctxt, tmp);
9453 ctxt->context->contextSize = oldlocset->locNr;
9454 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009455
Daniel Veillardf06307e2001-07-03 10:35:50 +00009456 if (op->ch2 != -1)
9457 total +=
9458 xmlXPathCompOpEval(ctxt,
9459 &comp->steps[op->ch2]);
9460 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009461
Daniel Veillardf06307e2001-07-03 10:35:50 +00009462 /*
9463 * The result of the evaluation need to be tested to
9464 * decided whether the filter succeeded or not
9465 */
9466 res = valuePop(ctxt);
9467 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9468 xmlXPtrLocationSetAdd(newlocset,
9469 xmlXPathObjectCopy
9470 (oldlocset->locTab[i]));
9471 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009472
Daniel Veillardf06307e2001-07-03 10:35:50 +00009473 /*
9474 * Cleanup
9475 */
9476 if (res != NULL)
9477 xmlXPathFreeObject(res);
9478 if (ctxt->value == tmp) {
9479 res = valuePop(ctxt);
9480 xmlXPathFreeObject(res);
9481 }
9482
9483 ctxt->context->node = NULL;
9484 }
9485
9486 /*
9487 * The result is used as the new evaluation locset.
9488 */
9489 xmlXPathFreeObject(obj);
9490 ctxt->context->node = NULL;
9491 ctxt->context->contextSize = -1;
9492 ctxt->context->proximityPosition = -1;
9493 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
9494 ctxt->context->node = oldnode;
9495 return (total);
9496 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009497#endif /* LIBXML_XPTR_ENABLED */
9498
Daniel Veillardf06307e2001-07-03 10:35:50 +00009499 /*
9500 * Extract the old set, and then evaluate the result of the
9501 * expression for all the element in the set. use it to grow
9502 * up a new set.
9503 */
9504 CHECK_TYPE0(XPATH_NODESET);
9505 obj = valuePop(ctxt);
9506 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00009507
Daniel Veillardf06307e2001-07-03 10:35:50 +00009508 oldnode = ctxt->context->node;
9509 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009510
Daniel Veillardf06307e2001-07-03 10:35:50 +00009511 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
9512 ctxt->context->contextSize = 0;
9513 ctxt->context->proximityPosition = 0;
9514 if (op->ch2 != -1)
9515 total +=
9516 xmlXPathCompOpEval(ctxt,
9517 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009518 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009519 res = valuePop(ctxt);
9520 if (res != NULL)
9521 xmlXPathFreeObject(res);
9522 valuePush(ctxt, obj);
9523 ctxt->context->node = oldnode;
9524 CHECK_ERROR0;
9525 } else {
9526 /*
9527 * Initialize the new set.
9528 */
9529 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009530
Daniel Veillardf06307e2001-07-03 10:35:50 +00009531 for (i = 0; i < oldset->nodeNr; i++) {
9532 /*
9533 * Run the evaluation with a node list made of
9534 * a single item in the nodeset.
9535 */
9536 ctxt->context->node = oldset->nodeTab[i];
9537 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9538 valuePush(ctxt, tmp);
9539 ctxt->context->contextSize = oldset->nodeNr;
9540 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009541
Daniel Veillardf06307e2001-07-03 10:35:50 +00009542 if (op->ch2 != -1)
9543 total +=
9544 xmlXPathCompOpEval(ctxt,
9545 &comp->steps[op->ch2]);
9546 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009547
Daniel Veillardf06307e2001-07-03 10:35:50 +00009548 /*
9549 * The result of the evaluation need to be tested to
9550 * decided whether the filter succeeded or not
9551 */
9552 res = valuePop(ctxt);
9553 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9554 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
9555 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009556
Daniel Veillardf06307e2001-07-03 10:35:50 +00009557 /*
9558 * Cleanup
9559 */
9560 if (res != NULL)
9561 xmlXPathFreeObject(res);
9562 if (ctxt->value == tmp) {
9563 res = valuePop(ctxt);
9564 xmlXPathFreeObject(res);
9565 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009566
Daniel Veillardf06307e2001-07-03 10:35:50 +00009567 ctxt->context->node = NULL;
9568 }
9569
9570 /*
9571 * The result is used as the new evaluation set.
9572 */
9573 xmlXPathFreeObject(obj);
9574 ctxt->context->node = NULL;
9575 ctxt->context->contextSize = -1;
9576 ctxt->context->proximityPosition = -1;
9577 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
9578 }
9579 ctxt->context->node = oldnode;
9580 return (total);
9581 }
9582 case XPATH_OP_SORT:
9583 if (op->ch1 != -1)
9584 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009585 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009586 if ((ctxt->value != NULL) &&
9587 (ctxt->value->type == XPATH_NODESET) &&
9588 (ctxt->value->nodesetval != NULL))
9589 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9590 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009591#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009592 case XPATH_OP_RANGETO:{
9593 xmlXPathObjectPtr range;
9594 xmlXPathObjectPtr res, obj;
9595 xmlXPathObjectPtr tmp;
9596 xmlLocationSetPtr newset = NULL;
9597 xmlNodeSetPtr oldset;
9598 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009599
Daniel Veillardf06307e2001-07-03 10:35:50 +00009600 if (op->ch1 != -1)
9601 total +=
9602 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9603 if (op->ch2 == -1)
9604 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009605
Daniel Veillardf06307e2001-07-03 10:35:50 +00009606 CHECK_TYPE0(XPATH_NODESET);
9607 obj = valuePop(ctxt);
9608 oldset = obj->nodesetval;
9609 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009610
Daniel Veillardf06307e2001-07-03 10:35:50 +00009611 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009612
Daniel Veillardf06307e2001-07-03 10:35:50 +00009613 if (oldset != NULL) {
9614 for (i = 0; i < oldset->nodeNr; i++) {
9615 /*
9616 * Run the evaluation with a node list made of a single item
9617 * in the nodeset.
9618 */
9619 ctxt->context->node = oldset->nodeTab[i];
9620 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9621 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009622
Daniel Veillardf06307e2001-07-03 10:35:50 +00009623 if (op->ch2 != -1)
9624 total +=
9625 xmlXPathCompOpEval(ctxt,
9626 &comp->steps[op->ch2]);
9627 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009628
Daniel Veillardf06307e2001-07-03 10:35:50 +00009629 /*
9630 * The result of the evaluation need to be tested to
9631 * decided whether the filter succeeded or not
9632 */
9633 res = valuePop(ctxt);
9634 range =
9635 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
9636 res);
9637 if (range != NULL) {
9638 xmlXPtrLocationSetAdd(newset, range);
9639 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009640
Daniel Veillardf06307e2001-07-03 10:35:50 +00009641 /*
9642 * Cleanup
9643 */
9644 if (res != NULL)
9645 xmlXPathFreeObject(res);
9646 if (ctxt->value == tmp) {
9647 res = valuePop(ctxt);
9648 xmlXPathFreeObject(res);
9649 }
9650
9651 ctxt->context->node = NULL;
9652 }
9653 }
9654
9655 /*
9656 * The result is used as the new evaluation set.
9657 */
9658 xmlXPathFreeObject(obj);
9659 ctxt->context->node = NULL;
9660 ctxt->context->contextSize = -1;
9661 ctxt->context->proximityPosition = -1;
9662 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
9663 return (total);
9664 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009665#endif /* LIBXML_XPTR_ENABLED */
9666 }
9667 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009668 "XPath: unknown precompiled operation %d\n", op->op);
9669 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009670}
9671
9672/**
9673 * xmlXPathRunEval:
9674 * @ctxt: the XPath parser context with the compiled expression
9675 *
9676 * Evaluate the Precompiled XPath expression in the given context.
9677 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009678static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009679xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
9680 xmlXPathCompExprPtr comp;
9681
9682 if ((ctxt == NULL) || (ctxt->comp == NULL))
9683 return;
9684
9685 if (ctxt->valueTab == NULL) {
9686 /* Allocate the value stack */
9687 ctxt->valueTab = (xmlXPathObjectPtr *)
9688 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
9689 if (ctxt->valueTab == NULL) {
9690 xmlFree(ctxt);
9691 xmlGenericError(xmlGenericErrorContext,
9692 "xmlXPathRunEval: out of memory\n");
9693 return;
9694 }
9695 ctxt->valueNr = 0;
9696 ctxt->valueMax = 10;
9697 ctxt->value = NULL;
9698 }
9699 comp = ctxt->comp;
9700 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
9701}
9702
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009703/************************************************************************
9704 * *
9705 * Public interfaces *
9706 * *
9707 ************************************************************************/
9708
9709/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009710 * xmlXPathEvalPredicate:
9711 * @ctxt: the XPath context
9712 * @res: the Predicate Expression evaluation result
9713 *
9714 * Evaluate a predicate result for the current node.
9715 * A PredicateExpr is evaluated by evaluating the Expr and converting
9716 * the result to a boolean. If the result is a number, the result will
9717 * be converted to true if the number is equal to the position of the
9718 * context node in the context node list (as returned by the position
9719 * function) and will be converted to false otherwise; if the result
9720 * is not a number, then the result will be converted as if by a call
9721 * to the boolean function.
9722 *
9723 * Return 1 if predicate is true, 0 otherwise
9724 */
9725int
9726xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
9727 if (res == NULL) return(0);
9728 switch (res->type) {
9729 case XPATH_BOOLEAN:
9730 return(res->boolval);
9731 case XPATH_NUMBER:
9732 return(res->floatval == ctxt->proximityPosition);
9733 case XPATH_NODESET:
9734 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009735 if (res->nodesetval == NULL)
9736 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009737 return(res->nodesetval->nodeNr != 0);
9738 case XPATH_STRING:
9739 return((res->stringval != NULL) &&
9740 (xmlStrlen(res->stringval) != 0));
9741 default:
9742 STRANGE
9743 }
9744 return(0);
9745}
9746
9747/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009748 * xmlXPathEvaluatePredicateResult:
9749 * @ctxt: the XPath Parser context
9750 * @res: the Predicate Expression evaluation result
9751 *
9752 * Evaluate a predicate result for the current node.
9753 * A PredicateExpr is evaluated by evaluating the Expr and converting
9754 * the result to a boolean. If the result is a number, the result will
9755 * be converted to true if the number is equal to the position of the
9756 * context node in the context node list (as returned by the position
9757 * function) and will be converted to false otherwise; if the result
9758 * is not a number, then the result will be converted as if by a call
9759 * to the boolean function.
9760 *
9761 * Return 1 if predicate is true, 0 otherwise
9762 */
9763int
9764xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
9765 xmlXPathObjectPtr res) {
9766 if (res == NULL) return(0);
9767 switch (res->type) {
9768 case XPATH_BOOLEAN:
9769 return(res->boolval);
9770 case XPATH_NUMBER:
9771 return(res->floatval == ctxt->context->proximityPosition);
9772 case XPATH_NODESET:
9773 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +00009774 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +00009775 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009776 return(res->nodesetval->nodeNr != 0);
9777 case XPATH_STRING:
9778 return((res->stringval != NULL) &&
9779 (xmlStrlen(res->stringval) != 0));
9780 default:
9781 STRANGE
9782 }
9783 return(0);
9784}
9785
9786/**
9787 * xmlXPathCompile:
9788 * @str: the XPath expression
9789 *
9790 * Compile an XPath expression
9791 *
9792 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9793 * the caller has to free the object.
9794 */
9795xmlXPathCompExprPtr
9796xmlXPathCompile(const xmlChar *str) {
9797 xmlXPathParserContextPtr ctxt;
9798 xmlXPathCompExprPtr comp;
9799
9800 xmlXPathInit();
9801
9802 ctxt = xmlXPathNewParserContext(str, NULL);
9803 xmlXPathCompileExpr(ctxt);
9804
Daniel Veillard40af6492001-04-22 08:50:55 +00009805 if (*ctxt->cur != 0) {
9806 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9807 comp = NULL;
9808 } else {
9809 comp = ctxt->comp;
9810 ctxt->comp = NULL;
9811 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009812 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009813#ifdef DEBUG_EVAL_COUNTS
9814 if (comp != NULL) {
9815 comp->string = xmlStrdup(str);
9816 comp->nb = 0;
9817 }
9818#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009819 return(comp);
9820}
9821
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009822/**
9823 * xmlXPathCompiledEval:
9824 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +00009825 * @ctx: the XPath context
9826 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009827 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +00009828 *
9829 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9830 * the caller has to free the object.
9831 */
9832xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009833xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +00009834 xmlXPathParserContextPtr ctxt;
9835 xmlXPathObjectPtr res, tmp, init = NULL;
9836 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +00009837#ifndef LIBXML_THREAD_ENABLED
9838 static int reentance = 0;
9839#endif
Owen Taylor3473f882001-02-23 17:55:21 +00009840
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009841 if ((comp == NULL) || (ctx == NULL))
9842 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00009843 xmlXPathInit();
9844
9845 CHECK_CONTEXT(ctx)
9846
Daniel Veillard81463942001-10-16 12:34:39 +00009847#ifndef LIBXML_THREAD_ENABLED
9848 reentance++;
9849 if (reentance > 1)
9850 xmlXPathDisableOptimizer = 1;
9851#endif
9852
Daniel Veillardf06307e2001-07-03 10:35:50 +00009853#ifdef DEBUG_EVAL_COUNTS
9854 comp->nb++;
9855 if ((comp->string != NULL) && (comp->nb > 100)) {
9856 fprintf(stderr, "100 x %s\n", comp->string);
9857 comp->nb = 0;
9858 }
9859#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009860 ctxt = xmlXPathCompParserContext(comp, ctx);
9861 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009862
9863 if (ctxt->value == NULL) {
9864 xmlGenericError(xmlGenericErrorContext,
9865 "xmlXPathEval: evaluation failed\n");
9866 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009867 } else {
9868 res = valuePop(ctxt);
9869 }
9870
Daniel Veillardf06307e2001-07-03 10:35:50 +00009871
Owen Taylor3473f882001-02-23 17:55:21 +00009872 do {
9873 tmp = valuePop(ctxt);
9874 if (tmp != NULL) {
9875 if (tmp != init)
9876 stack++;
9877 xmlXPathFreeObject(tmp);
9878 }
9879 } while (tmp != NULL);
9880 if ((stack != 0) && (res != NULL)) {
9881 xmlGenericError(xmlGenericErrorContext,
9882 "xmlXPathEval: %d object left on the stack\n",
9883 stack);
9884 }
9885 if (ctxt->error != XPATH_EXPRESSION_OK) {
9886 xmlXPathFreeObject(res);
9887 res = NULL;
9888 }
9889
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009890
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009891 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009892 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +00009893#ifndef LIBXML_THREAD_ENABLED
9894 reentance--;
9895#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009896 return(res);
9897}
9898
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009899/**
9900 * xmlXPathEvalExpr:
9901 * @ctxt: the XPath Parser context
9902 *
9903 * Parse and evaluate an XPath expression in the given context,
9904 * then push the result on the context stack
9905 */
9906void
9907xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
9908 xmlXPathCompileExpr(ctxt);
9909 xmlXPathRunEval(ctxt);
9910}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009911
9912/**
9913 * xmlXPathEval:
9914 * @str: the XPath expression
9915 * @ctx: the XPath context
9916 *
9917 * Evaluate the XPath Location Path in the given context.
9918 *
9919 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9920 * the caller has to free the object.
9921 */
9922xmlXPathObjectPtr
9923xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
9924 xmlXPathParserContextPtr ctxt;
9925 xmlXPathObjectPtr res, tmp, init = NULL;
9926 int stack = 0;
9927
9928 xmlXPathInit();
9929
9930 CHECK_CONTEXT(ctx)
9931
9932 ctxt = xmlXPathNewParserContext(str, ctx);
9933 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009934
9935 if (ctxt->value == NULL) {
9936 xmlGenericError(xmlGenericErrorContext,
9937 "xmlXPathEval: evaluation failed\n");
9938 res = NULL;
9939 } else if (*ctxt->cur != 0) {
9940 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9941 res = NULL;
9942 } else {
9943 res = valuePop(ctxt);
9944 }
9945
9946 do {
9947 tmp = valuePop(ctxt);
9948 if (tmp != NULL) {
9949 if (tmp != init)
9950 stack++;
9951 xmlXPathFreeObject(tmp);
9952 }
9953 } while (tmp != NULL);
9954 if ((stack != 0) && (res != NULL)) {
9955 xmlGenericError(xmlGenericErrorContext,
9956 "xmlXPathEval: %d object left on the stack\n",
9957 stack);
9958 }
9959 if (ctxt->error != XPATH_EXPRESSION_OK) {
9960 xmlXPathFreeObject(res);
9961 res = NULL;
9962 }
9963
Owen Taylor3473f882001-02-23 17:55:21 +00009964 xmlXPathFreeParserContext(ctxt);
9965 return(res);
9966}
9967
9968/**
9969 * xmlXPathEvalExpression:
9970 * @str: the XPath expression
9971 * @ctxt: the XPath context
9972 *
9973 * Evaluate the XPath expression in the given context.
9974 *
9975 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
9976 * the caller has to free the object.
9977 */
9978xmlXPathObjectPtr
9979xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
9980 xmlXPathParserContextPtr pctxt;
9981 xmlXPathObjectPtr res, tmp;
9982 int stack = 0;
9983
9984 xmlXPathInit();
9985
9986 CHECK_CONTEXT(ctxt)
9987
9988 pctxt = xmlXPathNewParserContext(str, ctxt);
9989 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009990
9991 if (*pctxt->cur != 0) {
9992 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9993 res = NULL;
9994 } else {
9995 res = valuePop(pctxt);
9996 }
9997 do {
9998 tmp = valuePop(pctxt);
9999 if (tmp != NULL) {
10000 xmlXPathFreeObject(tmp);
10001 stack++;
10002 }
10003 } while (tmp != NULL);
10004 if ((stack != 0) && (res != NULL)) {
10005 xmlGenericError(xmlGenericErrorContext,
10006 "xmlXPathEvalExpression: %d object left on the stack\n",
10007 stack);
10008 }
10009 xmlXPathFreeParserContext(pctxt);
10010 return(res);
10011}
10012
10013/**
10014 * xmlXPathRegisterAllFunctions:
10015 * @ctxt: the XPath context
10016 *
10017 * Registers all default XPath functions in this context
10018 */
10019void
10020xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
10021{
10022 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
10023 xmlXPathBooleanFunction);
10024 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
10025 xmlXPathCeilingFunction);
10026 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
10027 xmlXPathCountFunction);
10028 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
10029 xmlXPathConcatFunction);
10030 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
10031 xmlXPathContainsFunction);
10032 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
10033 xmlXPathIdFunction);
10034 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
10035 xmlXPathFalseFunction);
10036 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
10037 xmlXPathFloorFunction);
10038 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
10039 xmlXPathLastFunction);
10040 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
10041 xmlXPathLangFunction);
10042 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
10043 xmlXPathLocalNameFunction);
10044 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
10045 xmlXPathNotFunction);
10046 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
10047 xmlXPathNameFunction);
10048 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
10049 xmlXPathNamespaceURIFunction);
10050 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
10051 xmlXPathNormalizeFunction);
10052 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
10053 xmlXPathNumberFunction);
10054 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
10055 xmlXPathPositionFunction);
10056 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
10057 xmlXPathRoundFunction);
10058 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
10059 xmlXPathStringFunction);
10060 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
10061 xmlXPathStringLengthFunction);
10062 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
10063 xmlXPathStartsWithFunction);
10064 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
10065 xmlXPathSubstringFunction);
10066 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
10067 xmlXPathSubstringBeforeFunction);
10068 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
10069 xmlXPathSubstringAfterFunction);
10070 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
10071 xmlXPathSumFunction);
10072 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
10073 xmlXPathTrueFunction);
10074 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
10075 xmlXPathTranslateFunction);
10076}
10077
10078#endif /* LIBXML_XPATH_ENABLED */