blob: 24d8dc01ac05fe29ec68b00056fff0fe371b3455 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
5 *
6 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011 * See Copyright for the status of this software
Owen Taylor3473f882001-02-23 17:55:21 +000012 *
Daniel Veillardc5d64342001-06-24 12:13:24 +000013 * Author: daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000014 *
15 * 14 Nov 2000 ht - truncated declaration of xmlXPathEvalRelativeLocationPath
16 * for VMS
17 */
18
Daniel Veillard34ce8be2002-03-18 19:37:11 +000019#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000020#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000021#ifdef LIBXML_XPATH_ENABLED
22
Owen Taylor3473f882001-02-23 17:55:21 +000023#include <string.h>
24
25#ifdef HAVE_SYS_TYPES_H
26#include <sys/types.h>
27#endif
28#ifdef HAVE_MATH_H
29#include <math.h>
30#endif
31#ifdef HAVE_FLOAT_H
32#include <float.h>
33#endif
Owen Taylor3473f882001-02-23 17:55:21 +000034#ifdef HAVE_CTYPE_H
35#include <ctype.h>
36#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000037#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000038#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000039#endif
Owen Taylor3473f882001-02-23 17:55:21 +000040
41#include <libxml/xmlmemory.h>
42#include <libxml/tree.h>
43#include <libxml/valid.h>
44#include <libxml/xpath.h>
45#include <libxml/xpathInternals.h>
46#include <libxml/parserInternals.h>
47#include <libxml/hash.h>
48#ifdef LIBXML_XPTR_ENABLED
49#include <libxml/xpointer.h>
50#endif
51#ifdef LIBXML_DEBUG_ENABLED
52#include <libxml/debugXML.h>
53#endif
54#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000055#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000056#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000057
58/* #define DEBUG */
59/* #define DEBUG_STEP */
Daniel Veillardf06307e2001-07-03 10:35:50 +000060/* #define DEBUG_STEP_NTH */
Owen Taylor3473f882001-02-23 17:55:21 +000061/* #define DEBUG_EXPR */
Daniel Veillardf06307e2001-07-03 10:35:50 +000062/* #define DEBUG_EVAL_COUNTS */
Owen Taylor3473f882001-02-23 17:55:21 +000063
Daniel Veillard5792e162001-04-30 17:44:45 +000064double xmlXPathDivideBy(double f, double fzero);
Owen Taylor3473f882001-02-23 17:55:21 +000065
Daniel Veillard20ee8c02001-10-05 09:18:14 +000066static xmlNs xmlXPathXMLNamespaceStruct = {
67 NULL,
68 XML_NAMESPACE_DECL,
69 XML_XML_NAMESPACE,
70 BAD_CAST "xml"
71};
72static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
Daniel Veillard81463942001-10-16 12:34:39 +000073#ifndef LIBXML_THREADS_ENABLED
74/*
75 * Optimizer is disabled only when threaded apps are detected while
76 * the library ain't compiled for thread safety.
77 */
78static int xmlXPathDisableOptimizer = 0;
79#endif
Daniel Veillard20ee8c02001-10-05 09:18:14 +000080
Daniel Veillard9e7160d2001-03-18 23:17:47 +000081/************************************************************************
82 * *
83 * Floating point stuff *
84 * *
85 ************************************************************************/
86
Daniel Veillardc0631a62001-09-20 13:56:06 +000087#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +000088#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +000089#endif
Daniel Veillardcda96922001-08-21 10:56:31 +000090#include "trionan.c"
91
Owen Taylor3473f882001-02-23 17:55:21 +000092/*
Owen Taylor3473f882001-02-23 17:55:21 +000093 * The lack of portability of this section of the libc is annoying !
94 */
95double xmlXPathNAN = 0;
96double xmlXPathPINF = 1;
97double xmlXPathNINF = -1;
Daniel Veillard20ee8c02001-10-05 09:18:14 +000098static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000099
Owen Taylor3473f882001-02-23 17:55:21 +0000100/**
101 * xmlXPathInit:
102 *
103 * Initialize the XPath environment
104 */
105void
106xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000107 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +0000108
Bjorn Reese45029602001-08-21 09:23:53 +0000109 xmlXPathPINF = trio_pinf();
110 xmlXPathNINF = trio_ninf();
111 xmlXPathNAN = trio_nan();
Owen Taylor3473f882001-02-23 17:55:21 +0000112
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000113 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000114}
115
Daniel Veillardcda96922001-08-21 10:56:31 +0000116/**
117 * xmlXPathIsNaN:
118 * @val: a double value
119 *
120 * Provides a portable isnan() function to detect whether a double
121 * is a NotaNumber. Based on trio code
122 * http://sourceforge.net/projects/ctrio/
123 *
124 * Returns 1 if the value is a NaN, 0 otherwise
125 */
126int
127xmlXPathIsNaN(double val) {
128 return(trio_isnan(val));
129}
130
131/**
132 * xmlXPathIsInf:
133 * @val: a double value
134 *
135 * Provides a portable isinf() function to detect whether a double
136 * is a +Infinite or -Infinite. Based on trio code
137 * http://sourceforge.net/projects/ctrio/
138 *
139 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
140 */
141int
142xmlXPathIsInf(double val) {
143 return(trio_isinf(val));
144}
145
Owen Taylor3473f882001-02-23 17:55:21 +0000146/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000147 * *
148 * Parser Types *
149 * *
150 ************************************************************************/
151
152/*
153 * Types are private:
154 */
155
156typedef enum {
157 XPATH_OP_END=0,
158 XPATH_OP_AND,
159 XPATH_OP_OR,
160 XPATH_OP_EQUAL,
161 XPATH_OP_CMP,
162 XPATH_OP_PLUS,
163 XPATH_OP_MULT,
164 XPATH_OP_UNION,
165 XPATH_OP_ROOT,
166 XPATH_OP_NODE,
167 XPATH_OP_RESET,
168 XPATH_OP_COLLECT,
169 XPATH_OP_VALUE,
170 XPATH_OP_VARIABLE,
171 XPATH_OP_FUNCTION,
172 XPATH_OP_ARG,
173 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000174 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000175 XPATH_OP_SORT
176#ifdef LIBXML_XPTR_ENABLED
177 ,XPATH_OP_RANGETO
178#endif
179} xmlXPathOp;
180
181typedef enum {
182 AXIS_ANCESTOR = 1,
183 AXIS_ANCESTOR_OR_SELF,
184 AXIS_ATTRIBUTE,
185 AXIS_CHILD,
186 AXIS_DESCENDANT,
187 AXIS_DESCENDANT_OR_SELF,
188 AXIS_FOLLOWING,
189 AXIS_FOLLOWING_SIBLING,
190 AXIS_NAMESPACE,
191 AXIS_PARENT,
192 AXIS_PRECEDING,
193 AXIS_PRECEDING_SIBLING,
194 AXIS_SELF
195} xmlXPathAxisVal;
196
197typedef enum {
198 NODE_TEST_NONE = 0,
199 NODE_TEST_TYPE = 1,
200 NODE_TEST_PI = 2,
201 NODE_TEST_ALL = 3,
202 NODE_TEST_NS = 4,
203 NODE_TEST_NAME = 5
204} xmlXPathTestVal;
205
206typedef enum {
207 NODE_TYPE_NODE = 0,
208 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
209 NODE_TYPE_TEXT = XML_TEXT_NODE,
210 NODE_TYPE_PI = XML_PI_NODE
211} xmlXPathTypeVal;
212
213
214typedef struct _xmlXPathStepOp xmlXPathStepOp;
215typedef xmlXPathStepOp *xmlXPathStepOpPtr;
216struct _xmlXPathStepOp {
217 xmlXPathOp op;
218 int ch1;
219 int ch2;
220 int value;
221 int value2;
222 int value3;
223 void *value4;
224 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000225 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000226 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000227};
228
229struct _xmlXPathCompExpr {
230 int nbStep;
231 int maxStep;
232 xmlXPathStepOp *steps; /* ops for computation */
233 int last;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000234#ifdef DEBUG_EVAL_COUNTS
235 int nb;
236 xmlChar *string;
237#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000238};
239
240/************************************************************************
241 * *
242 * Parser Type functions *
243 * *
244 ************************************************************************/
245
246/**
247 * xmlXPathNewCompExpr:
248 *
249 * Create a new Xpath component
250 *
251 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
252 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000253static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000254xmlXPathNewCompExpr(void) {
255 xmlXPathCompExprPtr cur;
256
257 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
258 if (cur == NULL) {
259 xmlGenericError(xmlGenericErrorContext,
260 "xmlXPathNewCompExpr : malloc failed\n");
261 return(NULL);
262 }
263 memset(cur, 0, sizeof(xmlXPathCompExpr));
264 cur->maxStep = 10;
265 cur->nbStep = 0;
266 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
267 sizeof(xmlXPathStepOp));
268 if (cur->steps == NULL) {
269 xmlGenericError(xmlGenericErrorContext,
270 "xmlXPathNewCompExpr : malloc failed\n");
271 xmlFree(cur);
272 return(NULL);
273 }
274 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
275 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000276#ifdef DEBUG_EVAL_COUNTS
277 cur->nb = 0;
278#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000279 return(cur);
280}
281
282/**
283 * xmlXPathFreeCompExpr:
284 * @comp: an XPATH comp
285 *
286 * Free up the memory allocated by @comp
287 */
288void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000289xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
290{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000291 xmlXPathStepOpPtr op;
292 int i;
293
294 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000295 return;
296 for (i = 0; i < comp->nbStep; i++) {
297 op = &comp->steps[i];
298 if (op->value4 != NULL) {
299 if (op->op == XPATH_OP_VALUE)
300 xmlXPathFreeObject(op->value4);
301 else
302 xmlFree(op->value4);
303 }
304 if (op->value5 != NULL)
305 xmlFree(op->value5);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000306 }
307 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000308 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000309 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000310#ifdef DEBUG_EVAL_COUNTS
311 if (comp->string != NULL) {
312 xmlFree(comp->string);
313 }
314#endif
315
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000316 xmlFree(comp);
317}
318
319/**
320 * xmlXPathCompExprAdd:
321 * @comp: the compiled expression
322 * @ch1: first child index
323 * @ch2: second child index
324 * @op: an op
325 * @value: the first int value
326 * @value2: the second int value
327 * @value3: the third int value
328 * @value4: the first string value
329 * @value5: the second string value
330 *
331 * Add an step to an XPath Compiled Expression
332 *
333 * Returns -1 in case of failure, the index otherwise
334 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000335static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000336xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
337 xmlXPathOp op, int value,
338 int value2, int value3, void *value4, void *value5) {
339 if (comp->nbStep >= comp->maxStep) {
340 xmlXPathStepOp *real;
341
342 comp->maxStep *= 2;
343 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
344 comp->maxStep * sizeof(xmlXPathStepOp));
345 if (real == NULL) {
346 comp->maxStep /= 2;
347 xmlGenericError(xmlGenericErrorContext,
348 "xmlXPathCompExprAdd : realloc failed\n");
349 return(-1);
350 }
351 comp->steps = real;
352 }
353 comp->last = comp->nbStep;
354 comp->steps[comp->nbStep].ch1 = ch1;
355 comp->steps[comp->nbStep].ch2 = ch2;
356 comp->steps[comp->nbStep].op = op;
357 comp->steps[comp->nbStep].value = value;
358 comp->steps[comp->nbStep].value2 = value2;
359 comp->steps[comp->nbStep].value3 = value3;
360 comp->steps[comp->nbStep].value4 = value4;
361 comp->steps[comp->nbStep].value5 = value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000362 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000363 return(comp->nbStep++);
364}
365
Daniel Veillardf06307e2001-07-03 10:35:50 +0000366/**
367 * xmlXPathCompSwap:
368 * @comp: the compiled expression
369 * @op: operation index
370 *
371 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000372 */
373static void
374xmlXPathCompSwap(xmlXPathStepOpPtr op) {
375 int tmp;
376
Daniel Veillard81463942001-10-16 12:34:39 +0000377#ifdef LIBXML_THREADS_ENABLED
378 /*
379 * Since this manipulates possibly shared variables, this is
380 * disable if one detects that the library is used in a multithreaded
381 * application
382 */
383 if (xmlXPathDisableOptimizer)
384 return;
385#endif
386
Daniel Veillardf06307e2001-07-03 10:35:50 +0000387 tmp = op->ch1;
388 op->ch1 = op->ch2;
389 op->ch2 = tmp;
390}
391
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000392#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
393 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
394 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000395#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
396 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
397 (op), (val), (val2), (val3), (val4), (val5))
398
399#define PUSH_LEAVE_EXPR(op, val, val2) \
400xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
401
402#define PUSH_UNARY_EXPR(op, ch, val, val2) \
403xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
404
405#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
406xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
407
408/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000409 * *
410 * Debugging related functions *
411 * *
412 ************************************************************************/
413
414#define TODO \
415 xmlGenericError(xmlGenericErrorContext, \
416 "Unimplemented block at %s:%d\n", \
417 __FILE__, __LINE__);
418
419#define STRANGE \
420 xmlGenericError(xmlGenericErrorContext, \
421 "Internal error at %s:%d\n", \
422 __FILE__, __LINE__);
423
424#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000425static void
426xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000427 int i;
428 char shift[100];
429
430 for (i = 0;((i < depth) && (i < 25));i++)
431 shift[2 * i] = shift[2 * i + 1] = ' ';
432 shift[2 * i] = shift[2 * i + 1] = 0;
433 if (cur == NULL) {
434 fprintf(output, shift);
435 fprintf(output, "Node is NULL !\n");
436 return;
437
438 }
439
440 if ((cur->type == XML_DOCUMENT_NODE) ||
441 (cur->type == XML_HTML_DOCUMENT_NODE)) {
442 fprintf(output, shift);
443 fprintf(output, " /\n");
444 } else if (cur->type == XML_ATTRIBUTE_NODE)
445 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
446 else
447 xmlDebugDumpOneNode(output, cur, depth);
448}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000449static void
450xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000451 xmlNodePtr tmp;
452 int i;
453 char shift[100];
454
455 for (i = 0;((i < depth) && (i < 25));i++)
456 shift[2 * i] = shift[2 * i + 1] = ' ';
457 shift[2 * i] = shift[2 * i + 1] = 0;
458 if (cur == NULL) {
459 fprintf(output, shift);
460 fprintf(output, "Node is NULL !\n");
461 return;
462
463 }
464
465 while (cur != NULL) {
466 tmp = cur;
467 cur = cur->next;
468 xmlDebugDumpOneNode(output, tmp, depth);
469 }
470}
Owen Taylor3473f882001-02-23 17:55:21 +0000471
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000472static void
473xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000474 int i;
475 char shift[100];
476
477 for (i = 0;((i < depth) && (i < 25));i++)
478 shift[2 * i] = shift[2 * i + 1] = ' ';
479 shift[2 * i] = shift[2 * i + 1] = 0;
480
481 if (cur == NULL) {
482 fprintf(output, shift);
483 fprintf(output, "NodeSet is NULL !\n");
484 return;
485
486 }
487
Daniel Veillard911f49a2001-04-07 15:39:35 +0000488 if (cur != NULL) {
489 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
490 for (i = 0;i < cur->nodeNr;i++) {
491 fprintf(output, shift);
492 fprintf(output, "%d", i + 1);
493 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
494 }
Owen Taylor3473f882001-02-23 17:55:21 +0000495 }
496}
497
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000498static void
499xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000500 int i;
501 char shift[100];
502
503 for (i = 0;((i < depth) && (i < 25));i++)
504 shift[2 * i] = shift[2 * i + 1] = ' ';
505 shift[2 * i] = shift[2 * i + 1] = 0;
506
507 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
508 fprintf(output, shift);
509 fprintf(output, "Value Tree is NULL !\n");
510 return;
511
512 }
513
514 fprintf(output, shift);
515 fprintf(output, "%d", i + 1);
516 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
517}
Owen Taylor3473f882001-02-23 17:55:21 +0000518#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000519static void
520xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000521 int i;
522 char shift[100];
523
524 for (i = 0;((i < depth) && (i < 25));i++)
525 shift[2 * i] = shift[2 * i + 1] = ' ';
526 shift[2 * i] = shift[2 * i + 1] = 0;
527
528 if (cur == NULL) {
529 fprintf(output, shift);
530 fprintf(output, "LocationSet is NULL !\n");
531 return;
532
533 }
534
535 for (i = 0;i < cur->locNr;i++) {
536 fprintf(output, shift);
537 fprintf(output, "%d : ", i + 1);
538 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
539 }
540}
Daniel Veillard017b1082001-06-21 11:20:21 +0000541#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000542
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000543/**
544 * xmlXPathDebugDumpObject:
545 * @output: the FILE * to dump the output
546 * @cur: the object to inspect
547 * @depth: indentation level
548 *
549 * Dump the content of the object for debugging purposes
550 */
551void
552xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000553 int i;
554 char shift[100];
555
556 for (i = 0;((i < depth) && (i < 25));i++)
557 shift[2 * i] = shift[2 * i + 1] = ' ';
558 shift[2 * i] = shift[2 * i + 1] = 0;
559
560 fprintf(output, shift);
561
562 if (cur == NULL) {
563 fprintf(output, "Object is empty (NULL)\n");
564 return;
565 }
566 switch(cur->type) {
567 case XPATH_UNDEFINED:
568 fprintf(output, "Object is uninitialized\n");
569 break;
570 case XPATH_NODESET:
571 fprintf(output, "Object is a Node Set :\n");
572 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
573 break;
574 case XPATH_XSLT_TREE:
575 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000576 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000577 break;
578 case XPATH_BOOLEAN:
579 fprintf(output, "Object is a Boolean : ");
580 if (cur->boolval) fprintf(output, "true\n");
581 else fprintf(output, "false\n");
582 break;
583 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000584 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000585 case 1:
586 fprintf(output, "Object is a number : +Infinity\n");
587 break;
588 case -1:
589 fprintf(output, "Object is a number : -Infinity\n");
590 break;
591 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000592 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000593 fprintf(output, "Object is a number : NaN\n");
594 } else {
595 fprintf(output, "Object is a number : %0g\n", cur->floatval);
596 }
597 }
Owen Taylor3473f882001-02-23 17:55:21 +0000598 break;
599 case XPATH_STRING:
600 fprintf(output, "Object is a string : ");
601 xmlDebugDumpString(output, cur->stringval);
602 fprintf(output, "\n");
603 break;
604 case XPATH_POINT:
605 fprintf(output, "Object is a point : index %d in node", cur->index);
606 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
607 fprintf(output, "\n");
608 break;
609 case XPATH_RANGE:
610 if ((cur->user2 == NULL) ||
611 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
612 fprintf(output, "Object is a collapsed range :\n");
613 fprintf(output, shift);
614 if (cur->index >= 0)
615 fprintf(output, "index %d in ", cur->index);
616 fprintf(output, "node\n");
617 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
618 depth + 1);
619 } else {
620 fprintf(output, "Object is a range :\n");
621 fprintf(output, shift);
622 fprintf(output, "From ");
623 if (cur->index >= 0)
624 fprintf(output, "index %d in ", cur->index);
625 fprintf(output, "node\n");
626 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
627 depth + 1);
628 fprintf(output, shift);
629 fprintf(output, "To ");
630 if (cur->index2 >= 0)
631 fprintf(output, "index %d in ", cur->index2);
632 fprintf(output, "node\n");
633 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
634 depth + 1);
635 fprintf(output, "\n");
636 }
637 break;
638 case XPATH_LOCATIONSET:
639#if defined(LIBXML_XPTR_ENABLED)
640 fprintf(output, "Object is a Location Set:\n");
641 xmlXPathDebugDumpLocationSet(output,
642 (xmlLocationSetPtr) cur->user, depth);
643#endif
644 break;
645 case XPATH_USERS:
646 fprintf(output, "Object is user defined\n");
647 break;
648 }
649}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000650
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000651static void
652xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000653 xmlXPathStepOpPtr op, int depth) {
654 int i;
655 char shift[100];
656
657 for (i = 0;((i < depth) && (i < 25));i++)
658 shift[2 * i] = shift[2 * i + 1] = ' ';
659 shift[2 * i] = shift[2 * i + 1] = 0;
660
661 fprintf(output, shift);
662 if (op == NULL) {
663 fprintf(output, "Step is NULL\n");
664 return;
665 }
666 switch (op->op) {
667 case XPATH_OP_END:
668 fprintf(output, "END"); break;
669 case XPATH_OP_AND:
670 fprintf(output, "AND"); break;
671 case XPATH_OP_OR:
672 fprintf(output, "OR"); break;
673 case XPATH_OP_EQUAL:
674 if (op->value)
675 fprintf(output, "EQUAL =");
676 else
677 fprintf(output, "EQUAL !=");
678 break;
679 case XPATH_OP_CMP:
680 if (op->value)
681 fprintf(output, "CMP <");
682 else
683 fprintf(output, "CMP >");
684 if (!op->value2)
685 fprintf(output, "=");
686 break;
687 case XPATH_OP_PLUS:
688 if (op->value == 0)
689 fprintf(output, "PLUS -");
690 else if (op->value == 1)
691 fprintf(output, "PLUS +");
692 else if (op->value == 2)
693 fprintf(output, "PLUS unary -");
694 else if (op->value == 3)
695 fprintf(output, "PLUS unary - -");
696 break;
697 case XPATH_OP_MULT:
698 if (op->value == 0)
699 fprintf(output, "MULT *");
700 else if (op->value == 1)
701 fprintf(output, "MULT div");
702 else
703 fprintf(output, "MULT mod");
704 break;
705 case XPATH_OP_UNION:
706 fprintf(output, "UNION"); break;
707 case XPATH_OP_ROOT:
708 fprintf(output, "ROOT"); break;
709 case XPATH_OP_NODE:
710 fprintf(output, "NODE"); break;
711 case XPATH_OP_RESET:
712 fprintf(output, "RESET"); break;
713 case XPATH_OP_SORT:
714 fprintf(output, "SORT"); break;
715 case XPATH_OP_COLLECT: {
716 xmlXPathAxisVal axis = op->value;
717 xmlXPathTestVal test = op->value2;
718 xmlXPathTypeVal type = op->value3;
719 const xmlChar *prefix = op->value4;
720 const xmlChar *name = op->value5;
721
722 fprintf(output, "COLLECT ");
723 switch (axis) {
724 case AXIS_ANCESTOR:
725 fprintf(output, " 'ancestors' "); break;
726 case AXIS_ANCESTOR_OR_SELF:
727 fprintf(output, " 'ancestors-or-self' "); break;
728 case AXIS_ATTRIBUTE:
729 fprintf(output, " 'attributes' "); break;
730 case AXIS_CHILD:
731 fprintf(output, " 'child' "); break;
732 case AXIS_DESCENDANT:
733 fprintf(output, " 'descendant' "); break;
734 case AXIS_DESCENDANT_OR_SELF:
735 fprintf(output, " 'descendant-or-self' "); break;
736 case AXIS_FOLLOWING:
737 fprintf(output, " 'following' "); break;
738 case AXIS_FOLLOWING_SIBLING:
739 fprintf(output, " 'following-siblings' "); break;
740 case AXIS_NAMESPACE:
741 fprintf(output, " 'namespace' "); break;
742 case AXIS_PARENT:
743 fprintf(output, " 'parent' "); break;
744 case AXIS_PRECEDING:
745 fprintf(output, " 'preceding' "); break;
746 case AXIS_PRECEDING_SIBLING:
747 fprintf(output, " 'preceding-sibling' "); break;
748 case AXIS_SELF:
749 fprintf(output, " 'self' "); break;
750 }
751 switch (test) {
752 case NODE_TEST_NONE:
753 fprintf(output, "'none' "); break;
754 case NODE_TEST_TYPE:
755 fprintf(output, "'type' "); break;
756 case NODE_TEST_PI:
757 fprintf(output, "'PI' "); break;
758 case NODE_TEST_ALL:
759 fprintf(output, "'all' "); break;
760 case NODE_TEST_NS:
761 fprintf(output, "'namespace' "); break;
762 case NODE_TEST_NAME:
763 fprintf(output, "'name' "); break;
764 }
765 switch (type) {
766 case NODE_TYPE_NODE:
767 fprintf(output, "'node' "); break;
768 case NODE_TYPE_COMMENT:
769 fprintf(output, "'comment' "); break;
770 case NODE_TYPE_TEXT:
771 fprintf(output, "'text' "); break;
772 case NODE_TYPE_PI:
773 fprintf(output, "'PI' "); break;
774 }
775 if (prefix != NULL)
776 fprintf(output, "%s:", prefix);
777 if (name != NULL)
778 fprintf(output, "%s", name);
779 break;
780
781 }
782 case XPATH_OP_VALUE: {
783 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
784
785 fprintf(output, "ELEM ");
786 xmlXPathDebugDumpObject(output, object, 0);
787 goto finish;
788 }
789 case XPATH_OP_VARIABLE: {
790 const xmlChar *prefix = op->value5;
791 const xmlChar *name = op->value4;
792
793 if (prefix != NULL)
794 fprintf(output, "VARIABLE %s:%s", prefix, name);
795 else
796 fprintf(output, "VARIABLE %s", name);
797 break;
798 }
799 case XPATH_OP_FUNCTION: {
800 int nbargs = op->value;
801 const xmlChar *prefix = op->value5;
802 const xmlChar *name = op->value4;
803
804 if (prefix != NULL)
805 fprintf(output, "FUNCTION %s:%s(%d args)",
806 prefix, name, nbargs);
807 else
808 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
809 break;
810 }
811 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
812 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000813 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +0000814#ifdef LIBXML_XPTR_ENABLED
815 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
816#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000817 default:
818 fprintf(output, "UNKNOWN %d\n", op->op); return;
819 }
820 fprintf(output, "\n");
821finish:
822 if (op->ch1 >= 0)
823 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
824 if (op->ch2 >= 0)
825 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
826}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000827
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000828/**
829 * xmlXPathDebugDumpCompExpr:
830 * @output: the FILE * for the output
831 * @comp: the precompiled XPath expression
832 * @depth: the indentation level.
833 *
834 * Dumps the tree of the compiled XPath expression.
835 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000836void
837xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
838 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000839 int i;
840 char shift[100];
841
842 for (i = 0;((i < depth) && (i < 25));i++)
843 shift[2 * i] = shift[2 * i + 1] = ' ';
844 shift[2 * i] = shift[2 * i + 1] = 0;
845
846 fprintf(output, shift);
847
848 if (comp == NULL) {
849 fprintf(output, "Compiled Expression is NULL\n");
850 return;
851 }
852 fprintf(output, "Compiled Expression : %d elements\n",
853 comp->nbStep);
854 i = comp->last;
855 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
856}
Daniel Veillard017b1082001-06-21 11:20:21 +0000857#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000858
859/************************************************************************
860 * *
861 * Parser stacks related functions and macros *
862 * *
863 ************************************************************************/
864
865/*
866 * Generic function for accessing stacks in the Parser Context
867 */
868
869#define PUSH_AND_POP(type, name) \
870extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
871 if (ctxt->name##Nr >= ctxt->name##Max) { \
872 ctxt->name##Max *= 2; \
873 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
874 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
875 if (ctxt->name##Tab == NULL) { \
876 xmlGenericError(xmlGenericErrorContext, \
877 "realloc failed !\n"); \
878 return(0); \
879 } \
880 } \
881 ctxt->name##Tab[ctxt->name##Nr] = value; \
882 ctxt->name = value; \
883 return(ctxt->name##Nr++); \
884} \
885extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
886 type ret; \
887 if (ctxt->name##Nr <= 0) return(0); \
888 ctxt->name##Nr--; \
889 if (ctxt->name##Nr > 0) \
890 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
891 else \
892 ctxt->name = NULL; \
893 ret = ctxt->name##Tab[ctxt->name##Nr]; \
894 ctxt->name##Tab[ctxt->name##Nr] = 0; \
895 return(ret); \
896} \
897
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000898/**
899 * valuePop:
900 * @ctxt: an XPath evaluation context
901 *
902 * Pops the top XPath object from the value stack
903 *
904 * Returns the XPath object just removed
905 */
906/**
907 * valuePush:
908 * @ctxt: an XPath evaluation context
909 * @value: the XPath object
910 *
911 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000912 *
913 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000914 */
Owen Taylor3473f882001-02-23 17:55:21 +0000915PUSH_AND_POP(xmlXPathObjectPtr, value)
916
Thomas Broyerf06a3d82001-07-16 04:52:57 +0000917/**
918 * xmlXPathPopBoolean:
919 * @ctxt: an XPath parser context
920 *
921 * Pops a boolean from the stack, handling conversion if needed.
922 * Check error with #xmlXPathCheckError.
923 *
924 * Returns the boolean
925 */
926int
927xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
928 xmlXPathObjectPtr obj;
929 int ret;
930
931 obj = valuePop(ctxt);
932 if (obj == NULL) {
933 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
934 return(0);
935 }
936 ret = xmlXPathCastToBoolean(obj);
937 xmlXPathFreeObject(obj);
938 return(ret);
939}
940
941/**
942 * xmlXPathPopNumber:
943 * @ctxt: an XPath parser context
944 *
945 * Pops a number from the stack, handling conversion if needed.
946 * Check error with #xmlXPathCheckError.
947 *
948 * Returns the number
949 */
950double
951xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
952 xmlXPathObjectPtr obj;
953 double ret;
954
955 obj = valuePop(ctxt);
956 if (obj == NULL) {
957 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
958 return(0);
959 }
960 ret = xmlXPathCastToNumber(obj);
961 xmlXPathFreeObject(obj);
962 return(ret);
963}
964
965/**
966 * xmlXPathPopString:
967 * @ctxt: an XPath parser context
968 *
969 * Pops a string from the stack, handling conversion if needed.
970 * Check error with #xmlXPathCheckError.
971 *
972 * Returns the string
973 */
974xmlChar *
975xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
976 xmlXPathObjectPtr obj;
977 xmlChar * ret;
978
979 obj = valuePop(ctxt);
980 if (obj == NULL) {
981 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
982 return(NULL);
983 }
984 ret = xmlXPathCastToString(obj);
985 /* TODO: needs refactoring somewhere else */
986 if (obj->stringval == ret)
987 obj->stringval = NULL;
988 xmlXPathFreeObject(obj);
989 return(ret);
990}
991
992/**
993 * xmlXPathPopNodeSet:
994 * @ctxt: an XPath parser context
995 *
996 * Pops a node-set from the stack, handling conversion if needed.
997 * Check error with #xmlXPathCheckError.
998 *
999 * Returns the node-set
1000 */
1001xmlNodeSetPtr
1002xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1003 xmlXPathObjectPtr obj;
1004 xmlNodeSetPtr ret;
1005
1006 if (ctxt->value == NULL) {
1007 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1008 return(NULL);
1009 }
1010 if (!xmlXPathStackIsNodeSet(ctxt)) {
1011 xmlXPathSetTypeError(ctxt);
1012 return(NULL);
1013 }
1014 obj = valuePop(ctxt);
1015 ret = obj->nodesetval;
1016 xmlXPathFreeNodeSetList(obj);
1017 return(ret);
1018}
1019
1020/**
1021 * xmlXPathPopExternal:
1022 * @ctxt: an XPath parser context
1023 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001024 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001025 * Check error with #xmlXPathCheckError.
1026 *
1027 * Returns the object
1028 */
1029void *
1030xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1031 xmlXPathObjectPtr obj;
1032 void * ret;
1033
1034 if (ctxt->value == NULL) {
1035 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1036 return(NULL);
1037 }
1038 if (ctxt->value->type != XPATH_USERS) {
1039 xmlXPathSetTypeError(ctxt);
1040 return(NULL);
1041 }
1042 obj = valuePop(ctxt);
1043 ret = obj->user;
1044 xmlXPathFreeObject(obj);
1045 return(ret);
1046}
1047
Owen Taylor3473f882001-02-23 17:55:21 +00001048/*
1049 * Macros for accessing the content. Those should be used only by the parser,
1050 * and not exported.
1051 *
1052 * Dirty macros, i.e. one need to make assumption on the context to use them
1053 *
1054 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1055 * CUR returns the current xmlChar value, i.e. a 8 bit value
1056 * in ISO-Latin or UTF-8.
1057 * This should be used internally by the parser
1058 * only to compare to ASCII values otherwise it would break when
1059 * running with UTF-8 encoding.
1060 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1061 * to compare on ASCII based substring.
1062 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1063 * strings within the parser.
1064 * CURRENT Returns the current char value, with the full decoding of
1065 * UTF-8 if we are using this mode. It returns an int.
1066 * NEXT Skip to the next character, this does the proper decoding
1067 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1068 * It returns the pointer to the current xmlChar.
1069 */
1070
1071#define CUR (*ctxt->cur)
1072#define SKIP(val) ctxt->cur += (val)
1073#define NXT(val) ctxt->cur[(val)]
1074#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001075#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1076
1077#define COPY_BUF(l,b,i,v) \
1078 if (l == 1) b[i++] = (xmlChar) v; \
1079 else i += xmlCopyChar(l,&b[i],v)
1080
1081#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001082
1083#define SKIP_BLANKS \
1084 while (IS_BLANK(*(ctxt->cur))) NEXT
1085
1086#define CURRENT (*ctxt->cur)
1087#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1088
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001089
1090#ifndef DBL_DIG
1091#define DBL_DIG 16
1092#endif
1093#ifndef DBL_EPSILON
1094#define DBL_EPSILON 1E-9
1095#endif
1096
1097#define UPPER_DOUBLE 1E9
1098#define LOWER_DOUBLE 1E-5
1099
1100#define INTEGER_DIGITS DBL_DIG
1101#define FRACTION_DIGITS (DBL_DIG + 1)
1102#define EXPONENT_DIGITS (3 + 2)
1103
1104/**
1105 * xmlXPathFormatNumber:
1106 * @number: number to format
1107 * @buffer: output buffer
1108 * @buffersize: size of output buffer
1109 *
1110 * Convert the number into a string representation.
1111 */
1112static void
1113xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1114{
Daniel Veillardcda96922001-08-21 10:56:31 +00001115 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001116 case 1:
1117 if (buffersize > (int)sizeof("+Infinity"))
1118 sprintf(buffer, "+Infinity");
1119 break;
1120 case -1:
1121 if (buffersize > (int)sizeof("-Infinity"))
1122 sprintf(buffer, "-Infinity");
1123 break;
1124 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001125 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001126 if (buffersize > (int)sizeof("NaN"))
1127 sprintf(buffer, "NaN");
1128 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001129 /* 3 is sign, decimal point, and terminating zero */
1130 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1131 int integer_place, fraction_place;
1132 char *ptr;
1133 char *after_fraction;
1134 double absolute_value;
1135 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001136
Bjorn Reese70a9da52001-04-21 16:57:29 +00001137 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001138
Bjorn Reese70a9da52001-04-21 16:57:29 +00001139 /*
1140 * First choose format - scientific or regular floating point.
1141 * In either case, result is in work, and after_fraction points
1142 * just past the fractional part.
1143 */
1144 if ( ((absolute_value > UPPER_DOUBLE) ||
1145 (absolute_value < LOWER_DOUBLE)) &&
1146 (absolute_value != 0.0) ) {
1147 /* Use scientific notation */
1148 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1149 fraction_place = DBL_DIG - 1;
1150 snprintf(work, sizeof(work),"%*.*e",
1151 integer_place, fraction_place, number);
1152 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001153 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001154 else {
1155 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001156 if (absolute_value > 0.0)
1157 integer_place = 1 + (int)log10(absolute_value);
1158 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001159 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001160 fraction_place = (integer_place > 0)
1161 ? DBL_DIG - integer_place
1162 : DBL_DIG;
1163 size = snprintf(work, sizeof(work), "%0.*f",
1164 fraction_place, number);
1165 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001166 }
1167
Bjorn Reese70a9da52001-04-21 16:57:29 +00001168 /* Remove fractional trailing zeroes */
1169 ptr = after_fraction;
1170 while (*(--ptr) == '0')
1171 ;
1172 if (*ptr != '.')
1173 ptr++;
1174 strcpy(ptr, after_fraction);
1175
1176 /* Finally copy result back to caller */
1177 size = strlen(work) + 1;
1178 if (size > buffersize) {
1179 work[buffersize - 1] = 0;
1180 size = buffersize;
1181 }
1182 memcpy(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001183 }
1184 break;
1185 }
1186}
1187
Owen Taylor3473f882001-02-23 17:55:21 +00001188/************************************************************************
1189 * *
1190 * Error handling routines *
1191 * *
1192 ************************************************************************/
1193
1194
Daniel Veillardb44025c2001-10-11 22:55:55 +00001195static const char *xmlXPathErrorMessages[] = {
Owen Taylor3473f882001-02-23 17:55:21 +00001196 "Ok",
1197 "Number encoding",
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001198 "Unfinished literal",
1199 "Start of literal",
Owen Taylor3473f882001-02-23 17:55:21 +00001200 "Expected $ for variable reference",
1201 "Undefined variable",
1202 "Invalid predicate",
1203 "Invalid expression",
1204 "Missing closing curly brace",
1205 "Unregistered function",
1206 "Invalid operand",
1207 "Invalid type",
1208 "Invalid number of arguments",
1209 "Invalid context size",
1210 "Invalid context position",
1211 "Memory allocation error",
1212 "Syntax error",
1213 "Resource error",
1214 "Sub resource error",
Daniel Veillard61d80a22001-04-27 17:13:01 +00001215 "Undefined namespace prefix",
1216 "Encoding error",
1217 "Char out of XML range"
Owen Taylor3473f882001-02-23 17:55:21 +00001218};
1219
1220/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001221 * xmlXPatherror:
Owen Taylor3473f882001-02-23 17:55:21 +00001222 * @ctxt: the XPath Parser context
1223 * @file: the file name
1224 * @line: the line number
1225 * @no: the error number
1226 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001227 * Formats an error message.
Owen Taylor3473f882001-02-23 17:55:21 +00001228 */
1229void
1230xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
1231 int line, int no) {
1232 int n;
1233 const xmlChar *cur;
1234 const xmlChar *base;
1235
1236 xmlGenericError(xmlGenericErrorContext,
1237 "Error %s:%d: %s\n", file, line,
1238 xmlXPathErrorMessages[no]);
1239
1240 cur = ctxt->cur;
1241 base = ctxt->base;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001242 if ((cur == NULL) || (base == NULL))
1243 return;
1244
Owen Taylor3473f882001-02-23 17:55:21 +00001245 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
1246 cur--;
1247 }
1248 n = 0;
1249 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
1250 cur--;
1251 if ((*cur == '\n') || (*cur == '\r')) cur++;
1252 base = cur;
1253 n = 0;
1254 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1255 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
1256 n++;
1257 }
1258 xmlGenericError(xmlGenericErrorContext, "\n");
1259 cur = ctxt->cur;
1260 while ((*cur == '\n') || (*cur == '\r'))
1261 cur--;
1262 n = 0;
1263 while ((cur != base) && (n++ < 80)) {
1264 xmlGenericError(xmlGenericErrorContext, " ");
1265 base++;
1266 }
1267 xmlGenericError(xmlGenericErrorContext,"^\n");
1268}
1269
1270
1271/************************************************************************
1272 * *
1273 * Routines to handle NodeSets *
1274 * *
1275 ************************************************************************/
1276
1277/**
1278 * xmlXPathCmpNodes:
1279 * @node1: the first node
1280 * @node2: the second node
1281 *
1282 * Compare two nodes w.r.t document order
1283 *
1284 * Returns -2 in case of error 1 if first point < second point, 0 if
1285 * that's the same node, -1 otherwise
1286 */
1287int
1288xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1289 int depth1, depth2;
1290 xmlNodePtr cur, root;
1291
1292 if ((node1 == NULL) || (node2 == NULL))
1293 return(-2);
1294 /*
1295 * a couple of optimizations which will avoid computations in most cases
1296 */
1297 if (node1 == node2)
1298 return(0);
Daniel Veillardb33c2012001-04-25 12:59:04 +00001299 if ((node1->type == XML_NAMESPACE_DECL) ||
1300 (node2->type == XML_NAMESPACE_DECL))
1301 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001302 if (node1 == node2->prev)
1303 return(1);
1304 if (node1 == node2->next)
1305 return(-1);
1306
1307 /*
1308 * compute depth to root
1309 */
1310 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1311 if (cur == node1)
1312 return(1);
1313 depth2++;
1314 }
1315 root = cur;
1316 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1317 if (cur == node2)
1318 return(-1);
1319 depth1++;
1320 }
1321 /*
1322 * Distinct document (or distinct entities :-( ) case.
1323 */
1324 if (root != cur) {
1325 return(-2);
1326 }
1327 /*
1328 * get the nearest common ancestor.
1329 */
1330 while (depth1 > depth2) {
1331 depth1--;
1332 node1 = node1->parent;
1333 }
1334 while (depth2 > depth1) {
1335 depth2--;
1336 node2 = node2->parent;
1337 }
1338 while (node1->parent != node2->parent) {
1339 node1 = node1->parent;
1340 node2 = node2->parent;
1341 /* should not happen but just in case ... */
1342 if ((node1 == NULL) || (node2 == NULL))
1343 return(-2);
1344 }
1345 /*
1346 * Find who's first.
1347 */
1348 if (node1 == node2->next)
1349 return(-1);
1350 for (cur = node1->next;cur != NULL;cur = cur->next)
1351 if (cur == node2)
1352 return(1);
1353 return(-1); /* assume there is no sibling list corruption */
1354}
1355
1356/**
1357 * xmlXPathNodeSetSort:
1358 * @set: the node set
1359 *
1360 * Sort the node set in document order
1361 */
1362void
1363xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001364 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001365 xmlNodePtr tmp;
1366
1367 if (set == NULL)
1368 return;
1369
1370 /* Use Shell's sort to sort the node-set */
1371 len = set->nodeNr;
1372 for (incr = len / 2; incr > 0; incr /= 2) {
1373 for (i = incr; i < len; i++) {
1374 j = i - incr;
1375 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001376 if (xmlXPathCmpNodes(set->nodeTab[j],
1377 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001378 tmp = set->nodeTab[j];
1379 set->nodeTab[j] = set->nodeTab[j + incr];
1380 set->nodeTab[j + incr] = tmp;
1381 j -= incr;
1382 } else
1383 break;
1384 }
1385 }
1386 }
1387}
1388
1389#define XML_NODESET_DEFAULT 10
1390/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001391 * xmlXPathNodeSetDupNs:
1392 * @node: the parent node of the namespace XPath node
1393 * @ns: the libxml namespace declaration node.
1394 *
1395 * Namespace node in libxml don't match the XPath semantic. In a node set
1396 * the namespace nodes are duplicated and the next pointer is set to the
1397 * parent node in the XPath semantic.
1398 *
1399 * Returns the newly created object.
1400 */
1401static xmlNodePtr
1402xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1403 xmlNsPtr cur;
1404
1405 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1406 return(NULL);
1407 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1408 return((xmlNodePtr) ns);
1409
1410 /*
1411 * Allocate a new Namespace and fill the fields.
1412 */
1413 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1414 if (cur == NULL) {
1415 xmlGenericError(xmlGenericErrorContext,
1416 "xmlXPathNodeSetDupNs : malloc failed\n");
1417 return(NULL);
1418 }
1419 memset(cur, 0, sizeof(xmlNs));
1420 cur->type = XML_NAMESPACE_DECL;
1421 if (ns->href != NULL)
1422 cur->href = xmlStrdup(ns->href);
1423 if (ns->prefix != NULL)
1424 cur->prefix = xmlStrdup(ns->prefix);
1425 cur->next = (xmlNsPtr) node;
1426 return((xmlNodePtr) cur);
1427}
1428
1429/**
1430 * xmlXPathNodeSetFreeNs:
1431 * @ns: the XPath namespace node found in a nodeset.
1432 *
1433 * Namespace node in libxml don't match the XPath semantic. In a node set
1434 * the namespace nodes are duplicated and the next pointer is set to the
1435 * parent node in the XPath semantic. Check if such a node need to be freed
1436 */
1437static void
1438xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1439 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1440 return;
1441
1442 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1443 if (ns->href != NULL)
1444 xmlFree((xmlChar *)ns->href);
1445 if (ns->prefix != NULL)
1446 xmlFree((xmlChar *)ns->prefix);
1447 xmlFree(ns);
1448 }
1449}
1450
1451/**
Owen Taylor3473f882001-02-23 17:55:21 +00001452 * xmlXPathNodeSetCreate:
1453 * @val: an initial xmlNodePtr, or NULL
1454 *
1455 * Create a new xmlNodeSetPtr of type double and of value @val
1456 *
1457 * Returns the newly created object.
1458 */
1459xmlNodeSetPtr
1460xmlXPathNodeSetCreate(xmlNodePtr val) {
1461 xmlNodeSetPtr ret;
1462
1463 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1464 if (ret == NULL) {
1465 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001466 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001467 return(NULL);
1468 }
1469 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1470 if (val != NULL) {
1471 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1472 sizeof(xmlNodePtr));
1473 if (ret->nodeTab == NULL) {
1474 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001475 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001476 return(NULL);
1477 }
1478 memset(ret->nodeTab, 0 ,
1479 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1480 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001481 if (val->type == XML_NAMESPACE_DECL) {
1482 xmlNsPtr ns = (xmlNsPtr) val;
1483
1484 ret->nodeTab[ret->nodeNr++] =
1485 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1486 } else
1487 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001488 }
1489 return(ret);
1490}
1491
1492/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001493 * xmlXPathNodeSetContains:
1494 * @cur: the node-set
1495 * @val: the node
1496 *
1497 * checks whether @cur contains @val
1498 *
1499 * Returns true (1) if @cur contains @val, false (0) otherwise
1500 */
1501int
1502xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1503 int i;
1504
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001505 if (val->type == XML_NAMESPACE_DECL) {
1506 for (i = 0; i < cur->nodeNr; i++) {
1507 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1508 xmlNsPtr ns1, ns2;
1509
1510 ns1 = (xmlNsPtr) val;
1511 ns2 = (xmlNsPtr) cur->nodeTab[i];
1512 if (ns1 == ns2)
1513 return(1);
1514 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1515 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1516 return(1);
1517 }
1518 }
1519 } else {
1520 for (i = 0; i < cur->nodeNr; i++) {
1521 if (cur->nodeTab[i] == val)
1522 return(1);
1523 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001524 }
1525 return(0);
1526}
1527
1528/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001529 * xmlXPathNodeSetAddNs:
1530 * @cur: the initial node set
1531 * @node: the hosting node
1532 * @ns: a the namespace node
1533 *
1534 * add a new namespace node to an existing NodeSet
1535 */
1536static void
1537xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1538 int i;
1539
1540 if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) ||
1541 (node->type != XML_ELEMENT_NODE))
1542 return;
1543
1544 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1545 /*
1546 * check against doublons
1547 */
1548 for (i = 0;i < cur->nodeNr;i++) {
1549 if ((cur->nodeTab[i] != NULL) &&
1550 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
1551 (cur->nodeTab[i]->next == node) &&
1552 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1553 return;
1554 }
1555
1556 /*
1557 * grow the nodeTab if needed
1558 */
1559 if (cur->nodeMax == 0) {
1560 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1561 sizeof(xmlNodePtr));
1562 if (cur->nodeTab == NULL) {
1563 xmlGenericError(xmlGenericErrorContext,
1564 "xmlXPathNodeSetAdd: out of memory\n");
1565 return;
1566 }
1567 memset(cur->nodeTab, 0 ,
1568 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1569 cur->nodeMax = XML_NODESET_DEFAULT;
1570 } else if (cur->nodeNr == cur->nodeMax) {
1571 xmlNodePtr *temp;
1572
1573 cur->nodeMax *= 2;
1574 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1575 sizeof(xmlNodePtr));
1576 if (temp == NULL) {
1577 xmlGenericError(xmlGenericErrorContext,
1578 "xmlXPathNodeSetAdd: out of memory\n");
1579 return;
1580 }
1581 cur->nodeTab = temp;
1582 }
1583 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1584}
1585
1586/**
Owen Taylor3473f882001-02-23 17:55:21 +00001587 * xmlXPathNodeSetAdd:
1588 * @cur: the initial node set
1589 * @val: a new xmlNodePtr
1590 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001591 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001592 */
1593void
1594xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1595 int i;
1596
1597 if (val == NULL) return;
1598
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001599 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001600 /*
1601 * check against doublons
1602 */
1603 for (i = 0;i < cur->nodeNr;i++)
1604 if (cur->nodeTab[i] == val) return;
1605
1606 /*
1607 * grow the nodeTab if needed
1608 */
1609 if (cur->nodeMax == 0) {
1610 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1611 sizeof(xmlNodePtr));
1612 if (cur->nodeTab == NULL) {
1613 xmlGenericError(xmlGenericErrorContext,
1614 "xmlXPathNodeSetAdd: out of memory\n");
1615 return;
1616 }
1617 memset(cur->nodeTab, 0 ,
1618 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1619 cur->nodeMax = XML_NODESET_DEFAULT;
1620 } else if (cur->nodeNr == cur->nodeMax) {
1621 xmlNodePtr *temp;
1622
1623 cur->nodeMax *= 2;
1624 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1625 sizeof(xmlNodePtr));
1626 if (temp == NULL) {
1627 xmlGenericError(xmlGenericErrorContext,
1628 "xmlXPathNodeSetAdd: out of memory\n");
1629 return;
1630 }
1631 cur->nodeTab = temp;
1632 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001633 if (val->type == XML_NAMESPACE_DECL) {
1634 xmlNsPtr ns = (xmlNsPtr) val;
1635
1636 cur->nodeTab[cur->nodeNr++] =
1637 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1638 } else
1639 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001640}
1641
1642/**
1643 * xmlXPathNodeSetAddUnique:
1644 * @cur: the initial node set
1645 * @val: a new xmlNodePtr
1646 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001647 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001648 * when we are sure the node is not already in the set.
1649 */
1650void
1651xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1652 if (val == NULL) return;
1653
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001654 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001655 /*
1656 * grow the nodeTab if needed
1657 */
1658 if (cur->nodeMax == 0) {
1659 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1660 sizeof(xmlNodePtr));
1661 if (cur->nodeTab == NULL) {
1662 xmlGenericError(xmlGenericErrorContext,
1663 "xmlXPathNodeSetAddUnique: out of memory\n");
1664 return;
1665 }
1666 memset(cur->nodeTab, 0 ,
1667 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1668 cur->nodeMax = XML_NODESET_DEFAULT;
1669 } else if (cur->nodeNr == cur->nodeMax) {
1670 xmlNodePtr *temp;
1671
1672 cur->nodeMax *= 2;
1673 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1674 sizeof(xmlNodePtr));
1675 if (temp == NULL) {
1676 xmlGenericError(xmlGenericErrorContext,
1677 "xmlXPathNodeSetAddUnique: out of memory\n");
1678 return;
1679 }
1680 cur->nodeTab = temp;
1681 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001682 if (val->type == XML_NAMESPACE_DECL) {
1683 xmlNsPtr ns = (xmlNsPtr) val;
1684
1685 cur->nodeTab[cur->nodeNr++] =
1686 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1687 } else
1688 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001689}
1690
1691/**
1692 * xmlXPathNodeSetMerge:
1693 * @val1: the first NodeSet or NULL
1694 * @val2: the second NodeSet
1695 *
1696 * Merges two nodesets, all nodes from @val2 are added to @val1
1697 * if @val1 is NULL, a new set is created and copied from @val2
1698 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001699 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001700 */
1701xmlNodeSetPtr
1702xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001703 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001704
1705 if (val2 == NULL) return(val1);
1706 if (val1 == NULL) {
1707 val1 = xmlXPathNodeSetCreate(NULL);
1708 }
1709
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001710 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001711 initNr = val1->nodeNr;
1712
1713 for (i = 0;i < val2->nodeNr;i++) {
1714 /*
1715 * check against doublons
1716 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001717 skip = 0;
1718 for (j = 0; j < initNr; j++) {
1719 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1720 skip = 1;
1721 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001722 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
1723 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
1724 xmlNsPtr ns1, ns2;
1725 ns1 = (xmlNsPtr) val1->nodeTab[j];
1726 ns2 = (xmlNsPtr) val2->nodeTab[i];
1727 if ((ns1->next == ns2->next) &&
1728 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
1729 skip = 1;
1730 break;
1731 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001732 }
1733 }
1734 if (skip)
1735 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001736
1737 /*
1738 * grow the nodeTab if needed
1739 */
1740 if (val1->nodeMax == 0) {
1741 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1742 sizeof(xmlNodePtr));
1743 if (val1->nodeTab == NULL) {
1744 xmlGenericError(xmlGenericErrorContext,
1745 "xmlXPathNodeSetMerge: out of memory\n");
1746 return(NULL);
1747 }
1748 memset(val1->nodeTab, 0 ,
1749 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1750 val1->nodeMax = XML_NODESET_DEFAULT;
1751 } else if (val1->nodeNr == val1->nodeMax) {
1752 xmlNodePtr *temp;
1753
1754 val1->nodeMax *= 2;
1755 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1756 sizeof(xmlNodePtr));
1757 if (temp == NULL) {
1758 xmlGenericError(xmlGenericErrorContext,
1759 "xmlXPathNodeSetMerge: out of memory\n");
1760 return(NULL);
1761 }
1762 val1->nodeTab = temp;
1763 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001764 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1765 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1766
1767 val1->nodeTab[val1->nodeNr++] =
1768 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1769 } else
1770 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00001771 }
1772
1773 return(val1);
1774}
1775
1776/**
Daniel Veillard75be0132002-03-13 10:03:35 +00001777 * xmlXPathNodeSetMergeUnique:
1778 * @val1: the first NodeSet or NULL
1779 * @val2: the second NodeSet
1780 *
1781 * Merges two nodesets, all nodes from @val2 are added to @val1
1782 * if @val1 is NULL, a new set is created and copied from @val2
1783 *
1784 * Returns @val1 once extended or NULL in case of error.
1785 */
1786static xmlNodeSetPtr
1787xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
1788 int i, initNr;
1789
1790 if (val2 == NULL) return(val1);
1791 if (val1 == NULL) {
1792 val1 = xmlXPathNodeSetCreate(NULL);
1793 }
1794
1795 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1796 initNr = val1->nodeNr;
1797
1798 for (i = 0;i < val2->nodeNr;i++) {
1799 /*
1800 * grow the nodeTab if needed
1801 */
1802 if (val1->nodeMax == 0) {
1803 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1804 sizeof(xmlNodePtr));
1805 if (val1->nodeTab == NULL) {
1806 xmlGenericError(xmlGenericErrorContext,
1807 "xmlXPathNodeSetMerge: out of memory\n");
1808 return(NULL);
1809 }
1810 memset(val1->nodeTab, 0 ,
1811 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1812 val1->nodeMax = XML_NODESET_DEFAULT;
1813 } else if (val1->nodeNr == val1->nodeMax) {
1814 xmlNodePtr *temp;
1815
1816 val1->nodeMax *= 2;
1817 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1818 sizeof(xmlNodePtr));
1819 if (temp == NULL) {
1820 xmlGenericError(xmlGenericErrorContext,
1821 "xmlXPathNodeSetMerge: out of memory\n");
1822 return(NULL);
1823 }
1824 val1->nodeTab = temp;
1825 }
1826 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1827 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1828
1829 val1->nodeTab[val1->nodeNr++] =
1830 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1831 } else
1832 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1833 }
1834
1835 return(val1);
1836}
1837
1838/**
Owen Taylor3473f882001-02-23 17:55:21 +00001839 * xmlXPathNodeSetDel:
1840 * @cur: the initial node set
1841 * @val: an xmlNodePtr
1842 *
1843 * Removes an xmlNodePtr from an existing NodeSet
1844 */
1845void
1846xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
1847 int i;
1848
1849 if (cur == NULL) return;
1850 if (val == NULL) return;
1851
1852 /*
1853 * check against doublons
1854 */
1855 for (i = 0;i < cur->nodeNr;i++)
1856 if (cur->nodeTab[i] == val) break;
1857
1858 if (i >= cur->nodeNr) {
1859#ifdef DEBUG
1860 xmlGenericError(xmlGenericErrorContext,
1861 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
1862 val->name);
1863#endif
1864 return;
1865 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001866 if ((cur->nodeTab[i] != NULL) &&
1867 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
1868 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001869 cur->nodeNr--;
1870 for (;i < cur->nodeNr;i++)
1871 cur->nodeTab[i] = cur->nodeTab[i + 1];
1872 cur->nodeTab[cur->nodeNr] = NULL;
1873}
1874
1875/**
1876 * xmlXPathNodeSetRemove:
1877 * @cur: the initial node set
1878 * @val: the index to remove
1879 *
1880 * Removes an entry from an existing NodeSet list.
1881 */
1882void
1883xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
1884 if (cur == NULL) return;
1885 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001886 if ((cur->nodeTab[val] != NULL) &&
1887 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
1888 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00001889 cur->nodeNr--;
1890 for (;val < cur->nodeNr;val++)
1891 cur->nodeTab[val] = cur->nodeTab[val + 1];
1892 cur->nodeTab[cur->nodeNr] = NULL;
1893}
1894
1895/**
1896 * xmlXPathFreeNodeSet:
1897 * @obj: the xmlNodeSetPtr to free
1898 *
1899 * Free the NodeSet compound (not the actual nodes !).
1900 */
1901void
1902xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
1903 if (obj == NULL) return;
1904 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001905 int i;
1906
1907 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1908 for (i = 0;i < obj->nodeNr;i++)
1909 if ((obj->nodeTab[i] != NULL) &&
1910 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
1911 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001912 xmlFree(obj->nodeTab);
1913 }
Owen Taylor3473f882001-02-23 17:55:21 +00001914 xmlFree(obj);
1915}
1916
1917/**
1918 * xmlXPathFreeValueTree:
1919 * @obj: the xmlNodeSetPtr to free
1920 *
1921 * Free the NodeSet compound and the actual tree, this is different
1922 * from xmlXPathFreeNodeSet()
1923 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001924static void
Owen Taylor3473f882001-02-23 17:55:21 +00001925xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
1926 int i;
1927
1928 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001929
1930 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001931 for (i = 0;i < obj->nodeNr;i++) {
1932 if (obj->nodeTab[i] != NULL) {
1933 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1934 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
1935 } else {
1936 xmlFreeNodeList(obj->nodeTab[i]);
1937 }
1938 }
1939 }
Owen Taylor3473f882001-02-23 17:55:21 +00001940 xmlFree(obj->nodeTab);
1941 }
Owen Taylor3473f882001-02-23 17:55:21 +00001942 xmlFree(obj);
1943}
1944
1945#if defined(DEBUG) || defined(DEBUG_STEP)
1946/**
1947 * xmlGenericErrorContextNodeSet:
1948 * @output: a FILE * for the output
1949 * @obj: the xmlNodeSetPtr to free
1950 *
1951 * Quick display of a NodeSet
1952 */
1953void
1954xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
1955 int i;
1956
1957 if (output == NULL) output = xmlGenericErrorContext;
1958 if (obj == NULL) {
1959 fprintf(output, "NodeSet == NULL !\n");
1960 return;
1961 }
1962 if (obj->nodeNr == 0) {
1963 fprintf(output, "NodeSet is empty\n");
1964 return;
1965 }
1966 if (obj->nodeTab == NULL) {
1967 fprintf(output, " nodeTab == NULL !\n");
1968 return;
1969 }
1970 for (i = 0; i < obj->nodeNr; i++) {
1971 if (obj->nodeTab[i] == NULL) {
1972 fprintf(output, " NULL !\n");
1973 return;
1974 }
1975 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
1976 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
1977 fprintf(output, " /");
1978 else if (obj->nodeTab[i]->name == NULL)
1979 fprintf(output, " noname!");
1980 else fprintf(output, " %s", obj->nodeTab[i]->name);
1981 }
1982 fprintf(output, "\n");
1983}
1984#endif
1985
1986/**
1987 * xmlXPathNewNodeSet:
1988 * @val: the NodePtr value
1989 *
1990 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1991 * it with the single Node @val
1992 *
1993 * Returns the newly created object.
1994 */
1995xmlXPathObjectPtr
1996xmlXPathNewNodeSet(xmlNodePtr val) {
1997 xmlXPathObjectPtr ret;
1998
1999 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2000 if (ret == NULL) {
2001 xmlGenericError(xmlGenericErrorContext,
2002 "xmlXPathNewNodeSet: out of memory\n");
2003 return(NULL);
2004 }
2005 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2006 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002007 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002008 ret->nodesetval = xmlXPathNodeSetCreate(val);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002009 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002010 return(ret);
2011}
2012
2013/**
2014 * xmlXPathNewValueTree:
2015 * @val: the NodePtr value
2016 *
2017 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2018 * it with the tree root @val
2019 *
2020 * Returns the newly created object.
2021 */
2022xmlXPathObjectPtr
2023xmlXPathNewValueTree(xmlNodePtr val) {
2024 xmlXPathObjectPtr ret;
2025
2026 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2027 if (ret == NULL) {
2028 xmlGenericError(xmlGenericErrorContext,
2029 "xmlXPathNewNodeSet: out of memory\n");
2030 return(NULL);
2031 }
2032 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2033 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002034 ret->boolval = 1;
2035 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002036 ret->nodesetval = xmlXPathNodeSetCreate(val);
2037 return(ret);
2038}
2039
2040/**
2041 * xmlXPathNewNodeSetList:
2042 * @val: an existing NodeSet
2043 *
2044 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2045 * it with the Nodeset @val
2046 *
2047 * Returns the newly created object.
2048 */
2049xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002050xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2051{
Owen Taylor3473f882001-02-23 17:55:21 +00002052 xmlXPathObjectPtr ret;
2053 int i;
2054
2055 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002056 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002057 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002058 ret = xmlXPathNewNodeSet(NULL);
2059 else {
2060 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2061 for (i = 1; i < val->nodeNr; ++i)
2062 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2063 }
Owen Taylor3473f882001-02-23 17:55:21 +00002064
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002065 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002066}
2067
2068/**
2069 * xmlXPathWrapNodeSet:
2070 * @val: the NodePtr value
2071 *
2072 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2073 *
2074 * Returns the newly created object.
2075 */
2076xmlXPathObjectPtr
2077xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2078 xmlXPathObjectPtr ret;
2079
2080 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2081 if (ret == NULL) {
2082 xmlGenericError(xmlGenericErrorContext,
2083 "xmlXPathWrapNodeSet: out of memory\n");
2084 return(NULL);
2085 }
2086 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2087 ret->type = XPATH_NODESET;
2088 ret->nodesetval = val;
2089 return(ret);
2090}
2091
2092/**
2093 * xmlXPathFreeNodeSetList:
2094 * @obj: an existing NodeSetList object
2095 *
2096 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2097 * the list contrary to xmlXPathFreeObject().
2098 */
2099void
2100xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2101 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002102 xmlFree(obj);
2103}
2104
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002105/**
2106 * xmlXPathDifference:
2107 * @nodes1: a node-set
2108 * @nodes2: a node-set
2109 *
2110 * Implements the EXSLT - Sets difference() function:
2111 * node-set set:difference (node-set, node-set)
2112 *
2113 * Returns the difference between the two node sets, or nodes1 if
2114 * nodes2 is empty
2115 */
2116xmlNodeSetPtr
2117xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2118 xmlNodeSetPtr ret;
2119 int i, l1;
2120 xmlNodePtr cur;
2121
2122 if (xmlXPathNodeSetIsEmpty(nodes2))
2123 return(nodes1);
2124
2125 ret = xmlXPathNodeSetCreate(NULL);
2126 if (xmlXPathNodeSetIsEmpty(nodes1))
2127 return(ret);
2128
2129 l1 = xmlXPathNodeSetGetLength(nodes1);
2130
2131 for (i = 0; i < l1; i++) {
2132 cur = xmlXPathNodeSetItem(nodes1, i);
2133 if (!xmlXPathNodeSetContains(nodes2, cur))
2134 xmlXPathNodeSetAddUnique(ret, cur);
2135 }
2136 return(ret);
2137}
2138
2139/**
2140 * xmlXPathIntersection:
2141 * @nodes1: a node-set
2142 * @nodes2: a node-set
2143 *
2144 * Implements the EXSLT - Sets intersection() function:
2145 * node-set set:intersection (node-set, node-set)
2146 *
2147 * Returns a node set comprising the nodes that are within both the
2148 * node sets passed as arguments
2149 */
2150xmlNodeSetPtr
2151xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2152 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2153 int i, l1;
2154 xmlNodePtr cur;
2155
2156 if (xmlXPathNodeSetIsEmpty(nodes1))
2157 return(ret);
2158 if (xmlXPathNodeSetIsEmpty(nodes2))
2159 return(ret);
2160
2161 l1 = xmlXPathNodeSetGetLength(nodes1);
2162
2163 for (i = 0; i < l1; i++) {
2164 cur = xmlXPathNodeSetItem(nodes1, i);
2165 if (xmlXPathNodeSetContains(nodes2, cur))
2166 xmlXPathNodeSetAddUnique(ret, cur);
2167 }
2168 return(ret);
2169}
2170
2171/**
2172 * xmlXPathDistinctSorted:
2173 * @nodes: a node-set, sorted by document order
2174 *
2175 * Implements the EXSLT - Sets distinct() function:
2176 * node-set set:distinct (node-set)
2177 *
2178 * Returns a subset of the nodes contained in @nodes, or @nodes if
2179 * it is empty
2180 */
2181xmlNodeSetPtr
2182xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2183 xmlNodeSetPtr ret;
2184 xmlHashTablePtr hash;
2185 int i, l;
2186 xmlChar * strval;
2187 xmlNodePtr cur;
2188
2189 if (xmlXPathNodeSetIsEmpty(nodes))
2190 return(nodes);
2191
2192 ret = xmlXPathNodeSetCreate(NULL);
2193 l = xmlXPathNodeSetGetLength(nodes);
2194 hash = xmlHashCreate (l);
2195 for (i = 0; i < l; i++) {
2196 cur = xmlXPathNodeSetItem(nodes, i);
2197 strval = xmlXPathCastNodeToString(cur);
2198 if (xmlHashLookup(hash, strval) == NULL) {
2199 xmlHashAddEntry(hash, strval, strval);
2200 xmlXPathNodeSetAddUnique(ret, cur);
2201 } else {
2202 xmlFree(strval);
2203 }
2204 }
2205 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2206 return(ret);
2207}
2208
2209/**
2210 * xmlXPathDistinct:
2211 * @nodes: a node-set
2212 *
2213 * Implements the EXSLT - Sets distinct() function:
2214 * node-set set:distinct (node-set)
2215 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2216 * is called with the sorted node-set
2217 *
2218 * Returns a subset of the nodes contained in @nodes, or @nodes if
2219 * it is empty
2220 */
2221xmlNodeSetPtr
2222xmlXPathDistinct (xmlNodeSetPtr nodes) {
2223 if (xmlXPathNodeSetIsEmpty(nodes))
2224 return(nodes);
2225
2226 xmlXPathNodeSetSort(nodes);
2227 return(xmlXPathDistinctSorted(nodes));
2228}
2229
2230/**
2231 * xmlXPathHasSameNodes:
2232 * @nodes1: a node-set
2233 * @nodes2: a node-set
2234 *
2235 * Implements the EXSLT - Sets has-same-nodes function:
2236 * boolean set:has-same-node(node-set, node-set)
2237 *
2238 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2239 * otherwise
2240 */
2241int
2242xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2243 int i, l;
2244 xmlNodePtr cur;
2245
2246 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2247 xmlXPathNodeSetIsEmpty(nodes2))
2248 return(0);
2249
2250 l = xmlXPathNodeSetGetLength(nodes1);
2251 for (i = 0; i < l; i++) {
2252 cur = xmlXPathNodeSetItem(nodes1, i);
2253 if (xmlXPathNodeSetContains(nodes2, cur))
2254 return(1);
2255 }
2256 return(0);
2257}
2258
2259/**
2260 * xmlXPathNodeLeadingSorted:
2261 * @nodes: a node-set, sorted by document order
2262 * @node: a node
2263 *
2264 * Implements the EXSLT - Sets leading() function:
2265 * node-set set:leading (node-set, node-set)
2266 *
2267 * Returns the nodes in @nodes that precede @node in document order,
2268 * @nodes if @node is NULL or an empty node-set if @nodes
2269 * doesn't contain @node
2270 */
2271xmlNodeSetPtr
2272xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2273 int i, l;
2274 xmlNodePtr cur;
2275 xmlNodeSetPtr ret;
2276
2277 if (node == NULL)
2278 return(nodes);
2279
2280 ret = xmlXPathNodeSetCreate(NULL);
2281 if (xmlXPathNodeSetIsEmpty(nodes) ||
2282 (!xmlXPathNodeSetContains(nodes, node)))
2283 return(ret);
2284
2285 l = xmlXPathNodeSetGetLength(nodes);
2286 for (i = 0; i < l; i++) {
2287 cur = xmlXPathNodeSetItem(nodes, i);
2288 if (cur == node)
2289 break;
2290 xmlXPathNodeSetAddUnique(ret, cur);
2291 }
2292 return(ret);
2293}
2294
2295/**
2296 * xmlXPathNodeLeading:
2297 * @nodes: a node-set
2298 * @node: a node
2299 *
2300 * Implements the EXSLT - Sets leading() function:
2301 * node-set set:leading (node-set, node-set)
2302 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2303 * is called.
2304 *
2305 * Returns the nodes in @nodes that precede @node in document order,
2306 * @nodes if @node is NULL or an empty node-set if @nodes
2307 * doesn't contain @node
2308 */
2309xmlNodeSetPtr
2310xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2311 xmlXPathNodeSetSort(nodes);
2312 return(xmlXPathNodeLeadingSorted(nodes, node));
2313}
2314
2315/**
2316 * xmlXPathLeadingSorted:
2317 * @nodes1: a node-set, sorted by document order
2318 * @nodes2: a node-set, sorted by document order
2319 *
2320 * Implements the EXSLT - Sets leading() function:
2321 * node-set set:leading (node-set, node-set)
2322 *
2323 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2324 * in document order, @nodes1 if @nodes2 is NULL or empty or
2325 * an empty node-set if @nodes1 doesn't contain @nodes2
2326 */
2327xmlNodeSetPtr
2328xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2329 if (xmlXPathNodeSetIsEmpty(nodes2))
2330 return(nodes1);
2331 return(xmlXPathNodeLeadingSorted(nodes1,
2332 xmlXPathNodeSetItem(nodes2, 1)));
2333}
2334
2335/**
2336 * xmlXPathLeading:
2337 * @nodes1: a node-set
2338 * @nodes2: a node-set
2339 *
2340 * Implements the EXSLT - Sets leading() function:
2341 * node-set set:leading (node-set, node-set)
2342 * @nodes1 and @nodes2 are sorted by document order, then
2343 * #exslSetsLeadingSorted is called.
2344 *
2345 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2346 * in document order, @nodes1 if @nodes2 is NULL or empty or
2347 * an empty node-set if @nodes1 doesn't contain @nodes2
2348 */
2349xmlNodeSetPtr
2350xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2351 if (xmlXPathNodeSetIsEmpty(nodes2))
2352 return(nodes1);
2353 if (xmlXPathNodeSetIsEmpty(nodes1))
2354 return(xmlXPathNodeSetCreate(NULL));
2355 xmlXPathNodeSetSort(nodes1);
2356 xmlXPathNodeSetSort(nodes2);
2357 return(xmlXPathNodeLeadingSorted(nodes1,
2358 xmlXPathNodeSetItem(nodes2, 1)));
2359}
2360
2361/**
2362 * xmlXPathNodeTrailingSorted:
2363 * @nodes: a node-set, sorted by document order
2364 * @node: a node
2365 *
2366 * Implements the EXSLT - Sets trailing() function:
2367 * node-set set:trailing (node-set, node-set)
2368 *
2369 * Returns the nodes in @nodes that follow @node in document order,
2370 * @nodes if @node is NULL or an empty node-set if @nodes
2371 * doesn't contain @node
2372 */
2373xmlNodeSetPtr
2374xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2375 int i, l;
2376 xmlNodePtr cur;
2377 xmlNodeSetPtr ret;
2378
2379 if (node == NULL)
2380 return(nodes);
2381
2382 ret = xmlXPathNodeSetCreate(NULL);
2383 if (xmlXPathNodeSetIsEmpty(nodes) ||
2384 (!xmlXPathNodeSetContains(nodes, node)))
2385 return(ret);
2386
2387 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002388 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002389 cur = xmlXPathNodeSetItem(nodes, i);
2390 if (cur == node)
2391 break;
2392 xmlXPathNodeSetAddUnique(ret, cur);
2393 }
2394 return(ret);
2395}
2396
2397/**
2398 * xmlXPathNodeTrailing:
2399 * @nodes: a node-set
2400 * @node: a node
2401 *
2402 * Implements the EXSLT - Sets trailing() function:
2403 * node-set set:trailing (node-set, node-set)
2404 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2405 * is called.
2406 *
2407 * Returns the nodes in @nodes that follow @node in document order,
2408 * @nodes if @node is NULL or an empty node-set if @nodes
2409 * doesn't contain @node
2410 */
2411xmlNodeSetPtr
2412xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2413 xmlXPathNodeSetSort(nodes);
2414 return(xmlXPathNodeTrailingSorted(nodes, node));
2415}
2416
2417/**
2418 * xmlXPathTrailingSorted:
2419 * @nodes1: a node-set, sorted by document order
2420 * @nodes2: a node-set, sorted by document order
2421 *
2422 * Implements the EXSLT - Sets trailing() function:
2423 * node-set set:trailing (node-set, node-set)
2424 *
2425 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2426 * in document order, @nodes1 if @nodes2 is NULL or empty or
2427 * an empty node-set if @nodes1 doesn't contain @nodes2
2428 */
2429xmlNodeSetPtr
2430xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2431 if (xmlXPathNodeSetIsEmpty(nodes2))
2432 return(nodes1);
2433 return(xmlXPathNodeTrailingSorted(nodes1,
2434 xmlXPathNodeSetItem(nodes2, 0)));
2435}
2436
2437/**
2438 * xmlXPathTrailing:
2439 * @nodes1: a node-set
2440 * @nodes2: a node-set
2441 *
2442 * Implements the EXSLT - Sets trailing() function:
2443 * node-set set:trailing (node-set, node-set)
2444 * @nodes1 and @nodes2 are sorted by document order, then
2445 * #xmlXPathTrailingSorted is called.
2446 *
2447 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2448 * in document order, @nodes1 if @nodes2 is NULL or empty or
2449 * an empty node-set if @nodes1 doesn't contain @nodes2
2450 */
2451xmlNodeSetPtr
2452xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2453 if (xmlXPathNodeSetIsEmpty(nodes2))
2454 return(nodes1);
2455 if (xmlXPathNodeSetIsEmpty(nodes1))
2456 return(xmlXPathNodeSetCreate(NULL));
2457 xmlXPathNodeSetSort(nodes1);
2458 xmlXPathNodeSetSort(nodes2);
2459 return(xmlXPathNodeTrailingSorted(nodes1,
2460 xmlXPathNodeSetItem(nodes2, 0)));
2461}
2462
Owen Taylor3473f882001-02-23 17:55:21 +00002463/************************************************************************
2464 * *
2465 * Routines to handle extra functions *
2466 * *
2467 ************************************************************************/
2468
2469/**
2470 * xmlXPathRegisterFunc:
2471 * @ctxt: the XPath context
2472 * @name: the function name
2473 * @f: the function implementation or NULL
2474 *
2475 * Register a new function. If @f is NULL it unregisters the function
2476 *
2477 * Returns 0 in case of success, -1 in case of error
2478 */
2479int
2480xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2481 xmlXPathFunction f) {
2482 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2483}
2484
2485/**
2486 * xmlXPathRegisterFuncNS:
2487 * @ctxt: the XPath context
2488 * @name: the function name
2489 * @ns_uri: the function namespace URI
2490 * @f: the function implementation or NULL
2491 *
2492 * Register a new function. If @f is NULL it unregisters the function
2493 *
2494 * Returns 0 in case of success, -1 in case of error
2495 */
2496int
2497xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2498 const xmlChar *ns_uri, xmlXPathFunction f) {
2499 if (ctxt == NULL)
2500 return(-1);
2501 if (name == NULL)
2502 return(-1);
2503
2504 if (ctxt->funcHash == NULL)
2505 ctxt->funcHash = xmlHashCreate(0);
2506 if (ctxt->funcHash == NULL)
2507 return(-1);
2508 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2509}
2510
2511/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002512 * xmlXPathRegisterFuncLookup:
2513 * @ctxt: the XPath context
2514 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002515 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002516 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002517 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002518 */
2519void
2520xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2521 xmlXPathFuncLookupFunc f,
2522 void *funcCtxt) {
2523 if (ctxt == NULL)
2524 return;
2525 ctxt->funcLookupFunc = (void *) f;
2526 ctxt->funcLookupData = funcCtxt;
2527}
2528
2529/**
Owen Taylor3473f882001-02-23 17:55:21 +00002530 * xmlXPathFunctionLookup:
2531 * @ctxt: the XPath context
2532 * @name: the function name
2533 *
2534 * Search in the Function array of the context for the given
2535 * function.
2536 *
2537 * Returns the xmlXPathFunction or NULL if not found
2538 */
2539xmlXPathFunction
2540xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002541 if (ctxt == NULL)
2542 return (NULL);
2543
2544 if (ctxt->funcLookupFunc != NULL) {
2545 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002546 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002547
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002548 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002549 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002550 if (ret != NULL)
2551 return(ret);
2552 }
Owen Taylor3473f882001-02-23 17:55:21 +00002553 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2554}
2555
2556/**
2557 * xmlXPathFunctionLookupNS:
2558 * @ctxt: the XPath context
2559 * @name: the function name
2560 * @ns_uri: the function namespace URI
2561 *
2562 * Search in the Function array of the context for the given
2563 * function.
2564 *
2565 * Returns the xmlXPathFunction or NULL if not found
2566 */
2567xmlXPathFunction
2568xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2569 const xmlChar *ns_uri) {
2570 if (ctxt == NULL)
2571 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002572 if (name == NULL)
2573 return(NULL);
2574
Thomas Broyerba4ad322001-07-26 16:55:21 +00002575 if (ctxt->funcLookupFunc != NULL) {
2576 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002577 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002578
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002579 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002580 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002581 if (ret != NULL)
2582 return(ret);
2583 }
2584
2585 if (ctxt->funcHash == NULL)
2586 return(NULL);
2587
Owen Taylor3473f882001-02-23 17:55:21 +00002588 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2589}
2590
2591/**
2592 * xmlXPathRegisteredFuncsCleanup:
2593 * @ctxt: the XPath context
2594 *
2595 * Cleanup the XPath context data associated to registered functions
2596 */
2597void
2598xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2599 if (ctxt == NULL)
2600 return;
2601
2602 xmlHashFree(ctxt->funcHash, NULL);
2603 ctxt->funcHash = NULL;
2604}
2605
2606/************************************************************************
2607 * *
2608 * Routines to handle Variable *
2609 * *
2610 ************************************************************************/
2611
2612/**
2613 * xmlXPathRegisterVariable:
2614 * @ctxt: the XPath context
2615 * @name: the variable name
2616 * @value: the variable value or NULL
2617 *
2618 * Register a new variable value. If @value is NULL it unregisters
2619 * the variable
2620 *
2621 * Returns 0 in case of success, -1 in case of error
2622 */
2623int
2624xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2625 xmlXPathObjectPtr value) {
2626 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2627}
2628
2629/**
2630 * xmlXPathRegisterVariableNS:
2631 * @ctxt: the XPath context
2632 * @name: the variable name
2633 * @ns_uri: the variable namespace URI
2634 * @value: the variable value or NULL
2635 *
2636 * Register a new variable value. If @value is NULL it unregisters
2637 * the variable
2638 *
2639 * Returns 0 in case of success, -1 in case of error
2640 */
2641int
2642xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2643 const xmlChar *ns_uri,
2644 xmlXPathObjectPtr value) {
2645 if (ctxt == NULL)
2646 return(-1);
2647 if (name == NULL)
2648 return(-1);
2649
2650 if (ctxt->varHash == NULL)
2651 ctxt->varHash = xmlHashCreate(0);
2652 if (ctxt->varHash == NULL)
2653 return(-1);
2654 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2655 (void *) value,
2656 (xmlHashDeallocator)xmlXPathFreeObject));
2657}
2658
2659/**
2660 * xmlXPathRegisterVariableLookup:
2661 * @ctxt: the XPath context
2662 * @f: the lookup function
2663 * @data: the lookup data
2664 *
2665 * register an external mechanism to do variable lookup
2666 */
2667void
2668xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2669 xmlXPathVariableLookupFunc f, void *data) {
2670 if (ctxt == NULL)
2671 return;
2672 ctxt->varLookupFunc = (void *) f;
2673 ctxt->varLookupData = data;
2674}
2675
2676/**
2677 * xmlXPathVariableLookup:
2678 * @ctxt: the XPath context
2679 * @name: the variable name
2680 *
2681 * Search in the Variable array of the context for the given
2682 * variable value.
2683 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002684 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002685 */
2686xmlXPathObjectPtr
2687xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2688 if (ctxt == NULL)
2689 return(NULL);
2690
2691 if (ctxt->varLookupFunc != NULL) {
2692 xmlXPathObjectPtr ret;
2693
2694 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2695 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002696 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002697 }
2698 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2699}
2700
2701/**
2702 * xmlXPathVariableLookupNS:
2703 * @ctxt: the XPath context
2704 * @name: the variable name
2705 * @ns_uri: the variable namespace URI
2706 *
2707 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002708 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002709 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002710 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002711 */
2712xmlXPathObjectPtr
2713xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2714 const xmlChar *ns_uri) {
2715 if (ctxt == NULL)
2716 return(NULL);
2717
2718 if (ctxt->varLookupFunc != NULL) {
2719 xmlXPathObjectPtr ret;
2720
2721 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2722 (ctxt->varLookupData, name, ns_uri);
2723 if (ret != NULL) return(ret);
2724 }
2725
2726 if (ctxt->varHash == NULL)
2727 return(NULL);
2728 if (name == NULL)
2729 return(NULL);
2730
Daniel Veillard8c357d52001-07-03 23:43:33 +00002731 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2732 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002733}
2734
2735/**
2736 * xmlXPathRegisteredVariablesCleanup:
2737 * @ctxt: the XPath context
2738 *
2739 * Cleanup the XPath context data associated to registered variables
2740 */
2741void
2742xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2743 if (ctxt == NULL)
2744 return;
2745
Daniel Veillard76d66f42001-05-16 21:05:17 +00002746 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002747 ctxt->varHash = NULL;
2748}
2749
2750/**
2751 * xmlXPathRegisterNs:
2752 * @ctxt: the XPath context
2753 * @prefix: the namespace prefix
2754 * @ns_uri: the namespace name
2755 *
2756 * Register a new namespace. If @ns_uri is NULL it unregisters
2757 * the namespace
2758 *
2759 * Returns 0 in case of success, -1 in case of error
2760 */
2761int
2762xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2763 const xmlChar *ns_uri) {
2764 if (ctxt == NULL)
2765 return(-1);
2766 if (prefix == NULL)
2767 return(-1);
2768
2769 if (ctxt->nsHash == NULL)
2770 ctxt->nsHash = xmlHashCreate(10);
2771 if (ctxt->nsHash == NULL)
2772 return(-1);
2773 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) ns_uri,
2774 (xmlHashDeallocator)xmlFree));
2775}
2776
2777/**
2778 * xmlXPathNsLookup:
2779 * @ctxt: the XPath context
2780 * @prefix: the namespace prefix value
2781 *
2782 * Search in the namespace declaration array of the context for the given
2783 * namespace name associated to the given prefix
2784 *
2785 * Returns the value or NULL if not found
2786 */
2787const xmlChar *
2788xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2789 if (ctxt == NULL)
2790 return(NULL);
2791 if (prefix == NULL)
2792 return(NULL);
2793
2794#ifdef XML_XML_NAMESPACE
2795 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
2796 return(XML_XML_NAMESPACE);
2797#endif
2798
Daniel Veillardc8f620b2001-04-30 20:31:33 +00002799 if (ctxt->namespaces != NULL) {
2800 int i;
2801
2802 for (i = 0;i < ctxt->nsNr;i++) {
2803 if ((ctxt->namespaces[i] != NULL) &&
2804 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
2805 return(ctxt->namespaces[i]->href);
2806 }
2807 }
Owen Taylor3473f882001-02-23 17:55:21 +00002808
2809 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
2810}
2811
2812/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002813 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00002814 * @ctxt: the XPath context
2815 *
2816 * Cleanup the XPath context data associated to registered variables
2817 */
2818void
2819xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2820 if (ctxt == NULL)
2821 return;
2822
2823 xmlHashFree(ctxt->nsHash, NULL);
2824 ctxt->nsHash = NULL;
2825}
2826
2827/************************************************************************
2828 * *
2829 * Routines to handle Values *
2830 * *
2831 ************************************************************************/
2832
2833/* Allocations are terrible, one need to optimize all this !!! */
2834
2835/**
2836 * xmlXPathNewFloat:
2837 * @val: the double value
2838 *
2839 * Create a new xmlXPathObjectPtr of type double and of value @val
2840 *
2841 * Returns the newly created object.
2842 */
2843xmlXPathObjectPtr
2844xmlXPathNewFloat(double val) {
2845 xmlXPathObjectPtr ret;
2846
2847 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2848 if (ret == NULL) {
2849 xmlGenericError(xmlGenericErrorContext,
2850 "xmlXPathNewFloat: out of memory\n");
2851 return(NULL);
2852 }
2853 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2854 ret->type = XPATH_NUMBER;
2855 ret->floatval = val;
2856 return(ret);
2857}
2858
2859/**
2860 * xmlXPathNewBoolean:
2861 * @val: the boolean value
2862 *
2863 * Create a new xmlXPathObjectPtr of type boolean and of value @val
2864 *
2865 * Returns the newly created object.
2866 */
2867xmlXPathObjectPtr
2868xmlXPathNewBoolean(int val) {
2869 xmlXPathObjectPtr ret;
2870
2871 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2872 if (ret == NULL) {
2873 xmlGenericError(xmlGenericErrorContext,
2874 "xmlXPathNewBoolean: out of memory\n");
2875 return(NULL);
2876 }
2877 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2878 ret->type = XPATH_BOOLEAN;
2879 ret->boolval = (val != 0);
2880 return(ret);
2881}
2882
2883/**
2884 * xmlXPathNewString:
2885 * @val: the xmlChar * value
2886 *
2887 * Create a new xmlXPathObjectPtr of type string and of value @val
2888 *
2889 * Returns the newly created object.
2890 */
2891xmlXPathObjectPtr
2892xmlXPathNewString(const xmlChar *val) {
2893 xmlXPathObjectPtr ret;
2894
2895 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2896 if (ret == NULL) {
2897 xmlGenericError(xmlGenericErrorContext,
2898 "xmlXPathNewString: out of memory\n");
2899 return(NULL);
2900 }
2901 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2902 ret->type = XPATH_STRING;
2903 if (val != NULL)
2904 ret->stringval = xmlStrdup(val);
2905 else
2906 ret->stringval = xmlStrdup((const xmlChar *)"");
2907 return(ret);
2908}
2909
2910/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002911 * xmlXPathWrapString:
2912 * @val: the xmlChar * value
2913 *
2914 * Wraps the @val string into an XPath object.
2915 *
2916 * Returns the newly created object.
2917 */
2918xmlXPathObjectPtr
2919xmlXPathWrapString (xmlChar *val) {
2920 xmlXPathObjectPtr ret;
2921
2922 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2923 if (ret == NULL) {
2924 xmlGenericError(xmlGenericErrorContext,
2925 "xmlXPathWrapString: out of memory\n");
2926 return(NULL);
2927 }
2928 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2929 ret->type = XPATH_STRING;
2930 ret->stringval = val;
2931 return(ret);
2932}
2933
2934/**
Owen Taylor3473f882001-02-23 17:55:21 +00002935 * xmlXPathNewCString:
2936 * @val: the char * value
2937 *
2938 * Create a new xmlXPathObjectPtr of type string and of value @val
2939 *
2940 * Returns the newly created object.
2941 */
2942xmlXPathObjectPtr
2943xmlXPathNewCString(const char *val) {
2944 xmlXPathObjectPtr ret;
2945
2946 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2947 if (ret == NULL) {
2948 xmlGenericError(xmlGenericErrorContext,
2949 "xmlXPathNewCString: out of memory\n");
2950 return(NULL);
2951 }
2952 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2953 ret->type = XPATH_STRING;
2954 ret->stringval = xmlStrdup(BAD_CAST val);
2955 return(ret);
2956}
2957
2958/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002959 * xmlXPathWrapCString:
2960 * @val: the char * value
2961 *
2962 * Wraps a string into an XPath object.
2963 *
2964 * Returns the newly created object.
2965 */
2966xmlXPathObjectPtr
2967xmlXPathWrapCString (char * val) {
2968 return(xmlXPathWrapString((xmlChar *)(val)));
2969}
2970
2971/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002972 * xmlXPathWrapExternal:
2973 * @val: the user data
2974 *
2975 * Wraps the @val data into an XPath object.
2976 *
2977 * Returns the newly created object.
2978 */
2979xmlXPathObjectPtr
2980xmlXPathWrapExternal (void *val) {
2981 xmlXPathObjectPtr ret;
2982
2983 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2984 if (ret == NULL) {
2985 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002986 "xmlXPathWrapExternal: out of memory\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002987 return(NULL);
2988 }
2989 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2990 ret->type = XPATH_USERS;
2991 ret->user = val;
2992 return(ret);
2993}
2994
2995/**
Owen Taylor3473f882001-02-23 17:55:21 +00002996 * xmlXPathObjectCopy:
2997 * @val: the original object
2998 *
2999 * allocate a new copy of a given object
3000 *
3001 * Returns the newly created object.
3002 */
3003xmlXPathObjectPtr
3004xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3005 xmlXPathObjectPtr ret;
3006
3007 if (val == NULL)
3008 return(NULL);
3009
3010 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3011 if (ret == NULL) {
3012 xmlGenericError(xmlGenericErrorContext,
3013 "xmlXPathObjectCopy: out of memory\n");
3014 return(NULL);
3015 }
3016 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3017 switch (val->type) {
3018 case XPATH_BOOLEAN:
3019 case XPATH_NUMBER:
3020 case XPATH_POINT:
3021 case XPATH_RANGE:
3022 break;
3023 case XPATH_STRING:
3024 ret->stringval = xmlStrdup(val->stringval);
3025 break;
3026 case XPATH_XSLT_TREE:
3027 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003028 (val->nodesetval->nodeTab != NULL)) {
3029 ret->boolval = 1;
Daniel Veillard6ab38382001-10-06 13:08:27 +00003030 ret->user = xmlDocCopyNode(val->nodesetval->nodeTab[0],
3031 val->nodesetval->nodeTab[0]->doc, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003032 ret->nodesetval = xmlXPathNodeSetCreate(
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003033 (xmlNodePtr) ret->user);
3034 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003035 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003036 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003037 break;
3038 case XPATH_NODESET:
3039 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003040 /* Do not deallocate the copied tree value */
3041 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003042 break;
3043 case XPATH_LOCATIONSET:
3044#ifdef LIBXML_XPTR_ENABLED
3045 {
3046 xmlLocationSetPtr loc = val->user;
3047 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3048 break;
3049 }
3050#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003051 case XPATH_USERS:
3052 ret->user = val->user;
3053 break;
3054 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003055 xmlGenericError(xmlGenericErrorContext,
3056 "xmlXPathObjectCopy: unsupported type %d\n",
3057 val->type);
3058 break;
3059 }
3060 return(ret);
3061}
3062
3063/**
3064 * xmlXPathFreeObject:
3065 * @obj: the object to free
3066 *
3067 * Free up an xmlXPathObjectPtr object.
3068 */
3069void
3070xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3071 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003072 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003073 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003074 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003075 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003076 xmlFreeNodeList((xmlNodePtr) obj->user);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003077 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003078 xmlXPathFreeValueTree(obj->nodesetval);
3079 } else {
3080 if (obj->nodesetval != NULL)
3081 xmlXPathFreeNodeSet(obj->nodesetval);
3082 }
Owen Taylor3473f882001-02-23 17:55:21 +00003083#ifdef LIBXML_XPTR_ENABLED
3084 } else if (obj->type == XPATH_LOCATIONSET) {
3085 if (obj->user != NULL)
3086 xmlXPtrFreeLocationSet(obj->user);
3087#endif
3088 } else if (obj->type == XPATH_STRING) {
3089 if (obj->stringval != NULL)
3090 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003091 }
3092
Owen Taylor3473f882001-02-23 17:55:21 +00003093 xmlFree(obj);
3094}
3095
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003096
3097/************************************************************************
3098 * *
3099 * Type Casting Routines *
3100 * *
3101 ************************************************************************/
3102
3103/**
3104 * xmlXPathCastBooleanToString:
3105 * @val: a boolean
3106 *
3107 * Converts a boolean to its string value.
3108 *
3109 * Returns a newly allocated string.
3110 */
3111xmlChar *
3112xmlXPathCastBooleanToString (int val) {
3113 xmlChar *ret;
3114 if (val)
3115 ret = xmlStrdup((const xmlChar *) "true");
3116 else
3117 ret = xmlStrdup((const xmlChar *) "false");
3118 return(ret);
3119}
3120
3121/**
3122 * xmlXPathCastNumberToString:
3123 * @val: a number
3124 *
3125 * Converts a number to its string value.
3126 *
3127 * Returns a newly allocated string.
3128 */
3129xmlChar *
3130xmlXPathCastNumberToString (double val) {
3131 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003132 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003133 case 1:
3134 ret = xmlStrdup((const xmlChar *) "+Infinity");
3135 break;
3136 case -1:
3137 ret = xmlStrdup((const xmlChar *) "-Infinity");
3138 break;
3139 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003140 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003141 ret = xmlStrdup((const xmlChar *) "NaN");
3142 } else {
3143 /* could be improved */
3144 char buf[100];
3145 xmlXPathFormatNumber(val, buf, 100);
3146 ret = xmlStrdup((const xmlChar *) buf);
3147 }
3148 }
3149 return(ret);
3150}
3151
3152/**
3153 * xmlXPathCastNodeToString:
3154 * @node: a node
3155 *
3156 * Converts a node to its string value.
3157 *
3158 * Returns a newly allocated string.
3159 */
3160xmlChar *
3161xmlXPathCastNodeToString (xmlNodePtr node) {
3162 return(xmlNodeGetContent(node));
3163}
3164
3165/**
3166 * xmlXPathCastNodeSetToString:
3167 * @ns: a node-set
3168 *
3169 * Converts a node-set to its string value.
3170 *
3171 * Returns a newly allocated string.
3172 */
3173xmlChar *
3174xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3175 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3176 return(xmlStrdup((const xmlChar *) ""));
3177
3178 xmlXPathNodeSetSort(ns);
3179 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3180}
3181
3182/**
3183 * xmlXPathCastToString:
3184 * @val: an XPath object
3185 *
3186 * Converts an existing object to its string() equivalent
3187 *
3188 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003189 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003190 * string object).
3191 */
3192xmlChar *
3193xmlXPathCastToString(xmlXPathObjectPtr val) {
3194 xmlChar *ret = NULL;
3195
3196 if (val == NULL)
3197 return(xmlStrdup((const xmlChar *) ""));
3198 switch (val->type) {
3199 case XPATH_UNDEFINED:
3200#ifdef DEBUG_EXPR
3201 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3202#endif
3203 ret = xmlStrdup((const xmlChar *) "");
3204 break;
3205 case XPATH_XSLT_TREE:
3206 case XPATH_NODESET:
3207 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3208 break;
3209 case XPATH_STRING:
3210 return(val->stringval);
3211 case XPATH_BOOLEAN:
3212 ret = xmlXPathCastBooleanToString(val->boolval);
3213 break;
3214 case XPATH_NUMBER: {
3215 ret = xmlXPathCastNumberToString(val->floatval);
3216 break;
3217 }
3218 case XPATH_USERS:
3219 case XPATH_POINT:
3220 case XPATH_RANGE:
3221 case XPATH_LOCATIONSET:
3222 TODO
3223 ret = xmlStrdup((const xmlChar *) "");
3224 break;
3225 }
3226 return(ret);
3227}
3228
3229/**
3230 * xmlXPathConvertString:
3231 * @val: an XPath object
3232 *
3233 * Converts an existing object to its string() equivalent
3234 *
3235 * Returns the new object, the old one is freed (or the operation
3236 * is done directly on @val)
3237 */
3238xmlXPathObjectPtr
3239xmlXPathConvertString(xmlXPathObjectPtr val) {
3240 xmlChar *res = NULL;
3241
3242 if (val == NULL)
3243 return(xmlXPathNewCString(""));
3244
3245 switch (val->type) {
3246 case XPATH_UNDEFINED:
3247#ifdef DEBUG_EXPR
3248 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3249#endif
3250 break;
3251 case XPATH_XSLT_TREE:
3252 case XPATH_NODESET:
3253 res = xmlXPathCastNodeSetToString(val->nodesetval);
3254 break;
3255 case XPATH_STRING:
3256 return(val);
3257 case XPATH_BOOLEAN:
3258 res = xmlXPathCastBooleanToString(val->boolval);
3259 break;
3260 case XPATH_NUMBER:
3261 res = xmlXPathCastNumberToString(val->floatval);
3262 break;
3263 case XPATH_USERS:
3264 case XPATH_POINT:
3265 case XPATH_RANGE:
3266 case XPATH_LOCATIONSET:
3267 TODO;
3268 break;
3269 }
3270 xmlXPathFreeObject(val);
3271 if (res == NULL)
3272 return(xmlXPathNewCString(""));
3273 return(xmlXPathWrapString(res));
3274}
3275
3276/**
3277 * xmlXPathCastBooleanToNumber:
3278 * @val: a boolean
3279 *
3280 * Converts a boolean to its number value
3281 *
3282 * Returns the number value
3283 */
3284double
3285xmlXPathCastBooleanToNumber(int val) {
3286 if (val)
3287 return(1.0);
3288 return(0.0);
3289}
3290
3291/**
3292 * xmlXPathCastStringToNumber:
3293 * @val: a string
3294 *
3295 * Converts a string to its number value
3296 *
3297 * Returns the number value
3298 */
3299double
3300xmlXPathCastStringToNumber(const xmlChar * val) {
3301 return(xmlXPathStringEvalNumber(val));
3302}
3303
3304/**
3305 * xmlXPathCastNodeToNumber:
3306 * @node: a node
3307 *
3308 * Converts a node to its number value
3309 *
3310 * Returns the number value
3311 */
3312double
3313xmlXPathCastNodeToNumber (xmlNodePtr node) {
3314 xmlChar *strval;
3315 double ret;
3316
3317 if (node == NULL)
3318 return(xmlXPathNAN);
3319 strval = xmlXPathCastNodeToString(node);
3320 if (strval == NULL)
3321 return(xmlXPathNAN);
3322 ret = xmlXPathCastStringToNumber(strval);
3323 xmlFree(strval);
3324
3325 return(ret);
3326}
3327
3328/**
3329 * xmlXPathCastNodeSetToNumber:
3330 * @ns: a node-set
3331 *
3332 * Converts a node-set to its number value
3333 *
3334 * Returns the number value
3335 */
3336double
3337xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3338 xmlChar *str;
3339 double ret;
3340
3341 if (ns == NULL)
3342 return(xmlXPathNAN);
3343 str = xmlXPathCastNodeSetToString(ns);
3344 ret = xmlXPathCastStringToNumber(str);
3345 xmlFree(str);
3346 return(ret);
3347}
3348
3349/**
3350 * xmlXPathCastToNumber:
3351 * @val: an XPath object
3352 *
3353 * Converts an XPath object to its number value
3354 *
3355 * Returns the number value
3356 */
3357double
3358xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3359 double ret = 0.0;
3360
3361 if (val == NULL)
3362 return(xmlXPathNAN);
3363 switch (val->type) {
3364 case XPATH_UNDEFINED:
3365#ifdef DEGUB_EXPR
3366 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3367#endif
3368 ret = xmlXPathNAN;
3369 break;
3370 case XPATH_XSLT_TREE:
3371 case XPATH_NODESET:
3372 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3373 break;
3374 case XPATH_STRING:
3375 ret = xmlXPathCastStringToNumber(val->stringval);
3376 break;
3377 case XPATH_NUMBER:
3378 ret = val->floatval;
3379 break;
3380 case XPATH_BOOLEAN:
3381 ret = xmlXPathCastBooleanToNumber(val->boolval);
3382 break;
3383 case XPATH_USERS:
3384 case XPATH_POINT:
3385 case XPATH_RANGE:
3386 case XPATH_LOCATIONSET:
3387 TODO;
3388 ret = xmlXPathNAN;
3389 break;
3390 }
3391 return(ret);
3392}
3393
3394/**
3395 * xmlXPathConvertNumber:
3396 * @val: an XPath object
3397 *
3398 * Converts an existing object to its number() equivalent
3399 *
3400 * Returns the new object, the old one is freed (or the operation
3401 * is done directly on @val)
3402 */
3403xmlXPathObjectPtr
3404xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3405 xmlXPathObjectPtr ret;
3406
3407 if (val == NULL)
3408 return(xmlXPathNewFloat(0.0));
3409 if (val->type == XPATH_NUMBER)
3410 return(val);
3411 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3412 xmlXPathFreeObject(val);
3413 return(ret);
3414}
3415
3416/**
3417 * xmlXPathCastNumberToBoolean:
3418 * @val: a number
3419 *
3420 * Converts a number to its boolean value
3421 *
3422 * Returns the boolean value
3423 */
3424int
3425xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003426 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003427 return(0);
3428 return(1);
3429}
3430
3431/**
3432 * xmlXPathCastStringToBoolean:
3433 * @val: a string
3434 *
3435 * Converts a string to its boolean value
3436 *
3437 * Returns the boolean value
3438 */
3439int
3440xmlXPathCastStringToBoolean (const xmlChar *val) {
3441 if ((val == NULL) || (xmlStrlen(val) == 0))
3442 return(0);
3443 return(1);
3444}
3445
3446/**
3447 * xmlXPathCastNodeSetToBoolean:
3448 * @ns: a node-set
3449 *
3450 * Converts a node-set to its boolean value
3451 *
3452 * Returns the boolean value
3453 */
3454int
3455xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3456 if ((ns == NULL) || (ns->nodeNr == 0))
3457 return(0);
3458 return(1);
3459}
3460
3461/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003462 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003463 * @val: an XPath object
3464 *
3465 * Converts an XPath object to its boolean value
3466 *
3467 * Returns the boolean value
3468 */
3469int
3470xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3471 int ret = 0;
3472
3473 if (val == NULL)
3474 return(0);
3475 switch (val->type) {
3476 case XPATH_UNDEFINED:
3477#ifdef DEBUG_EXPR
3478 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3479#endif
3480 ret = 0;
3481 break;
3482 case XPATH_XSLT_TREE:
3483 case XPATH_NODESET:
3484 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3485 break;
3486 case XPATH_STRING:
3487 ret = xmlXPathCastStringToBoolean(val->stringval);
3488 break;
3489 case XPATH_NUMBER:
3490 ret = xmlXPathCastNumberToBoolean(val->floatval);
3491 break;
3492 case XPATH_BOOLEAN:
3493 ret = val->boolval;
3494 break;
3495 case XPATH_USERS:
3496 case XPATH_POINT:
3497 case XPATH_RANGE:
3498 case XPATH_LOCATIONSET:
3499 TODO;
3500 ret = 0;
3501 break;
3502 }
3503 return(ret);
3504}
3505
3506
3507/**
3508 * xmlXPathConvertBoolean:
3509 * @val: an XPath object
3510 *
3511 * Converts an existing object to its boolean() equivalent
3512 *
3513 * Returns the new object, the old one is freed (or the operation
3514 * is done directly on @val)
3515 */
3516xmlXPathObjectPtr
3517xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3518 xmlXPathObjectPtr ret;
3519
3520 if (val == NULL)
3521 return(xmlXPathNewBoolean(0));
3522 if (val->type == XPATH_BOOLEAN)
3523 return(val);
3524 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3525 xmlXPathFreeObject(val);
3526 return(ret);
3527}
3528
Owen Taylor3473f882001-02-23 17:55:21 +00003529/************************************************************************
3530 * *
3531 * Routines to handle XPath contexts *
3532 * *
3533 ************************************************************************/
3534
3535/**
3536 * xmlXPathNewContext:
3537 * @doc: the XML document
3538 *
3539 * Create a new xmlXPathContext
3540 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003541 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003542 */
3543xmlXPathContextPtr
3544xmlXPathNewContext(xmlDocPtr doc) {
3545 xmlXPathContextPtr ret;
3546
3547 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3548 if (ret == NULL) {
3549 xmlGenericError(xmlGenericErrorContext,
3550 "xmlXPathNewContext: out of memory\n");
3551 return(NULL);
3552 }
3553 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3554 ret->doc = doc;
3555 ret->node = NULL;
3556
3557 ret->varHash = NULL;
3558
3559 ret->nb_types = 0;
3560 ret->max_types = 0;
3561 ret->types = NULL;
3562
3563 ret->funcHash = xmlHashCreate(0);
3564
3565 ret->nb_axis = 0;
3566 ret->max_axis = 0;
3567 ret->axis = NULL;
3568
3569 ret->nsHash = NULL;
3570 ret->user = NULL;
3571
3572 ret->contextSize = -1;
3573 ret->proximityPosition = -1;
3574
3575 xmlXPathRegisterAllFunctions(ret);
3576
3577 return(ret);
3578}
3579
3580/**
3581 * xmlXPathFreeContext:
3582 * @ctxt: the context to free
3583 *
3584 * Free up an xmlXPathContext
3585 */
3586void
3587xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3588 xmlXPathRegisteredNsCleanup(ctxt);
3589 xmlXPathRegisteredFuncsCleanup(ctxt);
3590 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003591 xmlFree(ctxt);
3592}
3593
3594/************************************************************************
3595 * *
3596 * Routines to handle XPath parser contexts *
3597 * *
3598 ************************************************************************/
3599
3600#define CHECK_CTXT(ctxt) \
3601 if (ctxt == NULL) { \
3602 xmlGenericError(xmlGenericErrorContext, \
3603 "%s:%d Internal error: ctxt == NULL\n", \
3604 __FILE__, __LINE__); \
3605 } \
3606
3607
3608#define CHECK_CONTEXT(ctxt) \
3609 if (ctxt == NULL) { \
3610 xmlGenericError(xmlGenericErrorContext, \
3611 "%s:%d Internal error: no context\n", \
3612 __FILE__, __LINE__); \
3613 } \
3614 else if (ctxt->doc == NULL) { \
3615 xmlGenericError(xmlGenericErrorContext, \
3616 "%s:%d Internal error: no document\n", \
3617 __FILE__, __LINE__); \
3618 } \
3619 else if (ctxt->doc->children == NULL) { \
3620 xmlGenericError(xmlGenericErrorContext, \
3621 "%s:%d Internal error: document without root\n", \
3622 __FILE__, __LINE__); \
3623 } \
3624
3625
3626/**
3627 * xmlXPathNewParserContext:
3628 * @str: the XPath expression
3629 * @ctxt: the XPath context
3630 *
3631 * Create a new xmlXPathParserContext
3632 *
3633 * Returns the xmlXPathParserContext just allocated.
3634 */
3635xmlXPathParserContextPtr
3636xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3637 xmlXPathParserContextPtr ret;
3638
3639 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3640 if (ret == NULL) {
3641 xmlGenericError(xmlGenericErrorContext,
3642 "xmlXPathNewParserContext: out of memory\n");
3643 return(NULL);
3644 }
3645 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3646 ret->cur = ret->base = str;
3647 ret->context = ctxt;
3648
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003649 ret->comp = xmlXPathNewCompExpr();
3650 if (ret->comp == NULL) {
3651 xmlFree(ret->valueTab);
3652 xmlFree(ret);
3653 return(NULL);
3654 }
3655
3656 return(ret);
3657}
3658
3659/**
3660 * xmlXPathCompParserContext:
3661 * @comp: the XPath compiled expression
3662 * @ctxt: the XPath context
3663 *
3664 * Create a new xmlXPathParserContext when processing a compiled expression
3665 *
3666 * Returns the xmlXPathParserContext just allocated.
3667 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003668static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003669xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3670 xmlXPathParserContextPtr ret;
3671
3672 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3673 if (ret == NULL) {
3674 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003675 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003676 return(NULL);
3677 }
3678 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3679
Owen Taylor3473f882001-02-23 17:55:21 +00003680 /* Allocate the value stack */
3681 ret->valueTab = (xmlXPathObjectPtr *)
3682 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003683 if (ret->valueTab == NULL) {
3684 xmlFree(ret);
3685 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003686 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003687 return(NULL);
3688 }
Owen Taylor3473f882001-02-23 17:55:21 +00003689 ret->valueNr = 0;
3690 ret->valueMax = 10;
3691 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003692
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003693 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003694 ret->comp = comp;
3695
Owen Taylor3473f882001-02-23 17:55:21 +00003696 return(ret);
3697}
3698
3699/**
3700 * xmlXPathFreeParserContext:
3701 * @ctxt: the context to free
3702 *
3703 * Free up an xmlXPathParserContext
3704 */
3705void
3706xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3707 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003708 xmlFree(ctxt->valueTab);
3709 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003710 if (ctxt->comp)
3711 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003712 xmlFree(ctxt);
3713}
3714
3715/************************************************************************
3716 * *
3717 * The implicit core function library *
3718 * *
3719 ************************************************************************/
3720
Owen Taylor3473f882001-02-23 17:55:21 +00003721/**
Daniel Veillardf06307e2001-07-03 10:35:50 +00003722 * xmlXPathNodeStringHash:
3723 * @node: a node pointer
3724 *
3725 * Function computing the beginning of the string value of the node,
3726 * used to speed up comparisons
3727 *
3728 * Returns an int usable as a hash
3729 */
3730static unsigned int
3731xmlXPathNodeValHash(xmlNodePtr node) {
3732 int len = 2;
3733 const xmlChar * string = NULL;
3734 xmlNodePtr tmp = NULL;
3735 unsigned int ret = 0;
3736
3737 if (node == NULL)
3738 return(0);
3739
3740
3741 switch (node->type) {
3742 case XML_COMMENT_NODE:
3743 case XML_PI_NODE:
3744 case XML_CDATA_SECTION_NODE:
3745 case XML_TEXT_NODE:
3746 string = node->content;
3747 if (string == NULL)
3748 return(0);
3749 if (string[0] == 0)
3750 return(0);
3751 return(((unsigned int) string[0]) +
3752 (((unsigned int) string[1]) << 8));
3753 case XML_NAMESPACE_DECL:
3754 string = ((xmlNsPtr)node)->href;
3755 if (string == NULL)
3756 return(0);
3757 if (string[0] == 0)
3758 return(0);
3759 return(((unsigned int) string[0]) +
3760 (((unsigned int) string[1]) << 8));
3761 case XML_ATTRIBUTE_NODE:
3762 tmp = ((xmlAttrPtr) node)->children;
3763 break;
3764 case XML_ELEMENT_NODE:
3765 tmp = node->children;
3766 break;
3767 default:
3768 return(0);
3769 }
3770 while (tmp != NULL) {
3771 switch (tmp->type) {
3772 case XML_COMMENT_NODE:
3773 case XML_PI_NODE:
3774 case XML_CDATA_SECTION_NODE:
3775 case XML_TEXT_NODE:
3776 string = tmp->content;
3777 break;
3778 case XML_NAMESPACE_DECL:
3779 string = ((xmlNsPtr)tmp)->href;
3780 break;
3781 default:
3782 break;
3783 }
3784 if ((string != NULL) && (string[0] != 0)) {
3785 if (string[0] == 0)
3786 return(0);
3787 if (len == 1) {
3788 return(ret + (((unsigned int) string[0]) << 8));
3789 }
3790 if (string[1] == 0) {
3791 len = 1;
3792 ret = (unsigned int) string[0];
3793 } else {
3794 return(((unsigned int) string[0]) +
3795 (((unsigned int) string[1]) << 8));
3796 }
3797 }
3798 /*
3799 * Skip to next node
3800 */
3801 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
3802 if (tmp->children->type != XML_ENTITY_DECL) {
3803 tmp = tmp->children;
3804 continue;
3805 }
3806 }
3807 if (tmp == node)
3808 break;
3809
3810 if (tmp->next != NULL) {
3811 tmp = tmp->next;
3812 continue;
3813 }
3814
3815 do {
3816 tmp = tmp->parent;
3817 if (tmp == NULL)
3818 break;
3819 if (tmp == node) {
3820 tmp = NULL;
3821 break;
3822 }
3823 if (tmp->next != NULL) {
3824 tmp = tmp->next;
3825 break;
3826 }
3827 } while (tmp != NULL);
3828 }
3829 return(ret);
3830}
3831
3832/**
3833 * xmlXPathStringHash:
3834 * @string: a string
3835 *
3836 * Function computing the beginning of the string value of the node,
3837 * used to speed up comparisons
3838 *
3839 * Returns an int usable as a hash
3840 */
3841static unsigned int
3842xmlXPathStringHash(const xmlChar * string) {
3843 if (string == NULL)
3844 return((unsigned int) 0);
3845 if (string[0] == 0)
3846 return(0);
3847 return(((unsigned int) string[0]) +
3848 (((unsigned int) string[1]) << 8));
3849}
3850
3851/**
Owen Taylor3473f882001-02-23 17:55:21 +00003852 * xmlXPathCompareNodeSetFloat:
3853 * @ctxt: the XPath Parser context
3854 * @inf: less than (1) or greater than (0)
3855 * @strict: is the comparison strict
3856 * @arg: the node set
3857 * @f: the value
3858 *
3859 * Implement the compare operation between a nodeset and a number
3860 * @ns < @val (1, 1, ...
3861 * @ns <= @val (1, 0, ...
3862 * @ns > @val (0, 1, ...
3863 * @ns >= @val (0, 0, ...
3864 *
3865 * If one object to be compared is a node-set and the other is a number,
3866 * then the comparison will be true if and only if there is a node in the
3867 * node-set such that the result of performing the comparison on the number
3868 * to be compared and on the result of converting the string-value of that
3869 * node to a number using the number function is true.
3870 *
3871 * Returns 0 or 1 depending on the results of the test.
3872 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003873static int
Owen Taylor3473f882001-02-23 17:55:21 +00003874xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
3875 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
3876 int i, ret = 0;
3877 xmlNodeSetPtr ns;
3878 xmlChar *str2;
3879
3880 if ((f == NULL) || (arg == NULL) ||
3881 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3882 xmlXPathFreeObject(arg);
3883 xmlXPathFreeObject(f);
3884 return(0);
3885 }
3886 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003887 if (ns != NULL) {
3888 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003889 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003890 if (str2 != NULL) {
3891 valuePush(ctxt,
3892 xmlXPathNewString(str2));
3893 xmlFree(str2);
3894 xmlXPathNumberFunction(ctxt, 1);
3895 valuePush(ctxt, xmlXPathObjectCopy(f));
3896 ret = xmlXPathCompareValues(ctxt, inf, strict);
3897 if (ret)
3898 break;
3899 }
3900 }
Owen Taylor3473f882001-02-23 17:55:21 +00003901 }
3902 xmlXPathFreeObject(arg);
3903 xmlXPathFreeObject(f);
3904 return(ret);
3905}
3906
3907/**
3908 * xmlXPathCompareNodeSetString:
3909 * @ctxt: the XPath Parser context
3910 * @inf: less than (1) or greater than (0)
3911 * @strict: is the comparison strict
3912 * @arg: the node set
3913 * @s: the value
3914 *
3915 * Implement the compare operation between a nodeset and a string
3916 * @ns < @val (1, 1, ...
3917 * @ns <= @val (1, 0, ...
3918 * @ns > @val (0, 1, ...
3919 * @ns >= @val (0, 0, ...
3920 *
3921 * If one object to be compared is a node-set and the other is a string,
3922 * then the comparison will be true if and only if there is a node in
3923 * the node-set such that the result of performing the comparison on the
3924 * string-value of the node and the other string is true.
3925 *
3926 * Returns 0 or 1 depending on the results of the test.
3927 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003928static int
Owen Taylor3473f882001-02-23 17:55:21 +00003929xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
3930 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
3931 int i, ret = 0;
3932 xmlNodeSetPtr ns;
3933 xmlChar *str2;
3934
3935 if ((s == NULL) || (arg == NULL) ||
3936 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3937 xmlXPathFreeObject(arg);
3938 xmlXPathFreeObject(s);
3939 return(0);
3940 }
3941 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003942 if (ns != NULL) {
3943 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003944 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003945 if (str2 != NULL) {
3946 valuePush(ctxt,
3947 xmlXPathNewString(str2));
3948 xmlFree(str2);
3949 valuePush(ctxt, xmlXPathObjectCopy(s));
3950 ret = xmlXPathCompareValues(ctxt, inf, strict);
3951 if (ret)
3952 break;
3953 }
3954 }
Owen Taylor3473f882001-02-23 17:55:21 +00003955 }
3956 xmlXPathFreeObject(arg);
3957 xmlXPathFreeObject(s);
3958 return(ret);
3959}
3960
3961/**
3962 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003963 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00003964 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003965 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00003966 * @arg2: the second node set object
3967 *
3968 * Implement the compare operation on nodesets:
3969 *
3970 * If both objects to be compared are node-sets, then the comparison
3971 * will be true if and only if there is a node in the first node-set
3972 * and a node in the second node-set such that the result of performing
3973 * the comparison on the string-values of the two nodes is true.
3974 * ....
3975 * When neither object to be compared is a node-set and the operator
3976 * is <=, <, >= or >, then the objects are compared by converting both
3977 * objects to numbers and comparing the numbers according to IEEE 754.
3978 * ....
3979 * The number function converts its argument to a number as follows:
3980 * - a string that consists of optional whitespace followed by an
3981 * optional minus sign followed by a Number followed by whitespace
3982 * is converted to the IEEE 754 number that is nearest (according
3983 * to the IEEE 754 round-to-nearest rule) to the mathematical value
3984 * represented by the string; any other string is converted to NaN
3985 *
3986 * Conclusion all nodes need to be converted first to their string value
3987 * and then the comparison must be done when possible
3988 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003989static int
3990xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00003991 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3992 int i, j, init = 0;
3993 double val1;
3994 double *values2;
3995 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003996 xmlNodeSetPtr ns1;
3997 xmlNodeSetPtr ns2;
3998
3999 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004000 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4001 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004002 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004003 }
Owen Taylor3473f882001-02-23 17:55:21 +00004004 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004005 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4006 xmlXPathFreeObject(arg1);
4007 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004008 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004009 }
Owen Taylor3473f882001-02-23 17:55:21 +00004010
4011 ns1 = arg1->nodesetval;
4012 ns2 = arg2->nodesetval;
4013
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004014 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004015 xmlXPathFreeObject(arg1);
4016 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004017 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004018 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004019 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004020 xmlXPathFreeObject(arg1);
4021 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004022 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004023 }
Owen Taylor3473f882001-02-23 17:55:21 +00004024
4025 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4026 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004027 xmlXPathFreeObject(arg1);
4028 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004029 return(0);
4030 }
4031 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004032 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004033 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004034 continue;
4035 for (j = 0;j < ns2->nodeNr;j++) {
4036 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004037 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004038 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004039 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004040 continue;
4041 if (inf && strict)
4042 ret = (val1 < values2[j]);
4043 else if (inf && !strict)
4044 ret = (val1 <= values2[j]);
4045 else if (!inf && strict)
4046 ret = (val1 > values2[j]);
4047 else if (!inf && !strict)
4048 ret = (val1 >= values2[j]);
4049 if (ret)
4050 break;
4051 }
4052 if (ret)
4053 break;
4054 init = 1;
4055 }
4056 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004057 xmlXPathFreeObject(arg1);
4058 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004059 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004060}
4061
4062/**
4063 * xmlXPathCompareNodeSetValue:
4064 * @ctxt: the XPath Parser context
4065 * @inf: less than (1) or greater than (0)
4066 * @strict: is the comparison strict
4067 * @arg: the node set
4068 * @val: the value
4069 *
4070 * Implement the compare operation between a nodeset and a value
4071 * @ns < @val (1, 1, ...
4072 * @ns <= @val (1, 0, ...
4073 * @ns > @val (0, 1, ...
4074 * @ns >= @val (0, 0, ...
4075 *
4076 * If one object to be compared is a node-set and the other is a boolean,
4077 * then the comparison will be true if and only if the result of performing
4078 * the comparison on the boolean and on the result of converting
4079 * the node-set to a boolean using the boolean function is true.
4080 *
4081 * Returns 0 or 1 depending on the results of the test.
4082 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004083static int
Owen Taylor3473f882001-02-23 17:55:21 +00004084xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4085 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4086 if ((val == NULL) || (arg == NULL) ||
4087 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4088 return(0);
4089
4090 switch(val->type) {
4091 case XPATH_NUMBER:
4092 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4093 case XPATH_NODESET:
4094 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004095 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004096 case XPATH_STRING:
4097 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4098 case XPATH_BOOLEAN:
4099 valuePush(ctxt, arg);
4100 xmlXPathBooleanFunction(ctxt, 1);
4101 valuePush(ctxt, val);
4102 return(xmlXPathCompareValues(ctxt, inf, strict));
4103 default:
4104 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004105 }
4106 return(0);
4107}
4108
4109/**
4110 * xmlXPathEqualNodeSetString
4111 * @arg: the nodeset object argument
4112 * @str: the string to compare to.
4113 *
4114 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4115 * If one object to be compared is a node-set and the other is a string,
4116 * then the comparison will be true if and only if there is a node in
4117 * the node-set such that the result of performing the comparison on the
4118 * string-value of the node and the other string is true.
4119 *
4120 * Returns 0 or 1 depending on the results of the test.
4121 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004122static int
Daniel Veillardf06307e2001-07-03 10:35:50 +00004123xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str)
4124{
Owen Taylor3473f882001-02-23 17:55:21 +00004125 int i;
4126 xmlNodeSetPtr ns;
4127 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004128 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004129
4130 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004131 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4132 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004133 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004134 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004135 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004136 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004137 if (ns->nodeNr <= 0) {
4138 if (hash == 0)
4139 return(1);
4140 return(0);
4141 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004142 for (i = 0; i < ns->nodeNr; i++) {
4143 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4144 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4145 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4146 xmlFree(str2);
4147 return (1);
4148 }
4149 if (str2 != NULL)
4150 xmlFree(str2);
4151 }
Owen Taylor3473f882001-02-23 17:55:21 +00004152 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004153 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004154}
4155
4156/**
4157 * xmlXPathEqualNodeSetFloat
4158 * @arg: the nodeset object argument
4159 * @f: the float to compare to
4160 *
4161 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4162 * If one object to be compared is a node-set and the other is a number,
4163 * then the comparison will be true if and only if there is a node in
4164 * the node-set such that the result of performing the comparison on the
4165 * number to be compared and on the result of converting the string-value
4166 * of that node to a number using the number function is true.
4167 *
4168 * Returns 0 or 1 depending on the results of the test.
4169 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004170static int
Owen Taylor3473f882001-02-23 17:55:21 +00004171xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) {
4172 char buf[100] = "";
4173
4174 if ((arg == NULL) ||
4175 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4176 return(0);
4177
Bjorn Reesee1dc0112001-03-03 12:09:03 +00004178 xmlXPathFormatNumber(f, buf, sizeof(buf));
Owen Taylor3473f882001-02-23 17:55:21 +00004179 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
4180}
4181
4182
4183/**
4184 * xmlXPathEqualNodeSets
4185 * @arg1: first nodeset object argument
4186 * @arg2: second nodeset object argument
4187 *
4188 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
4189 * If both objects to be compared are node-sets, then the comparison
4190 * will be true if and only if there is a node in the first node-set and
4191 * a node in the second node-set such that the result of performing the
4192 * comparison on the string-values of the two nodes is true.
4193 *
4194 * (needless to say, this is a costly operation)
4195 *
4196 * Returns 0 or 1 depending on the results of the test.
4197 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004198static int
Owen Taylor3473f882001-02-23 17:55:21 +00004199xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4200 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004201 unsigned int *hashs1;
4202 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004203 xmlChar **values1;
4204 xmlChar **values2;
4205 int ret = 0;
4206 xmlNodeSetPtr ns1;
4207 xmlNodeSetPtr ns2;
4208
4209 if ((arg1 == NULL) ||
4210 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4211 return(0);
4212 if ((arg2 == NULL) ||
4213 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4214 return(0);
4215
4216 ns1 = arg1->nodesetval;
4217 ns2 = arg2->nodesetval;
4218
Daniel Veillard911f49a2001-04-07 15:39:35 +00004219 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004220 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004221 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004222 return(0);
4223
4224 /*
4225 * check if there is a node pertaining to both sets
4226 */
4227 for (i = 0;i < ns1->nodeNr;i++)
4228 for (j = 0;j < ns2->nodeNr;j++)
4229 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4230 return(1);
4231
4232 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
4233 if (values1 == NULL)
4234 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004235 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4236 if (hashs1 == NULL) {
4237 xmlFree(values1);
4238 return(0);
4239 }
Owen Taylor3473f882001-02-23 17:55:21 +00004240 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4241 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4242 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004243 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004244 xmlFree(values1);
4245 return(0);
4246 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004247 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4248 if (hashs2 == NULL) {
4249 xmlFree(hashs1);
4250 xmlFree(values1);
4251 xmlFree(values2);
4252 return(0);
4253 }
Owen Taylor3473f882001-02-23 17:55:21 +00004254 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4255 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004256 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004257 for (j = 0;j < ns2->nodeNr;j++) {
4258 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004259 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
4260 if (hashs1[i] == hashs2[j]) {
4261 if (values1[i] == NULL)
4262 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4263 if (values2[j] == NULL)
4264 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
4265 ret = xmlStrEqual(values1[i], values2[j]);
4266 if (ret)
4267 break;
4268 }
Owen Taylor3473f882001-02-23 17:55:21 +00004269 }
4270 if (ret)
4271 break;
4272 }
4273 for (i = 0;i < ns1->nodeNr;i++)
4274 if (values1[i] != NULL)
4275 xmlFree(values1[i]);
4276 for (j = 0;j < ns2->nodeNr;j++)
4277 if (values2[j] != NULL)
4278 xmlFree(values2[j]);
4279 xmlFree(values1);
4280 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004281 xmlFree(hashs1);
4282 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004283 return(ret);
4284}
4285
4286/**
4287 * xmlXPathEqualValues:
4288 * @ctxt: the XPath Parser context
4289 *
4290 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4291 *
4292 * Returns 0 or 1 depending on the results of the test.
4293 */
4294int
4295xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4296 xmlXPathObjectPtr arg1, arg2;
4297 int ret = 0;
4298
4299 arg1 = valuePop(ctxt);
4300 if (arg1 == NULL)
4301 XP_ERROR0(XPATH_INVALID_OPERAND);
4302
4303 arg2 = valuePop(ctxt);
4304 if (arg2 == NULL) {
4305 xmlXPathFreeObject(arg1);
4306 XP_ERROR0(XPATH_INVALID_OPERAND);
4307 }
4308
4309 if (arg1 == arg2) {
4310#ifdef DEBUG_EXPR
4311 xmlGenericError(xmlGenericErrorContext,
4312 "Equal: by pointer\n");
4313#endif
4314 return(1);
4315 }
4316
4317 switch (arg1->type) {
4318 case XPATH_UNDEFINED:
4319#ifdef DEBUG_EXPR
4320 xmlGenericError(xmlGenericErrorContext,
4321 "Equal: undefined\n");
4322#endif
4323 break;
4324 case XPATH_XSLT_TREE:
4325 case XPATH_NODESET:
4326 switch (arg2->type) {
4327 case XPATH_UNDEFINED:
4328#ifdef DEBUG_EXPR
4329 xmlGenericError(xmlGenericErrorContext,
4330 "Equal: undefined\n");
4331#endif
4332 break;
4333 case XPATH_XSLT_TREE:
4334 case XPATH_NODESET:
4335 ret = xmlXPathEqualNodeSets(arg1, arg2);
4336 break;
4337 case XPATH_BOOLEAN:
4338 if ((arg1->nodesetval == NULL) ||
4339 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4340 else
4341 ret = 1;
4342 ret = (ret == arg2->boolval);
4343 break;
4344 case XPATH_NUMBER:
4345 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
4346 break;
4347 case XPATH_STRING:
4348 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
4349 break;
4350 case XPATH_USERS:
4351 case XPATH_POINT:
4352 case XPATH_RANGE:
4353 case XPATH_LOCATIONSET:
4354 TODO
4355 break;
4356 }
4357 break;
4358 case XPATH_BOOLEAN:
4359 switch (arg2->type) {
4360 case XPATH_UNDEFINED:
4361#ifdef DEBUG_EXPR
4362 xmlGenericError(xmlGenericErrorContext,
4363 "Equal: undefined\n");
4364#endif
4365 break;
4366 case XPATH_NODESET:
4367 case XPATH_XSLT_TREE:
4368 if ((arg2->nodesetval == NULL) ||
4369 (arg2->nodesetval->nodeNr == 0)) ret = 0;
4370 else
4371 ret = 1;
4372 break;
4373 case XPATH_BOOLEAN:
4374#ifdef DEBUG_EXPR
4375 xmlGenericError(xmlGenericErrorContext,
4376 "Equal: %d boolean %d \n",
4377 arg1->boolval, arg2->boolval);
4378#endif
4379 ret = (arg1->boolval == arg2->boolval);
4380 break;
4381 case XPATH_NUMBER:
4382 if (arg2->floatval) ret = 1;
4383 else ret = 0;
4384 ret = (arg1->boolval == ret);
4385 break;
4386 case XPATH_STRING:
4387 if ((arg2->stringval == NULL) ||
4388 (arg2->stringval[0] == 0)) ret = 0;
4389 else
4390 ret = 1;
4391 ret = (arg1->boolval == ret);
4392 break;
4393 case XPATH_USERS:
4394 case XPATH_POINT:
4395 case XPATH_RANGE:
4396 case XPATH_LOCATIONSET:
4397 TODO
4398 break;
4399 }
4400 break;
4401 case XPATH_NUMBER:
4402 switch (arg2->type) {
4403 case XPATH_UNDEFINED:
4404#ifdef DEBUG_EXPR
4405 xmlGenericError(xmlGenericErrorContext,
4406 "Equal: undefined\n");
4407#endif
4408 break;
4409 case XPATH_NODESET:
4410 case XPATH_XSLT_TREE:
4411 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
4412 break;
4413 case XPATH_BOOLEAN:
4414 if (arg1->floatval) ret = 1;
4415 else ret = 0;
4416 ret = (arg2->boolval == ret);
4417 break;
4418 case XPATH_STRING:
4419 valuePush(ctxt, arg2);
4420 xmlXPathNumberFunction(ctxt, 1);
4421 arg2 = valuePop(ctxt);
4422 /* no break on purpose */
4423 case XPATH_NUMBER:
4424 ret = (arg1->floatval == arg2->floatval);
4425 break;
4426 case XPATH_USERS:
4427 case XPATH_POINT:
4428 case XPATH_RANGE:
4429 case XPATH_LOCATIONSET:
4430 TODO
4431 break;
4432 }
4433 break;
4434 case XPATH_STRING:
4435 switch (arg2->type) {
4436 case XPATH_UNDEFINED:
4437#ifdef DEBUG_EXPR
4438 xmlGenericError(xmlGenericErrorContext,
4439 "Equal: undefined\n");
4440#endif
4441 break;
4442 case XPATH_NODESET:
4443 case XPATH_XSLT_TREE:
4444 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
4445 break;
4446 case XPATH_BOOLEAN:
4447 if ((arg1->stringval == NULL) ||
4448 (arg1->stringval[0] == 0)) ret = 0;
4449 else
4450 ret = 1;
4451 ret = (arg2->boolval == ret);
4452 break;
4453 case XPATH_STRING:
4454 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4455 break;
4456 case XPATH_NUMBER:
4457 valuePush(ctxt, arg1);
4458 xmlXPathNumberFunction(ctxt, 1);
4459 arg1 = valuePop(ctxt);
4460 ret = (arg1->floatval == arg2->floatval);
4461 break;
4462 case XPATH_USERS:
4463 case XPATH_POINT:
4464 case XPATH_RANGE:
4465 case XPATH_LOCATIONSET:
4466 TODO
4467 break;
4468 }
4469 break;
4470 case XPATH_USERS:
4471 case XPATH_POINT:
4472 case XPATH_RANGE:
4473 case XPATH_LOCATIONSET:
4474 TODO
4475 break;
4476 }
4477 xmlXPathFreeObject(arg1);
4478 xmlXPathFreeObject(arg2);
4479 return(ret);
4480}
4481
4482
4483/**
4484 * xmlXPathCompareValues:
4485 * @ctxt: the XPath Parser context
4486 * @inf: less than (1) or greater than (0)
4487 * @strict: is the comparison strict
4488 *
4489 * Implement the compare operation on XPath objects:
4490 * @arg1 < @arg2 (1, 1, ...
4491 * @arg1 <= @arg2 (1, 0, ...
4492 * @arg1 > @arg2 (0, 1, ...
4493 * @arg1 >= @arg2 (0, 0, ...
4494 *
4495 * When neither object to be compared is a node-set and the operator is
4496 * <=, <, >=, >, then the objects are compared by converted both objects
4497 * to numbers and comparing the numbers according to IEEE 754. The <
4498 * comparison will be true if and only if the first number is less than the
4499 * second number. The <= comparison will be true if and only if the first
4500 * number is less than or equal to the second number. The > comparison
4501 * will be true if and only if the first number is greater than the second
4502 * number. The >= comparison will be true if and only if the first number
4503 * is greater than or equal to the second number.
4504 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004505 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00004506 */
4507int
4508xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
4509 int ret = 0;
4510 xmlXPathObjectPtr arg1, arg2;
4511
4512 arg2 = valuePop(ctxt);
4513 if (arg2 == NULL) {
4514 XP_ERROR0(XPATH_INVALID_OPERAND);
4515 }
4516
4517 arg1 = valuePop(ctxt);
4518 if (arg1 == NULL) {
4519 xmlXPathFreeObject(arg2);
4520 XP_ERROR0(XPATH_INVALID_OPERAND);
4521 }
4522
4523 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
4524 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004525 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004526 } else {
4527 if (arg1->type == XPATH_NODESET) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004528 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4529 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004530 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004531 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4532 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004533 }
4534 }
4535 return(ret);
4536 }
4537
4538 if (arg1->type != XPATH_NUMBER) {
4539 valuePush(ctxt, arg1);
4540 xmlXPathNumberFunction(ctxt, 1);
4541 arg1 = valuePop(ctxt);
4542 }
4543 if (arg1->type != XPATH_NUMBER) {
4544 xmlXPathFreeObject(arg1);
4545 xmlXPathFreeObject(arg2);
4546 XP_ERROR0(XPATH_INVALID_OPERAND);
4547 }
4548 if (arg2->type != XPATH_NUMBER) {
4549 valuePush(ctxt, arg2);
4550 xmlXPathNumberFunction(ctxt, 1);
4551 arg2 = valuePop(ctxt);
4552 }
4553 if (arg2->type != XPATH_NUMBER) {
4554 xmlXPathFreeObject(arg1);
4555 xmlXPathFreeObject(arg2);
4556 XP_ERROR0(XPATH_INVALID_OPERAND);
4557 }
4558 /*
4559 * Add tests for infinity and nan
4560 * => feedback on 3.4 for Inf and NaN
4561 */
4562 if (inf && strict)
4563 ret = (arg1->floatval < arg2->floatval);
4564 else if (inf && !strict)
4565 ret = (arg1->floatval <= arg2->floatval);
4566 else if (!inf && strict)
4567 ret = (arg1->floatval > arg2->floatval);
4568 else if (!inf && !strict)
4569 ret = (arg1->floatval >= arg2->floatval);
4570 xmlXPathFreeObject(arg1);
4571 xmlXPathFreeObject(arg2);
4572 return(ret);
4573}
4574
4575/**
4576 * xmlXPathValueFlipSign:
4577 * @ctxt: the XPath Parser context
4578 *
4579 * Implement the unary - operation on an XPath object
4580 * The numeric operators convert their operands to numbers as if
4581 * by calling the number function.
4582 */
4583void
4584xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004585 CAST_TO_NUMBER;
4586 CHECK_TYPE(XPATH_NUMBER);
4587 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00004588}
4589
4590/**
4591 * xmlXPathAddValues:
4592 * @ctxt: the XPath Parser context
4593 *
4594 * Implement the add operation on XPath objects:
4595 * The numeric operators convert their operands to numbers as if
4596 * by calling the number function.
4597 */
4598void
4599xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
4600 xmlXPathObjectPtr arg;
4601 double val;
4602
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004603 arg = valuePop(ctxt);
4604 if (arg == NULL)
4605 XP_ERROR(XPATH_INVALID_OPERAND);
4606 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004607 xmlXPathFreeObject(arg);
4608
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004609 CAST_TO_NUMBER;
4610 CHECK_TYPE(XPATH_NUMBER);
4611 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00004612}
4613
4614/**
4615 * xmlXPathSubValues:
4616 * @ctxt: the XPath Parser context
4617 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004618 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00004619 * The numeric operators convert their operands to numbers as if
4620 * by calling the number function.
4621 */
4622void
4623xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
4624 xmlXPathObjectPtr arg;
4625 double val;
4626
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004627 arg = valuePop(ctxt);
4628 if (arg == NULL)
4629 XP_ERROR(XPATH_INVALID_OPERAND);
4630 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004631 xmlXPathFreeObject(arg);
4632
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004633 CAST_TO_NUMBER;
4634 CHECK_TYPE(XPATH_NUMBER);
4635 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004636}
4637
4638/**
4639 * xmlXPathMultValues:
4640 * @ctxt: the XPath Parser context
4641 *
4642 * Implement the multiply operation on XPath objects:
4643 * The numeric operators convert their operands to numbers as if
4644 * by calling the number function.
4645 */
4646void
4647xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
4648 xmlXPathObjectPtr arg;
4649 double val;
4650
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004651 arg = valuePop(ctxt);
4652 if (arg == NULL)
4653 XP_ERROR(XPATH_INVALID_OPERAND);
4654 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004655 xmlXPathFreeObject(arg);
4656
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004657 CAST_TO_NUMBER;
4658 CHECK_TYPE(XPATH_NUMBER);
4659 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004660}
4661
4662/**
4663 * xmlXPathDivValues:
4664 * @ctxt: the XPath Parser context
4665 *
4666 * Implement the div operation on XPath objects @arg1 / @arg2:
4667 * The numeric operators convert their operands to numbers as if
4668 * by calling the number function.
4669 */
4670void
4671xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
4672 xmlXPathObjectPtr arg;
4673 double val;
4674
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004675 arg = valuePop(ctxt);
4676 if (arg == NULL)
4677 XP_ERROR(XPATH_INVALID_OPERAND);
4678 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004679 xmlXPathFreeObject(arg);
4680
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004681 CAST_TO_NUMBER;
4682 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5f4b5992002-02-20 10:22:49 +00004683 if (val == 0) {
4684 if (ctxt->value->floatval == 0)
4685 ctxt->value->floatval = xmlXPathNAN;
4686 else if (ctxt->value->floatval > 0)
4687 ctxt->value->floatval = xmlXPathPINF;
4688 else if (ctxt->value->floatval < 0)
4689 ctxt->value->floatval = xmlXPathNINF;
4690 } else
4691 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004692}
4693
4694/**
4695 * xmlXPathModValues:
4696 * @ctxt: the XPath Parser context
4697 *
4698 * Implement the mod operation on XPath objects: @arg1 / @arg2
4699 * The numeric operators convert their operands to numbers as if
4700 * by calling the number function.
4701 */
4702void
4703xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
4704 xmlXPathObjectPtr arg;
4705 int arg1, arg2;
4706
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004707 arg = valuePop(ctxt);
4708 if (arg == NULL)
4709 XP_ERROR(XPATH_INVALID_OPERAND);
4710 arg2 = (int) xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004711 xmlXPathFreeObject(arg);
4712
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004713 CAST_TO_NUMBER;
4714 CHECK_TYPE(XPATH_NUMBER);
4715 arg1 = (int) ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00004716 if (arg2 == 0)
4717 ctxt->value->floatval = xmlXPathNAN;
4718 else
4719 ctxt->value->floatval = arg1 % arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00004720}
4721
4722/************************************************************************
4723 * *
4724 * The traversal functions *
4725 * *
4726 ************************************************************************/
4727
Owen Taylor3473f882001-02-23 17:55:21 +00004728/*
4729 * A traversal function enumerates nodes along an axis.
4730 * Initially it must be called with NULL, and it indicates
4731 * termination on the axis by returning NULL.
4732 */
4733typedef xmlNodePtr (*xmlXPathTraversalFunction)
4734 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
4735
4736/**
4737 * xmlXPathNextSelf:
4738 * @ctxt: the XPath Parser context
4739 * @cur: the current node in the traversal
4740 *
4741 * Traversal function for the "self" direction
4742 * The self axis contains just the context node itself
4743 *
4744 * Returns the next element following that axis
4745 */
4746xmlNodePtr
4747xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4748 if (cur == NULL)
4749 return(ctxt->context->node);
4750 return(NULL);
4751}
4752
4753/**
4754 * xmlXPathNextChild:
4755 * @ctxt: the XPath Parser context
4756 * @cur: the current node in the traversal
4757 *
4758 * Traversal function for the "child" direction
4759 * The child axis contains the children of the context node in document order.
4760 *
4761 * Returns the next element following that axis
4762 */
4763xmlNodePtr
4764xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4765 if (cur == NULL) {
4766 if (ctxt->context->node == NULL) return(NULL);
4767 switch (ctxt->context->node->type) {
4768 case XML_ELEMENT_NODE:
4769 case XML_TEXT_NODE:
4770 case XML_CDATA_SECTION_NODE:
4771 case XML_ENTITY_REF_NODE:
4772 case XML_ENTITY_NODE:
4773 case XML_PI_NODE:
4774 case XML_COMMENT_NODE:
4775 case XML_NOTATION_NODE:
4776 case XML_DTD_NODE:
4777 return(ctxt->context->node->children);
4778 case XML_DOCUMENT_NODE:
4779 case XML_DOCUMENT_TYPE_NODE:
4780 case XML_DOCUMENT_FRAG_NODE:
4781 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004782#ifdef LIBXML_DOCB_ENABLED
4783 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004784#endif
4785 return(((xmlDocPtr) ctxt->context->node)->children);
4786 case XML_ELEMENT_DECL:
4787 case XML_ATTRIBUTE_DECL:
4788 case XML_ENTITY_DECL:
4789 case XML_ATTRIBUTE_NODE:
4790 case XML_NAMESPACE_DECL:
4791 case XML_XINCLUDE_START:
4792 case XML_XINCLUDE_END:
4793 return(NULL);
4794 }
4795 return(NULL);
4796 }
4797 if ((cur->type == XML_DOCUMENT_NODE) ||
4798 (cur->type == XML_HTML_DOCUMENT_NODE))
4799 return(NULL);
4800 return(cur->next);
4801}
4802
4803/**
4804 * xmlXPathNextDescendant:
4805 * @ctxt: the XPath Parser context
4806 * @cur: the current node in the traversal
4807 *
4808 * Traversal function for the "descendant" direction
4809 * the descendant axis contains the descendants of the context node in document
4810 * order; a descendant is a child or a child of a child and so on.
4811 *
4812 * Returns the next element following that axis
4813 */
4814xmlNodePtr
4815xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4816 if (cur == NULL) {
4817 if (ctxt->context->node == NULL)
4818 return(NULL);
4819 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4820 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4821 return(NULL);
4822
4823 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
4824 return(ctxt->context->doc->children);
4825 return(ctxt->context->node->children);
4826 }
4827
Daniel Veillard567e1b42001-08-01 15:53:47 +00004828 if (cur->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004829 if (cur->children->type != XML_ENTITY_DECL)
Daniel Veillard567e1b42001-08-01 15:53:47 +00004830 return(cur->children);
4831 }
4832
4833 if (cur == ctxt->context->node) return(NULL);
4834
Owen Taylor3473f882001-02-23 17:55:21 +00004835 if (cur->next != NULL) return(cur->next);
4836
4837 do {
4838 cur = cur->parent;
4839 if (cur == NULL) return(NULL);
4840 if (cur == ctxt->context->node) return(NULL);
4841 if (cur->next != NULL) {
4842 cur = cur->next;
4843 return(cur);
4844 }
4845 } while (cur != NULL);
4846 return(cur);
4847}
4848
4849/**
4850 * xmlXPathNextDescendantOrSelf:
4851 * @ctxt: the XPath Parser context
4852 * @cur: the current node in the traversal
4853 *
4854 * Traversal function for the "descendant-or-self" direction
4855 * the descendant-or-self axis contains the context node and the descendants
4856 * of the context node in document order; thus the context node is the first
4857 * node on the axis, and the first child of the context node is the second node
4858 * on the axis
4859 *
4860 * Returns the next element following that axis
4861 */
4862xmlNodePtr
4863xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4864 if (cur == NULL) {
4865 if (ctxt->context->node == NULL)
4866 return(NULL);
4867 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4868 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4869 return(NULL);
4870 return(ctxt->context->node);
4871 }
4872
4873 return(xmlXPathNextDescendant(ctxt, cur));
4874}
4875
4876/**
4877 * xmlXPathNextParent:
4878 * @ctxt: the XPath Parser context
4879 * @cur: the current node in the traversal
4880 *
4881 * Traversal function for the "parent" direction
4882 * The parent axis contains the parent of the context node, if there is one.
4883 *
4884 * Returns the next element following that axis
4885 */
4886xmlNodePtr
4887xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4888 /*
4889 * the parent of an attribute or namespace node is the element
4890 * to which the attribute or namespace node is attached
4891 * Namespace handling !!!
4892 */
4893 if (cur == NULL) {
4894 if (ctxt->context->node == NULL) return(NULL);
4895 switch (ctxt->context->node->type) {
4896 case XML_ELEMENT_NODE:
4897 case XML_TEXT_NODE:
4898 case XML_CDATA_SECTION_NODE:
4899 case XML_ENTITY_REF_NODE:
4900 case XML_ENTITY_NODE:
4901 case XML_PI_NODE:
4902 case XML_COMMENT_NODE:
4903 case XML_NOTATION_NODE:
4904 case XML_DTD_NODE:
4905 case XML_ELEMENT_DECL:
4906 case XML_ATTRIBUTE_DECL:
4907 case XML_XINCLUDE_START:
4908 case XML_XINCLUDE_END:
4909 case XML_ENTITY_DECL:
4910 if (ctxt->context->node->parent == NULL)
4911 return((xmlNodePtr) ctxt->context->doc);
4912 return(ctxt->context->node->parent);
4913 case XML_ATTRIBUTE_NODE: {
4914 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4915
4916 return(att->parent);
4917 }
4918 case XML_DOCUMENT_NODE:
4919 case XML_DOCUMENT_TYPE_NODE:
4920 case XML_DOCUMENT_FRAG_NODE:
4921 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004922#ifdef LIBXML_DOCB_ENABLED
4923 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004924#endif
4925 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004926 case XML_NAMESPACE_DECL: {
4927 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
4928
4929 if ((ns->next != NULL) &&
4930 (ns->next->type != XML_NAMESPACE_DECL))
4931 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00004932 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004933 }
Owen Taylor3473f882001-02-23 17:55:21 +00004934 }
4935 }
4936 return(NULL);
4937}
4938
4939/**
4940 * xmlXPathNextAncestor:
4941 * @ctxt: the XPath Parser context
4942 * @cur: the current node in the traversal
4943 *
4944 * Traversal function for the "ancestor" direction
4945 * the ancestor axis contains the ancestors of the context node; the ancestors
4946 * of the context node consist of the parent of context node and the parent's
4947 * parent and so on; the nodes are ordered in reverse document order; thus the
4948 * parent is the first node on the axis, and the parent's parent is the second
4949 * node on the axis
4950 *
4951 * Returns the next element following that axis
4952 */
4953xmlNodePtr
4954xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4955 /*
4956 * the parent of an attribute or namespace node is the element
4957 * to which the attribute or namespace node is attached
4958 * !!!!!!!!!!!!!
4959 */
4960 if (cur == NULL) {
4961 if (ctxt->context->node == NULL) return(NULL);
4962 switch (ctxt->context->node->type) {
4963 case XML_ELEMENT_NODE:
4964 case XML_TEXT_NODE:
4965 case XML_CDATA_SECTION_NODE:
4966 case XML_ENTITY_REF_NODE:
4967 case XML_ENTITY_NODE:
4968 case XML_PI_NODE:
4969 case XML_COMMENT_NODE:
4970 case XML_DTD_NODE:
4971 case XML_ELEMENT_DECL:
4972 case XML_ATTRIBUTE_DECL:
4973 case XML_ENTITY_DECL:
4974 case XML_NOTATION_NODE:
4975 case XML_XINCLUDE_START:
4976 case XML_XINCLUDE_END:
4977 if (ctxt->context->node->parent == NULL)
4978 return((xmlNodePtr) ctxt->context->doc);
4979 return(ctxt->context->node->parent);
4980 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004981 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00004982
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004983 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00004984 }
4985 case XML_DOCUMENT_NODE:
4986 case XML_DOCUMENT_TYPE_NODE:
4987 case XML_DOCUMENT_FRAG_NODE:
4988 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004989#ifdef LIBXML_DOCB_ENABLED
4990 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004991#endif
4992 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004993 case XML_NAMESPACE_DECL: {
4994 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
4995
4996 if ((ns->next != NULL) &&
4997 (ns->next->type != XML_NAMESPACE_DECL))
4998 return((xmlNodePtr) ns->next);
4999 /* Bad, how did that namespace ended-up there ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005000 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005001 }
Owen Taylor3473f882001-02-23 17:55:21 +00005002 }
5003 return(NULL);
5004 }
5005 if (cur == ctxt->context->doc->children)
5006 return((xmlNodePtr) ctxt->context->doc);
5007 if (cur == (xmlNodePtr) ctxt->context->doc)
5008 return(NULL);
5009 switch (cur->type) {
5010 case XML_ELEMENT_NODE:
5011 case XML_TEXT_NODE:
5012 case XML_CDATA_SECTION_NODE:
5013 case XML_ENTITY_REF_NODE:
5014 case XML_ENTITY_NODE:
5015 case XML_PI_NODE:
5016 case XML_COMMENT_NODE:
5017 case XML_NOTATION_NODE:
5018 case XML_DTD_NODE:
5019 case XML_ELEMENT_DECL:
5020 case XML_ATTRIBUTE_DECL:
5021 case XML_ENTITY_DECL:
5022 case XML_XINCLUDE_START:
5023 case XML_XINCLUDE_END:
5024 return(cur->parent);
5025 case XML_ATTRIBUTE_NODE: {
5026 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5027
5028 return(att->parent);
5029 }
5030 case XML_DOCUMENT_NODE:
5031 case XML_DOCUMENT_TYPE_NODE:
5032 case XML_DOCUMENT_FRAG_NODE:
5033 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005034#ifdef LIBXML_DOCB_ENABLED
5035 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005036#endif
5037 return(NULL);
5038 case XML_NAMESPACE_DECL:
5039 /*
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005040 * this should not hapen a namespace can't be
5041 * the ancestor of another node
Owen Taylor3473f882001-02-23 17:55:21 +00005042 */
5043 return(NULL);
5044 }
5045 return(NULL);
5046}
5047
5048/**
5049 * xmlXPathNextAncestorOrSelf:
5050 * @ctxt: the XPath Parser context
5051 * @cur: the current node in the traversal
5052 *
5053 * Traversal function for the "ancestor-or-self" direction
5054 * he ancestor-or-self axis contains the context node and ancestors of
5055 * the context node in reverse document order; thus the context node is
5056 * the first node on the axis, and the context node's parent the second;
5057 * parent here is defined the same as with the parent axis.
5058 *
5059 * Returns the next element following that axis
5060 */
5061xmlNodePtr
5062xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5063 if (cur == NULL)
5064 return(ctxt->context->node);
5065 return(xmlXPathNextAncestor(ctxt, cur));
5066}
5067
5068/**
5069 * xmlXPathNextFollowingSibling:
5070 * @ctxt: the XPath Parser context
5071 * @cur: the current node in the traversal
5072 *
5073 * Traversal function for the "following-sibling" direction
5074 * The following-sibling axis contains the following siblings of the context
5075 * node in document order.
5076 *
5077 * Returns the next element following that axis
5078 */
5079xmlNodePtr
5080xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5081 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5082 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5083 return(NULL);
5084 if (cur == (xmlNodePtr) ctxt->context->doc)
5085 return(NULL);
5086 if (cur == NULL)
5087 return(ctxt->context->node->next);
5088 return(cur->next);
5089}
5090
5091/**
5092 * xmlXPathNextPrecedingSibling:
5093 * @ctxt: the XPath Parser context
5094 * @cur: the current node in the traversal
5095 *
5096 * Traversal function for the "preceding-sibling" direction
5097 * The preceding-sibling axis contains the preceding siblings of the context
5098 * node in reverse document order; the first preceding sibling is first on the
5099 * axis; the sibling preceding that node is the second on the axis and so on.
5100 *
5101 * Returns the next element following that axis
5102 */
5103xmlNodePtr
5104xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5105 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5106 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5107 return(NULL);
5108 if (cur == (xmlNodePtr) ctxt->context->doc)
5109 return(NULL);
5110 if (cur == NULL)
5111 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005112 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5113 cur = cur->prev;
5114 if (cur == NULL)
5115 return(ctxt->context->node->prev);
5116 }
Owen Taylor3473f882001-02-23 17:55:21 +00005117 return(cur->prev);
5118}
5119
5120/**
5121 * xmlXPathNextFollowing:
5122 * @ctxt: the XPath Parser context
5123 * @cur: the current node in the traversal
5124 *
5125 * Traversal function for the "following" direction
5126 * The following axis contains all nodes in the same document as the context
5127 * node that are after the context node in document order, excluding any
5128 * descendants and excluding attribute nodes and namespace nodes; the nodes
5129 * are ordered in document order
5130 *
5131 * Returns the next element following that axis
5132 */
5133xmlNodePtr
5134xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5135 if (cur != NULL && cur->children != NULL)
5136 return cur->children ;
5137 if (cur == NULL) cur = ctxt->context->node;
5138 if (cur == NULL) return(NULL) ; /* ERROR */
5139 if (cur->next != NULL) return(cur->next) ;
5140 do {
5141 cur = cur->parent;
5142 if (cur == NULL) return(NULL);
5143 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5144 if (cur->next != NULL) return(cur->next);
5145 } while (cur != NULL);
5146 return(cur);
5147}
5148
5149/*
5150 * xmlXPathIsAncestor:
5151 * @ancestor: the ancestor node
5152 * @node: the current node
5153 *
5154 * Check that @ancestor is a @node's ancestor
5155 *
5156 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5157 */
5158static int
5159xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5160 if ((ancestor == NULL) || (node == NULL)) return(0);
5161 /* nodes need to be in the same document */
5162 if (ancestor->doc != node->doc) return(0);
5163 /* avoid searching if ancestor or node is the root node */
5164 if (ancestor == (xmlNodePtr) node->doc) return(1);
5165 if (node == (xmlNodePtr) ancestor->doc) return(0);
5166 while (node->parent != NULL) {
5167 if (node->parent == ancestor)
5168 return(1);
5169 node = node->parent;
5170 }
5171 return(0);
5172}
5173
5174/**
5175 * xmlXPathNextPreceding:
5176 * @ctxt: the XPath Parser context
5177 * @cur: the current node in the traversal
5178 *
5179 * Traversal function for the "preceding" direction
5180 * the preceding axis contains all nodes in the same document as the context
5181 * node that are before the context node in document order, excluding any
5182 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5183 * ordered in reverse document order
5184 *
5185 * Returns the next element following that axis
5186 */
5187xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005188xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5189{
Owen Taylor3473f882001-02-23 17:55:21 +00005190 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005191 cur = ctxt->context->node;
5192 if (cur == NULL)
5193 return (NULL);
5194 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5195 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005196 do {
5197 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005198 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5199 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005200 }
5201
5202 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005203 if (cur == NULL)
5204 return (NULL);
5205 if (cur == ctxt->context->doc->children)
5206 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005207 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005208 return (cur);
5209}
5210
5211/**
5212 * xmlXPathNextPrecedingInternal:
5213 * @ctxt: the XPath Parser context
5214 * @cur: the current node in the traversal
5215 *
5216 * Traversal function for the "preceding" direction
5217 * the preceding axis contains all nodes in the same document as the context
5218 * node that are before the context node in document order, excluding any
5219 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5220 * ordered in reverse document order
5221 * This is a faster implementation but internal only since it requires a
5222 * state kept in the parser context: ctxt->ancestor.
5223 *
5224 * Returns the next element following that axis
5225 */
5226static xmlNodePtr
5227xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5228 xmlNodePtr cur)
5229{
5230 if (cur == NULL) {
5231 cur = ctxt->context->node;
5232 if (cur == NULL)
5233 return (NULL);
5234 ctxt->ancestor = cur->parent;
5235 }
5236 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5237 cur = cur->prev;
5238 while (cur->prev == NULL) {
5239 cur = cur->parent;
5240 if (cur == NULL)
5241 return (NULL);
5242 if (cur == ctxt->context->doc->children)
5243 return (NULL);
5244 if (cur != ctxt->ancestor)
5245 return (cur);
5246 ctxt->ancestor = cur->parent;
5247 }
5248 cur = cur->prev;
5249 while (cur->last != NULL)
5250 cur = cur->last;
5251 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005252}
5253
5254/**
5255 * xmlXPathNextNamespace:
5256 * @ctxt: the XPath Parser context
5257 * @cur: the current attribute in the traversal
5258 *
5259 * Traversal function for the "namespace" direction
5260 * the namespace axis contains the namespace nodes of the context node;
5261 * the order of nodes on this axis is implementation-defined; the axis will
5262 * be empty unless the context node is an element
5263 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005264 * We keep the XML namespace node at the end of the list.
5265 *
Owen Taylor3473f882001-02-23 17:55:21 +00005266 * Returns the next element following that axis
5267 */
5268xmlNodePtr
5269xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005270 xmlNodePtr ret;
5271
Owen Taylor3473f882001-02-23 17:55:21 +00005272 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005273 if (cur == (xmlNodePtr) xmlXPathXMLNamespace)
5274 return(NULL);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005275 if ((cur == NULL) || (ctxt->context->tmpNsList == NULL)) {
5276 if (ctxt->context->tmpNsList != NULL)
5277 xmlFree(ctxt->context->tmpNsList);
5278 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005279 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005280 if (ctxt->context->tmpNsList == NULL) return(NULL);
5281 ctxt->context->tmpNsNr = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005282 }
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005283 ret = (xmlNodePtr)ctxt->context->tmpNsList[ctxt->context->tmpNsNr++];
5284 if (ret == NULL) {
5285 xmlFree(ctxt->context->tmpNsList);
5286 ctxt->context->tmpNsList = NULL;
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005287 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005288 }
5289 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005290}
5291
5292/**
5293 * xmlXPathNextAttribute:
5294 * @ctxt: the XPath Parser context
5295 * @cur: the current attribute in the traversal
5296 *
5297 * Traversal function for the "attribute" direction
5298 * TODO: support DTD inherited default attributes
5299 *
5300 * Returns the next element following that axis
5301 */
5302xmlNodePtr
5303xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005304 if (ctxt->context->node == NULL)
5305 return(NULL);
5306 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5307 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005308 if (cur == NULL) {
5309 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5310 return(NULL);
5311 return((xmlNodePtr)ctxt->context->node->properties);
5312 }
5313 return((xmlNodePtr)cur->next);
5314}
5315
5316/************************************************************************
5317 * *
5318 * NodeTest Functions *
5319 * *
5320 ************************************************************************/
5321
Owen Taylor3473f882001-02-23 17:55:21 +00005322#define IS_FUNCTION 200
5323
Owen Taylor3473f882001-02-23 17:55:21 +00005324
5325/************************************************************************
5326 * *
5327 * Implicit tree core function library *
5328 * *
5329 ************************************************************************/
5330
5331/**
5332 * xmlXPathRoot:
5333 * @ctxt: the XPath Parser context
5334 *
5335 * Initialize the context to the root of the document
5336 */
5337void
5338xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5339 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5340 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5341}
5342
5343/************************************************************************
5344 * *
5345 * The explicit core function library *
5346 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5347 * *
5348 ************************************************************************/
5349
5350
5351/**
5352 * xmlXPathLastFunction:
5353 * @ctxt: the XPath Parser context
5354 * @nargs: the number of arguments
5355 *
5356 * Implement the last() XPath function
5357 * number last()
5358 * The last function returns the number of nodes in the context node list.
5359 */
5360void
5361xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5362 CHECK_ARITY(0);
5363 if (ctxt->context->contextSize >= 0) {
5364 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5365#ifdef DEBUG_EXPR
5366 xmlGenericError(xmlGenericErrorContext,
5367 "last() : %d\n", ctxt->context->contextSize);
5368#endif
5369 } else {
5370 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5371 }
5372}
5373
5374/**
5375 * xmlXPathPositionFunction:
5376 * @ctxt: the XPath Parser context
5377 * @nargs: the number of arguments
5378 *
5379 * Implement the position() XPath function
5380 * number position()
5381 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005382 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005383 * will be equal to last().
5384 */
5385void
5386xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5387 CHECK_ARITY(0);
5388 if (ctxt->context->proximityPosition >= 0) {
5389 valuePush(ctxt,
5390 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5391#ifdef DEBUG_EXPR
5392 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5393 ctxt->context->proximityPosition);
5394#endif
5395 } else {
5396 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5397 }
5398}
5399
5400/**
5401 * xmlXPathCountFunction:
5402 * @ctxt: the XPath Parser context
5403 * @nargs: the number of arguments
5404 *
5405 * Implement the count() XPath function
5406 * number count(node-set)
5407 */
5408void
5409xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5410 xmlXPathObjectPtr cur;
5411
5412 CHECK_ARITY(1);
5413 if ((ctxt->value == NULL) ||
5414 ((ctxt->value->type != XPATH_NODESET) &&
5415 (ctxt->value->type != XPATH_XSLT_TREE)))
5416 XP_ERROR(XPATH_INVALID_TYPE);
5417 cur = valuePop(ctxt);
5418
Daniel Veillard911f49a2001-04-07 15:39:35 +00005419 if ((cur == NULL) || (cur->nodesetval == NULL))
5420 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00005421 else if (cur->type == XPATH_NODESET) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005422 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005423 } else {
5424 if ((cur->nodesetval->nodeNr != 1) ||
5425 (cur->nodesetval->nodeTab == NULL)) {
5426 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5427 } else {
5428 xmlNodePtr tmp;
5429 int i = 0;
5430
5431 tmp = cur->nodesetval->nodeTab[0];
5432 if (tmp != NULL) {
5433 tmp = tmp->children;
5434 while (tmp != NULL) {
5435 tmp = tmp->next;
5436 i++;
5437 }
5438 }
5439 valuePush(ctxt, xmlXPathNewFloat((double) i));
5440 }
5441 }
Owen Taylor3473f882001-02-23 17:55:21 +00005442 xmlXPathFreeObject(cur);
5443}
5444
5445/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005446 * xmlXPathGetElementsByIds:
5447 * @doc: the document
5448 * @ids: a whitespace separated list of IDs
5449 *
5450 * Selects elements by their unique ID.
5451 *
5452 * Returns a node-set of selected elements.
5453 */
5454static xmlNodeSetPtr
5455xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5456 xmlNodeSetPtr ret;
5457 const xmlChar *cur = ids;
5458 xmlChar *ID;
5459 xmlAttrPtr attr;
5460 xmlNodePtr elem = NULL;
5461
5462 ret = xmlXPathNodeSetCreate(NULL);
5463
5464 while (IS_BLANK(*cur)) cur++;
5465 while (*cur != 0) {
5466 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
5467 (*cur == '.') || (*cur == '-') ||
5468 (*cur == '_') || (*cur == ':') ||
5469 (IS_COMBINING(*cur)) ||
5470 (IS_EXTENDER(*cur)))
5471 cur++;
5472
5473 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
5474
5475 ID = xmlStrndup(ids, cur - ids);
5476 attr = xmlGetID(doc, ID);
5477 if (attr != NULL) {
5478 elem = attr->parent;
5479 xmlXPathNodeSetAdd(ret, elem);
5480 }
5481 if (ID != NULL)
5482 xmlFree(ID);
5483
5484 while (IS_BLANK(*cur)) cur++;
5485 ids = cur;
5486 }
5487 return(ret);
5488}
5489
5490/**
Owen Taylor3473f882001-02-23 17:55:21 +00005491 * xmlXPathIdFunction:
5492 * @ctxt: the XPath Parser context
5493 * @nargs: the number of arguments
5494 *
5495 * Implement the id() XPath function
5496 * node-set id(object)
5497 * The id function selects elements by their unique ID
5498 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5499 * then the result is the union of the result of applying id to the
5500 * string value of each of the nodes in the argument node-set. When the
5501 * argument to id is of any other type, the argument is converted to a
5502 * string as if by a call to the string function; the string is split
5503 * into a whitespace-separated list of tokens (whitespace is any sequence
5504 * of characters matching the production S); the result is a node-set
5505 * containing the elements in the same document as the context node that
5506 * have a unique ID equal to any of the tokens in the list.
5507 */
5508void
5509xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005510 xmlChar *tokens;
5511 xmlNodeSetPtr ret;
5512 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00005513
5514 CHECK_ARITY(1);
5515 obj = valuePop(ctxt);
5516 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
5517 if (obj->type == XPATH_NODESET) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005518 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00005519 int i;
5520
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005521 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005522
Daniel Veillard911f49a2001-04-07 15:39:35 +00005523 if (obj->nodesetval != NULL) {
5524 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005525 tokens =
5526 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
5527 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
5528 ret = xmlXPathNodeSetMerge(ret, ns);
5529 xmlXPathFreeNodeSet(ns);
5530 if (tokens != NULL)
5531 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00005532 }
Owen Taylor3473f882001-02-23 17:55:21 +00005533 }
5534
5535 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005536 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005537 return;
5538 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005539 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00005540
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005541 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
5542 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005543
Owen Taylor3473f882001-02-23 17:55:21 +00005544 xmlXPathFreeObject(obj);
5545 return;
5546}
5547
5548/**
5549 * xmlXPathLocalNameFunction:
5550 * @ctxt: the XPath Parser context
5551 * @nargs: the number of arguments
5552 *
5553 * Implement the local-name() XPath function
5554 * string local-name(node-set?)
5555 * The local-name function returns a string containing the local part
5556 * of the name of the node in the argument node-set that is first in
5557 * document order. If the node-set is empty or the first node has no
5558 * name, an empty string is returned. If the argument is omitted it
5559 * defaults to the context node.
5560 */
5561void
5562xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5563 xmlXPathObjectPtr cur;
5564
5565 if (nargs == 0) {
5566 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5567 nargs = 1;
5568 }
5569
5570 CHECK_ARITY(1);
5571 if ((ctxt->value == NULL) ||
5572 ((ctxt->value->type != XPATH_NODESET) &&
5573 (ctxt->value->type != XPATH_XSLT_TREE)))
5574 XP_ERROR(XPATH_INVALID_TYPE);
5575 cur = valuePop(ctxt);
5576
Daniel Veillard911f49a2001-04-07 15:39:35 +00005577 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005578 valuePush(ctxt, xmlXPathNewCString(""));
5579 } else {
5580 int i = 0; /* Should be first in document order !!!!! */
5581 switch (cur->nodesetval->nodeTab[i]->type) {
5582 case XML_ELEMENT_NODE:
5583 case XML_ATTRIBUTE_NODE:
5584 case XML_PI_NODE:
5585 valuePush(ctxt,
5586 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
5587 break;
5588 case XML_NAMESPACE_DECL:
5589 valuePush(ctxt, xmlXPathNewString(
5590 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
5591 break;
5592 default:
5593 valuePush(ctxt, xmlXPathNewCString(""));
5594 }
5595 }
5596 xmlXPathFreeObject(cur);
5597}
5598
5599/**
5600 * xmlXPathNamespaceURIFunction:
5601 * @ctxt: the XPath Parser context
5602 * @nargs: the number of arguments
5603 *
5604 * Implement the namespace-uri() XPath function
5605 * string namespace-uri(node-set?)
5606 * The namespace-uri function returns a string containing the
5607 * namespace URI of the expanded name of the node in the argument
5608 * node-set that is first in document order. If the node-set is empty,
5609 * the first node has no name, or the expanded name has no namespace
5610 * URI, an empty string is returned. If the argument is omitted it
5611 * defaults to the context node.
5612 */
5613void
5614xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5615 xmlXPathObjectPtr cur;
5616
5617 if (nargs == 0) {
5618 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5619 nargs = 1;
5620 }
5621 CHECK_ARITY(1);
5622 if ((ctxt->value == NULL) ||
5623 ((ctxt->value->type != XPATH_NODESET) &&
5624 (ctxt->value->type != XPATH_XSLT_TREE)))
5625 XP_ERROR(XPATH_INVALID_TYPE);
5626 cur = valuePop(ctxt);
5627
Daniel Veillard911f49a2001-04-07 15:39:35 +00005628 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005629 valuePush(ctxt, xmlXPathNewCString(""));
5630 } else {
5631 int i = 0; /* Should be first in document order !!!!! */
5632 switch (cur->nodesetval->nodeTab[i]->type) {
5633 case XML_ELEMENT_NODE:
5634 case XML_ATTRIBUTE_NODE:
5635 if (cur->nodesetval->nodeTab[i]->ns == NULL)
5636 valuePush(ctxt, xmlXPathNewCString(""));
5637 else
5638 valuePush(ctxt, xmlXPathNewString(
5639 cur->nodesetval->nodeTab[i]->ns->href));
5640 break;
5641 default:
5642 valuePush(ctxt, xmlXPathNewCString(""));
5643 }
5644 }
5645 xmlXPathFreeObject(cur);
5646}
5647
5648/**
5649 * xmlXPathNameFunction:
5650 * @ctxt: the XPath Parser context
5651 * @nargs: the number of arguments
5652 *
5653 * Implement the name() XPath function
5654 * string name(node-set?)
5655 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005656 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00005657 * order. The QName must represent the name with respect to the namespace
5658 * declarations in effect on the node whose name is being represented.
5659 * Typically, this will be the form in which the name occurred in the XML
5660 * source. This need not be the case if there are namespace declarations
5661 * in effect on the node that associate multiple prefixes with the same
5662 * namespace. However, an implementation may include information about
5663 * the original prefix in its representation of nodes; in this case, an
5664 * implementation can ensure that the returned string is always the same
5665 * as the QName used in the XML source. If the argument it omitted it
5666 * defaults to the context node.
5667 * Libxml keep the original prefix so the "real qualified name" used is
5668 * returned.
5669 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005670static void
Daniel Veillard04383752001-07-08 14:27:15 +00005671xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
5672{
Owen Taylor3473f882001-02-23 17:55:21 +00005673 xmlXPathObjectPtr cur;
5674
5675 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00005676 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5677 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00005678 }
5679
5680 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00005681 if ((ctxt->value == NULL) ||
5682 ((ctxt->value->type != XPATH_NODESET) &&
5683 (ctxt->value->type != XPATH_XSLT_TREE)))
5684 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00005685 cur = valuePop(ctxt);
5686
Daniel Veillard911f49a2001-04-07 15:39:35 +00005687 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00005688 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00005689 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00005690 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005691
Daniel Veillard04383752001-07-08 14:27:15 +00005692 switch (cur->nodesetval->nodeTab[i]->type) {
5693 case XML_ELEMENT_NODE:
5694 case XML_ATTRIBUTE_NODE:
5695 if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
5696 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL))
5697 valuePush(ctxt,
5698 xmlXPathNewString(cur->nodesetval->
5699 nodeTab[i]->name));
5700
5701 else {
5702 char name[2000];
5703
5704 snprintf(name, sizeof(name), "%s:%s",
5705 (char *) cur->nodesetval->nodeTab[i]->ns->
5706 prefix,
5707 (char *) cur->nodesetval->nodeTab[i]->name);
5708 name[sizeof(name) - 1] = 0;
5709 valuePush(ctxt, xmlXPathNewCString(name));
5710 }
5711 break;
5712 default:
5713 valuePush(ctxt,
5714 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
5715 xmlXPathLocalNameFunction(ctxt, 1);
5716 }
Owen Taylor3473f882001-02-23 17:55:21 +00005717 }
5718 xmlXPathFreeObject(cur);
5719}
5720
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005721
5722/**
Owen Taylor3473f882001-02-23 17:55:21 +00005723 * xmlXPathStringFunction:
5724 * @ctxt: the XPath Parser context
5725 * @nargs: the number of arguments
5726 *
5727 * Implement the string() XPath function
5728 * string string(object?)
5729 * he string function converts an object to a string as follows:
5730 * - A node-set is converted to a string by returning the value of
5731 * the node in the node-set that is first in document order.
5732 * If the node-set is empty, an empty string is returned.
5733 * - A number is converted to a string as follows
5734 * + NaN is converted to the string NaN
5735 * + positive zero is converted to the string 0
5736 * + negative zero is converted to the string 0
5737 * + positive infinity is converted to the string Infinity
5738 * + negative infinity is converted to the string -Infinity
5739 * + if the number is an integer, the number is represented in
5740 * decimal form as a Number with no decimal point and no leading
5741 * zeros, preceded by a minus sign (-) if the number is negative
5742 * + otherwise, the number is represented in decimal form as a
5743 * Number including a decimal point with at least one digit
5744 * before the decimal point and at least one digit after the
5745 * decimal point, preceded by a minus sign (-) if the number
5746 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005747 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00005748 * before the decimal point; beyond the one required digit
5749 * after the decimal point there must be as many, but only as
5750 * many, more digits as are needed to uniquely distinguish the
5751 * number from all other IEEE 754 numeric values.
5752 * - The boolean false value is converted to the string false.
5753 * The boolean true value is converted to the string true.
5754 *
5755 * If the argument is omitted, it defaults to a node-set with the
5756 * context node as its only member.
5757 */
5758void
5759xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5760 xmlXPathObjectPtr cur;
5761
5762 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005763 valuePush(ctxt,
5764 xmlXPathWrapString(
5765 xmlXPathCastNodeToString(ctxt->context->node)));
5766 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005767 }
5768
5769 CHECK_ARITY(1);
5770 cur = valuePop(ctxt);
5771 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005772 cur = xmlXPathConvertString(cur);
5773 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005774}
5775
5776/**
5777 * xmlXPathStringLengthFunction:
5778 * @ctxt: the XPath Parser context
5779 * @nargs: the number of arguments
5780 *
5781 * Implement the string-length() XPath function
5782 * number string-length(string?)
5783 * The string-length returns the number of characters in the string
5784 * (see [3.6 Strings]). If the argument is omitted, it defaults to
5785 * the context node converted to a string, in other words the value
5786 * of the context node.
5787 */
5788void
5789xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5790 xmlXPathObjectPtr cur;
5791
5792 if (nargs == 0) {
5793 if (ctxt->context->node == NULL) {
5794 valuePush(ctxt, xmlXPathNewFloat(0));
5795 } else {
5796 xmlChar *content;
5797
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005798 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005799 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00005800 xmlFree(content);
5801 }
5802 return;
5803 }
5804 CHECK_ARITY(1);
5805 CAST_TO_STRING;
5806 CHECK_TYPE(XPATH_STRING);
5807 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005808 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00005809 xmlXPathFreeObject(cur);
5810}
5811
5812/**
5813 * xmlXPathConcatFunction:
5814 * @ctxt: the XPath Parser context
5815 * @nargs: the number of arguments
5816 *
5817 * Implement the concat() XPath function
5818 * string concat(string, string, string*)
5819 * The concat function returns the concatenation of its arguments.
5820 */
5821void
5822xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5823 xmlXPathObjectPtr cur, newobj;
5824 xmlChar *tmp;
5825
5826 if (nargs < 2) {
5827 CHECK_ARITY(2);
5828 }
5829
5830 CAST_TO_STRING;
5831 cur = valuePop(ctxt);
5832 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
5833 xmlXPathFreeObject(cur);
5834 return;
5835 }
5836 nargs--;
5837
5838 while (nargs > 0) {
5839 CAST_TO_STRING;
5840 newobj = valuePop(ctxt);
5841 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
5842 xmlXPathFreeObject(newobj);
5843 xmlXPathFreeObject(cur);
5844 XP_ERROR(XPATH_INVALID_TYPE);
5845 }
5846 tmp = xmlStrcat(newobj->stringval, cur->stringval);
5847 newobj->stringval = cur->stringval;
5848 cur->stringval = tmp;
5849
5850 xmlXPathFreeObject(newobj);
5851 nargs--;
5852 }
5853 valuePush(ctxt, cur);
5854}
5855
5856/**
5857 * xmlXPathContainsFunction:
5858 * @ctxt: the XPath Parser context
5859 * @nargs: the number of arguments
5860 *
5861 * Implement the contains() XPath function
5862 * boolean contains(string, string)
5863 * The contains function returns true if the first argument string
5864 * contains the second argument string, and otherwise returns false.
5865 */
5866void
5867xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5868 xmlXPathObjectPtr hay, needle;
5869
5870 CHECK_ARITY(2);
5871 CAST_TO_STRING;
5872 CHECK_TYPE(XPATH_STRING);
5873 needle = valuePop(ctxt);
5874 CAST_TO_STRING;
5875 hay = valuePop(ctxt);
5876 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5877 xmlXPathFreeObject(hay);
5878 xmlXPathFreeObject(needle);
5879 XP_ERROR(XPATH_INVALID_TYPE);
5880 }
5881 if (xmlStrstr(hay->stringval, needle->stringval))
5882 valuePush(ctxt, xmlXPathNewBoolean(1));
5883 else
5884 valuePush(ctxt, xmlXPathNewBoolean(0));
5885 xmlXPathFreeObject(hay);
5886 xmlXPathFreeObject(needle);
5887}
5888
5889/**
5890 * xmlXPathStartsWithFunction:
5891 * @ctxt: the XPath Parser context
5892 * @nargs: the number of arguments
5893 *
5894 * Implement the starts-with() XPath function
5895 * boolean starts-with(string, string)
5896 * The starts-with function returns true if the first argument string
5897 * starts with the second argument string, and otherwise returns false.
5898 */
5899void
5900xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5901 xmlXPathObjectPtr hay, needle;
5902 int n;
5903
5904 CHECK_ARITY(2);
5905 CAST_TO_STRING;
5906 CHECK_TYPE(XPATH_STRING);
5907 needle = valuePop(ctxt);
5908 CAST_TO_STRING;
5909 hay = valuePop(ctxt);
5910 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5911 xmlXPathFreeObject(hay);
5912 xmlXPathFreeObject(needle);
5913 XP_ERROR(XPATH_INVALID_TYPE);
5914 }
5915 n = xmlStrlen(needle->stringval);
5916 if (xmlStrncmp(hay->stringval, needle->stringval, n))
5917 valuePush(ctxt, xmlXPathNewBoolean(0));
5918 else
5919 valuePush(ctxt, xmlXPathNewBoolean(1));
5920 xmlXPathFreeObject(hay);
5921 xmlXPathFreeObject(needle);
5922}
5923
5924/**
5925 * xmlXPathSubstringFunction:
5926 * @ctxt: the XPath Parser context
5927 * @nargs: the number of arguments
5928 *
5929 * Implement the substring() XPath function
5930 * string substring(string, number, number?)
5931 * The substring function returns the substring of the first argument
5932 * starting at the position specified in the second argument with
5933 * length specified in the third argument. For example,
5934 * substring("12345",2,3) returns "234". If the third argument is not
5935 * specified, it returns the substring starting at the position specified
5936 * in the second argument and continuing to the end of the string. For
5937 * example, substring("12345",2) returns "2345". More precisely, each
5938 * character in the string (see [3.6 Strings]) is considered to have a
5939 * numeric position: the position of the first character is 1, the position
5940 * of the second character is 2 and so on. The returned substring contains
5941 * those characters for which the position of the character is greater than
5942 * or equal to the second argument and, if the third argument is specified,
5943 * less than the sum of the second and third arguments; the comparisons
5944 * and addition used for the above follow the standard IEEE 754 rules. Thus:
5945 * - substring("12345", 1.5, 2.6) returns "234"
5946 * - substring("12345", 0, 3) returns "12"
5947 * - substring("12345", 0 div 0, 3) returns ""
5948 * - substring("12345", 1, 0 div 0) returns ""
5949 * - substring("12345", -42, 1 div 0) returns "12345"
5950 * - substring("12345", -1 div 0, 1 div 0) returns ""
5951 */
5952void
5953xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5954 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005955 double le=0, in;
5956 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00005957 xmlChar *ret;
5958
Owen Taylor3473f882001-02-23 17:55:21 +00005959 if (nargs < 2) {
5960 CHECK_ARITY(2);
5961 }
5962 if (nargs > 3) {
5963 CHECK_ARITY(3);
5964 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005965 /*
5966 * take care of possible last (position) argument
5967 */
Owen Taylor3473f882001-02-23 17:55:21 +00005968 if (nargs == 3) {
5969 CAST_TO_NUMBER;
5970 CHECK_TYPE(XPATH_NUMBER);
5971 len = valuePop(ctxt);
5972 le = len->floatval;
5973 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00005974 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005975
Owen Taylor3473f882001-02-23 17:55:21 +00005976 CAST_TO_NUMBER;
5977 CHECK_TYPE(XPATH_NUMBER);
5978 start = valuePop(ctxt);
5979 in = start->floatval;
5980 xmlXPathFreeObject(start);
5981 CAST_TO_STRING;
5982 CHECK_TYPE(XPATH_STRING);
5983 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00005984 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005985
Daniel Veillard97ac1312001-05-30 19:14:17 +00005986 /*
5987 * If last pos not present, calculate last position
5988 */
5989 if (nargs != 3)
5990 le = m;
5991
5992 /*
5993 * To meet our requirements, initial index calculations
5994 * must be done before we convert to integer format
5995 *
5996 * First we normalize indices
5997 */
5998 in -= 1.0;
5999 le += in;
6000 if (in < 0.0)
6001 in = 0.0;
6002 if (le > (double)m)
6003 le = (double)m;
6004
6005 /*
6006 * Now we go to integer form, rounding up
6007 */
Owen Taylor3473f882001-02-23 17:55:21 +00006008 i = (int) in;
6009 if (((double)i) != in) i++;
6010
Owen Taylor3473f882001-02-23 17:55:21 +00006011 l = (int) le;
6012 if (((double)l) != le) l++;
6013
Daniel Veillard97ac1312001-05-30 19:14:17 +00006014 if (l > m) l=m;
Owen Taylor3473f882001-02-23 17:55:21 +00006015
6016 /* number of chars to copy */
6017 l -= i;
6018
Daniel Veillard97ac1312001-05-30 19:14:17 +00006019 ret = xmlUTF8Strsub(str->stringval, i, l);
Owen Taylor3473f882001-02-23 17:55:21 +00006020 if (ret == NULL)
6021 valuePush(ctxt, xmlXPathNewCString(""));
6022 else {
6023 valuePush(ctxt, xmlXPathNewString(ret));
6024 xmlFree(ret);
6025 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006026
Owen Taylor3473f882001-02-23 17:55:21 +00006027 xmlXPathFreeObject(str);
6028}
6029
6030/**
6031 * xmlXPathSubstringBeforeFunction:
6032 * @ctxt: the XPath Parser context
6033 * @nargs: the number of arguments
6034 *
6035 * Implement the substring-before() XPath function
6036 * string substring-before(string, string)
6037 * The substring-before function returns the substring of the first
6038 * argument string that precedes the first occurrence of the second
6039 * argument string in the first argument string, or the empty string
6040 * if the first argument string does not contain the second argument
6041 * string. For example, substring-before("1999/04/01","/") returns 1999.
6042 */
6043void
6044xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6045 xmlXPathObjectPtr str;
6046 xmlXPathObjectPtr find;
6047 xmlBufferPtr target;
6048 const xmlChar *point;
6049 int offset;
6050
6051 CHECK_ARITY(2);
6052 CAST_TO_STRING;
6053 find = valuePop(ctxt);
6054 CAST_TO_STRING;
6055 str = valuePop(ctxt);
6056
6057 target = xmlBufferCreate();
6058 if (target) {
6059 point = xmlStrstr(str->stringval, find->stringval);
6060 if (point) {
6061 offset = (int)(point - str->stringval);
6062 xmlBufferAdd(target, str->stringval, offset);
6063 }
6064 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6065 xmlBufferFree(target);
6066 }
6067
6068 xmlXPathFreeObject(str);
6069 xmlXPathFreeObject(find);
6070}
6071
6072/**
6073 * xmlXPathSubstringAfterFunction:
6074 * @ctxt: the XPath Parser context
6075 * @nargs: the number of arguments
6076 *
6077 * Implement the substring-after() XPath function
6078 * string substring-after(string, string)
6079 * The substring-after function returns the substring of the first
6080 * argument string that follows the first occurrence of the second
6081 * argument string in the first argument string, or the empty stringi
6082 * if the first argument string does not contain the second argument
6083 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6084 * and substring-after("1999/04/01","19") returns 99/04/01.
6085 */
6086void
6087xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6088 xmlXPathObjectPtr str;
6089 xmlXPathObjectPtr find;
6090 xmlBufferPtr target;
6091 const xmlChar *point;
6092 int offset;
6093
6094 CHECK_ARITY(2);
6095 CAST_TO_STRING;
6096 find = valuePop(ctxt);
6097 CAST_TO_STRING;
6098 str = valuePop(ctxt);
6099
6100 target = xmlBufferCreate();
6101 if (target) {
6102 point = xmlStrstr(str->stringval, find->stringval);
6103 if (point) {
6104 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6105 xmlBufferAdd(target, &str->stringval[offset],
6106 xmlStrlen(str->stringval) - offset);
6107 }
6108 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6109 xmlBufferFree(target);
6110 }
6111
6112 xmlXPathFreeObject(str);
6113 xmlXPathFreeObject(find);
6114}
6115
6116/**
6117 * xmlXPathNormalizeFunction:
6118 * @ctxt: the XPath Parser context
6119 * @nargs: the number of arguments
6120 *
6121 * Implement the normalize-space() XPath function
6122 * string normalize-space(string?)
6123 * The normalize-space function returns the argument string with white
6124 * space normalized by stripping leading and trailing whitespace
6125 * and replacing sequences of whitespace characters by a single
6126 * space. Whitespace characters are the same allowed by the S production
6127 * in XML. If the argument is omitted, it defaults to the context
6128 * node converted to a string, in other words the value of the context node.
6129 */
6130void
6131xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6132 xmlXPathObjectPtr obj = NULL;
6133 xmlChar *source = NULL;
6134 xmlBufferPtr target;
6135 xmlChar blank;
6136
6137 if (nargs == 0) {
6138 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006139 valuePush(ctxt,
6140 xmlXPathWrapString(
6141 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006142 nargs = 1;
6143 }
6144
6145 CHECK_ARITY(1);
6146 CAST_TO_STRING;
6147 CHECK_TYPE(XPATH_STRING);
6148 obj = valuePop(ctxt);
6149 source = obj->stringval;
6150
6151 target = xmlBufferCreate();
6152 if (target && source) {
6153
6154 /* Skip leading whitespaces */
6155 while (IS_BLANK(*source))
6156 source++;
6157
6158 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6159 blank = 0;
6160 while (*source) {
6161 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006162 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006163 } else {
6164 if (blank) {
6165 xmlBufferAdd(target, &blank, 1);
6166 blank = 0;
6167 }
6168 xmlBufferAdd(target, source, 1);
6169 }
6170 source++;
6171 }
6172
6173 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6174 xmlBufferFree(target);
6175 }
6176 xmlXPathFreeObject(obj);
6177}
6178
6179/**
6180 * xmlXPathTranslateFunction:
6181 * @ctxt: the XPath Parser context
6182 * @nargs: the number of arguments
6183 *
6184 * Implement the translate() XPath function
6185 * string translate(string, string, string)
6186 * The translate function returns the first argument string with
6187 * occurrences of characters in the second argument string replaced
6188 * by the character at the corresponding position in the third argument
6189 * string. For example, translate("bar","abc","ABC") returns the string
6190 * BAr. If there is a character in the second argument string with no
6191 * character at a corresponding position in the third argument string
6192 * (because the second argument string is longer than the third argument
6193 * string), then occurrences of that character in the first argument
6194 * string are removed. For example, translate("--aaa--","abc-","ABC")
6195 * returns "AAA". If a character occurs more than once in second
6196 * argument string, then the first occurrence determines the replacement
6197 * character. If the third argument string is longer than the second
6198 * argument string, then excess characters are ignored.
6199 */
6200void
6201xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006202 xmlXPathObjectPtr str;
6203 xmlXPathObjectPtr from;
6204 xmlXPathObjectPtr to;
6205 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006206 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006207 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006208 xmlChar *point;
6209 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006210
Daniel Veillarde043ee12001-04-16 14:08:07 +00006211 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006212
Daniel Veillarde043ee12001-04-16 14:08:07 +00006213 CAST_TO_STRING;
6214 to = valuePop(ctxt);
6215 CAST_TO_STRING;
6216 from = valuePop(ctxt);
6217 CAST_TO_STRING;
6218 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006219
Daniel Veillarde043ee12001-04-16 14:08:07 +00006220 target = xmlBufferCreate();
6221 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006222 max = xmlUTF8Strlen(to->stringval);
6223 for (cptr = str->stringval; (ch=*cptr); ) {
6224 offset = xmlUTF8Strloc(from->stringval, cptr);
6225 if (offset >= 0) {
6226 if (offset < max) {
6227 point = xmlUTF8Strpos(to->stringval, offset);
6228 if (point)
6229 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6230 }
6231 } else
6232 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6233
6234 /* Step to next character in input */
6235 cptr++;
6236 if ( ch & 0x80 ) {
6237 /* if not simple ascii, verify proper format */
6238 if ( (ch & 0xc0) != 0xc0 ) {
6239 xmlGenericError(xmlGenericErrorContext,
6240 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6241 break;
6242 }
6243 /* then skip over remaining bytes for this char */
6244 while ( (ch <<= 1) & 0x80 )
6245 if ( (*cptr++ & 0xc0) != 0x80 ) {
6246 xmlGenericError(xmlGenericErrorContext,
6247 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6248 break;
6249 }
6250 if (ch & 0x80) /* must have had error encountered */
6251 break;
6252 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006253 }
Owen Taylor3473f882001-02-23 17:55:21 +00006254 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006255 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6256 xmlBufferFree(target);
6257 xmlXPathFreeObject(str);
6258 xmlXPathFreeObject(from);
6259 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006260}
6261
6262/**
6263 * xmlXPathBooleanFunction:
6264 * @ctxt: the XPath Parser context
6265 * @nargs: the number of arguments
6266 *
6267 * Implement the boolean() XPath function
6268 * boolean boolean(object)
6269 * he boolean function converts its argument to a boolean as follows:
6270 * - a number is true if and only if it is neither positive or
6271 * negative zero nor NaN
6272 * - a node-set is true if and only if it is non-empty
6273 * - a string is true if and only if its length is non-zero
6274 */
6275void
6276xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6277 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006278
6279 CHECK_ARITY(1);
6280 cur = valuePop(ctxt);
6281 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006282 cur = xmlXPathConvertBoolean(cur);
6283 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006284}
6285
6286/**
6287 * xmlXPathNotFunction:
6288 * @ctxt: the XPath Parser context
6289 * @nargs: the number of arguments
6290 *
6291 * Implement the not() XPath function
6292 * boolean not(boolean)
6293 * The not function returns true if its argument is false,
6294 * and false otherwise.
6295 */
6296void
6297xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6298 CHECK_ARITY(1);
6299 CAST_TO_BOOLEAN;
6300 CHECK_TYPE(XPATH_BOOLEAN);
6301 ctxt->value->boolval = ! ctxt->value->boolval;
6302}
6303
6304/**
6305 * xmlXPathTrueFunction:
6306 * @ctxt: the XPath Parser context
6307 * @nargs: the number of arguments
6308 *
6309 * Implement the true() XPath function
6310 * boolean true()
6311 */
6312void
6313xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6314 CHECK_ARITY(0);
6315 valuePush(ctxt, xmlXPathNewBoolean(1));
6316}
6317
6318/**
6319 * xmlXPathFalseFunction:
6320 * @ctxt: the XPath Parser context
6321 * @nargs: the number of arguments
6322 *
6323 * Implement the false() XPath function
6324 * boolean false()
6325 */
6326void
6327xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6328 CHECK_ARITY(0);
6329 valuePush(ctxt, xmlXPathNewBoolean(0));
6330}
6331
6332/**
6333 * xmlXPathLangFunction:
6334 * @ctxt: the XPath Parser context
6335 * @nargs: the number of arguments
6336 *
6337 * Implement the lang() XPath function
6338 * boolean lang(string)
6339 * The lang function returns true or false depending on whether the
6340 * language of the context node as specified by xml:lang attributes
6341 * is the same as or is a sublanguage of the language specified by
6342 * the argument string. The language of the context node is determined
6343 * by the value of the xml:lang attribute on the context node, or, if
6344 * the context node has no xml:lang attribute, by the value of the
6345 * xml:lang attribute on the nearest ancestor of the context node that
6346 * has an xml:lang attribute. If there is no such attribute, then lang
6347 * returns false. If there is such an attribute, then lang returns
6348 * true if the attribute value is equal to the argument ignoring case,
6349 * or if there is some suffix starting with - such that the attribute
6350 * value is equal to the argument ignoring that suffix of the attribute
6351 * value and ignoring case.
6352 */
6353void
6354xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6355 xmlXPathObjectPtr val;
6356 const xmlChar *theLang;
6357 const xmlChar *lang;
6358 int ret = 0;
6359 int i;
6360
6361 CHECK_ARITY(1);
6362 CAST_TO_STRING;
6363 CHECK_TYPE(XPATH_STRING);
6364 val = valuePop(ctxt);
6365 lang = val->stringval;
6366 theLang = xmlNodeGetLang(ctxt->context->node);
6367 if ((theLang != NULL) && (lang != NULL)) {
6368 for (i = 0;lang[i] != 0;i++)
6369 if (toupper(lang[i]) != toupper(theLang[i]))
6370 goto not_equal;
6371 ret = 1;
6372 }
6373not_equal:
6374 xmlXPathFreeObject(val);
6375 valuePush(ctxt, xmlXPathNewBoolean(ret));
6376}
6377
6378/**
6379 * xmlXPathNumberFunction:
6380 * @ctxt: the XPath Parser context
6381 * @nargs: the number of arguments
6382 *
6383 * Implement the number() XPath function
6384 * number number(object?)
6385 */
6386void
6387xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6388 xmlXPathObjectPtr cur;
6389 double res;
6390
6391 if (nargs == 0) {
6392 if (ctxt->context->node == NULL) {
6393 valuePush(ctxt, xmlXPathNewFloat(0.0));
6394 } else {
6395 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6396
6397 res = xmlXPathStringEvalNumber(content);
6398 valuePush(ctxt, xmlXPathNewFloat(res));
6399 xmlFree(content);
6400 }
6401 return;
6402 }
6403
6404 CHECK_ARITY(1);
6405 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006406 cur = xmlXPathConvertNumber(cur);
6407 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006408}
6409
6410/**
6411 * xmlXPathSumFunction:
6412 * @ctxt: the XPath Parser context
6413 * @nargs: the number of arguments
6414 *
6415 * Implement the sum() XPath function
6416 * number sum(node-set)
6417 * The sum function returns the sum of the values of the nodes in
6418 * the argument node-set.
6419 */
6420void
6421xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6422 xmlXPathObjectPtr cur;
6423 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006424 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006425
6426 CHECK_ARITY(1);
6427 if ((ctxt->value == NULL) ||
6428 ((ctxt->value->type != XPATH_NODESET) &&
6429 (ctxt->value->type != XPATH_XSLT_TREE)))
6430 XP_ERROR(XPATH_INVALID_TYPE);
6431 cur = valuePop(ctxt);
6432
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006433 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006434 valuePush(ctxt, xmlXPathNewFloat(0.0));
6435 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006436 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6437 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006438 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006439 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006440 }
6441 xmlXPathFreeObject(cur);
6442}
6443
6444/**
6445 * xmlXPathFloorFunction:
6446 * @ctxt: the XPath Parser context
6447 * @nargs: the number of arguments
6448 *
6449 * Implement the floor() XPath function
6450 * number floor(number)
6451 * The floor function returns the largest (closest to positive infinity)
6452 * number that is not greater than the argument and that is an integer.
6453 */
6454void
6455xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6456 CHECK_ARITY(1);
6457 CAST_TO_NUMBER;
6458 CHECK_TYPE(XPATH_NUMBER);
6459#if 0
6460 ctxt->value->floatval = floor(ctxt->value->floatval);
6461#else
6462 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
6463 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
6464#endif
6465}
6466
6467/**
6468 * xmlXPathCeilingFunction:
6469 * @ctxt: the XPath Parser context
6470 * @nargs: the number of arguments
6471 *
6472 * Implement the ceiling() XPath function
6473 * number ceiling(number)
6474 * The ceiling function returns the smallest (closest to negative infinity)
6475 * number that is not less than the argument and that is an integer.
6476 */
6477void
6478xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6479 double f;
6480
6481 CHECK_ARITY(1);
6482 CAST_TO_NUMBER;
6483 CHECK_TYPE(XPATH_NUMBER);
6484
6485#if 0
6486 ctxt->value->floatval = ceil(ctxt->value->floatval);
6487#else
6488 f = (double)((int) ctxt->value->floatval);
6489 if (f != ctxt->value->floatval)
6490 ctxt->value->floatval = f + 1;
6491#endif
6492}
6493
6494/**
6495 * xmlXPathRoundFunction:
6496 * @ctxt: the XPath Parser context
6497 * @nargs: the number of arguments
6498 *
6499 * Implement the round() XPath function
6500 * number round(number)
6501 * The round function returns the number that is closest to the
6502 * argument and that is an integer. If there are two such numbers,
6503 * then the one that is even is returned.
6504 */
6505void
6506xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6507 double f;
6508
6509 CHECK_ARITY(1);
6510 CAST_TO_NUMBER;
6511 CHECK_TYPE(XPATH_NUMBER);
6512
Daniel Veillardcda96922001-08-21 10:56:31 +00006513 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
6514 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
6515 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00006516 (ctxt->value->floatval == 0.0))
6517 return;
6518
6519#if 0
6520 f = floor(ctxt->value->floatval);
6521#else
6522 f = (double)((int) ctxt->value->floatval);
6523#endif
6524 if (ctxt->value->floatval < f + 0.5)
6525 ctxt->value->floatval = f;
6526 else
6527 ctxt->value->floatval = f + 1;
6528}
6529
6530/************************************************************************
6531 * *
6532 * The Parser *
6533 * *
6534 ************************************************************************/
6535
6536/*
6537 * a couple of forward declarations since we use a recursive call based
6538 * implementation.
6539 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006540static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006541static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006542static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006543#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006544static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
6545#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006546#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006547static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006548#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00006549static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
6550 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00006551
6552/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00006553 * xmlXPathCurrentChar:
6554 * @ctxt: the XPath parser context
6555 * @cur: pointer to the beginning of the char
6556 * @len: pointer to the length of the char read
6557 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006558 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00006559 * bytes in the input buffer.
6560 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006561 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00006562 */
6563
6564static int
6565xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
6566 unsigned char c;
6567 unsigned int val;
6568 const xmlChar *cur;
6569
6570 if (ctxt == NULL)
6571 return(0);
6572 cur = ctxt->cur;
6573
6574 /*
6575 * We are supposed to handle UTF8, check it's valid
6576 * From rfc2044: encoding of the Unicode values on UTF-8:
6577 *
6578 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
6579 * 0000 0000-0000 007F 0xxxxxxx
6580 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
6581 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
6582 *
6583 * Check for the 0x110000 limit too
6584 */
6585 c = *cur;
6586 if (c & 0x80) {
6587 if ((cur[1] & 0xc0) != 0x80)
6588 goto encoding_error;
6589 if ((c & 0xe0) == 0xe0) {
6590
6591 if ((cur[2] & 0xc0) != 0x80)
6592 goto encoding_error;
6593 if ((c & 0xf0) == 0xf0) {
6594 if (((c & 0xf8) != 0xf0) ||
6595 ((cur[3] & 0xc0) != 0x80))
6596 goto encoding_error;
6597 /* 4-byte code */
6598 *len = 4;
6599 val = (cur[0] & 0x7) << 18;
6600 val |= (cur[1] & 0x3f) << 12;
6601 val |= (cur[2] & 0x3f) << 6;
6602 val |= cur[3] & 0x3f;
6603 } else {
6604 /* 3-byte code */
6605 *len = 3;
6606 val = (cur[0] & 0xf) << 12;
6607 val |= (cur[1] & 0x3f) << 6;
6608 val |= cur[2] & 0x3f;
6609 }
6610 } else {
6611 /* 2-byte code */
6612 *len = 2;
6613 val = (cur[0] & 0x1f) << 6;
6614 val |= cur[1] & 0x3f;
6615 }
6616 if (!IS_CHAR(val)) {
6617 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
6618 }
6619 return(val);
6620 } else {
6621 /* 1-byte code */
6622 *len = 1;
6623 return((int) *cur);
6624 }
6625encoding_error:
6626 /*
6627 * If we detect an UTF8 error that probably mean that the
6628 * input encoding didn't get properly advertized in the
6629 * declaration header. Report the error and switch the encoding
6630 * to ISO-Latin-1 (if you don't like this policy, just declare the
6631 * encoding !)
6632 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00006633 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00006634 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006635}
6636
6637/**
Owen Taylor3473f882001-02-23 17:55:21 +00006638 * xmlXPathParseNCName:
6639 * @ctxt: the XPath Parser context
6640 *
6641 * parse an XML namespace non qualified name.
6642 *
6643 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
6644 *
6645 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
6646 * CombiningChar | Extender
6647 *
6648 * Returns the namespace name or NULL
6649 */
6650
6651xmlChar *
6652xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00006653 const xmlChar *in;
6654 xmlChar *ret;
6655 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006656
Daniel Veillard2156a562001-04-28 12:24:34 +00006657 /*
6658 * Accelerator for simple ASCII names
6659 */
6660 in = ctxt->cur;
6661 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6662 ((*in >= 0x41) && (*in <= 0x5A)) ||
6663 (*in == '_')) {
6664 in++;
6665 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6666 ((*in >= 0x41) && (*in <= 0x5A)) ||
6667 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00006668 (*in == '_') || (*in == '.') ||
6669 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00006670 in++;
6671 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
6672 (*in == '[') || (*in == ']') || (*in == ':') ||
6673 (*in == '@') || (*in == '*')) {
6674 count = in - ctxt->cur;
6675 if (count == 0)
6676 return(NULL);
6677 ret = xmlStrndup(ctxt->cur, count);
6678 ctxt->cur = in;
6679 return(ret);
6680 }
6681 }
6682 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00006683}
6684
Daniel Veillard2156a562001-04-28 12:24:34 +00006685
Owen Taylor3473f882001-02-23 17:55:21 +00006686/**
6687 * xmlXPathParseQName:
6688 * @ctxt: the XPath Parser context
6689 * @prefix: a xmlChar **
6690 *
6691 * parse an XML qualified name
6692 *
6693 * [NS 5] QName ::= (Prefix ':')? LocalPart
6694 *
6695 * [NS 6] Prefix ::= NCName
6696 *
6697 * [NS 7] LocalPart ::= NCName
6698 *
6699 * Returns the function returns the local part, and prefix is updated
6700 * to get the Prefix if any.
6701 */
6702
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006703static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006704xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
6705 xmlChar *ret = NULL;
6706
6707 *prefix = NULL;
6708 ret = xmlXPathParseNCName(ctxt);
6709 if (CUR == ':') {
6710 *prefix = ret;
6711 NEXT;
6712 ret = xmlXPathParseNCName(ctxt);
6713 }
6714 return(ret);
6715}
6716
6717/**
6718 * xmlXPathParseName:
6719 * @ctxt: the XPath Parser context
6720 *
6721 * parse an XML name
6722 *
6723 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6724 * CombiningChar | Extender
6725 *
6726 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6727 *
6728 * Returns the namespace name or NULL
6729 */
6730
6731xmlChar *
6732xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006733 const xmlChar *in;
6734 xmlChar *ret;
6735 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006736
Daniel Veillard61d80a22001-04-27 17:13:01 +00006737 /*
6738 * Accelerator for simple ASCII names
6739 */
6740 in = ctxt->cur;
6741 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6742 ((*in >= 0x41) && (*in <= 0x5A)) ||
6743 (*in == '_') || (*in == ':')) {
6744 in++;
6745 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6746 ((*in >= 0x41) && (*in <= 0x5A)) ||
6747 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00006748 (*in == '_') || (*in == '-') ||
6749 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00006750 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00006751 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006752 count = in - ctxt->cur;
6753 ret = xmlStrndup(ctxt->cur, count);
6754 ctxt->cur = in;
6755 return(ret);
6756 }
6757 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006758 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00006759}
6760
Daniel Veillard61d80a22001-04-27 17:13:01 +00006761static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00006762xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006763 xmlChar buf[XML_MAX_NAMELEN + 5];
6764 int len = 0, l;
6765 int c;
6766
6767 /*
6768 * Handler for more complex cases
6769 */
6770 c = CUR_CHAR(l);
6771 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00006772 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
6773 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00006774 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00006775 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006776 return(NULL);
6777 }
6778
6779 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
6780 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
6781 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006782 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006783 (IS_COMBINING(c)) ||
6784 (IS_EXTENDER(c)))) {
6785 COPY_BUF(l,buf,len,c);
6786 NEXTL(l);
6787 c = CUR_CHAR(l);
6788 if (len >= XML_MAX_NAMELEN) {
6789 /*
6790 * Okay someone managed to make a huge name, so he's ready to pay
6791 * for the processing speed.
6792 */
6793 xmlChar *buffer;
6794 int max = len * 2;
6795
6796 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
6797 if (buffer == NULL) {
6798 XP_ERROR0(XPATH_MEMORY_ERROR);
6799 }
6800 memcpy(buffer, buf, len);
6801 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
6802 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006803 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006804 (IS_COMBINING(c)) ||
6805 (IS_EXTENDER(c))) {
6806 if (len + 10 > max) {
6807 max *= 2;
6808 buffer = (xmlChar *) xmlRealloc(buffer,
6809 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00006810 if (buffer == NULL) {
6811 XP_ERROR0(XPATH_MEMORY_ERROR);
6812 }
6813 }
6814 COPY_BUF(l,buffer,len,c);
6815 NEXTL(l);
6816 c = CUR_CHAR(l);
6817 }
6818 buffer[len] = 0;
6819 return(buffer);
6820 }
6821 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006822 if (len == 0)
6823 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006824 return(xmlStrndup(buf, len));
6825}
Owen Taylor3473f882001-02-23 17:55:21 +00006826/**
6827 * xmlXPathStringEvalNumber:
6828 * @str: A string to scan
6829 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00006830 * [30a] Float ::= Number ('e' Digits?)?
6831 *
Owen Taylor3473f882001-02-23 17:55:21 +00006832 * [30] Number ::= Digits ('.' Digits?)?
6833 * | '.' Digits
6834 * [31] Digits ::= [0-9]+
6835 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006836 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00006837 * In complement of the Number expression, this function also handles
6838 * negative values : '-' Number.
6839 *
6840 * Returns the double value.
6841 */
6842double
6843xmlXPathStringEvalNumber(const xmlChar *str) {
6844 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00006845 double ret;
Owen Taylor3473f882001-02-23 17:55:21 +00006846 double mult = 1;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006847 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006848 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006849 int exponent = 0;
6850 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006851#ifdef __GNUC__
6852 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00006853 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006854#endif
Bjorn Reese70a9da52001-04-21 16:57:29 +00006855
Owen Taylor3473f882001-02-23 17:55:21 +00006856 while (IS_BLANK(*cur)) cur++;
6857 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
6858 return(xmlXPathNAN);
6859 }
6860 if (*cur == '-') {
6861 isneg = 1;
6862 cur++;
6863 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00006864
6865#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006866 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00006867 * tmp/temp is a workaround against a gcc compiler bug
6868 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006869 */
Daniel Veillard7b416132002-03-07 08:36:03 +00006870 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006871 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00006872 ret = ret * 10;
6873 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00006874 ok = 1;
6875 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00006876 temp = (double) tmp;
6877 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00006878 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00006879#else
Daniel Veillard7b416132002-03-07 08:36:03 +00006880 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006881 while ((*cur >= '0') && (*cur <= '9')) {
6882 ret = ret * 10 + (*cur - '0');
6883 ok = 1;
6884 cur++;
6885 }
6886#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006887
Owen Taylor3473f882001-02-23 17:55:21 +00006888 if (*cur == '.') {
6889 cur++;
6890 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
6891 return(xmlXPathNAN);
6892 }
6893 while ((*cur >= '0') && (*cur <= '9')) {
6894 mult /= 10;
6895 ret = ret + (*cur - '0') * mult;
6896 cur++;
6897 }
6898 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006899 if ((*cur == 'e') || (*cur == 'E')) {
6900 cur++;
6901 if (*cur == '-') {
6902 is_exponent_negative = 1;
6903 cur++;
6904 }
6905 while ((*cur >= '0') && (*cur <= '9')) {
6906 exponent = exponent * 10 + (*cur - '0');
6907 cur++;
6908 }
6909 }
Owen Taylor3473f882001-02-23 17:55:21 +00006910 while (IS_BLANK(*cur)) cur++;
6911 if (*cur != 0) return(xmlXPathNAN);
6912 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006913 if (is_exponent_negative) exponent = -exponent;
6914 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00006915 return(ret);
6916}
6917
6918/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006919 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00006920 * @ctxt: the XPath Parser context
6921 *
6922 * [30] Number ::= Digits ('.' Digits?)?
6923 * | '.' Digits
6924 * [31] Digits ::= [0-9]+
6925 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006926 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00006927 *
6928 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006929static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006930xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
6931{
Owen Taylor3473f882001-02-23 17:55:21 +00006932 double ret = 0.0;
6933 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00006934 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006935 int exponent = 0;
6936 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00006937#ifdef __GNUC__
6938 unsigned long tmp = 0;
6939 double temp;
6940#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006941
6942 CHECK_ERROR;
6943 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
6944 XP_ERROR(XPATH_NUMBER_ERROR);
6945 }
Daniel Veillard7b416132002-03-07 08:36:03 +00006946#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006947 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00006948 * tmp/temp is a workaround against a gcc compiler bug
6949 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006950 */
Daniel Veillard7b416132002-03-07 08:36:03 +00006951 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006952 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00006953 ret = ret * 10;
6954 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006955 ok = 1;
6956 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00006957 temp = (double) tmp;
6958 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00006959 }
Daniel Veillard7b416132002-03-07 08:36:03 +00006960#else
6961 ret = 0;
6962 while ((CUR >= '0') && (CUR <= '9')) {
6963 ret = ret * 10 + (CUR - '0');
6964 ok = 1;
6965 NEXT;
6966 }
6967#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006968 if (CUR == '.') {
6969 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006970 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
6971 XP_ERROR(XPATH_NUMBER_ERROR);
6972 }
6973 while ((CUR >= '0') && (CUR <= '9')) {
6974 mult /= 10;
6975 ret = ret + (CUR - '0') * mult;
6976 NEXT;
6977 }
Owen Taylor3473f882001-02-23 17:55:21 +00006978 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006979 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006980 NEXT;
6981 if (CUR == '-') {
6982 is_exponent_negative = 1;
6983 NEXT;
6984 }
6985 while ((CUR >= '0') && (CUR <= '9')) {
6986 exponent = exponent * 10 + (CUR - '0');
6987 NEXT;
6988 }
6989 if (is_exponent_negative)
6990 exponent = -exponent;
6991 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006992 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006993 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006994 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006995}
6996
6997/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006998 * xmlXPathParseLiteral:
6999 * @ctxt: the XPath Parser context
7000 *
7001 * Parse a Literal
7002 *
7003 * [29] Literal ::= '"' [^"]* '"'
7004 * | "'" [^']* "'"
7005 *
7006 * Returns the value found or NULL in case of error
7007 */
7008static xmlChar *
7009xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7010 const xmlChar *q;
7011 xmlChar *ret = NULL;
7012
7013 if (CUR == '"') {
7014 NEXT;
7015 q = CUR_PTR;
7016 while ((IS_CHAR(CUR)) && (CUR != '"'))
7017 NEXT;
7018 if (!IS_CHAR(CUR)) {
7019 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7020 } else {
7021 ret = xmlStrndup(q, CUR_PTR - q);
7022 NEXT;
7023 }
7024 } else if (CUR == '\'') {
7025 NEXT;
7026 q = CUR_PTR;
7027 while ((IS_CHAR(CUR)) && (CUR != '\''))
7028 NEXT;
7029 if (!IS_CHAR(CUR)) {
7030 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7031 } else {
7032 ret = xmlStrndup(q, CUR_PTR - q);
7033 NEXT;
7034 }
7035 } else {
7036 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7037 }
7038 return(ret);
7039}
7040
7041/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007042 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007043 * @ctxt: the XPath Parser context
7044 *
7045 * Parse a Literal and push it on the stack.
7046 *
7047 * [29] Literal ::= '"' [^"]* '"'
7048 * | "'" [^']* "'"
7049 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007050 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007051 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007052static void
7053xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007054 const xmlChar *q;
7055 xmlChar *ret = NULL;
7056
7057 if (CUR == '"') {
7058 NEXT;
7059 q = CUR_PTR;
7060 while ((IS_CHAR(CUR)) && (CUR != '"'))
7061 NEXT;
7062 if (!IS_CHAR(CUR)) {
7063 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7064 } else {
7065 ret = xmlStrndup(q, CUR_PTR - q);
7066 NEXT;
7067 }
7068 } else if (CUR == '\'') {
7069 NEXT;
7070 q = CUR_PTR;
7071 while ((IS_CHAR(CUR)) && (CUR != '\''))
7072 NEXT;
7073 if (!IS_CHAR(CUR)) {
7074 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7075 } else {
7076 ret = xmlStrndup(q, CUR_PTR - q);
7077 NEXT;
7078 }
7079 } else {
7080 XP_ERROR(XPATH_START_LITERAL_ERROR);
7081 }
7082 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007083 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7084 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007085 xmlFree(ret);
7086}
7087
7088/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007089 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007090 * @ctxt: the XPath Parser context
7091 *
7092 * Parse a VariableReference, evaluate it and push it on the stack.
7093 *
7094 * The variable bindings consist of a mapping from variable names
7095 * to variable values. The value of a variable is an object, which
7096 * of any of the types that are possible for the value of an expression,
7097 * and may also be of additional types not specified here.
7098 *
7099 * Early evaluation is possible since:
7100 * The variable bindings [...] used to evaluate a subexpression are
7101 * always the same as those used to evaluate the containing expression.
7102 *
7103 * [36] VariableReference ::= '$' QName
7104 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007105static void
7106xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007107 xmlChar *name;
7108 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007109
7110 SKIP_BLANKS;
7111 if (CUR != '$') {
7112 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7113 }
7114 NEXT;
7115 name = xmlXPathParseQName(ctxt, &prefix);
7116 if (name == NULL) {
7117 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7118 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007119 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007120 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7121 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007122 SKIP_BLANKS;
7123}
7124
7125/**
7126 * xmlXPathIsNodeType:
7127 * @ctxt: the XPath Parser context
7128 * @name: a name string
7129 *
7130 * Is the name given a NodeType one.
7131 *
7132 * [38] NodeType ::= 'comment'
7133 * | 'text'
7134 * | 'processing-instruction'
7135 * | 'node'
7136 *
7137 * Returns 1 if true 0 otherwise
7138 */
7139int
7140xmlXPathIsNodeType(const xmlChar *name) {
7141 if (name == NULL)
7142 return(0);
7143
Daniel Veillard1971ee22002-01-31 20:29:19 +00007144 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007145 return(1);
7146 if (xmlStrEqual(name, BAD_CAST "text"))
7147 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007148 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007149 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007150 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007151 return(1);
7152 return(0);
7153}
7154
7155/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007156 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007157 * @ctxt: the XPath Parser context
7158 *
7159 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7160 * [17] Argument ::= Expr
7161 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007162 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007163 * pushed on the stack
7164 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007165static void
7166xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007167 xmlChar *name;
7168 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007169 int nbargs = 0;
7170
7171 name = xmlXPathParseQName(ctxt, &prefix);
7172 if (name == NULL) {
7173 XP_ERROR(XPATH_EXPR_ERROR);
7174 }
7175 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007176#ifdef DEBUG_EXPR
7177 if (prefix == NULL)
7178 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7179 name);
7180 else
7181 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7182 prefix, name);
7183#endif
7184
Owen Taylor3473f882001-02-23 17:55:21 +00007185 if (CUR != '(') {
7186 XP_ERROR(XPATH_EXPR_ERROR);
7187 }
7188 NEXT;
7189 SKIP_BLANKS;
7190
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007191 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00007192 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007193 int op1 = ctxt->comp->last;
7194 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007195 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007196 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007197 nbargs++;
7198 if (CUR == ')') break;
7199 if (CUR != ',') {
7200 XP_ERROR(XPATH_EXPR_ERROR);
7201 }
7202 NEXT;
7203 SKIP_BLANKS;
7204 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007205 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7206 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007207 NEXT;
7208 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007209}
7210
7211/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007212 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007213 * @ctxt: the XPath Parser context
7214 *
7215 * [15] PrimaryExpr ::= VariableReference
7216 * | '(' Expr ')'
7217 * | Literal
7218 * | Number
7219 * | FunctionCall
7220 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007221 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007222 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007223static void
7224xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007225 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007226 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007227 else if (CUR == '(') {
7228 NEXT;
7229 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007230 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007231 if (CUR != ')') {
7232 XP_ERROR(XPATH_EXPR_ERROR);
7233 }
7234 NEXT;
7235 SKIP_BLANKS;
7236 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007237 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007238 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007239 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007240 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007241 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007242 }
7243 SKIP_BLANKS;
7244}
7245
7246/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007247 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007248 * @ctxt: the XPath Parser context
7249 *
7250 * [20] FilterExpr ::= PrimaryExpr
7251 * | FilterExpr Predicate
7252 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007253 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007254 * Square brackets are used to filter expressions in the same way that
7255 * they are used in location paths. It is an error if the expression to
7256 * be filtered does not evaluate to a node-set. The context node list
7257 * used for evaluating the expression in square brackets is the node-set
7258 * to be filtered listed in document order.
7259 */
7260
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007261static void
7262xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7263 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007264 CHECK_ERROR;
7265 SKIP_BLANKS;
7266
7267 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007268 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007269 SKIP_BLANKS;
7270 }
7271
7272
7273}
7274
7275/**
7276 * xmlXPathScanName:
7277 * @ctxt: the XPath Parser context
7278 *
7279 * Trickery: parse an XML name but without consuming the input flow
7280 * Needed to avoid insanity in the parser state.
7281 *
7282 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7283 * CombiningChar | Extender
7284 *
7285 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7286 *
7287 * [6] Names ::= Name (S Name)*
7288 *
7289 * Returns the Name parsed or NULL
7290 */
7291
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007292static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007293xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7294 xmlChar buf[XML_MAX_NAMELEN];
7295 int len = 0;
7296
7297 SKIP_BLANKS;
7298 if (!IS_LETTER(CUR) && (CUR != '_') &&
7299 (CUR != ':')) {
7300 return(NULL);
7301 }
7302
7303 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7304 (NXT(len) == '.') || (NXT(len) == '-') ||
7305 (NXT(len) == '_') || (NXT(len) == ':') ||
7306 (IS_COMBINING(NXT(len))) ||
7307 (IS_EXTENDER(NXT(len)))) {
7308 buf[len] = NXT(len);
7309 len++;
7310 if (len >= XML_MAX_NAMELEN) {
7311 xmlGenericError(xmlGenericErrorContext,
7312 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7313 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7314 (NXT(len) == '.') || (NXT(len) == '-') ||
7315 (NXT(len) == '_') || (NXT(len) == ':') ||
7316 (IS_COMBINING(NXT(len))) ||
7317 (IS_EXTENDER(NXT(len))))
7318 len++;
7319 break;
7320 }
7321 }
7322 return(xmlStrndup(buf, len));
7323}
7324
7325/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007326 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007327 * @ctxt: the XPath Parser context
7328 *
7329 * [19] PathExpr ::= LocationPath
7330 * | FilterExpr
7331 * | FilterExpr '/' RelativeLocationPath
7332 * | FilterExpr '//' RelativeLocationPath
7333 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007334 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007335 * The / operator and // operators combine an arbitrary expression
7336 * and a relative location path. It is an error if the expression
7337 * does not evaluate to a node-set.
7338 * The / operator does composition in the same way as when / is
7339 * used in a location path. As in location paths, // is short for
7340 * /descendant-or-self::node()/.
7341 */
7342
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007343static void
7344xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007345 int lc = 1; /* Should we branch to LocationPath ? */
7346 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7347
7348 SKIP_BLANKS;
7349 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
7350 (CUR == '\'') || (CUR == '"')) {
7351 lc = 0;
7352 } else if (CUR == '*') {
7353 /* relative or absolute location path */
7354 lc = 1;
7355 } else if (CUR == '/') {
7356 /* relative or absolute location path */
7357 lc = 1;
7358 } else if (CUR == '@') {
7359 /* relative abbreviated attribute location path */
7360 lc = 1;
7361 } else if (CUR == '.') {
7362 /* relative abbreviated attribute location path */
7363 lc = 1;
7364 } else {
7365 /*
7366 * Problem is finding if we have a name here whether it's:
7367 * - a nodetype
7368 * - a function call in which case it's followed by '('
7369 * - an axis in which case it's followed by ':'
7370 * - a element name
7371 * We do an a priori analysis here rather than having to
7372 * maintain parsed token content through the recursive function
7373 * calls. This looks uglier but makes the code quite easier to
7374 * read/write/debug.
7375 */
7376 SKIP_BLANKS;
7377 name = xmlXPathScanName(ctxt);
7378 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7379#ifdef DEBUG_STEP
7380 xmlGenericError(xmlGenericErrorContext,
7381 "PathExpr: Axis\n");
7382#endif
7383 lc = 1;
7384 xmlFree(name);
7385 } else if (name != NULL) {
7386 int len =xmlStrlen(name);
7387 int blank = 0;
7388
7389
7390 while (NXT(len) != 0) {
7391 if (NXT(len) == '/') {
7392 /* element name */
7393#ifdef DEBUG_STEP
7394 xmlGenericError(xmlGenericErrorContext,
7395 "PathExpr: AbbrRelLocation\n");
7396#endif
7397 lc = 1;
7398 break;
7399 } else if (IS_BLANK(NXT(len))) {
7400 /* skip to next */
7401 blank = 1;
7402 } else if (NXT(len) == ':') {
7403#ifdef DEBUG_STEP
7404 xmlGenericError(xmlGenericErrorContext,
7405 "PathExpr: AbbrRelLocation\n");
7406#endif
7407 lc = 1;
7408 break;
7409 } else if ((NXT(len) == '(')) {
7410 /* Note Type or Function */
7411 if (xmlXPathIsNodeType(name)) {
7412#ifdef DEBUG_STEP
7413 xmlGenericError(xmlGenericErrorContext,
7414 "PathExpr: Type search\n");
7415#endif
7416 lc = 1;
7417 } else {
7418#ifdef DEBUG_STEP
7419 xmlGenericError(xmlGenericErrorContext,
7420 "PathExpr: function call\n");
7421#endif
7422 lc = 0;
7423 }
7424 break;
7425 } else if ((NXT(len) == '[')) {
7426 /* element name */
7427#ifdef DEBUG_STEP
7428 xmlGenericError(xmlGenericErrorContext,
7429 "PathExpr: AbbrRelLocation\n");
7430#endif
7431 lc = 1;
7432 break;
7433 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7434 (NXT(len) == '=')) {
7435 lc = 1;
7436 break;
7437 } else {
7438 lc = 1;
7439 break;
7440 }
7441 len++;
7442 }
7443 if (NXT(len) == 0) {
7444#ifdef DEBUG_STEP
7445 xmlGenericError(xmlGenericErrorContext,
7446 "PathExpr: AbbrRelLocation\n");
7447#endif
7448 /* element name */
7449 lc = 1;
7450 }
7451 xmlFree(name);
7452 } else {
7453 /* make sure all cases are covered explicitely */
7454 XP_ERROR(XPATH_EXPR_ERROR);
7455 }
7456 }
7457
7458 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007459 if (CUR == '/') {
7460 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7461 } else {
7462 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007463 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007464 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007465 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007466 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007467 CHECK_ERROR;
7468 if ((CUR == '/') && (NXT(1) == '/')) {
7469 SKIP(2);
7470 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007471
7472 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7473 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7474 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7475
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007476 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007477 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007478 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007479 }
7480 }
7481 SKIP_BLANKS;
7482}
7483
7484/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007485 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007486 * @ctxt: the XPath Parser context
7487 *
7488 * [18] UnionExpr ::= PathExpr
7489 * | UnionExpr '|' PathExpr
7490 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007491 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007492 */
7493
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007494static void
7495xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7496 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007497 CHECK_ERROR;
7498 SKIP_BLANKS;
7499 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007500 int op1 = ctxt->comp->last;
7501 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007502
7503 NEXT;
7504 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007505 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007506
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007507 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
7508
Owen Taylor3473f882001-02-23 17:55:21 +00007509 SKIP_BLANKS;
7510 }
Owen Taylor3473f882001-02-23 17:55:21 +00007511}
7512
7513/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007514 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007515 * @ctxt: the XPath Parser context
7516 *
7517 * [27] UnaryExpr ::= UnionExpr
7518 * | '-' UnaryExpr
7519 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007520 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007521 */
7522
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007523static void
7524xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007525 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007526 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007527
7528 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00007529 while (CUR == '-') {
7530 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007531 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007532 NEXT;
7533 SKIP_BLANKS;
7534 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007535
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007536 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007537 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007538 if (found) {
7539 if (minus)
7540 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
7541 else
7542 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007543 }
7544}
7545
7546/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007547 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007548 * @ctxt: the XPath Parser context
7549 *
7550 * [26] MultiplicativeExpr ::= UnaryExpr
7551 * | MultiplicativeExpr MultiplyOperator UnaryExpr
7552 * | MultiplicativeExpr 'div' UnaryExpr
7553 * | MultiplicativeExpr 'mod' UnaryExpr
7554 * [34] MultiplyOperator ::= '*'
7555 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007556 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007557 */
7558
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007559static void
7560xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
7561 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007562 CHECK_ERROR;
7563 SKIP_BLANKS;
7564 while ((CUR == '*') ||
7565 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
7566 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
7567 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007568 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007569
7570 if (CUR == '*') {
7571 op = 0;
7572 NEXT;
7573 } else if (CUR == 'd') {
7574 op = 1;
7575 SKIP(3);
7576 } else if (CUR == 'm') {
7577 op = 2;
7578 SKIP(3);
7579 }
7580 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007581 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007582 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007583 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007584 SKIP_BLANKS;
7585 }
7586}
7587
7588/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007589 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007590 * @ctxt: the XPath Parser context
7591 *
7592 * [25] AdditiveExpr ::= MultiplicativeExpr
7593 * | AdditiveExpr '+' MultiplicativeExpr
7594 * | AdditiveExpr '-' MultiplicativeExpr
7595 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007596 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007597 */
7598
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007599static void
7600xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007601
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007602 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007603 CHECK_ERROR;
7604 SKIP_BLANKS;
7605 while ((CUR == '+') || (CUR == '-')) {
7606 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007607 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007608
7609 if (CUR == '+') plus = 1;
7610 else plus = 0;
7611 NEXT;
7612 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007613 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007614 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007615 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007616 SKIP_BLANKS;
7617 }
7618}
7619
7620/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007621 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007622 * @ctxt: the XPath Parser context
7623 *
7624 * [24] RelationalExpr ::= AdditiveExpr
7625 * | RelationalExpr '<' AdditiveExpr
7626 * | RelationalExpr '>' AdditiveExpr
7627 * | RelationalExpr '<=' AdditiveExpr
7628 * | RelationalExpr '>=' AdditiveExpr
7629 *
7630 * A <= B > C is allowed ? Answer from James, yes with
7631 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
7632 * which is basically what got implemented.
7633 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007634 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00007635 * on the stack
7636 */
7637
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007638static void
7639xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
7640 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007641 CHECK_ERROR;
7642 SKIP_BLANKS;
7643 while ((CUR == '<') ||
7644 (CUR == '>') ||
7645 ((CUR == '<') && (NXT(1) == '=')) ||
7646 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007647 int inf, strict;
7648 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007649
7650 if (CUR == '<') inf = 1;
7651 else inf = 0;
7652 if (NXT(1) == '=') strict = 0;
7653 else strict = 1;
7654 NEXT;
7655 if (!strict) NEXT;
7656 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007657 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007658 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007659 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00007660 SKIP_BLANKS;
7661 }
7662}
7663
7664/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007665 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007666 * @ctxt: the XPath Parser context
7667 *
7668 * [23] EqualityExpr ::= RelationalExpr
7669 * | EqualityExpr '=' RelationalExpr
7670 * | EqualityExpr '!=' RelationalExpr
7671 *
7672 * A != B != C is allowed ? Answer from James, yes with
7673 * (RelationalExpr = RelationalExpr) = RelationalExpr
7674 * (RelationalExpr != RelationalExpr) != RelationalExpr
7675 * which is basically what got implemented.
7676 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007677 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007678 *
7679 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007680static void
7681xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
7682 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007683 CHECK_ERROR;
7684 SKIP_BLANKS;
7685 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007686 int eq;
7687 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007688
7689 if (CUR == '=') eq = 1;
7690 else eq = 0;
7691 NEXT;
7692 if (!eq) NEXT;
7693 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007694 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007695 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007696 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007697 SKIP_BLANKS;
7698 }
7699}
7700
7701/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007702 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007703 * @ctxt: the XPath Parser context
7704 *
7705 * [22] AndExpr ::= EqualityExpr
7706 * | AndExpr 'and' EqualityExpr
7707 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007708 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007709 *
7710 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007711static void
7712xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
7713 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007714 CHECK_ERROR;
7715 SKIP_BLANKS;
7716 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007717 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007718 SKIP(3);
7719 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007720 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007721 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007722 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007723 SKIP_BLANKS;
7724 }
7725}
7726
7727/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007728 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007729 * @ctxt: the XPath Parser context
7730 *
7731 * [14] Expr ::= OrExpr
7732 * [21] OrExpr ::= AndExpr
7733 * | OrExpr 'or' AndExpr
7734 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007735 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00007736 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007737static void
7738xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
7739 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007740 CHECK_ERROR;
7741 SKIP_BLANKS;
7742 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007743 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007744 SKIP(2);
7745 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007746 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007747 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007748 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
7749 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00007750 SKIP_BLANKS;
7751 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007752 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
7753 /* more ops could be optimized too */
7754 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
7755 }
Owen Taylor3473f882001-02-23 17:55:21 +00007756}
7757
7758/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007759 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00007760 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007761 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00007762 *
7763 * [8] Predicate ::= '[' PredicateExpr ']'
7764 * [9] PredicateExpr ::= Expr
7765 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007766 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00007767 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007768static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007769xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007770 int op1 = ctxt->comp->last;
7771
7772 SKIP_BLANKS;
7773 if (CUR != '[') {
7774 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7775 }
7776 NEXT;
7777 SKIP_BLANKS;
7778
7779 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007780 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007781 CHECK_ERROR;
7782
7783 if (CUR != ']') {
7784 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7785 }
7786
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007787 if (filter)
7788 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
7789 else
7790 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007791
7792 NEXT;
7793 SKIP_BLANKS;
7794}
7795
7796/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007797 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00007798 * @ctxt: the XPath Parser context
7799 * @test: pointer to a xmlXPathTestVal
7800 * @type: pointer to a xmlXPathTypeVal
7801 * @prefix: placeholder for a possible name prefix
7802 *
7803 * [7] NodeTest ::= NameTest
7804 * | NodeType '(' ')'
7805 * | 'processing-instruction' '(' Literal ')'
7806 *
7807 * [37] NameTest ::= '*'
7808 * | NCName ':' '*'
7809 * | QName
7810 * [38] NodeType ::= 'comment'
7811 * | 'text'
7812 * | 'processing-instruction'
7813 * | 'node'
7814 *
7815 * Returns the name found and update @test, @type and @prefix appropriately
7816 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007817static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007818xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
7819 xmlXPathTypeVal *type, const xmlChar **prefix,
7820 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00007821 int blanks;
7822
7823 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
7824 STRANGE;
7825 return(NULL);
7826 }
7827 *type = 0;
7828 *test = 0;
7829 *prefix = NULL;
7830 SKIP_BLANKS;
7831
7832 if ((name == NULL) && (CUR == '*')) {
7833 /*
7834 * All elements
7835 */
7836 NEXT;
7837 *test = NODE_TEST_ALL;
7838 return(NULL);
7839 }
7840
7841 if (name == NULL)
7842 name = xmlXPathParseNCName(ctxt);
7843 if (name == NULL) {
7844 XP_ERROR0(XPATH_EXPR_ERROR);
7845 }
7846
7847 blanks = IS_BLANK(CUR);
7848 SKIP_BLANKS;
7849 if (CUR == '(') {
7850 NEXT;
7851 /*
7852 * NodeType or PI search
7853 */
7854 if (xmlStrEqual(name, BAD_CAST "comment"))
7855 *type = NODE_TYPE_COMMENT;
7856 else if (xmlStrEqual(name, BAD_CAST "node"))
7857 *type = NODE_TYPE_NODE;
7858 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
7859 *type = NODE_TYPE_PI;
7860 else if (xmlStrEqual(name, BAD_CAST "text"))
7861 *type = NODE_TYPE_TEXT;
7862 else {
7863 if (name != NULL)
7864 xmlFree(name);
7865 XP_ERROR0(XPATH_EXPR_ERROR);
7866 }
7867
7868 *test = NODE_TEST_TYPE;
7869
7870 SKIP_BLANKS;
7871 if (*type == NODE_TYPE_PI) {
7872 /*
7873 * Specific case: search a PI by name.
7874 */
Owen Taylor3473f882001-02-23 17:55:21 +00007875 if (name != NULL)
7876 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00007877 name = NULL;
7878 if (CUR != ')') {
7879 name = xmlXPathParseLiteral(ctxt);
7880 CHECK_ERROR 0;
7881 SKIP_BLANKS;
7882 }
Owen Taylor3473f882001-02-23 17:55:21 +00007883 }
7884 if (CUR != ')') {
7885 if (name != NULL)
7886 xmlFree(name);
7887 XP_ERROR0(XPATH_UNCLOSED_ERROR);
7888 }
7889 NEXT;
7890 return(name);
7891 }
7892 *test = NODE_TEST_NAME;
7893 if ((!blanks) && (CUR == ':')) {
7894 NEXT;
7895
7896 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007897 * Since currently the parser context don't have a
7898 * namespace list associated:
7899 * The namespace name for this prefix can be computed
7900 * only at evaluation time. The compilation is done
7901 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00007902 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007903#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00007904 *prefix = xmlXPathNsLookup(ctxt->context, name);
7905 if (name != NULL)
7906 xmlFree(name);
7907 if (*prefix == NULL) {
7908 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
7909 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007910#else
7911 *prefix = name;
7912#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007913
7914 if (CUR == '*') {
7915 /*
7916 * All elements
7917 */
7918 NEXT;
7919 *test = NODE_TEST_ALL;
7920 return(NULL);
7921 }
7922
7923 name = xmlXPathParseNCName(ctxt);
7924 if (name == NULL) {
7925 XP_ERROR0(XPATH_EXPR_ERROR);
7926 }
7927 }
7928 return(name);
7929}
7930
7931/**
7932 * xmlXPathIsAxisName:
7933 * @name: a preparsed name token
7934 *
7935 * [6] AxisName ::= 'ancestor'
7936 * | 'ancestor-or-self'
7937 * | 'attribute'
7938 * | 'child'
7939 * | 'descendant'
7940 * | 'descendant-or-self'
7941 * | 'following'
7942 * | 'following-sibling'
7943 * | 'namespace'
7944 * | 'parent'
7945 * | 'preceding'
7946 * | 'preceding-sibling'
7947 * | 'self'
7948 *
7949 * Returns the axis or 0
7950 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007951static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00007952xmlXPathIsAxisName(const xmlChar *name) {
7953 xmlXPathAxisVal ret = 0;
7954 switch (name[0]) {
7955 case 'a':
7956 if (xmlStrEqual(name, BAD_CAST "ancestor"))
7957 ret = AXIS_ANCESTOR;
7958 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
7959 ret = AXIS_ANCESTOR_OR_SELF;
7960 if (xmlStrEqual(name, BAD_CAST "attribute"))
7961 ret = AXIS_ATTRIBUTE;
7962 break;
7963 case 'c':
7964 if (xmlStrEqual(name, BAD_CAST "child"))
7965 ret = AXIS_CHILD;
7966 break;
7967 case 'd':
7968 if (xmlStrEqual(name, BAD_CAST "descendant"))
7969 ret = AXIS_DESCENDANT;
7970 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
7971 ret = AXIS_DESCENDANT_OR_SELF;
7972 break;
7973 case 'f':
7974 if (xmlStrEqual(name, BAD_CAST "following"))
7975 ret = AXIS_FOLLOWING;
7976 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
7977 ret = AXIS_FOLLOWING_SIBLING;
7978 break;
7979 case 'n':
7980 if (xmlStrEqual(name, BAD_CAST "namespace"))
7981 ret = AXIS_NAMESPACE;
7982 break;
7983 case 'p':
7984 if (xmlStrEqual(name, BAD_CAST "parent"))
7985 ret = AXIS_PARENT;
7986 if (xmlStrEqual(name, BAD_CAST "preceding"))
7987 ret = AXIS_PRECEDING;
7988 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
7989 ret = AXIS_PRECEDING_SIBLING;
7990 break;
7991 case 's':
7992 if (xmlStrEqual(name, BAD_CAST "self"))
7993 ret = AXIS_SELF;
7994 break;
7995 }
7996 return(ret);
7997}
7998
7999/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008000 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008001 * @ctxt: the XPath Parser context
8002 *
8003 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8004 * | AbbreviatedStep
8005 *
8006 * [12] AbbreviatedStep ::= '.' | '..'
8007 *
8008 * [5] AxisSpecifier ::= AxisName '::'
8009 * | AbbreviatedAxisSpecifier
8010 *
8011 * [13] AbbreviatedAxisSpecifier ::= '@'?
8012 *
8013 * Modified for XPtr range support as:
8014 *
8015 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8016 * | AbbreviatedStep
8017 * | 'range-to' '(' Expr ')' Predicate*
8018 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008019 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008020 * A location step of . is short for self::node(). This is
8021 * particularly useful in conjunction with //. For example, the
8022 * location path .//para is short for
8023 * self::node()/descendant-or-self::node()/child::para
8024 * and so will select all para descendant elements of the context
8025 * node.
8026 * Similarly, a location step of .. is short for parent::node().
8027 * For example, ../title is short for parent::node()/child::title
8028 * and so will select the title children of the parent of the context
8029 * node.
8030 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008031static void
8032xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008033#ifdef LIBXML_XPTR_ENABLED
8034 int rangeto = 0;
8035 int op2 = -1;
8036#endif
8037
Owen Taylor3473f882001-02-23 17:55:21 +00008038 SKIP_BLANKS;
8039 if ((CUR == '.') && (NXT(1) == '.')) {
8040 SKIP(2);
8041 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008042 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8043 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008044 } else if (CUR == '.') {
8045 NEXT;
8046 SKIP_BLANKS;
8047 } else {
8048 xmlChar *name = NULL;
8049 const xmlChar *prefix = NULL;
8050 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008051 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008052 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008053 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008054
8055 /*
8056 * The modification needed for XPointer change to the production
8057 */
8058#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008059 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008060 name = xmlXPathParseNCName(ctxt);
8061 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008062 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008063 xmlFree(name);
8064 SKIP_BLANKS;
8065 if (CUR != '(') {
8066 XP_ERROR(XPATH_EXPR_ERROR);
8067 }
8068 NEXT;
8069 SKIP_BLANKS;
8070
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008071 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008072 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008073 CHECK_ERROR;
8074
8075 SKIP_BLANKS;
8076 if (CUR != ')') {
8077 XP_ERROR(XPATH_EXPR_ERROR);
8078 }
8079 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008080 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008081 goto eval_predicates;
8082 }
8083 }
8084#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008085 if (CUR == '*') {
8086 axis = AXIS_CHILD;
8087 } else {
8088 if (name == NULL)
8089 name = xmlXPathParseNCName(ctxt);
8090 if (name != NULL) {
8091 axis = xmlXPathIsAxisName(name);
8092 if (axis != 0) {
8093 SKIP_BLANKS;
8094 if ((CUR == ':') && (NXT(1) == ':')) {
8095 SKIP(2);
8096 xmlFree(name);
8097 name = NULL;
8098 } else {
8099 /* an element name can conflict with an axis one :-\ */
8100 axis = AXIS_CHILD;
8101 }
Owen Taylor3473f882001-02-23 17:55:21 +00008102 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008103 axis = AXIS_CHILD;
8104 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008105 } else if (CUR == '@') {
8106 NEXT;
8107 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008108 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008109 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008110 }
Owen Taylor3473f882001-02-23 17:55:21 +00008111 }
8112
8113 CHECK_ERROR;
8114
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008115 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008116 if (test == 0)
8117 return;
8118
8119#ifdef DEBUG_STEP
8120 xmlGenericError(xmlGenericErrorContext,
8121 "Basis : computing new set\n");
8122#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008123
Owen Taylor3473f882001-02-23 17:55:21 +00008124#ifdef DEBUG_STEP
8125 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008126 if (ctxt->value == NULL)
8127 xmlGenericError(xmlGenericErrorContext, "no value\n");
8128 else if (ctxt->value->nodesetval == NULL)
8129 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8130 else
8131 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008132#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008133
8134eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008135 op1 = ctxt->comp->last;
8136 ctxt->comp->last = -1;
8137
Owen Taylor3473f882001-02-23 17:55:21 +00008138 SKIP_BLANKS;
8139 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008140 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008141 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008142
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008143#ifdef LIBXML_XPTR_ENABLED
8144 if (rangeto) {
8145 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8146 } else
8147#endif
8148 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8149 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008150
Owen Taylor3473f882001-02-23 17:55:21 +00008151 }
8152#ifdef DEBUG_STEP
8153 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008154 if (ctxt->value == NULL)
8155 xmlGenericError(xmlGenericErrorContext, "no value\n");
8156 else if (ctxt->value->nodesetval == NULL)
8157 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8158 else
8159 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8160 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008161#endif
8162}
8163
8164/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008165 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008166 * @ctxt: the XPath Parser context
8167 *
8168 * [3] RelativeLocationPath ::= Step
8169 * | RelativeLocationPath '/' Step
8170 * | AbbreviatedRelativeLocationPath
8171 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8172 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008173 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008174 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008175static void
Owen Taylor3473f882001-02-23 17:55:21 +00008176#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008177xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008178#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008179xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008180#endif
8181(xmlXPathParserContextPtr ctxt) {
8182 SKIP_BLANKS;
8183 if ((CUR == '/') && (NXT(1) == '/')) {
8184 SKIP(2);
8185 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008186 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8187 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008188 } else if (CUR == '/') {
8189 NEXT;
8190 SKIP_BLANKS;
8191 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008192 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008193 SKIP_BLANKS;
8194 while (CUR == '/') {
8195 if ((CUR == '/') && (NXT(1) == '/')) {
8196 SKIP(2);
8197 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008198 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008199 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008200 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008201 } else if (CUR == '/') {
8202 NEXT;
8203 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008204 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008205 }
8206 SKIP_BLANKS;
8207 }
8208}
8209
8210/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008211 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008212 * @ctxt: the XPath Parser context
8213 *
8214 * [1] LocationPath ::= RelativeLocationPath
8215 * | AbsoluteLocationPath
8216 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8217 * | AbbreviatedAbsoluteLocationPath
8218 * [10] AbbreviatedAbsoluteLocationPath ::=
8219 * '//' RelativeLocationPath
8220 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008221 * Compile a location path
8222 *
Owen Taylor3473f882001-02-23 17:55:21 +00008223 * // is short for /descendant-or-self::node()/. For example,
8224 * //para is short for /descendant-or-self::node()/child::para and
8225 * so will select any para element in the document (even a para element
8226 * that is a document element will be selected by //para since the
8227 * document element node is a child of the root node); div//para is
8228 * short for div/descendant-or-self::node()/child::para and so will
8229 * select all para descendants of div children.
8230 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008231static void
8232xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008233 SKIP_BLANKS;
8234 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008235 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008236 } else {
8237 while (CUR == '/') {
8238 if ((CUR == '/') && (NXT(1) == '/')) {
8239 SKIP(2);
8240 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008241 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8242 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008243 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008244 } else if (CUR == '/') {
8245 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008246 SKIP_BLANKS;
8247 if ((CUR != 0 ) &&
8248 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
8249 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008250 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008251 }
8252 }
8253 }
8254}
8255
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008256/************************************************************************
8257 * *
8258 * XPath precompiled expression evaluation *
8259 * *
8260 ************************************************************************/
8261
Daniel Veillardf06307e2001-07-03 10:35:50 +00008262static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008263xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8264
8265/**
8266 * xmlXPathNodeCollectAndTest:
8267 * @ctxt: the XPath Parser context
8268 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008269 * @first: pointer to the first element in document order
8270 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008271 *
8272 * This is the function implementing a step: based on the current list
8273 * of nodes, it builds up a new list, looking at all nodes under that
8274 * axis and selecting them it also do the predicate filtering
8275 *
8276 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008277 *
8278 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008279 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008280static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008281xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008282 xmlXPathStepOpPtr op,
8283 xmlNodePtr * first, xmlNodePtr * last)
8284{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008285 xmlXPathAxisVal axis = op->value;
8286 xmlXPathTestVal test = op->value2;
8287 xmlXPathTypeVal type = op->value3;
8288 const xmlChar *prefix = op->value4;
8289 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008290 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008291
8292#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008293 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008294#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008295 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008296 xmlNodeSetPtr ret, list;
8297 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008298 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008299 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008300 xmlNodePtr cur = NULL;
8301 xmlXPathObjectPtr obj;
8302 xmlNodeSetPtr nodelist;
8303 xmlNodePtr tmp;
8304
Daniel Veillardf06307e2001-07-03 10:35:50 +00008305 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008306 obj = valuePop(ctxt);
8307 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008308 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008309 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008310 URI = xmlXPathNsLookup(ctxt->context, prefix);
8311 if (URI == NULL)
8312 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008313 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008314#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008315 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008316#endif
8317 switch (axis) {
8318 case AXIS_ANCESTOR:
8319#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008320 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008321#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008322 first = NULL;
8323 next = xmlXPathNextAncestor;
8324 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008325 case AXIS_ANCESTOR_OR_SELF:
8326#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008327 xmlGenericError(xmlGenericErrorContext,
8328 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008329#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008330 first = NULL;
8331 next = xmlXPathNextAncestorOrSelf;
8332 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008333 case AXIS_ATTRIBUTE:
8334#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008335 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008336#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008337 first = NULL;
8338 last = NULL;
8339 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00008340 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008341 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008342 case AXIS_CHILD:
8343#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008344 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008345#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008346 last = NULL;
8347 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00008348 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008349 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008350 case AXIS_DESCENDANT:
8351#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008352 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008353#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008354 last = NULL;
8355 next = xmlXPathNextDescendant;
8356 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008357 case AXIS_DESCENDANT_OR_SELF:
8358#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008359 xmlGenericError(xmlGenericErrorContext,
8360 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008361#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008362 last = NULL;
8363 next = xmlXPathNextDescendantOrSelf;
8364 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008365 case AXIS_FOLLOWING:
8366#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008367 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008368#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008369 last = NULL;
8370 next = xmlXPathNextFollowing;
8371 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008372 case AXIS_FOLLOWING_SIBLING:
8373#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008374 xmlGenericError(xmlGenericErrorContext,
8375 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008376#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008377 last = NULL;
8378 next = xmlXPathNextFollowingSibling;
Daniel Veillard75be0132002-03-13 10:03:35 +00008379 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008380 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008381 case AXIS_NAMESPACE:
8382#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008383 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008384#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008385 first = NULL;
8386 last = NULL;
8387 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00008388 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008389 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008390 case AXIS_PARENT:
8391#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008392 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008393#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008394 first = NULL;
8395 next = xmlXPathNextParent;
8396 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008397 case AXIS_PRECEDING:
8398#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008399 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008400#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008401 first = NULL;
8402 next = xmlXPathNextPrecedingInternal;
8403 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008404 case AXIS_PRECEDING_SIBLING:
8405#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008406 xmlGenericError(xmlGenericErrorContext,
8407 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008408#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008409 first = NULL;
8410 next = xmlXPathNextPrecedingSibling;
Daniel Veillard75be0132002-03-13 10:03:35 +00008411 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008412 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008413 case AXIS_SELF:
8414#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008415 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008416#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008417 first = NULL;
8418 last = NULL;
8419 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00008420 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008421 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008422 }
8423 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008424 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008425
8426 nodelist = obj->nodesetval;
8427 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008428 xmlXPathFreeObject(obj);
8429 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8430 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008431 }
8432 addNode = xmlXPathNodeSetAddUnique;
8433 ret = NULL;
8434#ifdef DEBUG_STEP
8435 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008436 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008437 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008438 case NODE_TEST_NONE:
8439 xmlGenericError(xmlGenericErrorContext,
8440 " searching for none !!!\n");
8441 break;
8442 case NODE_TEST_TYPE:
8443 xmlGenericError(xmlGenericErrorContext,
8444 " searching for type %d\n", type);
8445 break;
8446 case NODE_TEST_PI:
8447 xmlGenericError(xmlGenericErrorContext,
8448 " searching for PI !!!\n");
8449 break;
8450 case NODE_TEST_ALL:
8451 xmlGenericError(xmlGenericErrorContext,
8452 " searching for *\n");
8453 break;
8454 case NODE_TEST_NS:
8455 xmlGenericError(xmlGenericErrorContext,
8456 " searching for namespace %s\n",
8457 prefix);
8458 break;
8459 case NODE_TEST_NAME:
8460 xmlGenericError(xmlGenericErrorContext,
8461 " searching for name %s\n", name);
8462 if (prefix != NULL)
8463 xmlGenericError(xmlGenericErrorContext,
8464 " with namespace %s\n", prefix);
8465 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008466 }
8467 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8468#endif
8469 /*
8470 * 2.3 Node Tests
8471 * - For the attribute axis, the principal node type is attribute.
8472 * - For the namespace axis, the principal node type is namespace.
8473 * - For other axes, the principal node type is element.
8474 *
8475 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008476 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008477 * select all element children of the context node
8478 */
8479 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008480 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008481 ctxt->context->node = nodelist->nodeTab[i];
8482
Daniel Veillardf06307e2001-07-03 10:35:50 +00008483 cur = NULL;
8484 list = xmlXPathNodeSetCreate(NULL);
8485 do {
8486 cur = next(ctxt, cur);
8487 if (cur == NULL)
8488 break;
8489 if ((first != NULL) && (*first == cur))
8490 break;
8491 if (((t % 256) == 0) &&
8492 (first != NULL) && (*first != NULL) &&
8493 (xmlXPathCmpNodes(*first, cur) >= 0))
8494 break;
8495 if ((last != NULL) && (*last == cur))
8496 break;
8497 if (((t % 256) == 0) &&
8498 (last != NULL) && (*last != NULL) &&
8499 (xmlXPathCmpNodes(cur, *last) >= 0))
8500 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008501 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008502#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008503 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8504#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008505 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008506 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008507 ctxt->context->node = tmp;
8508 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008509 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008510 if ((cur->type == type) ||
8511 ((type == NODE_TYPE_NODE) &&
8512 ((cur->type == XML_DOCUMENT_NODE) ||
8513 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8514 (cur->type == XML_ELEMENT_NODE) ||
8515 (cur->type == XML_PI_NODE) ||
8516 (cur->type == XML_COMMENT_NODE) ||
8517 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00008518 (cur->type == XML_TEXT_NODE))) ||
8519 ((type == NODE_TYPE_TEXT) &&
8520 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008521#ifdef DEBUG_STEP
8522 n++;
8523#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008524 addNode(list, cur);
8525 }
8526 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008527 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008528 if (cur->type == XML_PI_NODE) {
8529 if ((name != NULL) &&
8530 (!xmlStrEqual(name, cur->name)))
8531 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008532#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008533 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008534#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008535 addNode(list, cur);
8536 }
8537 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008538 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008539 if (axis == AXIS_ATTRIBUTE) {
8540 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008541#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008542 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008543#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008544 addNode(list, cur);
8545 }
8546 } else if (axis == AXIS_NAMESPACE) {
8547 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008548#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008549 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008550#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008551 xmlXPathNodeSetAddNs(list, ctxt->context->node,
8552 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008553 }
8554 } else {
8555 if (cur->type == XML_ELEMENT_NODE) {
8556 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008557#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008558 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008559#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008560 addNode(list, cur);
8561 } else if ((cur->ns != NULL) &&
8562 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008563#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008564 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008565#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008566 addNode(list, cur);
8567 }
8568 }
8569 }
8570 break;
8571 case NODE_TEST_NS:{
8572 TODO;
8573 break;
8574 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008575 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008576 switch (cur->type) {
8577 case XML_ELEMENT_NODE:
8578 if (xmlStrEqual(name, cur->name)) {
8579 if (prefix == NULL) {
8580 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008581#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008582 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008583#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008584 addNode(list, cur);
8585 }
8586 } else {
8587 if ((cur->ns != NULL) &&
8588 (xmlStrEqual(URI,
8589 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008590#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008591 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008592#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008593 addNode(list, cur);
8594 }
8595 }
8596 }
8597 break;
8598 case XML_ATTRIBUTE_NODE:{
8599 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008600
Daniel Veillardf06307e2001-07-03 10:35:50 +00008601 if (xmlStrEqual(name, attr->name)) {
8602 if (prefix == NULL) {
8603 if ((attr->ns == NULL) ||
8604 (attr->ns->prefix == NULL)) {
8605#ifdef DEBUG_STEP
8606 n++;
8607#endif
8608 addNode(list,
8609 (xmlNodePtr) attr);
8610 }
8611 } else {
8612 if ((attr->ns != NULL) &&
8613 (xmlStrEqual(URI,
8614 attr->ns->
8615 href))) {
8616#ifdef DEBUG_STEP
8617 n++;
8618#endif
8619 addNode(list,
8620 (xmlNodePtr) attr);
8621 }
8622 }
8623 }
8624 break;
8625 }
8626 case XML_NAMESPACE_DECL:
8627 if (cur->type == XML_NAMESPACE_DECL) {
8628 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008629
Daniel Veillardf06307e2001-07-03 10:35:50 +00008630 if ((ns->prefix != NULL) && (name != NULL)
8631 && (xmlStrEqual(ns->prefix, name))) {
8632#ifdef DEBUG_STEP
8633 n++;
8634#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008635 xmlXPathNodeSetAddNs(list,
8636 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008637 }
8638 }
8639 break;
8640 default:
8641 break;
8642 }
8643 break;
8644 break;
8645 }
8646 } while (cur != NULL);
8647
8648 /*
8649 * If there is some predicate filtering do it now
8650 */
8651 if (op->ch2 != -1) {
8652 xmlXPathObjectPtr obj2;
8653
8654 valuePush(ctxt, xmlXPathWrapNodeSet(list));
8655 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
8656 CHECK_TYPE0(XPATH_NODESET);
8657 obj2 = valuePop(ctxt);
8658 list = obj2->nodesetval;
8659 obj2->nodesetval = NULL;
8660 xmlXPathFreeObject(obj2);
8661 }
8662 if (ret == NULL) {
8663 ret = list;
8664 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00008665 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008666 xmlXPathFreeNodeSet(list);
8667 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008668 }
8669 ctxt->context->node = tmp;
8670#ifdef DEBUG_STEP
8671 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008672 "\nExamined %d nodes, found %d nodes at that step\n",
8673 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008674#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008675 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00008676 if ((obj->boolval) && (obj->user != NULL)) {
8677 ctxt->value->boolval = 1;
8678 ctxt->value->user = obj->user;
8679 obj->user = NULL;
8680 obj->boolval = 0;
8681 }
8682 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008683 return(t);
8684}
8685
8686/**
8687 * xmlXPathNodeCollectAndTestNth:
8688 * @ctxt: the XPath Parser context
8689 * @op: the XPath precompiled step operation
8690 * @indx: the index to collect
8691 * @first: pointer to the first element in document order
8692 * @last: pointer to the last element in document order
8693 *
8694 * This is the function implementing a step: based on the current list
8695 * of nodes, it builds up a new list, looking at all nodes under that
8696 * axis and selecting them it also do the predicate filtering
8697 *
8698 * Pushes the new NodeSet resulting from the search.
8699 * Returns the number of node traversed
8700 */
8701static int
8702xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
8703 xmlXPathStepOpPtr op, int indx,
8704 xmlNodePtr * first, xmlNodePtr * last)
8705{
8706 xmlXPathAxisVal axis = op->value;
8707 xmlXPathTestVal test = op->value2;
8708 xmlXPathTypeVal type = op->value3;
8709 const xmlChar *prefix = op->value4;
8710 const xmlChar *name = op->value5;
8711 const xmlChar *URI = NULL;
8712 int n = 0, t = 0;
8713
8714 int i;
8715 xmlNodeSetPtr list;
8716 xmlXPathTraversalFunction next = NULL;
8717 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
8718 xmlNodePtr cur = NULL;
8719 xmlXPathObjectPtr obj;
8720 xmlNodeSetPtr nodelist;
8721 xmlNodePtr tmp;
8722
8723 CHECK_TYPE0(XPATH_NODESET);
8724 obj = valuePop(ctxt);
8725 addNode = xmlXPathNodeSetAdd;
8726 if (prefix != NULL) {
8727 URI = xmlXPathNsLookup(ctxt->context, prefix);
8728 if (URI == NULL)
8729 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8730 }
8731#ifdef DEBUG_STEP_NTH
8732 xmlGenericError(xmlGenericErrorContext, "new step : ");
8733 if (first != NULL) {
8734 if (*first != NULL)
8735 xmlGenericError(xmlGenericErrorContext, "first = %s ",
8736 (*first)->name);
8737 else
8738 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
8739 }
8740 if (last != NULL) {
8741 if (*last != NULL)
8742 xmlGenericError(xmlGenericErrorContext, "last = %s ",
8743 (*last)->name);
8744 else
8745 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
8746 }
8747#endif
8748 switch (axis) {
8749 case AXIS_ANCESTOR:
8750#ifdef DEBUG_STEP_NTH
8751 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
8752#endif
8753 first = NULL;
8754 next = xmlXPathNextAncestor;
8755 break;
8756 case AXIS_ANCESTOR_OR_SELF:
8757#ifdef DEBUG_STEP_NTH
8758 xmlGenericError(xmlGenericErrorContext,
8759 "axis 'ancestors-or-self' ");
8760#endif
8761 first = NULL;
8762 next = xmlXPathNextAncestorOrSelf;
8763 break;
8764 case AXIS_ATTRIBUTE:
8765#ifdef DEBUG_STEP_NTH
8766 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
8767#endif
8768 first = NULL;
8769 last = NULL;
8770 next = xmlXPathNextAttribute;
8771 break;
8772 case AXIS_CHILD:
8773#ifdef DEBUG_STEP_NTH
8774 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
8775#endif
8776 last = NULL;
8777 next = xmlXPathNextChild;
8778 break;
8779 case AXIS_DESCENDANT:
8780#ifdef DEBUG_STEP_NTH
8781 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
8782#endif
8783 last = NULL;
8784 next = xmlXPathNextDescendant;
8785 break;
8786 case AXIS_DESCENDANT_OR_SELF:
8787#ifdef DEBUG_STEP_NTH
8788 xmlGenericError(xmlGenericErrorContext,
8789 "axis 'descendant-or-self' ");
8790#endif
8791 last = NULL;
8792 next = xmlXPathNextDescendantOrSelf;
8793 break;
8794 case AXIS_FOLLOWING:
8795#ifdef DEBUG_STEP_NTH
8796 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
8797#endif
8798 last = NULL;
8799 next = xmlXPathNextFollowing;
8800 break;
8801 case AXIS_FOLLOWING_SIBLING:
8802#ifdef DEBUG_STEP_NTH
8803 xmlGenericError(xmlGenericErrorContext,
8804 "axis 'following-siblings' ");
8805#endif
8806 last = NULL;
8807 next = xmlXPathNextFollowingSibling;
8808 break;
8809 case AXIS_NAMESPACE:
8810#ifdef DEBUG_STEP_NTH
8811 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
8812#endif
8813 last = NULL;
8814 first = NULL;
8815 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8816 break;
8817 case AXIS_PARENT:
8818#ifdef DEBUG_STEP_NTH
8819 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
8820#endif
8821 first = NULL;
8822 next = xmlXPathNextParent;
8823 break;
8824 case AXIS_PRECEDING:
8825#ifdef DEBUG_STEP_NTH
8826 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
8827#endif
8828 first = NULL;
8829 next = xmlXPathNextPrecedingInternal;
8830 break;
8831 case AXIS_PRECEDING_SIBLING:
8832#ifdef DEBUG_STEP_NTH
8833 xmlGenericError(xmlGenericErrorContext,
8834 "axis 'preceding-sibling' ");
8835#endif
8836 first = NULL;
8837 next = xmlXPathNextPrecedingSibling;
8838 break;
8839 case AXIS_SELF:
8840#ifdef DEBUG_STEP_NTH
8841 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
8842#endif
8843 first = NULL;
8844 last = NULL;
8845 next = xmlXPathNextSelf;
8846 break;
8847 }
8848 if (next == NULL)
8849 return(0);
8850
8851 nodelist = obj->nodesetval;
8852 if (nodelist == NULL) {
8853 xmlXPathFreeObject(obj);
8854 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8855 return(0);
8856 }
8857 addNode = xmlXPathNodeSetAddUnique;
8858#ifdef DEBUG_STEP_NTH
8859 xmlGenericError(xmlGenericErrorContext,
8860 " context contains %d nodes\n", nodelist->nodeNr);
8861 switch (test) {
8862 case NODE_TEST_NONE:
8863 xmlGenericError(xmlGenericErrorContext,
8864 " searching for none !!!\n");
8865 break;
8866 case NODE_TEST_TYPE:
8867 xmlGenericError(xmlGenericErrorContext,
8868 " searching for type %d\n", type);
8869 break;
8870 case NODE_TEST_PI:
8871 xmlGenericError(xmlGenericErrorContext,
8872 " searching for PI !!!\n");
8873 break;
8874 case NODE_TEST_ALL:
8875 xmlGenericError(xmlGenericErrorContext,
8876 " searching for *\n");
8877 break;
8878 case NODE_TEST_NS:
8879 xmlGenericError(xmlGenericErrorContext,
8880 " searching for namespace %s\n",
8881 prefix);
8882 break;
8883 case NODE_TEST_NAME:
8884 xmlGenericError(xmlGenericErrorContext,
8885 " searching for name %s\n", name);
8886 if (prefix != NULL)
8887 xmlGenericError(xmlGenericErrorContext,
8888 " with namespace %s\n", prefix);
8889 break;
8890 }
8891 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8892#endif
8893 /*
8894 * 2.3 Node Tests
8895 * - For the attribute axis, the principal node type is attribute.
8896 * - For the namespace axis, the principal node type is namespace.
8897 * - For other axes, the principal node type is element.
8898 *
8899 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008900 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00008901 * select all element children of the context node
8902 */
8903 tmp = ctxt->context->node;
8904 list = xmlXPathNodeSetCreate(NULL);
8905 for (i = 0; i < nodelist->nodeNr; i++) {
8906 ctxt->context->node = nodelist->nodeTab[i];
8907
8908 cur = NULL;
8909 n = 0;
8910 do {
8911 cur = next(ctxt, cur);
8912 if (cur == NULL)
8913 break;
8914 if ((first != NULL) && (*first == cur))
8915 break;
8916 if (((t % 256) == 0) &&
8917 (first != NULL) && (*first != NULL) &&
8918 (xmlXPathCmpNodes(*first, cur) >= 0))
8919 break;
8920 if ((last != NULL) && (*last == cur))
8921 break;
8922 if (((t % 256) == 0) &&
8923 (last != NULL) && (*last != NULL) &&
8924 (xmlXPathCmpNodes(cur, *last) >= 0))
8925 break;
8926 t++;
8927 switch (test) {
8928 case NODE_TEST_NONE:
8929 ctxt->context->node = tmp;
8930 STRANGE return(0);
8931 case NODE_TEST_TYPE:
8932 if ((cur->type == type) ||
8933 ((type == NODE_TYPE_NODE) &&
8934 ((cur->type == XML_DOCUMENT_NODE) ||
8935 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8936 (cur->type == XML_ELEMENT_NODE) ||
8937 (cur->type == XML_PI_NODE) ||
8938 (cur->type == XML_COMMENT_NODE) ||
8939 (cur->type == XML_CDATA_SECTION_NODE) ||
8940 (cur->type == XML_TEXT_NODE)))) {
8941 n++;
8942 if (n == indx)
8943 addNode(list, cur);
8944 }
8945 break;
8946 case NODE_TEST_PI:
8947 if (cur->type == XML_PI_NODE) {
8948 if ((name != NULL) &&
8949 (!xmlStrEqual(name, cur->name)))
8950 break;
8951 n++;
8952 if (n == indx)
8953 addNode(list, cur);
8954 }
8955 break;
8956 case NODE_TEST_ALL:
8957 if (axis == AXIS_ATTRIBUTE) {
8958 if (cur->type == XML_ATTRIBUTE_NODE) {
8959 n++;
8960 if (n == indx)
8961 addNode(list, cur);
8962 }
8963 } else if (axis == AXIS_NAMESPACE) {
8964 if (cur->type == XML_NAMESPACE_DECL) {
8965 n++;
8966 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008967 xmlXPathNodeSetAddNs(list, ctxt->context->node,
8968 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008969 }
8970 } else {
8971 if (cur->type == XML_ELEMENT_NODE) {
8972 if (prefix == NULL) {
8973 n++;
8974 if (n == indx)
8975 addNode(list, cur);
8976 } else if ((cur->ns != NULL) &&
8977 (xmlStrEqual(URI, cur->ns->href))) {
8978 n++;
8979 if (n == indx)
8980 addNode(list, cur);
8981 }
8982 }
8983 }
8984 break;
8985 case NODE_TEST_NS:{
8986 TODO;
8987 break;
8988 }
8989 case NODE_TEST_NAME:
8990 switch (cur->type) {
8991 case XML_ELEMENT_NODE:
8992 if (xmlStrEqual(name, cur->name)) {
8993 if (prefix == NULL) {
8994 if (cur->ns == NULL) {
8995 n++;
8996 if (n == indx)
8997 addNode(list, cur);
8998 }
8999 } else {
9000 if ((cur->ns != NULL) &&
9001 (xmlStrEqual(URI,
9002 cur->ns->href))) {
9003 n++;
9004 if (n == indx)
9005 addNode(list, cur);
9006 }
9007 }
9008 }
9009 break;
9010 case XML_ATTRIBUTE_NODE:{
9011 xmlAttrPtr attr = (xmlAttrPtr) cur;
9012
9013 if (xmlStrEqual(name, attr->name)) {
9014 if (prefix == NULL) {
9015 if ((attr->ns == NULL) ||
9016 (attr->ns->prefix == NULL)) {
9017 n++;
9018 if (n == indx)
9019 addNode(list, cur);
9020 }
9021 } else {
9022 if ((attr->ns != NULL) &&
9023 (xmlStrEqual(URI,
9024 attr->ns->
9025 href))) {
9026 n++;
9027 if (n == indx)
9028 addNode(list, cur);
9029 }
9030 }
9031 }
9032 break;
9033 }
9034 case XML_NAMESPACE_DECL:
9035 if (cur->type == XML_NAMESPACE_DECL) {
9036 xmlNsPtr ns = (xmlNsPtr) cur;
9037
9038 if ((ns->prefix != NULL) && (name != NULL)
9039 && (xmlStrEqual(ns->prefix, name))) {
9040 n++;
9041 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009042 xmlXPathNodeSetAddNs(list,
9043 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009044 }
9045 }
9046 break;
9047 default:
9048 break;
9049 }
9050 break;
9051 break;
9052 }
9053 } while (n < indx);
9054 }
9055 ctxt->context->node = tmp;
9056#ifdef DEBUG_STEP_NTH
9057 xmlGenericError(xmlGenericErrorContext,
9058 "\nExamined %d nodes, found %d nodes at that step\n",
9059 t, list->nodeNr);
9060#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009061 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009062 if ((obj->boolval) && (obj->user != NULL)) {
9063 ctxt->value->boolval = 1;
9064 ctxt->value->user = obj->user;
9065 obj->user = NULL;
9066 obj->boolval = 0;
9067 }
9068 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009069 return(t);
9070}
9071
9072/**
9073 * xmlXPathCompOpEvalFirst:
9074 * @ctxt: the XPath parser context with the compiled expression
9075 * @op: an XPath compiled operation
9076 * @first: the first elem found so far
9077 *
9078 * Evaluate the Precompiled XPath operation searching only the first
9079 * element in document order
9080 *
9081 * Returns the number of examined objects.
9082 */
9083static int
9084xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9085 xmlXPathStepOpPtr op, xmlNodePtr * first)
9086{
9087 int total = 0, cur;
9088 xmlXPathCompExprPtr comp;
9089 xmlXPathObjectPtr arg1, arg2;
9090
Daniel Veillard556c6682001-10-06 09:59:51 +00009091 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009092 comp = ctxt->comp;
9093 switch (op->op) {
9094 case XPATH_OP_END:
9095 return (0);
9096 case XPATH_OP_UNION:
9097 total =
9098 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9099 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009100 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009101 if ((ctxt->value != NULL)
9102 && (ctxt->value->type == XPATH_NODESET)
9103 && (ctxt->value->nodesetval != NULL)
9104 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9105 /*
9106 * limit tree traversing to first node in the result
9107 */
9108 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9109 *first = ctxt->value->nodesetval->nodeTab[0];
9110 }
9111 cur =
9112 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9113 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009114 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009115 CHECK_TYPE0(XPATH_NODESET);
9116 arg2 = valuePop(ctxt);
9117
9118 CHECK_TYPE0(XPATH_NODESET);
9119 arg1 = valuePop(ctxt);
9120
9121 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9122 arg2->nodesetval);
9123 valuePush(ctxt, arg1);
9124 xmlXPathFreeObject(arg2);
9125 /* optimizer */
9126 if (total > cur)
9127 xmlXPathCompSwap(op);
9128 return (total + cur);
9129 case XPATH_OP_ROOT:
9130 xmlXPathRoot(ctxt);
9131 return (0);
9132 case XPATH_OP_NODE:
9133 if (op->ch1 != -1)
9134 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009135 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009136 if (op->ch2 != -1)
9137 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009138 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009139 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9140 return (total);
9141 case XPATH_OP_RESET:
9142 if (op->ch1 != -1)
9143 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009144 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009145 if (op->ch2 != -1)
9146 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 ctxt->context->node = NULL;
9149 return (total);
9150 case XPATH_OP_COLLECT:{
9151 if (op->ch1 == -1)
9152 return (total);
9153
9154 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009155 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009156
9157 /*
9158 * Optimization for [n] selection where n is a number
9159 */
9160 if ((op->ch2 != -1) &&
9161 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9162 (comp->steps[op->ch2].ch1 == -1) &&
9163 (comp->steps[op->ch2].ch2 != -1) &&
9164 (comp->steps[comp->steps[op->ch2].ch2].op ==
9165 XPATH_OP_VALUE)) {
9166 xmlXPathObjectPtr val;
9167
9168 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9169 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9170 int indx = (int) val->floatval;
9171
9172 if (val->floatval == (float) indx) {
9173 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9174 first, NULL);
9175 return (total);
9176 }
9177 }
9178 }
9179 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9180 return (total);
9181 }
9182 case XPATH_OP_VALUE:
9183 valuePush(ctxt,
9184 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9185 return (0);
9186 case XPATH_OP_SORT:
9187 if (op->ch1 != -1)
9188 total +=
9189 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9190 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009191 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009192 if ((ctxt->value != NULL)
9193 && (ctxt->value->type == XPATH_NODESET)
9194 && (ctxt->value->nodesetval != NULL))
9195 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9196 return (total);
9197 default:
9198 return (xmlXPathCompOpEval(ctxt, op));
9199 }
9200}
9201
9202/**
9203 * xmlXPathCompOpEvalLast:
9204 * @ctxt: the XPath parser context with the compiled expression
9205 * @op: an XPath compiled operation
9206 * @last: the last elem found so far
9207 *
9208 * Evaluate the Precompiled XPath operation searching only the last
9209 * element in document order
9210 *
9211 * Returns the number of node traversed
9212 */
9213static int
9214xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9215 xmlNodePtr * last)
9216{
9217 int total = 0, cur;
9218 xmlXPathCompExprPtr comp;
9219 xmlXPathObjectPtr arg1, arg2;
9220
Daniel Veillard556c6682001-10-06 09:59:51 +00009221 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009222 comp = ctxt->comp;
9223 switch (op->op) {
9224 case XPATH_OP_END:
9225 return (0);
9226 case XPATH_OP_UNION:
9227 total =
9228 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009229 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009230 if ((ctxt->value != NULL)
9231 && (ctxt->value->type == XPATH_NODESET)
9232 && (ctxt->value->nodesetval != NULL)
9233 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9234 /*
9235 * limit tree traversing to first node in the result
9236 */
9237 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9238 *last =
9239 ctxt->value->nodesetval->nodeTab[ctxt->value->
9240 nodesetval->nodeNr -
9241 1];
9242 }
9243 cur =
9244 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009245 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009246 if ((ctxt->value != NULL)
9247 && (ctxt->value->type == XPATH_NODESET)
9248 && (ctxt->value->nodesetval != NULL)
9249 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9250 }
9251 CHECK_TYPE0(XPATH_NODESET);
9252 arg2 = valuePop(ctxt);
9253
9254 CHECK_TYPE0(XPATH_NODESET);
9255 arg1 = valuePop(ctxt);
9256
9257 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9258 arg2->nodesetval);
9259 valuePush(ctxt, arg1);
9260 xmlXPathFreeObject(arg2);
9261 /* optimizer */
9262 if (total > cur)
9263 xmlXPathCompSwap(op);
9264 return (total + cur);
9265 case XPATH_OP_ROOT:
9266 xmlXPathRoot(ctxt);
9267 return (0);
9268 case XPATH_OP_NODE:
9269 if (op->ch1 != -1)
9270 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009271 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009272 if (op->ch2 != -1)
9273 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009274 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009275 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9276 return (total);
9277 case XPATH_OP_RESET:
9278 if (op->ch1 != -1)
9279 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009280 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009281 if (op->ch2 != -1)
9282 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009283 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009284 ctxt->context->node = NULL;
9285 return (total);
9286 case XPATH_OP_COLLECT:{
9287 if (op->ch1 == -1)
9288 return (0);
9289
9290 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009291 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009292
9293 /*
9294 * Optimization for [n] selection where n is a number
9295 */
9296 if ((op->ch2 != -1) &&
9297 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9298 (comp->steps[op->ch2].ch1 == -1) &&
9299 (comp->steps[op->ch2].ch2 != -1) &&
9300 (comp->steps[comp->steps[op->ch2].ch2].op ==
9301 XPATH_OP_VALUE)) {
9302 xmlXPathObjectPtr val;
9303
9304 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9305 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9306 int indx = (int) val->floatval;
9307
9308 if (val->floatval == (float) indx) {
9309 total +=
9310 xmlXPathNodeCollectAndTestNth(ctxt, op,
9311 indx, NULL,
9312 last);
9313 return (total);
9314 }
9315 }
9316 }
9317 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9318 return (total);
9319 }
9320 case XPATH_OP_VALUE:
9321 valuePush(ctxt,
9322 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9323 return (0);
9324 case XPATH_OP_SORT:
9325 if (op->ch1 != -1)
9326 total +=
9327 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9328 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009329 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009330 if ((ctxt->value != NULL)
9331 && (ctxt->value->type == XPATH_NODESET)
9332 && (ctxt->value->nodesetval != NULL))
9333 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9334 return (total);
9335 default:
9336 return (xmlXPathCompOpEval(ctxt, op));
9337 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009338}
9339
Owen Taylor3473f882001-02-23 17:55:21 +00009340/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009341 * xmlXPathCompOpEval:
9342 * @ctxt: the XPath parser context with the compiled expression
9343 * @op: an XPath compiled operation
9344 *
9345 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009346 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009347 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009348static int
9349xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9350{
9351 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009352 int equal, ret;
9353 xmlXPathCompExprPtr comp;
9354 xmlXPathObjectPtr arg1, arg2;
9355
Daniel Veillard556c6682001-10-06 09:59:51 +00009356 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009357 comp = ctxt->comp;
9358 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009359 case XPATH_OP_END:
9360 return (0);
9361 case XPATH_OP_AND:
9362 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009363 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009364 xmlXPathBooleanFunction(ctxt, 1);
9365 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9366 return (total);
9367 arg2 = valuePop(ctxt);
9368 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009369 if (ctxt->error) {
9370 xmlXPathFreeObject(arg2);
9371 return(0);
9372 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009373 xmlXPathBooleanFunction(ctxt, 1);
9374 arg1 = valuePop(ctxt);
9375 arg1->boolval &= arg2->boolval;
9376 valuePush(ctxt, arg1);
9377 xmlXPathFreeObject(arg2);
9378 return (total);
9379 case XPATH_OP_OR:
9380 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009381 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009382 xmlXPathBooleanFunction(ctxt, 1);
9383 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9384 return (total);
9385 arg2 = valuePop(ctxt);
9386 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009387 if (ctxt->error) {
9388 xmlXPathFreeObject(arg2);
9389 return(0);
9390 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009391 xmlXPathBooleanFunction(ctxt, 1);
9392 arg1 = valuePop(ctxt);
9393 arg1->boolval |= arg2->boolval;
9394 valuePush(ctxt, arg1);
9395 xmlXPathFreeObject(arg2);
9396 return (total);
9397 case XPATH_OP_EQUAL:
9398 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009399 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009400 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009401 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009402 equal = xmlXPathEqualValues(ctxt);
9403 if (op->value)
9404 valuePush(ctxt, xmlXPathNewBoolean(equal));
9405 else
9406 valuePush(ctxt, xmlXPathNewBoolean(!equal));
9407 return (total);
9408 case XPATH_OP_CMP:
9409 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009410 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009411 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009412 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009413 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9414 valuePush(ctxt, xmlXPathNewBoolean(ret));
9415 return (total);
9416 case XPATH_OP_PLUS:
9417 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009418 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009419 if (op->ch2 != -1)
9420 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009421 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009422 if (op->value == 0)
9423 xmlXPathSubValues(ctxt);
9424 else if (op->value == 1)
9425 xmlXPathAddValues(ctxt);
9426 else if (op->value == 2)
9427 xmlXPathValueFlipSign(ctxt);
9428 else if (op->value == 3) {
9429 CAST_TO_NUMBER;
9430 CHECK_TYPE0(XPATH_NUMBER);
9431 }
9432 return (total);
9433 case XPATH_OP_MULT:
9434 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009435 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009436 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009437 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009438 if (op->value == 0)
9439 xmlXPathMultValues(ctxt);
9440 else if (op->value == 1)
9441 xmlXPathDivValues(ctxt);
9442 else if (op->value == 2)
9443 xmlXPathModValues(ctxt);
9444 return (total);
9445 case XPATH_OP_UNION:
9446 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009447 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009448 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009449 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009450 CHECK_TYPE0(XPATH_NODESET);
9451 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009452
Daniel Veillardf06307e2001-07-03 10:35:50 +00009453 CHECK_TYPE0(XPATH_NODESET);
9454 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009455
Daniel Veillardf06307e2001-07-03 10:35:50 +00009456 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9457 arg2->nodesetval);
9458 valuePush(ctxt, arg1);
9459 xmlXPathFreeObject(arg2);
9460 return (total);
9461 case XPATH_OP_ROOT:
9462 xmlXPathRoot(ctxt);
9463 return (total);
9464 case XPATH_OP_NODE:
9465 if (op->ch1 != -1)
9466 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009467 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009468 if (op->ch2 != -1)
9469 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009470 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009471 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9472 return (total);
9473 case XPATH_OP_RESET:
9474 if (op->ch1 != -1)
9475 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009476 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009477 if (op->ch2 != -1)
9478 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009479 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009480 ctxt->context->node = NULL;
9481 return (total);
9482 case XPATH_OP_COLLECT:{
9483 if (op->ch1 == -1)
9484 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009485
Daniel Veillardf06307e2001-07-03 10:35:50 +00009486 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009487 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009488
Daniel Veillardf06307e2001-07-03 10:35:50 +00009489 /*
9490 * Optimization for [n] selection where n is a number
9491 */
9492 if ((op->ch2 != -1) &&
9493 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9494 (comp->steps[op->ch2].ch1 == -1) &&
9495 (comp->steps[op->ch2].ch2 != -1) &&
9496 (comp->steps[comp->steps[op->ch2].ch2].op ==
9497 XPATH_OP_VALUE)) {
9498 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00009499
Daniel Veillardf06307e2001-07-03 10:35:50 +00009500 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9501 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9502 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009503
Daniel Veillardf06307e2001-07-03 10:35:50 +00009504 if (val->floatval == (float) indx) {
9505 total +=
9506 xmlXPathNodeCollectAndTestNth(ctxt, op,
9507 indx, NULL,
9508 NULL);
9509 return (total);
9510 }
9511 }
9512 }
9513 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
9514 return (total);
9515 }
9516 case XPATH_OP_VALUE:
9517 valuePush(ctxt,
9518 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9519 return (total);
9520 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +00009521 xmlXPathObjectPtr val;
9522
Daniel Veillardf06307e2001-07-03 10:35:50 +00009523 if (op->ch1 != -1)
9524 total +=
9525 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009526 if (op->value5 == NULL) {
9527 val = xmlXPathVariableLookup(ctxt->context, op->value4);
9528 if (val == NULL) {
9529 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9530 return(0);
9531 }
9532 valuePush(ctxt, val);
9533 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009534 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009535
Daniel Veillardf06307e2001-07-03 10:35:50 +00009536 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9537 if (URI == NULL) {
9538 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009539 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009540 op->value4, op->value5);
9541 return (total);
9542 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009543 val = xmlXPathVariableLookupNS(ctxt->context,
9544 op->value4, URI);
9545 if (val == NULL) {
9546 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9547 return(0);
9548 }
9549 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009550 }
9551 return (total);
9552 }
9553 case XPATH_OP_FUNCTION:{
9554 xmlXPathFunction func;
9555 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +00009556 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009557
9558 if (op->ch1 != -1)
9559 total +=
9560 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009561 if (ctxt->valueNr < op->value) {
9562 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009563 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +00009564 ctxt->error = XPATH_INVALID_OPERAND;
9565 return (total);
9566 }
9567 for (i = 0; i < op->value; i++)
9568 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
9569 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009570 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +00009571 ctxt->error = XPATH_INVALID_OPERAND;
9572 return (total);
9573 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009574 if (op->cache != NULL)
9575 func = (xmlXPathFunction) op->cache;
9576 else {
9577 const xmlChar *URI = NULL;
9578
9579 if (op->value5 == NULL)
9580 func =
9581 xmlXPathFunctionLookup(ctxt->context,
9582 op->value4);
9583 else {
9584 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9585 if (URI == NULL) {
9586 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009587 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009588 op->value4, op->value5);
9589 return (total);
9590 }
9591 func = xmlXPathFunctionLookupNS(ctxt->context,
9592 op->value4, URI);
9593 }
9594 if (func == NULL) {
9595 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009596 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009597 op->value4);
9598 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009599 }
9600 op->cache = (void *) func;
9601 op->cacheURI = (void *) URI;
9602 }
9603 oldFunc = ctxt->context->function;
9604 oldFuncURI = ctxt->context->functionURI;
9605 ctxt->context->function = op->value4;
9606 ctxt->context->functionURI = op->cacheURI;
9607 func(ctxt, op->value);
9608 ctxt->context->function = oldFunc;
9609 ctxt->context->functionURI = oldFuncURI;
9610 return (total);
9611 }
9612 case XPATH_OP_ARG:
9613 if (op->ch1 != -1)
9614 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009615 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009616 if (op->ch2 != -1)
9617 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009618 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009619 return (total);
9620 case XPATH_OP_PREDICATE:
9621 case XPATH_OP_FILTER:{
9622 xmlXPathObjectPtr res;
9623 xmlXPathObjectPtr obj, tmp;
9624 xmlNodeSetPtr newset = NULL;
9625 xmlNodeSetPtr oldset;
9626 xmlNodePtr oldnode;
9627 int i;
9628
9629 /*
9630 * Optimization for ()[1] selection i.e. the first elem
9631 */
9632 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9633 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9634 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
9635 xmlXPathObjectPtr val;
9636
9637 val = comp->steps[op->ch2].value4;
9638 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
9639 (val->floatval == 1.0)) {
9640 xmlNodePtr first = NULL;
9641
9642 total +=
9643 xmlXPathCompOpEvalFirst(ctxt,
9644 &comp->steps[op->ch1],
9645 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009646 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009647 /*
9648 * The nodeset should be in document order,
9649 * Keep only the first value
9650 */
9651 if ((ctxt->value != NULL) &&
9652 (ctxt->value->type == XPATH_NODESET) &&
9653 (ctxt->value->nodesetval != NULL) &&
9654 (ctxt->value->nodesetval->nodeNr > 1))
9655 ctxt->value->nodesetval->nodeNr = 1;
9656 return (total);
9657 }
9658 }
9659 /*
9660 * Optimization for ()[last()] selection i.e. the last elem
9661 */
9662 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9663 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9664 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
9665 int f = comp->steps[op->ch2].ch1;
9666
9667 if ((f != -1) &&
9668 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
9669 (comp->steps[f].value5 == NULL) &&
9670 (comp->steps[f].value == 0) &&
9671 (comp->steps[f].value4 != NULL) &&
9672 (xmlStrEqual
9673 (comp->steps[f].value4, BAD_CAST "last"))) {
9674 xmlNodePtr last = NULL;
9675
9676 total +=
9677 xmlXPathCompOpEvalLast(ctxt,
9678 &comp->steps[op->ch1],
9679 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009680 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009681 /*
9682 * The nodeset should be in document order,
9683 * Keep only the last value
9684 */
9685 if ((ctxt->value != NULL) &&
9686 (ctxt->value->type == XPATH_NODESET) &&
9687 (ctxt->value->nodesetval != NULL) &&
9688 (ctxt->value->nodesetval->nodeTab != NULL) &&
9689 (ctxt->value->nodesetval->nodeNr > 1)) {
9690 ctxt->value->nodesetval->nodeTab[0] =
9691 ctxt->value->nodesetval->nodeTab[ctxt->
9692 value->
9693 nodesetval->
9694 nodeNr -
9695 1];
9696 ctxt->value->nodesetval->nodeNr = 1;
9697 }
9698 return (total);
9699 }
9700 }
9701
9702 if (op->ch1 != -1)
9703 total +=
9704 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009705 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009706 if (op->ch2 == -1)
9707 return (total);
9708 if (ctxt->value == NULL)
9709 return (total);
9710
9711 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009712
9713#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009714 /*
9715 * Hum are we filtering the result of an XPointer expression
9716 */
9717 if (ctxt->value->type == XPATH_LOCATIONSET) {
9718 xmlLocationSetPtr newlocset = NULL;
9719 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009720
Daniel Veillardf06307e2001-07-03 10:35:50 +00009721 /*
9722 * Extract the old locset, and then evaluate the result of the
9723 * expression for all the element in the locset. use it to grow
9724 * up a new locset.
9725 */
9726 CHECK_TYPE0(XPATH_LOCATIONSET);
9727 obj = valuePop(ctxt);
9728 oldlocset = obj->user;
9729 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009730
Daniel Veillardf06307e2001-07-03 10:35:50 +00009731 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
9732 ctxt->context->contextSize = 0;
9733 ctxt->context->proximityPosition = 0;
9734 if (op->ch2 != -1)
9735 total +=
9736 xmlXPathCompOpEval(ctxt,
9737 &comp->steps[op->ch2]);
9738 res = valuePop(ctxt);
9739 if (res != NULL)
9740 xmlXPathFreeObject(res);
9741 valuePush(ctxt, obj);
9742 CHECK_ERROR0;
9743 return (total);
9744 }
9745 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009746
Daniel Veillardf06307e2001-07-03 10:35:50 +00009747 for (i = 0; i < oldlocset->locNr; i++) {
9748 /*
9749 * Run the evaluation with a node list made of a
9750 * single item in the nodelocset.
9751 */
9752 ctxt->context->node = oldlocset->locTab[i]->user;
9753 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9754 valuePush(ctxt, tmp);
9755 ctxt->context->contextSize = oldlocset->locNr;
9756 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009757
Daniel Veillardf06307e2001-07-03 10:35:50 +00009758 if (op->ch2 != -1)
9759 total +=
9760 xmlXPathCompOpEval(ctxt,
9761 &comp->steps[op->ch2]);
9762 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009763
Daniel Veillardf06307e2001-07-03 10:35:50 +00009764 /*
9765 * The result of the evaluation need to be tested to
9766 * decided whether the filter succeeded or not
9767 */
9768 res = valuePop(ctxt);
9769 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9770 xmlXPtrLocationSetAdd(newlocset,
9771 xmlXPathObjectCopy
9772 (oldlocset->locTab[i]));
9773 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009774
Daniel Veillardf06307e2001-07-03 10:35:50 +00009775 /*
9776 * Cleanup
9777 */
9778 if (res != NULL)
9779 xmlXPathFreeObject(res);
9780 if (ctxt->value == tmp) {
9781 res = valuePop(ctxt);
9782 xmlXPathFreeObject(res);
9783 }
9784
9785 ctxt->context->node = NULL;
9786 }
9787
9788 /*
9789 * The result is used as the new evaluation locset.
9790 */
9791 xmlXPathFreeObject(obj);
9792 ctxt->context->node = NULL;
9793 ctxt->context->contextSize = -1;
9794 ctxt->context->proximityPosition = -1;
9795 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
9796 ctxt->context->node = oldnode;
9797 return (total);
9798 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009799#endif /* LIBXML_XPTR_ENABLED */
9800
Daniel Veillardf06307e2001-07-03 10:35:50 +00009801 /*
9802 * Extract the old set, and then evaluate the result of the
9803 * expression for all the element in the set. use it to grow
9804 * up a new set.
9805 */
9806 CHECK_TYPE0(XPATH_NODESET);
9807 obj = valuePop(ctxt);
9808 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00009809
Daniel Veillardf06307e2001-07-03 10:35:50 +00009810 oldnode = ctxt->context->node;
9811 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009812
Daniel Veillardf06307e2001-07-03 10:35:50 +00009813 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
9814 ctxt->context->contextSize = 0;
9815 ctxt->context->proximityPosition = 0;
9816 if (op->ch2 != -1)
9817 total +=
9818 xmlXPathCompOpEval(ctxt,
9819 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009820 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009821 res = valuePop(ctxt);
9822 if (res != NULL)
9823 xmlXPathFreeObject(res);
9824 valuePush(ctxt, obj);
9825 ctxt->context->node = oldnode;
9826 CHECK_ERROR0;
9827 } else {
9828 /*
9829 * Initialize the new set.
9830 */
9831 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009832
Daniel Veillardf06307e2001-07-03 10:35:50 +00009833 for (i = 0; i < oldset->nodeNr; i++) {
9834 /*
9835 * Run the evaluation with a node list made of
9836 * a single item in the nodeset.
9837 */
9838 ctxt->context->node = oldset->nodeTab[i];
9839 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9840 valuePush(ctxt, tmp);
9841 ctxt->context->contextSize = oldset->nodeNr;
9842 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009843
Daniel Veillardf06307e2001-07-03 10:35:50 +00009844 if (op->ch2 != -1)
9845 total +=
9846 xmlXPathCompOpEval(ctxt,
9847 &comp->steps[op->ch2]);
9848 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009849
Daniel Veillardf06307e2001-07-03 10:35:50 +00009850 /*
9851 * The result of the evaluation need to be tested to
9852 * decided whether the filter succeeded or not
9853 */
9854 res = valuePop(ctxt);
9855 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9856 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
9857 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009858
Daniel Veillardf06307e2001-07-03 10:35:50 +00009859 /*
9860 * Cleanup
9861 */
9862 if (res != NULL)
9863 xmlXPathFreeObject(res);
9864 if (ctxt->value == tmp) {
9865 res = valuePop(ctxt);
9866 xmlXPathFreeObject(res);
9867 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009868
Daniel Veillardf06307e2001-07-03 10:35:50 +00009869 ctxt->context->node = NULL;
9870 }
9871
9872 /*
9873 * The result is used as the new evaluation set.
9874 */
9875 xmlXPathFreeObject(obj);
9876 ctxt->context->node = NULL;
9877 ctxt->context->contextSize = -1;
9878 ctxt->context->proximityPosition = -1;
9879 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
9880 }
9881 ctxt->context->node = oldnode;
9882 return (total);
9883 }
9884 case XPATH_OP_SORT:
9885 if (op->ch1 != -1)
9886 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009887 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009888 if ((ctxt->value != NULL) &&
9889 (ctxt->value->type == XPATH_NODESET) &&
9890 (ctxt->value->nodesetval != NULL))
9891 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9892 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009893#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009894 case XPATH_OP_RANGETO:{
9895 xmlXPathObjectPtr range;
9896 xmlXPathObjectPtr res, obj;
9897 xmlXPathObjectPtr tmp;
9898 xmlLocationSetPtr newset = NULL;
9899 xmlNodeSetPtr oldset;
9900 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009901
Daniel Veillardf06307e2001-07-03 10:35:50 +00009902 if (op->ch1 != -1)
9903 total +=
9904 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9905 if (op->ch2 == -1)
9906 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009907
Daniel Veillardf06307e2001-07-03 10:35:50 +00009908 CHECK_TYPE0(XPATH_NODESET);
9909 obj = valuePop(ctxt);
9910 oldset = obj->nodesetval;
9911 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009912
Daniel Veillardf06307e2001-07-03 10:35:50 +00009913 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009914
Daniel Veillardf06307e2001-07-03 10:35:50 +00009915 if (oldset != NULL) {
9916 for (i = 0; i < oldset->nodeNr; i++) {
9917 /*
9918 * Run the evaluation with a node list made of a single item
9919 * in the nodeset.
9920 */
9921 ctxt->context->node = oldset->nodeTab[i];
9922 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9923 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009924
Daniel Veillardf06307e2001-07-03 10:35:50 +00009925 if (op->ch2 != -1)
9926 total +=
9927 xmlXPathCompOpEval(ctxt,
9928 &comp->steps[op->ch2]);
9929 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009930
Daniel Veillardf06307e2001-07-03 10:35:50 +00009931 /*
9932 * The result of the evaluation need to be tested to
9933 * decided whether the filter succeeded or not
9934 */
9935 res = valuePop(ctxt);
9936 range =
9937 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
9938 res);
9939 if (range != NULL) {
9940 xmlXPtrLocationSetAdd(newset, range);
9941 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009942
Daniel Veillardf06307e2001-07-03 10:35:50 +00009943 /*
9944 * Cleanup
9945 */
9946 if (res != NULL)
9947 xmlXPathFreeObject(res);
9948 if (ctxt->value == tmp) {
9949 res = valuePop(ctxt);
9950 xmlXPathFreeObject(res);
9951 }
9952
9953 ctxt->context->node = NULL;
9954 }
9955 }
9956
9957 /*
9958 * The result is used as the new evaluation set.
9959 */
9960 xmlXPathFreeObject(obj);
9961 ctxt->context->node = NULL;
9962 ctxt->context->contextSize = -1;
9963 ctxt->context->proximityPosition = -1;
9964 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
9965 return (total);
9966 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009967#endif /* LIBXML_XPTR_ENABLED */
9968 }
9969 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009970 "XPath: unknown precompiled operation %d\n", op->op);
9971 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009972}
9973
9974/**
9975 * xmlXPathRunEval:
9976 * @ctxt: the XPath parser context with the compiled expression
9977 *
9978 * Evaluate the Precompiled XPath expression in the given context.
9979 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009980static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009981xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
9982 xmlXPathCompExprPtr comp;
9983
9984 if ((ctxt == NULL) || (ctxt->comp == NULL))
9985 return;
9986
9987 if (ctxt->valueTab == NULL) {
9988 /* Allocate the value stack */
9989 ctxt->valueTab = (xmlXPathObjectPtr *)
9990 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
9991 if (ctxt->valueTab == NULL) {
9992 xmlFree(ctxt);
9993 xmlGenericError(xmlGenericErrorContext,
9994 "xmlXPathRunEval: out of memory\n");
9995 return;
9996 }
9997 ctxt->valueNr = 0;
9998 ctxt->valueMax = 10;
9999 ctxt->value = NULL;
10000 }
10001 comp = ctxt->comp;
10002 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10003}
10004
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010005/************************************************************************
10006 * *
10007 * Public interfaces *
10008 * *
10009 ************************************************************************/
10010
10011/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010012 * xmlXPathEvalPredicate:
10013 * @ctxt: the XPath context
10014 * @res: the Predicate Expression evaluation result
10015 *
10016 * Evaluate a predicate result for the current node.
10017 * A PredicateExpr is evaluated by evaluating the Expr and converting
10018 * the result to a boolean. If the result is a number, the result will
10019 * be converted to true if the number is equal to the position of the
10020 * context node in the context node list (as returned by the position
10021 * function) and will be converted to false otherwise; if the result
10022 * is not a number, then the result will be converted as if by a call
10023 * to the boolean function.
10024 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010025 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010026 */
10027int
10028xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10029 if (res == NULL) return(0);
10030 switch (res->type) {
10031 case XPATH_BOOLEAN:
10032 return(res->boolval);
10033 case XPATH_NUMBER:
10034 return(res->floatval == ctxt->proximityPosition);
10035 case XPATH_NODESET:
10036 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010037 if (res->nodesetval == NULL)
10038 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010039 return(res->nodesetval->nodeNr != 0);
10040 case XPATH_STRING:
10041 return((res->stringval != NULL) &&
10042 (xmlStrlen(res->stringval) != 0));
10043 default:
10044 STRANGE
10045 }
10046 return(0);
10047}
10048
10049/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010050 * xmlXPathEvaluatePredicateResult:
10051 * @ctxt: the XPath Parser context
10052 * @res: the Predicate Expression evaluation result
10053 *
10054 * Evaluate a predicate result for the current node.
10055 * A PredicateExpr is evaluated by evaluating the Expr and converting
10056 * the result to a boolean. If the result is a number, the result will
10057 * be converted to true if the number is equal to the position of the
10058 * context node in the context node list (as returned by the position
10059 * function) and will be converted to false otherwise; if the result
10060 * is not a number, then the result will be converted as if by a call
10061 * to the boolean function.
10062 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010063 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010064 */
10065int
10066xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10067 xmlXPathObjectPtr res) {
10068 if (res == NULL) return(0);
10069 switch (res->type) {
10070 case XPATH_BOOLEAN:
10071 return(res->boolval);
10072 case XPATH_NUMBER:
10073 return(res->floatval == ctxt->context->proximityPosition);
10074 case XPATH_NODESET:
10075 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010076 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010077 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010078 return(res->nodesetval->nodeNr != 0);
10079 case XPATH_STRING:
10080 return((res->stringval != NULL) &&
10081 (xmlStrlen(res->stringval) != 0));
10082 default:
10083 STRANGE
10084 }
10085 return(0);
10086}
10087
10088/**
10089 * xmlXPathCompile:
10090 * @str: the XPath expression
10091 *
10092 * Compile an XPath expression
10093 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010094 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010095 * the caller has to free the object.
10096 */
10097xmlXPathCompExprPtr
10098xmlXPathCompile(const xmlChar *str) {
10099 xmlXPathParserContextPtr ctxt;
10100 xmlXPathCompExprPtr comp;
10101
10102 xmlXPathInit();
10103
10104 ctxt = xmlXPathNewParserContext(str, NULL);
10105 xmlXPathCompileExpr(ctxt);
10106
Daniel Veillard40af6492001-04-22 08:50:55 +000010107 if (*ctxt->cur != 0) {
10108 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10109 comp = NULL;
10110 } else {
10111 comp = ctxt->comp;
10112 ctxt->comp = NULL;
10113 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010114 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010115#ifdef DEBUG_EVAL_COUNTS
10116 if (comp != NULL) {
10117 comp->string = xmlStrdup(str);
10118 comp->nb = 0;
10119 }
10120#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010121 return(comp);
10122}
10123
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010124/**
10125 * xmlXPathCompiledEval:
10126 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010127 * @ctx: the XPath context
10128 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010129 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010130 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010131 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010132 * the caller has to free the object.
10133 */
10134xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010135xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010136 xmlXPathParserContextPtr ctxt;
10137 xmlXPathObjectPtr res, tmp, init = NULL;
10138 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010139#ifndef LIBXML_THREAD_ENABLED
10140 static int reentance = 0;
10141#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010142
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010143 if ((comp == NULL) || (ctx == NULL))
10144 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010145 xmlXPathInit();
10146
10147 CHECK_CONTEXT(ctx)
10148
Daniel Veillard81463942001-10-16 12:34:39 +000010149#ifndef LIBXML_THREAD_ENABLED
10150 reentance++;
10151 if (reentance > 1)
10152 xmlXPathDisableOptimizer = 1;
10153#endif
10154
Daniel Veillardf06307e2001-07-03 10:35:50 +000010155#ifdef DEBUG_EVAL_COUNTS
10156 comp->nb++;
10157 if ((comp->string != NULL) && (comp->nb > 100)) {
10158 fprintf(stderr, "100 x %s\n", comp->string);
10159 comp->nb = 0;
10160 }
10161#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010162 ctxt = xmlXPathCompParserContext(comp, ctx);
10163 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010164
10165 if (ctxt->value == NULL) {
10166 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010167 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010168 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010169 } else {
10170 res = valuePop(ctxt);
10171 }
10172
Daniel Veillardf06307e2001-07-03 10:35:50 +000010173
Owen Taylor3473f882001-02-23 17:55:21 +000010174 do {
10175 tmp = valuePop(ctxt);
10176 if (tmp != NULL) {
10177 if (tmp != init)
10178 stack++;
10179 xmlXPathFreeObject(tmp);
10180 }
10181 } while (tmp != NULL);
10182 if ((stack != 0) && (res != NULL)) {
10183 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010184 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010185 stack);
10186 }
10187 if (ctxt->error != XPATH_EXPRESSION_OK) {
10188 xmlXPathFreeObject(res);
10189 res = NULL;
10190 }
10191
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010192
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010193 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010194 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010195#ifndef LIBXML_THREAD_ENABLED
10196 reentance--;
10197#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010198 return(res);
10199}
10200
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010201/**
10202 * xmlXPathEvalExpr:
10203 * @ctxt: the XPath Parser context
10204 *
10205 * Parse and evaluate an XPath expression in the given context,
10206 * then push the result on the context stack
10207 */
10208void
10209xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10210 xmlXPathCompileExpr(ctxt);
10211 xmlXPathRunEval(ctxt);
10212}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010213
10214/**
10215 * xmlXPathEval:
10216 * @str: the XPath expression
10217 * @ctx: the XPath context
10218 *
10219 * Evaluate the XPath Location Path in the given context.
10220 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010221 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010222 * the caller has to free the object.
10223 */
10224xmlXPathObjectPtr
10225xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10226 xmlXPathParserContextPtr ctxt;
10227 xmlXPathObjectPtr res, tmp, init = NULL;
10228 int stack = 0;
10229
10230 xmlXPathInit();
10231
10232 CHECK_CONTEXT(ctx)
10233
10234 ctxt = xmlXPathNewParserContext(str, ctx);
10235 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010236
10237 if (ctxt->value == NULL) {
10238 xmlGenericError(xmlGenericErrorContext,
10239 "xmlXPathEval: evaluation failed\n");
10240 res = NULL;
10241 } else if (*ctxt->cur != 0) {
10242 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10243 res = NULL;
10244 } else {
10245 res = valuePop(ctxt);
10246 }
10247
10248 do {
10249 tmp = valuePop(ctxt);
10250 if (tmp != NULL) {
10251 if (tmp != init)
10252 stack++;
10253 xmlXPathFreeObject(tmp);
10254 }
10255 } while (tmp != NULL);
10256 if ((stack != 0) && (res != NULL)) {
10257 xmlGenericError(xmlGenericErrorContext,
10258 "xmlXPathEval: %d object left on the stack\n",
10259 stack);
10260 }
10261 if (ctxt->error != XPATH_EXPRESSION_OK) {
10262 xmlXPathFreeObject(res);
10263 res = NULL;
10264 }
10265
Owen Taylor3473f882001-02-23 17:55:21 +000010266 xmlXPathFreeParserContext(ctxt);
10267 return(res);
10268}
10269
10270/**
10271 * xmlXPathEvalExpression:
10272 * @str: the XPath expression
10273 * @ctxt: the XPath context
10274 *
10275 * Evaluate the XPath expression in the given context.
10276 *
10277 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10278 * the caller has to free the object.
10279 */
10280xmlXPathObjectPtr
10281xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10282 xmlXPathParserContextPtr pctxt;
10283 xmlXPathObjectPtr res, tmp;
10284 int stack = 0;
10285
10286 xmlXPathInit();
10287
10288 CHECK_CONTEXT(ctxt)
10289
10290 pctxt = xmlXPathNewParserContext(str, ctxt);
10291 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010292
10293 if (*pctxt->cur != 0) {
10294 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10295 res = NULL;
10296 } else {
10297 res = valuePop(pctxt);
10298 }
10299 do {
10300 tmp = valuePop(pctxt);
10301 if (tmp != NULL) {
10302 xmlXPathFreeObject(tmp);
10303 stack++;
10304 }
10305 } while (tmp != NULL);
10306 if ((stack != 0) && (res != NULL)) {
10307 xmlGenericError(xmlGenericErrorContext,
10308 "xmlXPathEvalExpression: %d object left on the stack\n",
10309 stack);
10310 }
10311 xmlXPathFreeParserContext(pctxt);
10312 return(res);
10313}
10314
10315/**
10316 * xmlXPathRegisterAllFunctions:
10317 * @ctxt: the XPath context
10318 *
10319 * Registers all default XPath functions in this context
10320 */
10321void
10322xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
10323{
10324 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
10325 xmlXPathBooleanFunction);
10326 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
10327 xmlXPathCeilingFunction);
10328 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
10329 xmlXPathCountFunction);
10330 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
10331 xmlXPathConcatFunction);
10332 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
10333 xmlXPathContainsFunction);
10334 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
10335 xmlXPathIdFunction);
10336 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
10337 xmlXPathFalseFunction);
10338 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
10339 xmlXPathFloorFunction);
10340 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
10341 xmlXPathLastFunction);
10342 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
10343 xmlXPathLangFunction);
10344 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
10345 xmlXPathLocalNameFunction);
10346 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
10347 xmlXPathNotFunction);
10348 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
10349 xmlXPathNameFunction);
10350 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
10351 xmlXPathNamespaceURIFunction);
10352 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
10353 xmlXPathNormalizeFunction);
10354 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
10355 xmlXPathNumberFunction);
10356 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
10357 xmlXPathPositionFunction);
10358 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
10359 xmlXPathRoundFunction);
10360 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
10361 xmlXPathStringFunction);
10362 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
10363 xmlXPathStringLengthFunction);
10364 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
10365 xmlXPathStartsWithFunction);
10366 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
10367 xmlXPathSubstringFunction);
10368 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
10369 xmlXPathSubstringBeforeFunction);
10370 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
10371 xmlXPathSubstringAfterFunction);
10372 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
10373 xmlXPathSumFunction);
10374 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
10375 xmlXPathTrueFunction);
10376 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
10377 xmlXPathTranslateFunction);
10378}
10379
10380#endif /* LIBXML_XPATH_ENABLED */