blob: f71206441e0e7d2654630ee343be3f9c7e9fb7f2 [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
Bjorn Reese70a9da52001-04-21 16:57:29 +000019#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000020#ifdef LIBXML_XPATH_ENABLED
21
Owen Taylor3473f882001-02-23 17:55:21 +000022#include <string.h>
23
24#ifdef HAVE_SYS_TYPES_H
25#include <sys/types.h>
26#endif
27#ifdef HAVE_MATH_H
28#include <math.h>
29#endif
30#ifdef HAVE_FLOAT_H
31#include <float.h>
32#endif
Owen Taylor3473f882001-02-23 17:55:21 +000033#ifdef HAVE_CTYPE_H
34#include <ctype.h>
35#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000036#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000037#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000038#endif
Owen Taylor3473f882001-02-23 17:55:21 +000039
40#include <libxml/xmlmemory.h>
41#include <libxml/tree.h>
42#include <libxml/valid.h>
43#include <libxml/xpath.h>
44#include <libxml/xpathInternals.h>
45#include <libxml/parserInternals.h>
46#include <libxml/hash.h>
47#ifdef LIBXML_XPTR_ENABLED
48#include <libxml/xpointer.h>
49#endif
50#ifdef LIBXML_DEBUG_ENABLED
51#include <libxml/debugXML.h>
52#endif
53#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000054#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000055#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000056
57/* #define DEBUG */
58/* #define DEBUG_STEP */
Daniel Veillardf06307e2001-07-03 10:35:50 +000059/* #define DEBUG_STEP_NTH */
Owen Taylor3473f882001-02-23 17:55:21 +000060/* #define DEBUG_EXPR */
Daniel Veillardf06307e2001-07-03 10:35:50 +000061/* #define DEBUG_EVAL_COUNTS */
Owen Taylor3473f882001-02-23 17:55:21 +000062
63void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
64double xmlXPathStringEvalNumber(const xmlChar *str);
Daniel Veillard5792e162001-04-30 17:44:45 +000065double xmlXPathDivideBy(double f, double fzero);
Owen Taylor3473f882001-02-23 17:55:21 +000066
Daniel Veillard20ee8c02001-10-05 09:18:14 +000067static xmlNs xmlXPathXMLNamespaceStruct = {
68 NULL,
69 XML_NAMESPACE_DECL,
70 XML_XML_NAMESPACE,
71 BAD_CAST "xml"
72};
73static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
Daniel Veillard81463942001-10-16 12:34:39 +000074#ifndef LIBXML_THREADS_ENABLED
75/*
76 * Optimizer is disabled only when threaded apps are detected while
77 * the library ain't compiled for thread safety.
78 */
79static int xmlXPathDisableOptimizer = 0;
80#endif
Daniel Veillard20ee8c02001-10-05 09:18:14 +000081
Daniel Veillard9e7160d2001-03-18 23:17:47 +000082/************************************************************************
83 * *
84 * Floating point stuff *
85 * *
86 ************************************************************************/
87
Daniel Veillardc0631a62001-09-20 13:56:06 +000088#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +000089#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +000090#endif
Daniel Veillardcda96922001-08-21 10:56:31 +000091#include "trionan.c"
92
Owen Taylor3473f882001-02-23 17:55:21 +000093/*
Owen Taylor3473f882001-02-23 17:55:21 +000094 * The lack of portability of this section of the libc is annoying !
95 */
96double xmlXPathNAN = 0;
97double xmlXPathPINF = 1;
98double xmlXPathNINF = -1;
Daniel Veillard20ee8c02001-10-05 09:18:14 +000099static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000100
Owen Taylor3473f882001-02-23 17:55:21 +0000101/**
102 * xmlXPathInit:
103 *
104 * Initialize the XPath environment
105 */
106void
107xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000108 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +0000109
Bjorn Reese45029602001-08-21 09:23:53 +0000110 xmlXPathPINF = trio_pinf();
111 xmlXPathNINF = trio_ninf();
112 xmlXPathNAN = trio_nan();
Owen Taylor3473f882001-02-23 17:55:21 +0000113
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000114 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000115}
116
Daniel Veillardcda96922001-08-21 10:56:31 +0000117/**
118 * xmlXPathIsNaN:
119 * @val: a double value
120 *
121 * Provides a portable isnan() function to detect whether a double
122 * is a NotaNumber. Based on trio code
123 * http://sourceforge.net/projects/ctrio/
124 *
125 * Returns 1 if the value is a NaN, 0 otherwise
126 */
127int
128xmlXPathIsNaN(double val) {
129 return(trio_isnan(val));
130}
131
132/**
133 * xmlXPathIsInf:
134 * @val: a double value
135 *
136 * Provides a portable isinf() function to detect whether a double
137 * is a +Infinite or -Infinite. Based on trio code
138 * http://sourceforge.net/projects/ctrio/
139 *
140 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
141 */
142int
143xmlXPathIsInf(double val) {
144 return(trio_isinf(val));
145}
146
Owen Taylor3473f882001-02-23 17:55:21 +0000147/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000148 * *
149 * Parser Types *
150 * *
151 ************************************************************************/
152
153/*
154 * Types are private:
155 */
156
157typedef enum {
158 XPATH_OP_END=0,
159 XPATH_OP_AND,
160 XPATH_OP_OR,
161 XPATH_OP_EQUAL,
162 XPATH_OP_CMP,
163 XPATH_OP_PLUS,
164 XPATH_OP_MULT,
165 XPATH_OP_UNION,
166 XPATH_OP_ROOT,
167 XPATH_OP_NODE,
168 XPATH_OP_RESET,
169 XPATH_OP_COLLECT,
170 XPATH_OP_VALUE,
171 XPATH_OP_VARIABLE,
172 XPATH_OP_FUNCTION,
173 XPATH_OP_ARG,
174 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000175 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000176 XPATH_OP_SORT
177#ifdef LIBXML_XPTR_ENABLED
178 ,XPATH_OP_RANGETO
179#endif
180} xmlXPathOp;
181
182typedef enum {
183 AXIS_ANCESTOR = 1,
184 AXIS_ANCESTOR_OR_SELF,
185 AXIS_ATTRIBUTE,
186 AXIS_CHILD,
187 AXIS_DESCENDANT,
188 AXIS_DESCENDANT_OR_SELF,
189 AXIS_FOLLOWING,
190 AXIS_FOLLOWING_SIBLING,
191 AXIS_NAMESPACE,
192 AXIS_PARENT,
193 AXIS_PRECEDING,
194 AXIS_PRECEDING_SIBLING,
195 AXIS_SELF
196} xmlXPathAxisVal;
197
198typedef enum {
199 NODE_TEST_NONE = 0,
200 NODE_TEST_TYPE = 1,
201 NODE_TEST_PI = 2,
202 NODE_TEST_ALL = 3,
203 NODE_TEST_NS = 4,
204 NODE_TEST_NAME = 5
205} xmlXPathTestVal;
206
207typedef enum {
208 NODE_TYPE_NODE = 0,
209 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
210 NODE_TYPE_TEXT = XML_TEXT_NODE,
211 NODE_TYPE_PI = XML_PI_NODE
212} xmlXPathTypeVal;
213
214
215typedef struct _xmlXPathStepOp xmlXPathStepOp;
216typedef xmlXPathStepOp *xmlXPathStepOpPtr;
217struct _xmlXPathStepOp {
218 xmlXPathOp op;
219 int ch1;
220 int ch2;
221 int value;
222 int value2;
223 int value3;
224 void *value4;
225 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000226 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000227 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000228};
229
230struct _xmlXPathCompExpr {
231 int nbStep;
232 int maxStep;
233 xmlXPathStepOp *steps; /* ops for computation */
234 int last;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000235#ifdef DEBUG_EVAL_COUNTS
236 int nb;
237 xmlChar *string;
238#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000239};
240
241/************************************************************************
242 * *
243 * Parser Type functions *
244 * *
245 ************************************************************************/
246
247/**
248 * xmlXPathNewCompExpr:
249 *
250 * Create a new Xpath component
251 *
252 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
253 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000254static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000255xmlXPathNewCompExpr(void) {
256 xmlXPathCompExprPtr cur;
257
258 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
259 if (cur == NULL) {
260 xmlGenericError(xmlGenericErrorContext,
261 "xmlXPathNewCompExpr : malloc failed\n");
262 return(NULL);
263 }
264 memset(cur, 0, sizeof(xmlXPathCompExpr));
265 cur->maxStep = 10;
266 cur->nbStep = 0;
267 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
268 sizeof(xmlXPathStepOp));
269 if (cur->steps == NULL) {
270 xmlGenericError(xmlGenericErrorContext,
271 "xmlXPathNewCompExpr : malloc failed\n");
272 xmlFree(cur);
273 return(NULL);
274 }
275 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
276 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000277#ifdef DEBUG_EVAL_COUNTS
278 cur->nb = 0;
279#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000280 return(cur);
281}
282
283/**
284 * xmlXPathFreeCompExpr:
285 * @comp: an XPATH comp
286 *
287 * Free up the memory allocated by @comp
288 */
289void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000290xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
291{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000292 xmlXPathStepOpPtr op;
293 int i;
294
295 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000296 return;
297 for (i = 0; i < comp->nbStep; i++) {
298 op = &comp->steps[i];
299 if (op->value4 != NULL) {
300 if (op->op == XPATH_OP_VALUE)
301 xmlXPathFreeObject(op->value4);
302 else
303 xmlFree(op->value4);
304 }
305 if (op->value5 != NULL)
306 xmlFree(op->value5);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000307 }
308 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000309 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000310 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000311#ifdef DEBUG_EVAL_COUNTS
312 if (comp->string != NULL) {
313 xmlFree(comp->string);
314 }
315#endif
316
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000317 xmlFree(comp);
318}
319
320/**
321 * xmlXPathCompExprAdd:
322 * @comp: the compiled expression
323 * @ch1: first child index
324 * @ch2: second child index
325 * @op: an op
326 * @value: the first int value
327 * @value2: the second int value
328 * @value3: the third int value
329 * @value4: the first string value
330 * @value5: the second string value
331 *
332 * Add an step to an XPath Compiled Expression
333 *
334 * Returns -1 in case of failure, the index otherwise
335 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000336static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000337xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
338 xmlXPathOp op, int value,
339 int value2, int value3, void *value4, void *value5) {
340 if (comp->nbStep >= comp->maxStep) {
341 xmlXPathStepOp *real;
342
343 comp->maxStep *= 2;
344 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
345 comp->maxStep * sizeof(xmlXPathStepOp));
346 if (real == NULL) {
347 comp->maxStep /= 2;
348 xmlGenericError(xmlGenericErrorContext,
349 "xmlXPathCompExprAdd : realloc failed\n");
350 return(-1);
351 }
352 comp->steps = real;
353 }
354 comp->last = comp->nbStep;
355 comp->steps[comp->nbStep].ch1 = ch1;
356 comp->steps[comp->nbStep].ch2 = ch2;
357 comp->steps[comp->nbStep].op = op;
358 comp->steps[comp->nbStep].value = value;
359 comp->steps[comp->nbStep].value2 = value2;
360 comp->steps[comp->nbStep].value3 = value3;
361 comp->steps[comp->nbStep].value4 = value4;
362 comp->steps[comp->nbStep].value5 = value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000363 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000364 return(comp->nbStep++);
365}
366
Daniel Veillardf06307e2001-07-03 10:35:50 +0000367/**
368 * xmlXPathCompSwap:
369 * @comp: the compiled expression
370 * @op: operation index
371 *
372 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000373 */
374static void
375xmlXPathCompSwap(xmlXPathStepOpPtr op) {
376 int tmp;
377
Daniel Veillard81463942001-10-16 12:34:39 +0000378#ifdef LIBXML_THREADS_ENABLED
379 /*
380 * Since this manipulates possibly shared variables, this is
381 * disable if one detects that the library is used in a multithreaded
382 * application
383 */
384 if (xmlXPathDisableOptimizer)
385 return;
386#endif
387
Daniel Veillardf06307e2001-07-03 10:35:50 +0000388 tmp = op->ch1;
389 op->ch1 = op->ch2;
390 op->ch2 = tmp;
391}
392
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000393#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
394 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
395 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000396#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
397 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
398 (op), (val), (val2), (val3), (val4), (val5))
399
400#define PUSH_LEAVE_EXPR(op, val, val2) \
401xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
402
403#define PUSH_UNARY_EXPR(op, ch, val, val2) \
404xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
405
406#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
407xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
408
409/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000410 * *
411 * Debugging related functions *
412 * *
413 ************************************************************************/
414
415#define TODO \
416 xmlGenericError(xmlGenericErrorContext, \
417 "Unimplemented block at %s:%d\n", \
418 __FILE__, __LINE__);
419
420#define STRANGE \
421 xmlGenericError(xmlGenericErrorContext, \
422 "Internal error at %s:%d\n", \
423 __FILE__, __LINE__);
424
425#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000426static void
427xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000428 int i;
429 char shift[100];
430
431 for (i = 0;((i < depth) && (i < 25));i++)
432 shift[2 * i] = shift[2 * i + 1] = ' ';
433 shift[2 * i] = shift[2 * i + 1] = 0;
434 if (cur == NULL) {
435 fprintf(output, shift);
436 fprintf(output, "Node is NULL !\n");
437 return;
438
439 }
440
441 if ((cur->type == XML_DOCUMENT_NODE) ||
442 (cur->type == XML_HTML_DOCUMENT_NODE)) {
443 fprintf(output, shift);
444 fprintf(output, " /\n");
445 } else if (cur->type == XML_ATTRIBUTE_NODE)
446 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
447 else
448 xmlDebugDumpOneNode(output, cur, depth);
449}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000450static void
451xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000452 xmlNodePtr tmp;
453 int i;
454 char shift[100];
455
456 for (i = 0;((i < depth) && (i < 25));i++)
457 shift[2 * i] = shift[2 * i + 1] = ' ';
458 shift[2 * i] = shift[2 * i + 1] = 0;
459 if (cur == NULL) {
460 fprintf(output, shift);
461 fprintf(output, "Node is NULL !\n");
462 return;
463
464 }
465
466 while (cur != NULL) {
467 tmp = cur;
468 cur = cur->next;
469 xmlDebugDumpOneNode(output, tmp, depth);
470 }
471}
Owen Taylor3473f882001-02-23 17:55:21 +0000472
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000473static void
474xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000475 int i;
476 char shift[100];
477
478 for (i = 0;((i < depth) && (i < 25));i++)
479 shift[2 * i] = shift[2 * i + 1] = ' ';
480 shift[2 * i] = shift[2 * i + 1] = 0;
481
482 if (cur == NULL) {
483 fprintf(output, shift);
484 fprintf(output, "NodeSet is NULL !\n");
485 return;
486
487 }
488
Daniel Veillard911f49a2001-04-07 15:39:35 +0000489 if (cur != NULL) {
490 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
491 for (i = 0;i < cur->nodeNr;i++) {
492 fprintf(output, shift);
493 fprintf(output, "%d", i + 1);
494 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
495 }
Owen Taylor3473f882001-02-23 17:55:21 +0000496 }
497}
498
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000499static void
500xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000501 int i;
502 char shift[100];
503
504 for (i = 0;((i < depth) && (i < 25));i++)
505 shift[2 * i] = shift[2 * i + 1] = ' ';
506 shift[2 * i] = shift[2 * i + 1] = 0;
507
508 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
509 fprintf(output, shift);
510 fprintf(output, "Value Tree is NULL !\n");
511 return;
512
513 }
514
515 fprintf(output, shift);
516 fprintf(output, "%d", i + 1);
517 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
518}
Owen Taylor3473f882001-02-23 17:55:21 +0000519#if defined(LIBXML_XPTR_ENABLED)
520void xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth);
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000521static void
522xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000523 int i;
524 char shift[100];
525
526 for (i = 0;((i < depth) && (i < 25));i++)
527 shift[2 * i] = shift[2 * i + 1] = ' ';
528 shift[2 * i] = shift[2 * i + 1] = 0;
529
530 if (cur == NULL) {
531 fprintf(output, shift);
532 fprintf(output, "LocationSet is NULL !\n");
533 return;
534
535 }
536
537 for (i = 0;i < cur->locNr;i++) {
538 fprintf(output, shift);
539 fprintf(output, "%d : ", i + 1);
540 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
541 }
542}
Daniel Veillard017b1082001-06-21 11:20:21 +0000543#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000544
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000545/**
546 * xmlXPathDebugDumpObject:
547 * @output: the FILE * to dump the output
548 * @cur: the object to inspect
549 * @depth: indentation level
550 *
551 * Dump the content of the object for debugging purposes
552 */
553void
554xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000555 int i;
556 char shift[100];
557
558 for (i = 0;((i < depth) && (i < 25));i++)
559 shift[2 * i] = shift[2 * i + 1] = ' ';
560 shift[2 * i] = shift[2 * i + 1] = 0;
561
562 fprintf(output, shift);
563
564 if (cur == NULL) {
565 fprintf(output, "Object is empty (NULL)\n");
566 return;
567 }
568 switch(cur->type) {
569 case XPATH_UNDEFINED:
570 fprintf(output, "Object is uninitialized\n");
571 break;
572 case XPATH_NODESET:
573 fprintf(output, "Object is a Node Set :\n");
574 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
575 break;
576 case XPATH_XSLT_TREE:
577 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000578 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000579 break;
580 case XPATH_BOOLEAN:
581 fprintf(output, "Object is a Boolean : ");
582 if (cur->boolval) fprintf(output, "true\n");
583 else fprintf(output, "false\n");
584 break;
585 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000586 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000587 case 1:
588 fprintf(output, "Object is a number : +Infinity\n");
589 break;
590 case -1:
591 fprintf(output, "Object is a number : -Infinity\n");
592 break;
593 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000594 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000595 fprintf(output, "Object is a number : NaN\n");
596 } else {
597 fprintf(output, "Object is a number : %0g\n", cur->floatval);
598 }
599 }
Owen Taylor3473f882001-02-23 17:55:21 +0000600 break;
601 case XPATH_STRING:
602 fprintf(output, "Object is a string : ");
603 xmlDebugDumpString(output, cur->stringval);
604 fprintf(output, "\n");
605 break;
606 case XPATH_POINT:
607 fprintf(output, "Object is a point : index %d in node", cur->index);
608 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
609 fprintf(output, "\n");
610 break;
611 case XPATH_RANGE:
612 if ((cur->user2 == NULL) ||
613 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
614 fprintf(output, "Object is a collapsed range :\n");
615 fprintf(output, shift);
616 if (cur->index >= 0)
617 fprintf(output, "index %d in ", cur->index);
618 fprintf(output, "node\n");
619 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
620 depth + 1);
621 } else {
622 fprintf(output, "Object is a range :\n");
623 fprintf(output, shift);
624 fprintf(output, "From ");
625 if (cur->index >= 0)
626 fprintf(output, "index %d in ", cur->index);
627 fprintf(output, "node\n");
628 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
629 depth + 1);
630 fprintf(output, shift);
631 fprintf(output, "To ");
632 if (cur->index2 >= 0)
633 fprintf(output, "index %d in ", cur->index2);
634 fprintf(output, "node\n");
635 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
636 depth + 1);
637 fprintf(output, "\n");
638 }
639 break;
640 case XPATH_LOCATIONSET:
641#if defined(LIBXML_XPTR_ENABLED)
642 fprintf(output, "Object is a Location Set:\n");
643 xmlXPathDebugDumpLocationSet(output,
644 (xmlLocationSetPtr) cur->user, depth);
645#endif
646 break;
647 case XPATH_USERS:
648 fprintf(output, "Object is user defined\n");
649 break;
650 }
651}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000652
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000653static void
654xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000655 xmlXPathStepOpPtr op, int depth) {
656 int i;
657 char shift[100];
658
659 for (i = 0;((i < depth) && (i < 25));i++)
660 shift[2 * i] = shift[2 * i + 1] = ' ';
661 shift[2 * i] = shift[2 * i + 1] = 0;
662
663 fprintf(output, shift);
664 if (op == NULL) {
665 fprintf(output, "Step is NULL\n");
666 return;
667 }
668 switch (op->op) {
669 case XPATH_OP_END:
670 fprintf(output, "END"); break;
671 case XPATH_OP_AND:
672 fprintf(output, "AND"); break;
673 case XPATH_OP_OR:
674 fprintf(output, "OR"); break;
675 case XPATH_OP_EQUAL:
676 if (op->value)
677 fprintf(output, "EQUAL =");
678 else
679 fprintf(output, "EQUAL !=");
680 break;
681 case XPATH_OP_CMP:
682 if (op->value)
683 fprintf(output, "CMP <");
684 else
685 fprintf(output, "CMP >");
686 if (!op->value2)
687 fprintf(output, "=");
688 break;
689 case XPATH_OP_PLUS:
690 if (op->value == 0)
691 fprintf(output, "PLUS -");
692 else if (op->value == 1)
693 fprintf(output, "PLUS +");
694 else if (op->value == 2)
695 fprintf(output, "PLUS unary -");
696 else if (op->value == 3)
697 fprintf(output, "PLUS unary - -");
698 break;
699 case XPATH_OP_MULT:
700 if (op->value == 0)
701 fprintf(output, "MULT *");
702 else if (op->value == 1)
703 fprintf(output, "MULT div");
704 else
705 fprintf(output, "MULT mod");
706 break;
707 case XPATH_OP_UNION:
708 fprintf(output, "UNION"); break;
709 case XPATH_OP_ROOT:
710 fprintf(output, "ROOT"); break;
711 case XPATH_OP_NODE:
712 fprintf(output, "NODE"); break;
713 case XPATH_OP_RESET:
714 fprintf(output, "RESET"); break;
715 case XPATH_OP_SORT:
716 fprintf(output, "SORT"); break;
717 case XPATH_OP_COLLECT: {
718 xmlXPathAxisVal axis = op->value;
719 xmlXPathTestVal test = op->value2;
720 xmlXPathTypeVal type = op->value3;
721 const xmlChar *prefix = op->value4;
722 const xmlChar *name = op->value5;
723
724 fprintf(output, "COLLECT ");
725 switch (axis) {
726 case AXIS_ANCESTOR:
727 fprintf(output, " 'ancestors' "); break;
728 case AXIS_ANCESTOR_OR_SELF:
729 fprintf(output, " 'ancestors-or-self' "); break;
730 case AXIS_ATTRIBUTE:
731 fprintf(output, " 'attributes' "); break;
732 case AXIS_CHILD:
733 fprintf(output, " 'child' "); break;
734 case AXIS_DESCENDANT:
735 fprintf(output, " 'descendant' "); break;
736 case AXIS_DESCENDANT_OR_SELF:
737 fprintf(output, " 'descendant-or-self' "); break;
738 case AXIS_FOLLOWING:
739 fprintf(output, " 'following' "); break;
740 case AXIS_FOLLOWING_SIBLING:
741 fprintf(output, " 'following-siblings' "); break;
742 case AXIS_NAMESPACE:
743 fprintf(output, " 'namespace' "); break;
744 case AXIS_PARENT:
745 fprintf(output, " 'parent' "); break;
746 case AXIS_PRECEDING:
747 fprintf(output, " 'preceding' "); break;
748 case AXIS_PRECEDING_SIBLING:
749 fprintf(output, " 'preceding-sibling' "); break;
750 case AXIS_SELF:
751 fprintf(output, " 'self' "); break;
752 }
753 switch (test) {
754 case NODE_TEST_NONE:
755 fprintf(output, "'none' "); break;
756 case NODE_TEST_TYPE:
757 fprintf(output, "'type' "); break;
758 case NODE_TEST_PI:
759 fprintf(output, "'PI' "); break;
760 case NODE_TEST_ALL:
761 fprintf(output, "'all' "); break;
762 case NODE_TEST_NS:
763 fprintf(output, "'namespace' "); break;
764 case NODE_TEST_NAME:
765 fprintf(output, "'name' "); break;
766 }
767 switch (type) {
768 case NODE_TYPE_NODE:
769 fprintf(output, "'node' "); break;
770 case NODE_TYPE_COMMENT:
771 fprintf(output, "'comment' "); break;
772 case NODE_TYPE_TEXT:
773 fprintf(output, "'text' "); break;
774 case NODE_TYPE_PI:
775 fprintf(output, "'PI' "); break;
776 }
777 if (prefix != NULL)
778 fprintf(output, "%s:", prefix);
779 if (name != NULL)
780 fprintf(output, "%s", name);
781 break;
782
783 }
784 case XPATH_OP_VALUE: {
785 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
786
787 fprintf(output, "ELEM ");
788 xmlXPathDebugDumpObject(output, object, 0);
789 goto finish;
790 }
791 case XPATH_OP_VARIABLE: {
792 const xmlChar *prefix = op->value5;
793 const xmlChar *name = op->value4;
794
795 if (prefix != NULL)
796 fprintf(output, "VARIABLE %s:%s", prefix, name);
797 else
798 fprintf(output, "VARIABLE %s", name);
799 break;
800 }
801 case XPATH_OP_FUNCTION: {
802 int nbargs = op->value;
803 const xmlChar *prefix = op->value5;
804 const xmlChar *name = op->value4;
805
806 if (prefix != NULL)
807 fprintf(output, "FUNCTION %s:%s(%d args)",
808 prefix, name, nbargs);
809 else
810 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
811 break;
812 }
813 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
814 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000815 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +0000816#ifdef LIBXML_XPTR_ENABLED
817 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
818#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000819 default:
820 fprintf(output, "UNKNOWN %d\n", op->op); return;
821 }
822 fprintf(output, "\n");
823finish:
824 if (op->ch1 >= 0)
825 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
826 if (op->ch2 >= 0)
827 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
828}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000829
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000830/**
831 * xmlXPathDebugDumpCompExpr:
832 * @output: the FILE * for the output
833 * @comp: the precompiled XPath expression
834 * @depth: the indentation level.
835 *
836 * Dumps the tree of the compiled XPath expression.
837 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000838void
839xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
840 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000841 int i;
842 char shift[100];
843
844 for (i = 0;((i < depth) && (i < 25));i++)
845 shift[2 * i] = shift[2 * i + 1] = ' ';
846 shift[2 * i] = shift[2 * i + 1] = 0;
847
848 fprintf(output, shift);
849
850 if (comp == NULL) {
851 fprintf(output, "Compiled Expression is NULL\n");
852 return;
853 }
854 fprintf(output, "Compiled Expression : %d elements\n",
855 comp->nbStep);
856 i = comp->last;
857 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
858}
Daniel Veillard017b1082001-06-21 11:20:21 +0000859#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000860
861/************************************************************************
862 * *
863 * Parser stacks related functions and macros *
864 * *
865 ************************************************************************/
866
867/*
868 * Generic function for accessing stacks in the Parser Context
869 */
870
871#define PUSH_AND_POP(type, name) \
872extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
873 if (ctxt->name##Nr >= ctxt->name##Max) { \
874 ctxt->name##Max *= 2; \
875 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
876 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
877 if (ctxt->name##Tab == NULL) { \
878 xmlGenericError(xmlGenericErrorContext, \
879 "realloc failed !\n"); \
880 return(0); \
881 } \
882 } \
883 ctxt->name##Tab[ctxt->name##Nr] = value; \
884 ctxt->name = value; \
885 return(ctxt->name##Nr++); \
886} \
887extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
888 type ret; \
889 if (ctxt->name##Nr <= 0) return(0); \
890 ctxt->name##Nr--; \
891 if (ctxt->name##Nr > 0) \
892 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
893 else \
894 ctxt->name = NULL; \
895 ret = ctxt->name##Tab[ctxt->name##Nr]; \
896 ctxt->name##Tab[ctxt->name##Nr] = 0; \
897 return(ret); \
898} \
899
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000900/**
901 * valuePop:
902 * @ctxt: an XPath evaluation context
903 *
904 * Pops the top XPath object from the value stack
905 *
906 * Returns the XPath object just removed
907 */
908/**
909 * valuePush:
910 * @ctxt: an XPath evaluation context
911 * @value: the XPath object
912 *
913 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000914 *
915 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000916 */
Owen Taylor3473f882001-02-23 17:55:21 +0000917PUSH_AND_POP(xmlXPathObjectPtr, value)
918
Thomas Broyerf06a3d82001-07-16 04:52:57 +0000919/**
920 * xmlXPathPopBoolean:
921 * @ctxt: an XPath parser context
922 *
923 * Pops a boolean from the stack, handling conversion if needed.
924 * Check error with #xmlXPathCheckError.
925 *
926 * Returns the boolean
927 */
928int
929xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
930 xmlXPathObjectPtr obj;
931 int ret;
932
933 obj = valuePop(ctxt);
934 if (obj == NULL) {
935 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
936 return(0);
937 }
938 ret = xmlXPathCastToBoolean(obj);
939 xmlXPathFreeObject(obj);
940 return(ret);
941}
942
943/**
944 * xmlXPathPopNumber:
945 * @ctxt: an XPath parser context
946 *
947 * Pops a number from the stack, handling conversion if needed.
948 * Check error with #xmlXPathCheckError.
949 *
950 * Returns the number
951 */
952double
953xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
954 xmlXPathObjectPtr obj;
955 double ret;
956
957 obj = valuePop(ctxt);
958 if (obj == NULL) {
959 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
960 return(0);
961 }
962 ret = xmlXPathCastToNumber(obj);
963 xmlXPathFreeObject(obj);
964 return(ret);
965}
966
967/**
968 * xmlXPathPopString:
969 * @ctxt: an XPath parser context
970 *
971 * Pops a string from the stack, handling conversion if needed.
972 * Check error with #xmlXPathCheckError.
973 *
974 * Returns the string
975 */
976xmlChar *
977xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
978 xmlXPathObjectPtr obj;
979 xmlChar * ret;
980
981 obj = valuePop(ctxt);
982 if (obj == NULL) {
983 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
984 return(NULL);
985 }
986 ret = xmlXPathCastToString(obj);
987 /* TODO: needs refactoring somewhere else */
988 if (obj->stringval == ret)
989 obj->stringval = NULL;
990 xmlXPathFreeObject(obj);
991 return(ret);
992}
993
994/**
995 * xmlXPathPopNodeSet:
996 * @ctxt: an XPath parser context
997 *
998 * Pops a node-set from the stack, handling conversion if needed.
999 * Check error with #xmlXPathCheckError.
1000 *
1001 * Returns the node-set
1002 */
1003xmlNodeSetPtr
1004xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1005 xmlXPathObjectPtr obj;
1006 xmlNodeSetPtr ret;
1007
1008 if (ctxt->value == NULL) {
1009 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1010 return(NULL);
1011 }
1012 if (!xmlXPathStackIsNodeSet(ctxt)) {
1013 xmlXPathSetTypeError(ctxt);
1014 return(NULL);
1015 }
1016 obj = valuePop(ctxt);
1017 ret = obj->nodesetval;
1018 xmlXPathFreeNodeSetList(obj);
1019 return(ret);
1020}
1021
1022/**
1023 * xmlXPathPopExternal:
1024 * @ctxt: an XPath parser context
1025 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001026 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001027 * Check error with #xmlXPathCheckError.
1028 *
1029 * Returns the object
1030 */
1031void *
1032xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1033 xmlXPathObjectPtr obj;
1034 void * ret;
1035
1036 if (ctxt->value == NULL) {
1037 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1038 return(NULL);
1039 }
1040 if (ctxt->value->type != XPATH_USERS) {
1041 xmlXPathSetTypeError(ctxt);
1042 return(NULL);
1043 }
1044 obj = valuePop(ctxt);
1045 ret = obj->user;
1046 xmlXPathFreeObject(obj);
1047 return(ret);
1048}
1049
Owen Taylor3473f882001-02-23 17:55:21 +00001050/*
1051 * Macros for accessing the content. Those should be used only by the parser,
1052 * and not exported.
1053 *
1054 * Dirty macros, i.e. one need to make assumption on the context to use them
1055 *
1056 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1057 * CUR returns the current xmlChar value, i.e. a 8 bit value
1058 * in ISO-Latin or UTF-8.
1059 * This should be used internally by the parser
1060 * only to compare to ASCII values otherwise it would break when
1061 * running with UTF-8 encoding.
1062 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1063 * to compare on ASCII based substring.
1064 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1065 * strings within the parser.
1066 * CURRENT Returns the current char value, with the full decoding of
1067 * UTF-8 if we are using this mode. It returns an int.
1068 * NEXT Skip to the next character, this does the proper decoding
1069 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1070 * It returns the pointer to the current xmlChar.
1071 */
1072
1073#define CUR (*ctxt->cur)
1074#define SKIP(val) ctxt->cur += (val)
1075#define NXT(val) ctxt->cur[(val)]
1076#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001077#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1078
1079#define COPY_BUF(l,b,i,v) \
1080 if (l == 1) b[i++] = (xmlChar) v; \
1081 else i += xmlCopyChar(l,&b[i],v)
1082
1083#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001084
1085#define SKIP_BLANKS \
1086 while (IS_BLANK(*(ctxt->cur))) NEXT
1087
1088#define CURRENT (*ctxt->cur)
1089#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1090
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001091
1092#ifndef DBL_DIG
1093#define DBL_DIG 16
1094#endif
1095#ifndef DBL_EPSILON
1096#define DBL_EPSILON 1E-9
1097#endif
1098
1099#define UPPER_DOUBLE 1E9
1100#define LOWER_DOUBLE 1E-5
1101
1102#define INTEGER_DIGITS DBL_DIG
1103#define FRACTION_DIGITS (DBL_DIG + 1)
1104#define EXPONENT_DIGITS (3 + 2)
1105
1106/**
1107 * xmlXPathFormatNumber:
1108 * @number: number to format
1109 * @buffer: output buffer
1110 * @buffersize: size of output buffer
1111 *
1112 * Convert the number into a string representation.
1113 */
1114static void
1115xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1116{
Daniel Veillardcda96922001-08-21 10:56:31 +00001117 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001118 case 1:
1119 if (buffersize > (int)sizeof("+Infinity"))
1120 sprintf(buffer, "+Infinity");
1121 break;
1122 case -1:
1123 if (buffersize > (int)sizeof("-Infinity"))
1124 sprintf(buffer, "-Infinity");
1125 break;
1126 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001127 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001128 if (buffersize > (int)sizeof("NaN"))
1129 sprintf(buffer, "NaN");
1130 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001131 /* 3 is sign, decimal point, and terminating zero */
1132 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1133 int integer_place, fraction_place;
1134 char *ptr;
1135 char *after_fraction;
1136 double absolute_value;
1137 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001138
Bjorn Reese70a9da52001-04-21 16:57:29 +00001139 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001140
Bjorn Reese70a9da52001-04-21 16:57:29 +00001141 /*
1142 * First choose format - scientific or regular floating point.
1143 * In either case, result is in work, and after_fraction points
1144 * just past the fractional part.
1145 */
1146 if ( ((absolute_value > UPPER_DOUBLE) ||
1147 (absolute_value < LOWER_DOUBLE)) &&
1148 (absolute_value != 0.0) ) {
1149 /* Use scientific notation */
1150 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1151 fraction_place = DBL_DIG - 1;
1152 snprintf(work, sizeof(work),"%*.*e",
1153 integer_place, fraction_place, number);
1154 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001155 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001156 else {
1157 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001158 if (absolute_value > 0.0)
1159 integer_place = 1 + (int)log10(absolute_value);
1160 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001161 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001162 fraction_place = (integer_place > 0)
1163 ? DBL_DIG - integer_place
1164 : DBL_DIG;
1165 size = snprintf(work, sizeof(work), "%0.*f",
1166 fraction_place, number);
1167 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001168 }
1169
Bjorn Reese70a9da52001-04-21 16:57:29 +00001170 /* Remove fractional trailing zeroes */
1171 ptr = after_fraction;
1172 while (*(--ptr) == '0')
1173 ;
1174 if (*ptr != '.')
1175 ptr++;
1176 strcpy(ptr, after_fraction);
1177
1178 /* Finally copy result back to caller */
1179 size = strlen(work) + 1;
1180 if (size > buffersize) {
1181 work[buffersize - 1] = 0;
1182 size = buffersize;
1183 }
1184 memcpy(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001185 }
1186 break;
1187 }
1188}
1189
Owen Taylor3473f882001-02-23 17:55:21 +00001190/************************************************************************
1191 * *
1192 * Error handling routines *
1193 * *
1194 ************************************************************************/
1195
1196
Daniel Veillardb44025c2001-10-11 22:55:55 +00001197static const char *xmlXPathErrorMessages[] = {
Owen Taylor3473f882001-02-23 17:55:21 +00001198 "Ok",
1199 "Number encoding",
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001200 "Unfinished literal",
1201 "Start of literal",
Owen Taylor3473f882001-02-23 17:55:21 +00001202 "Expected $ for variable reference",
1203 "Undefined variable",
1204 "Invalid predicate",
1205 "Invalid expression",
1206 "Missing closing curly brace",
1207 "Unregistered function",
1208 "Invalid operand",
1209 "Invalid type",
1210 "Invalid number of arguments",
1211 "Invalid context size",
1212 "Invalid context position",
1213 "Memory allocation error",
1214 "Syntax error",
1215 "Resource error",
1216 "Sub resource error",
Daniel Veillard61d80a22001-04-27 17:13:01 +00001217 "Undefined namespace prefix",
1218 "Encoding error",
1219 "Char out of XML range"
Owen Taylor3473f882001-02-23 17:55:21 +00001220};
1221
1222/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001223 * xmlXPatherror:
Owen Taylor3473f882001-02-23 17:55:21 +00001224 * @ctxt: the XPath Parser context
1225 * @file: the file name
1226 * @line: the line number
1227 * @no: the error number
1228 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001229 * Formats an error message.
Owen Taylor3473f882001-02-23 17:55:21 +00001230 */
1231void
1232xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
1233 int line, int no) {
1234 int n;
1235 const xmlChar *cur;
1236 const xmlChar *base;
1237
1238 xmlGenericError(xmlGenericErrorContext,
1239 "Error %s:%d: %s\n", file, line,
1240 xmlXPathErrorMessages[no]);
1241
1242 cur = ctxt->cur;
1243 base = ctxt->base;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001244 if ((cur == NULL) || (base == NULL))
1245 return;
1246
Owen Taylor3473f882001-02-23 17:55:21 +00001247 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
1248 cur--;
1249 }
1250 n = 0;
1251 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
1252 cur--;
1253 if ((*cur == '\n') || (*cur == '\r')) cur++;
1254 base = cur;
1255 n = 0;
1256 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1257 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
1258 n++;
1259 }
1260 xmlGenericError(xmlGenericErrorContext, "\n");
1261 cur = ctxt->cur;
1262 while ((*cur == '\n') || (*cur == '\r'))
1263 cur--;
1264 n = 0;
1265 while ((cur != base) && (n++ < 80)) {
1266 xmlGenericError(xmlGenericErrorContext, " ");
1267 base++;
1268 }
1269 xmlGenericError(xmlGenericErrorContext,"^\n");
1270}
1271
1272
1273/************************************************************************
1274 * *
1275 * Routines to handle NodeSets *
1276 * *
1277 ************************************************************************/
1278
1279/**
1280 * xmlXPathCmpNodes:
1281 * @node1: the first node
1282 * @node2: the second node
1283 *
1284 * Compare two nodes w.r.t document order
1285 *
1286 * Returns -2 in case of error 1 if first point < second point, 0 if
1287 * that's the same node, -1 otherwise
1288 */
1289int
1290xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1291 int depth1, depth2;
1292 xmlNodePtr cur, root;
1293
1294 if ((node1 == NULL) || (node2 == NULL))
1295 return(-2);
1296 /*
1297 * a couple of optimizations which will avoid computations in most cases
1298 */
1299 if (node1 == node2)
1300 return(0);
Daniel Veillardb33c2012001-04-25 12:59:04 +00001301 if ((node1->type == XML_NAMESPACE_DECL) ||
1302 (node2->type == XML_NAMESPACE_DECL))
1303 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001304 if (node1 == node2->prev)
1305 return(1);
1306 if (node1 == node2->next)
1307 return(-1);
1308
1309 /*
1310 * compute depth to root
1311 */
1312 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1313 if (cur == node1)
1314 return(1);
1315 depth2++;
1316 }
1317 root = cur;
1318 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1319 if (cur == node2)
1320 return(-1);
1321 depth1++;
1322 }
1323 /*
1324 * Distinct document (or distinct entities :-( ) case.
1325 */
1326 if (root != cur) {
1327 return(-2);
1328 }
1329 /*
1330 * get the nearest common ancestor.
1331 */
1332 while (depth1 > depth2) {
1333 depth1--;
1334 node1 = node1->parent;
1335 }
1336 while (depth2 > depth1) {
1337 depth2--;
1338 node2 = node2->parent;
1339 }
1340 while (node1->parent != node2->parent) {
1341 node1 = node1->parent;
1342 node2 = node2->parent;
1343 /* should not happen but just in case ... */
1344 if ((node1 == NULL) || (node2 == NULL))
1345 return(-2);
1346 }
1347 /*
1348 * Find who's first.
1349 */
1350 if (node1 == node2->next)
1351 return(-1);
1352 for (cur = node1->next;cur != NULL;cur = cur->next)
1353 if (cur == node2)
1354 return(1);
1355 return(-1); /* assume there is no sibling list corruption */
1356}
1357
1358/**
1359 * xmlXPathNodeSetSort:
1360 * @set: the node set
1361 *
1362 * Sort the node set in document order
1363 */
1364void
1365xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001366 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001367 xmlNodePtr tmp;
1368
1369 if (set == NULL)
1370 return;
1371
1372 /* Use Shell's sort to sort the node-set */
1373 len = set->nodeNr;
1374 for (incr = len / 2; incr > 0; incr /= 2) {
1375 for (i = incr; i < len; i++) {
1376 j = i - incr;
1377 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001378 if (xmlXPathCmpNodes(set->nodeTab[j],
1379 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001380 tmp = set->nodeTab[j];
1381 set->nodeTab[j] = set->nodeTab[j + incr];
1382 set->nodeTab[j + incr] = tmp;
1383 j -= incr;
1384 } else
1385 break;
1386 }
1387 }
1388 }
1389}
1390
1391#define XML_NODESET_DEFAULT 10
1392/**
1393 * xmlXPathNodeSetCreate:
1394 * @val: an initial xmlNodePtr, or NULL
1395 *
1396 * Create a new xmlNodeSetPtr of type double and of value @val
1397 *
1398 * Returns the newly created object.
1399 */
1400xmlNodeSetPtr
1401xmlXPathNodeSetCreate(xmlNodePtr val) {
1402 xmlNodeSetPtr ret;
1403
1404 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1405 if (ret == NULL) {
1406 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001407 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001408 return(NULL);
1409 }
1410 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1411 if (val != NULL) {
1412 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1413 sizeof(xmlNodePtr));
1414 if (ret->nodeTab == NULL) {
1415 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001416 "xmlXPathNodeSetCreate: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001417 return(NULL);
1418 }
1419 memset(ret->nodeTab, 0 ,
1420 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1421 ret->nodeMax = XML_NODESET_DEFAULT;
1422 ret->nodeTab[ret->nodeNr++] = val;
1423 }
1424 return(ret);
1425}
1426
1427/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001428 * xmlXPathNodeSetContains:
1429 * @cur: the node-set
1430 * @val: the node
1431 *
1432 * checks whether @cur contains @val
1433 *
1434 * Returns true (1) if @cur contains @val, false (0) otherwise
1435 */
1436int
1437xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1438 int i;
1439
1440 for (i = 0; i < cur->nodeNr; i++) {
1441 if (cur->nodeTab[i] == val)
1442 return(1);
1443 }
1444 return(0);
1445}
1446
1447/**
Owen Taylor3473f882001-02-23 17:55:21 +00001448 * xmlXPathNodeSetAdd:
1449 * @cur: the initial node set
1450 * @val: a new xmlNodePtr
1451 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001452 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001453 */
1454void
1455xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1456 int i;
1457
1458 if (val == NULL) return;
1459
1460 /*
1461 * check against doublons
1462 */
1463 for (i = 0;i < cur->nodeNr;i++)
1464 if (cur->nodeTab[i] == val) return;
1465
1466 /*
1467 * grow the nodeTab if needed
1468 */
1469 if (cur->nodeMax == 0) {
1470 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1471 sizeof(xmlNodePtr));
1472 if (cur->nodeTab == NULL) {
1473 xmlGenericError(xmlGenericErrorContext,
1474 "xmlXPathNodeSetAdd: out of memory\n");
1475 return;
1476 }
1477 memset(cur->nodeTab, 0 ,
1478 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1479 cur->nodeMax = XML_NODESET_DEFAULT;
1480 } else if (cur->nodeNr == cur->nodeMax) {
1481 xmlNodePtr *temp;
1482
1483 cur->nodeMax *= 2;
1484 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1485 sizeof(xmlNodePtr));
1486 if (temp == NULL) {
1487 xmlGenericError(xmlGenericErrorContext,
1488 "xmlXPathNodeSetAdd: out of memory\n");
1489 return;
1490 }
1491 cur->nodeTab = temp;
1492 }
1493 cur->nodeTab[cur->nodeNr++] = val;
1494}
1495
1496/**
1497 * xmlXPathNodeSetAddUnique:
1498 * @cur: the initial node set
1499 * @val: a new xmlNodePtr
1500 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001501 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001502 * when we are sure the node is not already in the set.
1503 */
1504void
1505xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1506 if (val == NULL) return;
1507
1508 /*
1509 * grow the nodeTab if needed
1510 */
1511 if (cur->nodeMax == 0) {
1512 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1513 sizeof(xmlNodePtr));
1514 if (cur->nodeTab == NULL) {
1515 xmlGenericError(xmlGenericErrorContext,
1516 "xmlXPathNodeSetAddUnique: out of memory\n");
1517 return;
1518 }
1519 memset(cur->nodeTab, 0 ,
1520 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1521 cur->nodeMax = XML_NODESET_DEFAULT;
1522 } else if (cur->nodeNr == cur->nodeMax) {
1523 xmlNodePtr *temp;
1524
1525 cur->nodeMax *= 2;
1526 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1527 sizeof(xmlNodePtr));
1528 if (temp == NULL) {
1529 xmlGenericError(xmlGenericErrorContext,
1530 "xmlXPathNodeSetAddUnique: out of memory\n");
1531 return;
1532 }
1533 cur->nodeTab = temp;
1534 }
1535 cur->nodeTab[cur->nodeNr++] = val;
1536}
1537
1538/**
1539 * xmlXPathNodeSetMerge:
1540 * @val1: the first NodeSet or NULL
1541 * @val2: the second NodeSet
1542 *
1543 * Merges two nodesets, all nodes from @val2 are added to @val1
1544 * if @val1 is NULL, a new set is created and copied from @val2
1545 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001546 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001547 */
1548xmlNodeSetPtr
1549xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001550 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001551
1552 if (val2 == NULL) return(val1);
1553 if (val1 == NULL) {
1554 val1 = xmlXPathNodeSetCreate(NULL);
1555 }
1556
1557 initNr = val1->nodeNr;
1558
1559 for (i = 0;i < val2->nodeNr;i++) {
1560 /*
1561 * check against doublons
1562 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001563 skip = 0;
1564 for (j = 0; j < initNr; j++) {
1565 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1566 skip = 1;
1567 break;
1568 }
1569 }
1570 if (skip)
1571 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001572
1573 /*
1574 * grow the nodeTab if needed
1575 */
1576 if (val1->nodeMax == 0) {
1577 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1578 sizeof(xmlNodePtr));
1579 if (val1->nodeTab == NULL) {
1580 xmlGenericError(xmlGenericErrorContext,
1581 "xmlXPathNodeSetMerge: out of memory\n");
1582 return(NULL);
1583 }
1584 memset(val1->nodeTab, 0 ,
1585 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1586 val1->nodeMax = XML_NODESET_DEFAULT;
1587 } else if (val1->nodeNr == val1->nodeMax) {
1588 xmlNodePtr *temp;
1589
1590 val1->nodeMax *= 2;
1591 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1592 sizeof(xmlNodePtr));
1593 if (temp == NULL) {
1594 xmlGenericError(xmlGenericErrorContext,
1595 "xmlXPathNodeSetMerge: out of memory\n");
1596 return(NULL);
1597 }
1598 val1->nodeTab = temp;
1599 }
1600 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1601 }
1602
1603 return(val1);
1604}
1605
1606/**
1607 * xmlXPathNodeSetDel:
1608 * @cur: the initial node set
1609 * @val: an xmlNodePtr
1610 *
1611 * Removes an xmlNodePtr from an existing NodeSet
1612 */
1613void
1614xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
1615 int i;
1616
1617 if (cur == NULL) return;
1618 if (val == NULL) return;
1619
1620 /*
1621 * check against doublons
1622 */
1623 for (i = 0;i < cur->nodeNr;i++)
1624 if (cur->nodeTab[i] == val) break;
1625
1626 if (i >= cur->nodeNr) {
1627#ifdef DEBUG
1628 xmlGenericError(xmlGenericErrorContext,
1629 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
1630 val->name);
1631#endif
1632 return;
1633 }
1634 cur->nodeNr--;
1635 for (;i < cur->nodeNr;i++)
1636 cur->nodeTab[i] = cur->nodeTab[i + 1];
1637 cur->nodeTab[cur->nodeNr] = NULL;
1638}
1639
1640/**
1641 * xmlXPathNodeSetRemove:
1642 * @cur: the initial node set
1643 * @val: the index to remove
1644 *
1645 * Removes an entry from an existing NodeSet list.
1646 */
1647void
1648xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
1649 if (cur == NULL) return;
1650 if (val >= cur->nodeNr) return;
1651 cur->nodeNr--;
1652 for (;val < cur->nodeNr;val++)
1653 cur->nodeTab[val] = cur->nodeTab[val + 1];
1654 cur->nodeTab[cur->nodeNr] = NULL;
1655}
1656
1657/**
1658 * xmlXPathFreeNodeSet:
1659 * @obj: the xmlNodeSetPtr to free
1660 *
1661 * Free the NodeSet compound (not the actual nodes !).
1662 */
1663void
1664xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
1665 if (obj == NULL) return;
1666 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001667 xmlFree(obj->nodeTab);
1668 }
Owen Taylor3473f882001-02-23 17:55:21 +00001669 xmlFree(obj);
1670}
1671
1672/**
1673 * xmlXPathFreeValueTree:
1674 * @obj: the xmlNodeSetPtr to free
1675 *
1676 * Free the NodeSet compound and the actual tree, this is different
1677 * from xmlXPathFreeNodeSet()
1678 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001679static void
Owen Taylor3473f882001-02-23 17:55:21 +00001680xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
1681 int i;
1682
1683 if (obj == NULL) return;
1684 for (i = 0;i < obj->nodeNr;i++)
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00001685 if (obj->nodeTab[i] != NULL)
Daniel Veillardbbd51d52001-02-24 03:07:03 +00001686 xmlFreeNodeList(obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001687
1688 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001689 xmlFree(obj->nodeTab);
1690 }
Owen Taylor3473f882001-02-23 17:55:21 +00001691 xmlFree(obj);
1692}
1693
1694#if defined(DEBUG) || defined(DEBUG_STEP)
1695/**
1696 * xmlGenericErrorContextNodeSet:
1697 * @output: a FILE * for the output
1698 * @obj: the xmlNodeSetPtr to free
1699 *
1700 * Quick display of a NodeSet
1701 */
1702void
1703xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
1704 int i;
1705
1706 if (output == NULL) output = xmlGenericErrorContext;
1707 if (obj == NULL) {
1708 fprintf(output, "NodeSet == NULL !\n");
1709 return;
1710 }
1711 if (obj->nodeNr == 0) {
1712 fprintf(output, "NodeSet is empty\n");
1713 return;
1714 }
1715 if (obj->nodeTab == NULL) {
1716 fprintf(output, " nodeTab == NULL !\n");
1717 return;
1718 }
1719 for (i = 0; i < obj->nodeNr; i++) {
1720 if (obj->nodeTab[i] == NULL) {
1721 fprintf(output, " NULL !\n");
1722 return;
1723 }
1724 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
1725 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
1726 fprintf(output, " /");
1727 else if (obj->nodeTab[i]->name == NULL)
1728 fprintf(output, " noname!");
1729 else fprintf(output, " %s", obj->nodeTab[i]->name);
1730 }
1731 fprintf(output, "\n");
1732}
1733#endif
1734
1735/**
1736 * xmlXPathNewNodeSet:
1737 * @val: the NodePtr value
1738 *
1739 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1740 * it with the single Node @val
1741 *
1742 * Returns the newly created object.
1743 */
1744xmlXPathObjectPtr
1745xmlXPathNewNodeSet(xmlNodePtr val) {
1746 xmlXPathObjectPtr ret;
1747
1748 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1749 if (ret == NULL) {
1750 xmlGenericError(xmlGenericErrorContext,
1751 "xmlXPathNewNodeSet: out of memory\n");
1752 return(NULL);
1753 }
1754 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1755 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00001756 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001757 ret->nodesetval = xmlXPathNodeSetCreate(val);
1758 return(ret);
1759}
1760
1761/**
1762 * xmlXPathNewValueTree:
1763 * @val: the NodePtr value
1764 *
1765 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
1766 * it with the tree root @val
1767 *
1768 * Returns the newly created object.
1769 */
1770xmlXPathObjectPtr
1771xmlXPathNewValueTree(xmlNodePtr val) {
1772 xmlXPathObjectPtr ret;
1773
1774 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1775 if (ret == NULL) {
1776 xmlGenericError(xmlGenericErrorContext,
1777 "xmlXPathNewNodeSet: out of memory\n");
1778 return(NULL);
1779 }
1780 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1781 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00001782 ret->boolval = 1;
1783 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00001784 ret->nodesetval = xmlXPathNodeSetCreate(val);
1785 return(ret);
1786}
1787
1788/**
1789 * xmlXPathNewNodeSetList:
1790 * @val: an existing NodeSet
1791 *
1792 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1793 * it with the Nodeset @val
1794 *
1795 * Returns the newly created object.
1796 */
1797xmlXPathObjectPtr
1798xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
1799 xmlXPathObjectPtr ret;
1800 int i;
1801
1802 if (val == NULL)
1803 ret = NULL;
1804 else if (val->nodeTab == NULL)
1805 ret = xmlXPathNewNodeSet(NULL);
1806 else
1807 {
1808 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
1809 for (i = 1; i < val->nodeNr; ++i)
1810 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
1811 }
1812
1813 return(ret);
1814}
1815
1816/**
1817 * xmlXPathWrapNodeSet:
1818 * @val: the NodePtr value
1819 *
1820 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1821 *
1822 * Returns the newly created object.
1823 */
1824xmlXPathObjectPtr
1825xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
1826 xmlXPathObjectPtr ret;
1827
1828 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1829 if (ret == NULL) {
1830 xmlGenericError(xmlGenericErrorContext,
1831 "xmlXPathWrapNodeSet: out of memory\n");
1832 return(NULL);
1833 }
1834 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1835 ret->type = XPATH_NODESET;
1836 ret->nodesetval = val;
1837 return(ret);
1838}
1839
1840/**
1841 * xmlXPathFreeNodeSetList:
1842 * @obj: an existing NodeSetList object
1843 *
1844 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
1845 * the list contrary to xmlXPathFreeObject().
1846 */
1847void
1848xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
1849 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001850 xmlFree(obj);
1851}
1852
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001853/**
1854 * xmlXPathDifference:
1855 * @nodes1: a node-set
1856 * @nodes2: a node-set
1857 *
1858 * Implements the EXSLT - Sets difference() function:
1859 * node-set set:difference (node-set, node-set)
1860 *
1861 * Returns the difference between the two node sets, or nodes1 if
1862 * nodes2 is empty
1863 */
1864xmlNodeSetPtr
1865xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
1866 xmlNodeSetPtr ret;
1867 int i, l1;
1868 xmlNodePtr cur;
1869
1870 if (xmlXPathNodeSetIsEmpty(nodes2))
1871 return(nodes1);
1872
1873 ret = xmlXPathNodeSetCreate(NULL);
1874 if (xmlXPathNodeSetIsEmpty(nodes1))
1875 return(ret);
1876
1877 l1 = xmlXPathNodeSetGetLength(nodes1);
1878
1879 for (i = 0; i < l1; i++) {
1880 cur = xmlXPathNodeSetItem(nodes1, i);
1881 if (!xmlXPathNodeSetContains(nodes2, cur))
1882 xmlXPathNodeSetAddUnique(ret, cur);
1883 }
1884 return(ret);
1885}
1886
1887/**
1888 * xmlXPathIntersection:
1889 * @nodes1: a node-set
1890 * @nodes2: a node-set
1891 *
1892 * Implements the EXSLT - Sets intersection() function:
1893 * node-set set:intersection (node-set, node-set)
1894 *
1895 * Returns a node set comprising the nodes that are within both the
1896 * node sets passed as arguments
1897 */
1898xmlNodeSetPtr
1899xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
1900 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
1901 int i, l1;
1902 xmlNodePtr cur;
1903
1904 if (xmlXPathNodeSetIsEmpty(nodes1))
1905 return(ret);
1906 if (xmlXPathNodeSetIsEmpty(nodes2))
1907 return(ret);
1908
1909 l1 = xmlXPathNodeSetGetLength(nodes1);
1910
1911 for (i = 0; i < l1; i++) {
1912 cur = xmlXPathNodeSetItem(nodes1, i);
1913 if (xmlXPathNodeSetContains(nodes2, cur))
1914 xmlXPathNodeSetAddUnique(ret, cur);
1915 }
1916 return(ret);
1917}
1918
1919/**
1920 * xmlXPathDistinctSorted:
1921 * @nodes: a node-set, sorted by document order
1922 *
1923 * Implements the EXSLT - Sets distinct() function:
1924 * node-set set:distinct (node-set)
1925 *
1926 * Returns a subset of the nodes contained in @nodes, or @nodes if
1927 * it is empty
1928 */
1929xmlNodeSetPtr
1930xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
1931 xmlNodeSetPtr ret;
1932 xmlHashTablePtr hash;
1933 int i, l;
1934 xmlChar * strval;
1935 xmlNodePtr cur;
1936
1937 if (xmlXPathNodeSetIsEmpty(nodes))
1938 return(nodes);
1939
1940 ret = xmlXPathNodeSetCreate(NULL);
1941 l = xmlXPathNodeSetGetLength(nodes);
1942 hash = xmlHashCreate (l);
1943 for (i = 0; i < l; i++) {
1944 cur = xmlXPathNodeSetItem(nodes, i);
1945 strval = xmlXPathCastNodeToString(cur);
1946 if (xmlHashLookup(hash, strval) == NULL) {
1947 xmlHashAddEntry(hash, strval, strval);
1948 xmlXPathNodeSetAddUnique(ret, cur);
1949 } else {
1950 xmlFree(strval);
1951 }
1952 }
1953 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
1954 return(ret);
1955}
1956
1957/**
1958 * xmlXPathDistinct:
1959 * @nodes: a node-set
1960 *
1961 * Implements the EXSLT - Sets distinct() function:
1962 * node-set set:distinct (node-set)
1963 * @nodes is sorted by document order, then #exslSetsDistinctSorted
1964 * is called with the sorted node-set
1965 *
1966 * Returns a subset of the nodes contained in @nodes, or @nodes if
1967 * it is empty
1968 */
1969xmlNodeSetPtr
1970xmlXPathDistinct (xmlNodeSetPtr nodes) {
1971 if (xmlXPathNodeSetIsEmpty(nodes))
1972 return(nodes);
1973
1974 xmlXPathNodeSetSort(nodes);
1975 return(xmlXPathDistinctSorted(nodes));
1976}
1977
1978/**
1979 * xmlXPathHasSameNodes:
1980 * @nodes1: a node-set
1981 * @nodes2: a node-set
1982 *
1983 * Implements the EXSLT - Sets has-same-nodes function:
1984 * boolean set:has-same-node(node-set, node-set)
1985 *
1986 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
1987 * otherwise
1988 */
1989int
1990xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
1991 int i, l;
1992 xmlNodePtr cur;
1993
1994 if (xmlXPathNodeSetIsEmpty(nodes1) ||
1995 xmlXPathNodeSetIsEmpty(nodes2))
1996 return(0);
1997
1998 l = xmlXPathNodeSetGetLength(nodes1);
1999 for (i = 0; i < l; i++) {
2000 cur = xmlXPathNodeSetItem(nodes1, i);
2001 if (xmlXPathNodeSetContains(nodes2, cur))
2002 return(1);
2003 }
2004 return(0);
2005}
2006
2007/**
2008 * xmlXPathNodeLeadingSorted:
2009 * @nodes: a node-set, sorted by document order
2010 * @node: a node
2011 *
2012 * Implements the EXSLT - Sets leading() function:
2013 * node-set set:leading (node-set, node-set)
2014 *
2015 * Returns the nodes in @nodes that precede @node in document order,
2016 * @nodes if @node is NULL or an empty node-set if @nodes
2017 * doesn't contain @node
2018 */
2019xmlNodeSetPtr
2020xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2021 int i, l;
2022 xmlNodePtr cur;
2023 xmlNodeSetPtr ret;
2024
2025 if (node == NULL)
2026 return(nodes);
2027
2028 ret = xmlXPathNodeSetCreate(NULL);
2029 if (xmlXPathNodeSetIsEmpty(nodes) ||
2030 (!xmlXPathNodeSetContains(nodes, node)))
2031 return(ret);
2032
2033 l = xmlXPathNodeSetGetLength(nodes);
2034 for (i = 0; i < l; i++) {
2035 cur = xmlXPathNodeSetItem(nodes, i);
2036 if (cur == node)
2037 break;
2038 xmlXPathNodeSetAddUnique(ret, cur);
2039 }
2040 return(ret);
2041}
2042
2043/**
2044 * xmlXPathNodeLeading:
2045 * @nodes: a node-set
2046 * @node: a node
2047 *
2048 * Implements the EXSLT - Sets leading() function:
2049 * node-set set:leading (node-set, node-set)
2050 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2051 * is called.
2052 *
2053 * Returns the nodes in @nodes that precede @node in document order,
2054 * @nodes if @node is NULL or an empty node-set if @nodes
2055 * doesn't contain @node
2056 */
2057xmlNodeSetPtr
2058xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2059 xmlXPathNodeSetSort(nodes);
2060 return(xmlXPathNodeLeadingSorted(nodes, node));
2061}
2062
2063/**
2064 * xmlXPathLeadingSorted:
2065 * @nodes1: a node-set, sorted by document order
2066 * @nodes2: a node-set, sorted by document order
2067 *
2068 * Implements the EXSLT - Sets leading() function:
2069 * node-set set:leading (node-set, node-set)
2070 *
2071 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2072 * in document order, @nodes1 if @nodes2 is NULL or empty or
2073 * an empty node-set if @nodes1 doesn't contain @nodes2
2074 */
2075xmlNodeSetPtr
2076xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2077 if (xmlXPathNodeSetIsEmpty(nodes2))
2078 return(nodes1);
2079 return(xmlXPathNodeLeadingSorted(nodes1,
2080 xmlXPathNodeSetItem(nodes2, 1)));
2081}
2082
2083/**
2084 * xmlXPathLeading:
2085 * @nodes1: a node-set
2086 * @nodes2: a node-set
2087 *
2088 * Implements the EXSLT - Sets leading() function:
2089 * node-set set:leading (node-set, node-set)
2090 * @nodes1 and @nodes2 are sorted by document order, then
2091 * #exslSetsLeadingSorted is called.
2092 *
2093 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2094 * in document order, @nodes1 if @nodes2 is NULL or empty or
2095 * an empty node-set if @nodes1 doesn't contain @nodes2
2096 */
2097xmlNodeSetPtr
2098xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2099 if (xmlXPathNodeSetIsEmpty(nodes2))
2100 return(nodes1);
2101 if (xmlXPathNodeSetIsEmpty(nodes1))
2102 return(xmlXPathNodeSetCreate(NULL));
2103 xmlXPathNodeSetSort(nodes1);
2104 xmlXPathNodeSetSort(nodes2);
2105 return(xmlXPathNodeLeadingSorted(nodes1,
2106 xmlXPathNodeSetItem(nodes2, 1)));
2107}
2108
2109/**
2110 * xmlXPathNodeTrailingSorted:
2111 * @nodes: a node-set, sorted by document order
2112 * @node: a node
2113 *
2114 * Implements the EXSLT - Sets trailing() function:
2115 * node-set set:trailing (node-set, node-set)
2116 *
2117 * Returns the nodes in @nodes that follow @node in document order,
2118 * @nodes if @node is NULL or an empty node-set if @nodes
2119 * doesn't contain @node
2120 */
2121xmlNodeSetPtr
2122xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2123 int i, l;
2124 xmlNodePtr cur;
2125 xmlNodeSetPtr ret;
2126
2127 if (node == NULL)
2128 return(nodes);
2129
2130 ret = xmlXPathNodeSetCreate(NULL);
2131 if (xmlXPathNodeSetIsEmpty(nodes) ||
2132 (!xmlXPathNodeSetContains(nodes, node)))
2133 return(ret);
2134
2135 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002136 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002137 cur = xmlXPathNodeSetItem(nodes, i);
2138 if (cur == node)
2139 break;
2140 xmlXPathNodeSetAddUnique(ret, cur);
2141 }
2142 return(ret);
2143}
2144
2145/**
2146 * xmlXPathNodeTrailing:
2147 * @nodes: a node-set
2148 * @node: a node
2149 *
2150 * Implements the EXSLT - Sets trailing() function:
2151 * node-set set:trailing (node-set, node-set)
2152 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2153 * is called.
2154 *
2155 * Returns the nodes in @nodes that follow @node in document order,
2156 * @nodes if @node is NULL or an empty node-set if @nodes
2157 * doesn't contain @node
2158 */
2159xmlNodeSetPtr
2160xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2161 xmlXPathNodeSetSort(nodes);
2162 return(xmlXPathNodeTrailingSorted(nodes, node));
2163}
2164
2165/**
2166 * xmlXPathTrailingSorted:
2167 * @nodes1: a node-set, sorted by document order
2168 * @nodes2: a node-set, sorted by document order
2169 *
2170 * Implements the EXSLT - Sets trailing() function:
2171 * node-set set:trailing (node-set, node-set)
2172 *
2173 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2174 * in document order, @nodes1 if @nodes2 is NULL or empty or
2175 * an empty node-set if @nodes1 doesn't contain @nodes2
2176 */
2177xmlNodeSetPtr
2178xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2179 if (xmlXPathNodeSetIsEmpty(nodes2))
2180 return(nodes1);
2181 return(xmlXPathNodeTrailingSorted(nodes1,
2182 xmlXPathNodeSetItem(nodes2, 0)));
2183}
2184
2185/**
2186 * xmlXPathTrailing:
2187 * @nodes1: a node-set
2188 * @nodes2: a node-set
2189 *
2190 * Implements the EXSLT - Sets trailing() function:
2191 * node-set set:trailing (node-set, node-set)
2192 * @nodes1 and @nodes2 are sorted by document order, then
2193 * #xmlXPathTrailingSorted is called.
2194 *
2195 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2196 * in document order, @nodes1 if @nodes2 is NULL or empty or
2197 * an empty node-set if @nodes1 doesn't contain @nodes2
2198 */
2199xmlNodeSetPtr
2200xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2201 if (xmlXPathNodeSetIsEmpty(nodes2))
2202 return(nodes1);
2203 if (xmlXPathNodeSetIsEmpty(nodes1))
2204 return(xmlXPathNodeSetCreate(NULL));
2205 xmlXPathNodeSetSort(nodes1);
2206 xmlXPathNodeSetSort(nodes2);
2207 return(xmlXPathNodeTrailingSorted(nodes1,
2208 xmlXPathNodeSetItem(nodes2, 0)));
2209}
2210
Owen Taylor3473f882001-02-23 17:55:21 +00002211/************************************************************************
2212 * *
2213 * Routines to handle extra functions *
2214 * *
2215 ************************************************************************/
2216
2217/**
2218 * xmlXPathRegisterFunc:
2219 * @ctxt: the XPath context
2220 * @name: the function name
2221 * @f: the function implementation or NULL
2222 *
2223 * Register a new function. If @f is NULL it unregisters the function
2224 *
2225 * Returns 0 in case of success, -1 in case of error
2226 */
2227int
2228xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2229 xmlXPathFunction f) {
2230 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2231}
2232
2233/**
2234 * xmlXPathRegisterFuncNS:
2235 * @ctxt: the XPath context
2236 * @name: the function name
2237 * @ns_uri: the function namespace URI
2238 * @f: the function implementation or NULL
2239 *
2240 * Register a new function. If @f is NULL it unregisters the function
2241 *
2242 * Returns 0 in case of success, -1 in case of error
2243 */
2244int
2245xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2246 const xmlChar *ns_uri, xmlXPathFunction f) {
2247 if (ctxt == NULL)
2248 return(-1);
2249 if (name == NULL)
2250 return(-1);
2251
2252 if (ctxt->funcHash == NULL)
2253 ctxt->funcHash = xmlHashCreate(0);
2254 if (ctxt->funcHash == NULL)
2255 return(-1);
2256 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2257}
2258
2259/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002260 * xmlXPathRegisterFuncLookup:
2261 * @ctxt: the XPath context
2262 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002263 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002264 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002265 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002266 */
2267void
2268xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2269 xmlXPathFuncLookupFunc f,
2270 void *funcCtxt) {
2271 if (ctxt == NULL)
2272 return;
2273 ctxt->funcLookupFunc = (void *) f;
2274 ctxt->funcLookupData = funcCtxt;
2275}
2276
2277/**
Owen Taylor3473f882001-02-23 17:55:21 +00002278 * xmlXPathFunctionLookup:
2279 * @ctxt: the XPath context
2280 * @name: the function name
2281 *
2282 * Search in the Function array of the context for the given
2283 * function.
2284 *
2285 * Returns the xmlXPathFunction or NULL if not found
2286 */
2287xmlXPathFunction
2288xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002289 if (ctxt == NULL)
2290 return (NULL);
2291
2292 if (ctxt->funcLookupFunc != NULL) {
2293 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002294 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002295
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002296 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002297 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002298 if (ret != NULL)
2299 return(ret);
2300 }
Owen Taylor3473f882001-02-23 17:55:21 +00002301 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2302}
2303
2304/**
2305 * xmlXPathFunctionLookupNS:
2306 * @ctxt: the XPath context
2307 * @name: the function name
2308 * @ns_uri: the function namespace URI
2309 *
2310 * Search in the Function array of the context for the given
2311 * function.
2312 *
2313 * Returns the xmlXPathFunction or NULL if not found
2314 */
2315xmlXPathFunction
2316xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2317 const xmlChar *ns_uri) {
2318 if (ctxt == NULL)
2319 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002320 if (name == NULL)
2321 return(NULL);
2322
Thomas Broyerba4ad322001-07-26 16:55:21 +00002323 if (ctxt->funcLookupFunc != NULL) {
2324 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002325 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002326
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002327 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002328 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002329 if (ret != NULL)
2330 return(ret);
2331 }
2332
2333 if (ctxt->funcHash == NULL)
2334 return(NULL);
2335
Owen Taylor3473f882001-02-23 17:55:21 +00002336 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2337}
2338
2339/**
2340 * xmlXPathRegisteredFuncsCleanup:
2341 * @ctxt: the XPath context
2342 *
2343 * Cleanup the XPath context data associated to registered functions
2344 */
2345void
2346xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2347 if (ctxt == NULL)
2348 return;
2349
2350 xmlHashFree(ctxt->funcHash, NULL);
2351 ctxt->funcHash = NULL;
2352}
2353
2354/************************************************************************
2355 * *
2356 * Routines to handle Variable *
2357 * *
2358 ************************************************************************/
2359
2360/**
2361 * xmlXPathRegisterVariable:
2362 * @ctxt: the XPath context
2363 * @name: the variable name
2364 * @value: the variable value or NULL
2365 *
2366 * Register a new variable value. If @value is NULL it unregisters
2367 * the variable
2368 *
2369 * Returns 0 in case of success, -1 in case of error
2370 */
2371int
2372xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2373 xmlXPathObjectPtr value) {
2374 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2375}
2376
2377/**
2378 * xmlXPathRegisterVariableNS:
2379 * @ctxt: the XPath context
2380 * @name: the variable name
2381 * @ns_uri: the variable namespace URI
2382 * @value: the variable value or NULL
2383 *
2384 * Register a new variable value. If @value is NULL it unregisters
2385 * the variable
2386 *
2387 * Returns 0 in case of success, -1 in case of error
2388 */
2389int
2390xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2391 const xmlChar *ns_uri,
2392 xmlXPathObjectPtr value) {
2393 if (ctxt == NULL)
2394 return(-1);
2395 if (name == NULL)
2396 return(-1);
2397
2398 if (ctxt->varHash == NULL)
2399 ctxt->varHash = xmlHashCreate(0);
2400 if (ctxt->varHash == NULL)
2401 return(-1);
2402 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2403 (void *) value,
2404 (xmlHashDeallocator)xmlXPathFreeObject));
2405}
2406
2407/**
2408 * xmlXPathRegisterVariableLookup:
2409 * @ctxt: the XPath context
2410 * @f: the lookup function
2411 * @data: the lookup data
2412 *
2413 * register an external mechanism to do variable lookup
2414 */
2415void
2416xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2417 xmlXPathVariableLookupFunc f, void *data) {
2418 if (ctxt == NULL)
2419 return;
2420 ctxt->varLookupFunc = (void *) f;
2421 ctxt->varLookupData = data;
2422}
2423
2424/**
2425 * xmlXPathVariableLookup:
2426 * @ctxt: the XPath context
2427 * @name: the variable name
2428 *
2429 * Search in the Variable array of the context for the given
2430 * variable value.
2431 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002432 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002433 */
2434xmlXPathObjectPtr
2435xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2436 if (ctxt == NULL)
2437 return(NULL);
2438
2439 if (ctxt->varLookupFunc != NULL) {
2440 xmlXPathObjectPtr ret;
2441
2442 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2443 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002444 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002445 }
2446 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2447}
2448
2449/**
2450 * xmlXPathVariableLookupNS:
2451 * @ctxt: the XPath context
2452 * @name: the variable name
2453 * @ns_uri: the variable namespace URI
2454 *
2455 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002456 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002457 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002458 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002459 */
2460xmlXPathObjectPtr
2461xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2462 const xmlChar *ns_uri) {
2463 if (ctxt == NULL)
2464 return(NULL);
2465
2466 if (ctxt->varLookupFunc != NULL) {
2467 xmlXPathObjectPtr ret;
2468
2469 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2470 (ctxt->varLookupData, name, ns_uri);
2471 if (ret != NULL) return(ret);
2472 }
2473
2474 if (ctxt->varHash == NULL)
2475 return(NULL);
2476 if (name == NULL)
2477 return(NULL);
2478
Daniel Veillard8c357d52001-07-03 23:43:33 +00002479 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2480 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002481}
2482
2483/**
2484 * xmlXPathRegisteredVariablesCleanup:
2485 * @ctxt: the XPath context
2486 *
2487 * Cleanup the XPath context data associated to registered variables
2488 */
2489void
2490xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2491 if (ctxt == NULL)
2492 return;
2493
Daniel Veillard76d66f42001-05-16 21:05:17 +00002494 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002495 ctxt->varHash = NULL;
2496}
2497
2498/**
2499 * xmlXPathRegisterNs:
2500 * @ctxt: the XPath context
2501 * @prefix: the namespace prefix
2502 * @ns_uri: the namespace name
2503 *
2504 * Register a new namespace. If @ns_uri is NULL it unregisters
2505 * the namespace
2506 *
2507 * Returns 0 in case of success, -1 in case of error
2508 */
2509int
2510xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2511 const xmlChar *ns_uri) {
2512 if (ctxt == NULL)
2513 return(-1);
2514 if (prefix == NULL)
2515 return(-1);
2516
2517 if (ctxt->nsHash == NULL)
2518 ctxt->nsHash = xmlHashCreate(10);
2519 if (ctxt->nsHash == NULL)
2520 return(-1);
2521 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) ns_uri,
2522 (xmlHashDeallocator)xmlFree));
2523}
2524
2525/**
2526 * xmlXPathNsLookup:
2527 * @ctxt: the XPath context
2528 * @prefix: the namespace prefix value
2529 *
2530 * Search in the namespace declaration array of the context for the given
2531 * namespace name associated to the given prefix
2532 *
2533 * Returns the value or NULL if not found
2534 */
2535const xmlChar *
2536xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2537 if (ctxt == NULL)
2538 return(NULL);
2539 if (prefix == NULL)
2540 return(NULL);
2541
2542#ifdef XML_XML_NAMESPACE
2543 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
2544 return(XML_XML_NAMESPACE);
2545#endif
2546
Daniel Veillardc8f620b2001-04-30 20:31:33 +00002547 if (ctxt->namespaces != NULL) {
2548 int i;
2549
2550 for (i = 0;i < ctxt->nsNr;i++) {
2551 if ((ctxt->namespaces[i] != NULL) &&
2552 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
2553 return(ctxt->namespaces[i]->href);
2554 }
2555 }
Owen Taylor3473f882001-02-23 17:55:21 +00002556
2557 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
2558}
2559
2560/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002561 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00002562 * @ctxt: the XPath context
2563 *
2564 * Cleanup the XPath context data associated to registered variables
2565 */
2566void
2567xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2568 if (ctxt == NULL)
2569 return;
2570
2571 xmlHashFree(ctxt->nsHash, NULL);
2572 ctxt->nsHash = NULL;
2573}
2574
2575/************************************************************************
2576 * *
2577 * Routines to handle Values *
2578 * *
2579 ************************************************************************/
2580
2581/* Allocations are terrible, one need to optimize all this !!! */
2582
2583/**
2584 * xmlXPathNewFloat:
2585 * @val: the double value
2586 *
2587 * Create a new xmlXPathObjectPtr of type double and of value @val
2588 *
2589 * Returns the newly created object.
2590 */
2591xmlXPathObjectPtr
2592xmlXPathNewFloat(double val) {
2593 xmlXPathObjectPtr ret;
2594
2595 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2596 if (ret == NULL) {
2597 xmlGenericError(xmlGenericErrorContext,
2598 "xmlXPathNewFloat: out of memory\n");
2599 return(NULL);
2600 }
2601 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2602 ret->type = XPATH_NUMBER;
2603 ret->floatval = val;
2604 return(ret);
2605}
2606
2607/**
2608 * xmlXPathNewBoolean:
2609 * @val: the boolean value
2610 *
2611 * Create a new xmlXPathObjectPtr of type boolean and of value @val
2612 *
2613 * Returns the newly created object.
2614 */
2615xmlXPathObjectPtr
2616xmlXPathNewBoolean(int val) {
2617 xmlXPathObjectPtr ret;
2618
2619 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2620 if (ret == NULL) {
2621 xmlGenericError(xmlGenericErrorContext,
2622 "xmlXPathNewBoolean: out of memory\n");
2623 return(NULL);
2624 }
2625 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2626 ret->type = XPATH_BOOLEAN;
2627 ret->boolval = (val != 0);
2628 return(ret);
2629}
2630
2631/**
2632 * xmlXPathNewString:
2633 * @val: the xmlChar * value
2634 *
2635 * Create a new xmlXPathObjectPtr of type string and of value @val
2636 *
2637 * Returns the newly created object.
2638 */
2639xmlXPathObjectPtr
2640xmlXPathNewString(const xmlChar *val) {
2641 xmlXPathObjectPtr ret;
2642
2643 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2644 if (ret == NULL) {
2645 xmlGenericError(xmlGenericErrorContext,
2646 "xmlXPathNewString: out of memory\n");
2647 return(NULL);
2648 }
2649 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2650 ret->type = XPATH_STRING;
2651 if (val != NULL)
2652 ret->stringval = xmlStrdup(val);
2653 else
2654 ret->stringval = xmlStrdup((const xmlChar *)"");
2655 return(ret);
2656}
2657
2658/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002659 * xmlXPathWrapString:
2660 * @val: the xmlChar * value
2661 *
2662 * Wraps the @val string into an XPath object.
2663 *
2664 * Returns the newly created object.
2665 */
2666xmlXPathObjectPtr
2667xmlXPathWrapString (xmlChar *val) {
2668 xmlXPathObjectPtr ret;
2669
2670 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2671 if (ret == NULL) {
2672 xmlGenericError(xmlGenericErrorContext,
2673 "xmlXPathWrapString: out of memory\n");
2674 return(NULL);
2675 }
2676 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2677 ret->type = XPATH_STRING;
2678 ret->stringval = val;
2679 return(ret);
2680}
2681
2682/**
Owen Taylor3473f882001-02-23 17:55:21 +00002683 * xmlXPathNewCString:
2684 * @val: the char * value
2685 *
2686 * Create a new xmlXPathObjectPtr of type string and of value @val
2687 *
2688 * Returns the newly created object.
2689 */
2690xmlXPathObjectPtr
2691xmlXPathNewCString(const char *val) {
2692 xmlXPathObjectPtr ret;
2693
2694 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2695 if (ret == NULL) {
2696 xmlGenericError(xmlGenericErrorContext,
2697 "xmlXPathNewCString: out of memory\n");
2698 return(NULL);
2699 }
2700 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2701 ret->type = XPATH_STRING;
2702 ret->stringval = xmlStrdup(BAD_CAST val);
2703 return(ret);
2704}
2705
2706/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002707 * xmlXPathWrapCString:
2708 * @val: the char * value
2709 *
2710 * Wraps a string into an XPath object.
2711 *
2712 * Returns the newly created object.
2713 */
2714xmlXPathObjectPtr
2715xmlXPathWrapCString (char * val) {
2716 return(xmlXPathWrapString((xmlChar *)(val)));
2717}
2718
2719/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002720 * xmlXPathWrapExternal:
2721 * @val: the user data
2722 *
2723 * Wraps the @val data into an XPath object.
2724 *
2725 * Returns the newly created object.
2726 */
2727xmlXPathObjectPtr
2728xmlXPathWrapExternal (void *val) {
2729 xmlXPathObjectPtr ret;
2730
2731 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2732 if (ret == NULL) {
2733 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002734 "xmlXPathWrapExternal: out of memory\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002735 return(NULL);
2736 }
2737 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2738 ret->type = XPATH_USERS;
2739 ret->user = val;
2740 return(ret);
2741}
2742
2743/**
Owen Taylor3473f882001-02-23 17:55:21 +00002744 * xmlXPathObjectCopy:
2745 * @val: the original object
2746 *
2747 * allocate a new copy of a given object
2748 *
2749 * Returns the newly created object.
2750 */
2751xmlXPathObjectPtr
2752xmlXPathObjectCopy(xmlXPathObjectPtr val) {
2753 xmlXPathObjectPtr ret;
2754
2755 if (val == NULL)
2756 return(NULL);
2757
2758 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2759 if (ret == NULL) {
2760 xmlGenericError(xmlGenericErrorContext,
2761 "xmlXPathObjectCopy: out of memory\n");
2762 return(NULL);
2763 }
2764 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
2765 switch (val->type) {
2766 case XPATH_BOOLEAN:
2767 case XPATH_NUMBER:
2768 case XPATH_POINT:
2769 case XPATH_RANGE:
2770 break;
2771 case XPATH_STRING:
2772 ret->stringval = xmlStrdup(val->stringval);
2773 break;
2774 case XPATH_XSLT_TREE:
2775 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002776 (val->nodesetval->nodeTab != NULL)) {
2777 ret->boolval = 1;
Daniel Veillard6ab38382001-10-06 13:08:27 +00002778 ret->user = xmlDocCopyNode(val->nodesetval->nodeTab[0],
2779 val->nodesetval->nodeTab[0]->doc, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00002780 ret->nodesetval = xmlXPathNodeSetCreate(
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002781 (xmlNodePtr) ret->user);
2782 } else
Owen Taylor3473f882001-02-23 17:55:21 +00002783 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002784 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00002785 break;
2786 case XPATH_NODESET:
2787 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002788 /* Do not deallocate the copied tree value */
2789 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002790 break;
2791 case XPATH_LOCATIONSET:
2792#ifdef LIBXML_XPTR_ENABLED
2793 {
2794 xmlLocationSetPtr loc = val->user;
2795 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
2796 break;
2797 }
2798#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00002799 case XPATH_USERS:
2800 ret->user = val->user;
2801 break;
2802 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00002803 xmlGenericError(xmlGenericErrorContext,
2804 "xmlXPathObjectCopy: unsupported type %d\n",
2805 val->type);
2806 break;
2807 }
2808 return(ret);
2809}
2810
2811/**
2812 * xmlXPathFreeObject:
2813 * @obj: the object to free
2814 *
2815 * Free up an xmlXPathObjectPtr object.
2816 */
2817void
2818xmlXPathFreeObject(xmlXPathObjectPtr obj) {
2819 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002820 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00002821 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002822 if (obj->user != NULL) {
2823 xmlFreeNodeList((xmlNodePtr) obj->user);
2824 xmlXPathFreeNodeSet(obj->nodesetval);
2825 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00002826 xmlXPathFreeValueTree(obj->nodesetval);
2827 } else {
2828 if (obj->nodesetval != NULL)
2829 xmlXPathFreeNodeSet(obj->nodesetval);
2830 }
Owen Taylor3473f882001-02-23 17:55:21 +00002831#ifdef LIBXML_XPTR_ENABLED
2832 } else if (obj->type == XPATH_LOCATIONSET) {
2833 if (obj->user != NULL)
2834 xmlXPtrFreeLocationSet(obj->user);
2835#endif
2836 } else if (obj->type == XPATH_STRING) {
2837 if (obj->stringval != NULL)
2838 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00002839 }
2840
Owen Taylor3473f882001-02-23 17:55:21 +00002841 xmlFree(obj);
2842}
2843
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002844
2845/************************************************************************
2846 * *
2847 * Type Casting Routines *
2848 * *
2849 ************************************************************************/
2850
2851/**
2852 * xmlXPathCastBooleanToString:
2853 * @val: a boolean
2854 *
2855 * Converts a boolean to its string value.
2856 *
2857 * Returns a newly allocated string.
2858 */
2859xmlChar *
2860xmlXPathCastBooleanToString (int val) {
2861 xmlChar *ret;
2862 if (val)
2863 ret = xmlStrdup((const xmlChar *) "true");
2864 else
2865 ret = xmlStrdup((const xmlChar *) "false");
2866 return(ret);
2867}
2868
2869/**
2870 * xmlXPathCastNumberToString:
2871 * @val: a number
2872 *
2873 * Converts a number to its string value.
2874 *
2875 * Returns a newly allocated string.
2876 */
2877xmlChar *
2878xmlXPathCastNumberToString (double val) {
2879 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00002880 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002881 case 1:
2882 ret = xmlStrdup((const xmlChar *) "+Infinity");
2883 break;
2884 case -1:
2885 ret = xmlStrdup((const xmlChar *) "-Infinity");
2886 break;
2887 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00002888 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002889 ret = xmlStrdup((const xmlChar *) "NaN");
2890 } else {
2891 /* could be improved */
2892 char buf[100];
2893 xmlXPathFormatNumber(val, buf, 100);
2894 ret = xmlStrdup((const xmlChar *) buf);
2895 }
2896 }
2897 return(ret);
2898}
2899
2900/**
2901 * xmlXPathCastNodeToString:
2902 * @node: a node
2903 *
2904 * Converts a node to its string value.
2905 *
2906 * Returns a newly allocated string.
2907 */
2908xmlChar *
2909xmlXPathCastNodeToString (xmlNodePtr node) {
2910 return(xmlNodeGetContent(node));
2911}
2912
2913/**
2914 * xmlXPathCastNodeSetToString:
2915 * @ns: a node-set
2916 *
2917 * Converts a node-set to its string value.
2918 *
2919 * Returns a newly allocated string.
2920 */
2921xmlChar *
2922xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
2923 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
2924 return(xmlStrdup((const xmlChar *) ""));
2925
2926 xmlXPathNodeSetSort(ns);
2927 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
2928}
2929
2930/**
2931 * xmlXPathCastToString:
2932 * @val: an XPath object
2933 *
2934 * Converts an existing object to its string() equivalent
2935 *
2936 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002937 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002938 * string object).
2939 */
2940xmlChar *
2941xmlXPathCastToString(xmlXPathObjectPtr val) {
2942 xmlChar *ret = NULL;
2943
2944 if (val == NULL)
2945 return(xmlStrdup((const xmlChar *) ""));
2946 switch (val->type) {
2947 case XPATH_UNDEFINED:
2948#ifdef DEBUG_EXPR
2949 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
2950#endif
2951 ret = xmlStrdup((const xmlChar *) "");
2952 break;
2953 case XPATH_XSLT_TREE:
2954 case XPATH_NODESET:
2955 ret = xmlXPathCastNodeSetToString(val->nodesetval);
2956 break;
2957 case XPATH_STRING:
2958 return(val->stringval);
2959 case XPATH_BOOLEAN:
2960 ret = xmlXPathCastBooleanToString(val->boolval);
2961 break;
2962 case XPATH_NUMBER: {
2963 ret = xmlXPathCastNumberToString(val->floatval);
2964 break;
2965 }
2966 case XPATH_USERS:
2967 case XPATH_POINT:
2968 case XPATH_RANGE:
2969 case XPATH_LOCATIONSET:
2970 TODO
2971 ret = xmlStrdup((const xmlChar *) "");
2972 break;
2973 }
2974 return(ret);
2975}
2976
2977/**
2978 * xmlXPathConvertString:
2979 * @val: an XPath object
2980 *
2981 * Converts an existing object to its string() equivalent
2982 *
2983 * Returns the new object, the old one is freed (or the operation
2984 * is done directly on @val)
2985 */
2986xmlXPathObjectPtr
2987xmlXPathConvertString(xmlXPathObjectPtr val) {
2988 xmlChar *res = NULL;
2989
2990 if (val == NULL)
2991 return(xmlXPathNewCString(""));
2992
2993 switch (val->type) {
2994 case XPATH_UNDEFINED:
2995#ifdef DEBUG_EXPR
2996 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2997#endif
2998 break;
2999 case XPATH_XSLT_TREE:
3000 case XPATH_NODESET:
3001 res = xmlXPathCastNodeSetToString(val->nodesetval);
3002 break;
3003 case XPATH_STRING:
3004 return(val);
3005 case XPATH_BOOLEAN:
3006 res = xmlXPathCastBooleanToString(val->boolval);
3007 break;
3008 case XPATH_NUMBER:
3009 res = xmlXPathCastNumberToString(val->floatval);
3010 break;
3011 case XPATH_USERS:
3012 case XPATH_POINT:
3013 case XPATH_RANGE:
3014 case XPATH_LOCATIONSET:
3015 TODO;
3016 break;
3017 }
3018 xmlXPathFreeObject(val);
3019 if (res == NULL)
3020 return(xmlXPathNewCString(""));
3021 return(xmlXPathWrapString(res));
3022}
3023
3024/**
3025 * xmlXPathCastBooleanToNumber:
3026 * @val: a boolean
3027 *
3028 * Converts a boolean to its number value
3029 *
3030 * Returns the number value
3031 */
3032double
3033xmlXPathCastBooleanToNumber(int val) {
3034 if (val)
3035 return(1.0);
3036 return(0.0);
3037}
3038
3039/**
3040 * xmlXPathCastStringToNumber:
3041 * @val: a string
3042 *
3043 * Converts a string to its number value
3044 *
3045 * Returns the number value
3046 */
3047double
3048xmlXPathCastStringToNumber(const xmlChar * val) {
3049 return(xmlXPathStringEvalNumber(val));
3050}
3051
3052/**
3053 * xmlXPathCastNodeToNumber:
3054 * @node: a node
3055 *
3056 * Converts a node to its number value
3057 *
3058 * Returns the number value
3059 */
3060double
3061xmlXPathCastNodeToNumber (xmlNodePtr node) {
3062 xmlChar *strval;
3063 double ret;
3064
3065 if (node == NULL)
3066 return(xmlXPathNAN);
3067 strval = xmlXPathCastNodeToString(node);
3068 if (strval == NULL)
3069 return(xmlXPathNAN);
3070 ret = xmlXPathCastStringToNumber(strval);
3071 xmlFree(strval);
3072
3073 return(ret);
3074}
3075
3076/**
3077 * xmlXPathCastNodeSetToNumber:
3078 * @ns: a node-set
3079 *
3080 * Converts a node-set to its number value
3081 *
3082 * Returns the number value
3083 */
3084double
3085xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3086 xmlChar *str;
3087 double ret;
3088
3089 if (ns == NULL)
3090 return(xmlXPathNAN);
3091 str = xmlXPathCastNodeSetToString(ns);
3092 ret = xmlXPathCastStringToNumber(str);
3093 xmlFree(str);
3094 return(ret);
3095}
3096
3097/**
3098 * xmlXPathCastToNumber:
3099 * @val: an XPath object
3100 *
3101 * Converts an XPath object to its number value
3102 *
3103 * Returns the number value
3104 */
3105double
3106xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3107 double ret = 0.0;
3108
3109 if (val == NULL)
3110 return(xmlXPathNAN);
3111 switch (val->type) {
3112 case XPATH_UNDEFINED:
3113#ifdef DEGUB_EXPR
3114 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3115#endif
3116 ret = xmlXPathNAN;
3117 break;
3118 case XPATH_XSLT_TREE:
3119 case XPATH_NODESET:
3120 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3121 break;
3122 case XPATH_STRING:
3123 ret = xmlXPathCastStringToNumber(val->stringval);
3124 break;
3125 case XPATH_NUMBER:
3126 ret = val->floatval;
3127 break;
3128 case XPATH_BOOLEAN:
3129 ret = xmlXPathCastBooleanToNumber(val->boolval);
3130 break;
3131 case XPATH_USERS:
3132 case XPATH_POINT:
3133 case XPATH_RANGE:
3134 case XPATH_LOCATIONSET:
3135 TODO;
3136 ret = xmlXPathNAN;
3137 break;
3138 }
3139 return(ret);
3140}
3141
3142/**
3143 * xmlXPathConvertNumber:
3144 * @val: an XPath object
3145 *
3146 * Converts an existing object to its number() equivalent
3147 *
3148 * Returns the new object, the old one is freed (or the operation
3149 * is done directly on @val)
3150 */
3151xmlXPathObjectPtr
3152xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3153 xmlXPathObjectPtr ret;
3154
3155 if (val == NULL)
3156 return(xmlXPathNewFloat(0.0));
3157 if (val->type == XPATH_NUMBER)
3158 return(val);
3159 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3160 xmlXPathFreeObject(val);
3161 return(ret);
3162}
3163
3164/**
3165 * xmlXPathCastNumberToBoolean:
3166 * @val: a number
3167 *
3168 * Converts a number to its boolean value
3169 *
3170 * Returns the boolean value
3171 */
3172int
3173xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003174 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003175 return(0);
3176 return(1);
3177}
3178
3179/**
3180 * xmlXPathCastStringToBoolean:
3181 * @val: a string
3182 *
3183 * Converts a string to its boolean value
3184 *
3185 * Returns the boolean value
3186 */
3187int
3188xmlXPathCastStringToBoolean (const xmlChar *val) {
3189 if ((val == NULL) || (xmlStrlen(val) == 0))
3190 return(0);
3191 return(1);
3192}
3193
3194/**
3195 * xmlXPathCastNodeSetToBoolean:
3196 * @ns: a node-set
3197 *
3198 * Converts a node-set to its boolean value
3199 *
3200 * Returns the boolean value
3201 */
3202int
3203xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3204 if ((ns == NULL) || (ns->nodeNr == 0))
3205 return(0);
3206 return(1);
3207}
3208
3209/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003210 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003211 * @val: an XPath object
3212 *
3213 * Converts an XPath object to its boolean value
3214 *
3215 * Returns the boolean value
3216 */
3217int
3218xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3219 int ret = 0;
3220
3221 if (val == NULL)
3222 return(0);
3223 switch (val->type) {
3224 case XPATH_UNDEFINED:
3225#ifdef DEBUG_EXPR
3226 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3227#endif
3228 ret = 0;
3229 break;
3230 case XPATH_XSLT_TREE:
3231 case XPATH_NODESET:
3232 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3233 break;
3234 case XPATH_STRING:
3235 ret = xmlXPathCastStringToBoolean(val->stringval);
3236 break;
3237 case XPATH_NUMBER:
3238 ret = xmlXPathCastNumberToBoolean(val->floatval);
3239 break;
3240 case XPATH_BOOLEAN:
3241 ret = val->boolval;
3242 break;
3243 case XPATH_USERS:
3244 case XPATH_POINT:
3245 case XPATH_RANGE:
3246 case XPATH_LOCATIONSET:
3247 TODO;
3248 ret = 0;
3249 break;
3250 }
3251 return(ret);
3252}
3253
3254
3255/**
3256 * xmlXPathConvertBoolean:
3257 * @val: an XPath object
3258 *
3259 * Converts an existing object to its boolean() equivalent
3260 *
3261 * Returns the new object, the old one is freed (or the operation
3262 * is done directly on @val)
3263 */
3264xmlXPathObjectPtr
3265xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3266 xmlXPathObjectPtr ret;
3267
3268 if (val == NULL)
3269 return(xmlXPathNewBoolean(0));
3270 if (val->type == XPATH_BOOLEAN)
3271 return(val);
3272 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3273 xmlXPathFreeObject(val);
3274 return(ret);
3275}
3276
Owen Taylor3473f882001-02-23 17:55:21 +00003277/************************************************************************
3278 * *
3279 * Routines to handle XPath contexts *
3280 * *
3281 ************************************************************************/
3282
3283/**
3284 * xmlXPathNewContext:
3285 * @doc: the XML document
3286 *
3287 * Create a new xmlXPathContext
3288 *
3289 * Returns the xmlXPathContext just allocated.
3290 */
3291xmlXPathContextPtr
3292xmlXPathNewContext(xmlDocPtr doc) {
3293 xmlXPathContextPtr ret;
3294
3295 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3296 if (ret == NULL) {
3297 xmlGenericError(xmlGenericErrorContext,
3298 "xmlXPathNewContext: out of memory\n");
3299 return(NULL);
3300 }
3301 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3302 ret->doc = doc;
3303 ret->node = NULL;
3304
3305 ret->varHash = NULL;
3306
3307 ret->nb_types = 0;
3308 ret->max_types = 0;
3309 ret->types = NULL;
3310
3311 ret->funcHash = xmlHashCreate(0);
3312
3313 ret->nb_axis = 0;
3314 ret->max_axis = 0;
3315 ret->axis = NULL;
3316
3317 ret->nsHash = NULL;
3318 ret->user = NULL;
3319
3320 ret->contextSize = -1;
3321 ret->proximityPosition = -1;
3322
3323 xmlXPathRegisterAllFunctions(ret);
3324
3325 return(ret);
3326}
3327
3328/**
3329 * xmlXPathFreeContext:
3330 * @ctxt: the context to free
3331 *
3332 * Free up an xmlXPathContext
3333 */
3334void
3335xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3336 xmlXPathRegisteredNsCleanup(ctxt);
3337 xmlXPathRegisteredFuncsCleanup(ctxt);
3338 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003339 xmlFree(ctxt);
3340}
3341
3342/************************************************************************
3343 * *
3344 * Routines to handle XPath parser contexts *
3345 * *
3346 ************************************************************************/
3347
3348#define CHECK_CTXT(ctxt) \
3349 if (ctxt == NULL) { \
3350 xmlGenericError(xmlGenericErrorContext, \
3351 "%s:%d Internal error: ctxt == NULL\n", \
3352 __FILE__, __LINE__); \
3353 } \
3354
3355
3356#define CHECK_CONTEXT(ctxt) \
3357 if (ctxt == NULL) { \
3358 xmlGenericError(xmlGenericErrorContext, \
3359 "%s:%d Internal error: no context\n", \
3360 __FILE__, __LINE__); \
3361 } \
3362 else if (ctxt->doc == NULL) { \
3363 xmlGenericError(xmlGenericErrorContext, \
3364 "%s:%d Internal error: no document\n", \
3365 __FILE__, __LINE__); \
3366 } \
3367 else if (ctxt->doc->children == NULL) { \
3368 xmlGenericError(xmlGenericErrorContext, \
3369 "%s:%d Internal error: document without root\n", \
3370 __FILE__, __LINE__); \
3371 } \
3372
3373
3374/**
3375 * xmlXPathNewParserContext:
3376 * @str: the XPath expression
3377 * @ctxt: the XPath context
3378 *
3379 * Create a new xmlXPathParserContext
3380 *
3381 * Returns the xmlXPathParserContext just allocated.
3382 */
3383xmlXPathParserContextPtr
3384xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3385 xmlXPathParserContextPtr ret;
3386
3387 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3388 if (ret == NULL) {
3389 xmlGenericError(xmlGenericErrorContext,
3390 "xmlXPathNewParserContext: out of memory\n");
3391 return(NULL);
3392 }
3393 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3394 ret->cur = ret->base = str;
3395 ret->context = ctxt;
3396
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003397 ret->comp = xmlXPathNewCompExpr();
3398 if (ret->comp == NULL) {
3399 xmlFree(ret->valueTab);
3400 xmlFree(ret);
3401 return(NULL);
3402 }
3403
3404 return(ret);
3405}
3406
3407/**
3408 * xmlXPathCompParserContext:
3409 * @comp: the XPath compiled expression
3410 * @ctxt: the XPath context
3411 *
3412 * Create a new xmlXPathParserContext when processing a compiled expression
3413 *
3414 * Returns the xmlXPathParserContext just allocated.
3415 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003416static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003417xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3418 xmlXPathParserContextPtr ret;
3419
3420 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3421 if (ret == NULL) {
3422 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003423 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003424 return(NULL);
3425 }
3426 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3427
Owen Taylor3473f882001-02-23 17:55:21 +00003428 /* Allocate the value stack */
3429 ret->valueTab = (xmlXPathObjectPtr *)
3430 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003431 if (ret->valueTab == NULL) {
3432 xmlFree(ret);
3433 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003434 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003435 return(NULL);
3436 }
Owen Taylor3473f882001-02-23 17:55:21 +00003437 ret->valueNr = 0;
3438 ret->valueMax = 10;
3439 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003440
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003441 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003442 ret->comp = comp;
3443
Owen Taylor3473f882001-02-23 17:55:21 +00003444 return(ret);
3445}
3446
3447/**
3448 * xmlXPathFreeParserContext:
3449 * @ctxt: the context to free
3450 *
3451 * Free up an xmlXPathParserContext
3452 */
3453void
3454xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3455 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003456 xmlFree(ctxt->valueTab);
3457 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003458 if (ctxt->comp)
3459 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003460 xmlFree(ctxt);
3461}
3462
3463/************************************************************************
3464 * *
3465 * The implicit core function library *
3466 * *
3467 ************************************************************************/
3468
Owen Taylor3473f882001-02-23 17:55:21 +00003469/**
Daniel Veillardf06307e2001-07-03 10:35:50 +00003470 * xmlXPathNodeStringHash:
3471 * @node: a node pointer
3472 *
3473 * Function computing the beginning of the string value of the node,
3474 * used to speed up comparisons
3475 *
3476 * Returns an int usable as a hash
3477 */
3478static unsigned int
3479xmlXPathNodeValHash(xmlNodePtr node) {
3480 int len = 2;
3481 const xmlChar * string = NULL;
3482 xmlNodePtr tmp = NULL;
3483 unsigned int ret = 0;
3484
3485 if (node == NULL)
3486 return(0);
3487
3488
3489 switch (node->type) {
3490 case XML_COMMENT_NODE:
3491 case XML_PI_NODE:
3492 case XML_CDATA_SECTION_NODE:
3493 case XML_TEXT_NODE:
3494 string = node->content;
3495 if (string == NULL)
3496 return(0);
3497 if (string[0] == 0)
3498 return(0);
3499 return(((unsigned int) string[0]) +
3500 (((unsigned int) string[1]) << 8));
3501 case XML_NAMESPACE_DECL:
3502 string = ((xmlNsPtr)node)->href;
3503 if (string == NULL)
3504 return(0);
3505 if (string[0] == 0)
3506 return(0);
3507 return(((unsigned int) string[0]) +
3508 (((unsigned int) string[1]) << 8));
3509 case XML_ATTRIBUTE_NODE:
3510 tmp = ((xmlAttrPtr) node)->children;
3511 break;
3512 case XML_ELEMENT_NODE:
3513 tmp = node->children;
3514 break;
3515 default:
3516 return(0);
3517 }
3518 while (tmp != NULL) {
3519 switch (tmp->type) {
3520 case XML_COMMENT_NODE:
3521 case XML_PI_NODE:
3522 case XML_CDATA_SECTION_NODE:
3523 case XML_TEXT_NODE:
3524 string = tmp->content;
3525 break;
3526 case XML_NAMESPACE_DECL:
3527 string = ((xmlNsPtr)tmp)->href;
3528 break;
3529 default:
3530 break;
3531 }
3532 if ((string != NULL) && (string[0] != 0)) {
3533 if (string[0] == 0)
3534 return(0);
3535 if (len == 1) {
3536 return(ret + (((unsigned int) string[0]) << 8));
3537 }
3538 if (string[1] == 0) {
3539 len = 1;
3540 ret = (unsigned int) string[0];
3541 } else {
3542 return(((unsigned int) string[0]) +
3543 (((unsigned int) string[1]) << 8));
3544 }
3545 }
3546 /*
3547 * Skip to next node
3548 */
3549 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
3550 if (tmp->children->type != XML_ENTITY_DECL) {
3551 tmp = tmp->children;
3552 continue;
3553 }
3554 }
3555 if (tmp == node)
3556 break;
3557
3558 if (tmp->next != NULL) {
3559 tmp = tmp->next;
3560 continue;
3561 }
3562
3563 do {
3564 tmp = tmp->parent;
3565 if (tmp == NULL)
3566 break;
3567 if (tmp == node) {
3568 tmp = NULL;
3569 break;
3570 }
3571 if (tmp->next != NULL) {
3572 tmp = tmp->next;
3573 break;
3574 }
3575 } while (tmp != NULL);
3576 }
3577 return(ret);
3578}
3579
3580/**
3581 * xmlXPathStringHash:
3582 * @string: a string
3583 *
3584 * Function computing the beginning of the string value of the node,
3585 * used to speed up comparisons
3586 *
3587 * Returns an int usable as a hash
3588 */
3589static unsigned int
3590xmlXPathStringHash(const xmlChar * string) {
3591 if (string == NULL)
3592 return((unsigned int) 0);
3593 if (string[0] == 0)
3594 return(0);
3595 return(((unsigned int) string[0]) +
3596 (((unsigned int) string[1]) << 8));
3597}
3598
3599/**
Owen Taylor3473f882001-02-23 17:55:21 +00003600 * xmlXPathCompareNodeSetFloat:
3601 * @ctxt: the XPath Parser context
3602 * @inf: less than (1) or greater than (0)
3603 * @strict: is the comparison strict
3604 * @arg: the node set
3605 * @f: the value
3606 *
3607 * Implement the compare operation between a nodeset and a number
3608 * @ns < @val (1, 1, ...
3609 * @ns <= @val (1, 0, ...
3610 * @ns > @val (0, 1, ...
3611 * @ns >= @val (0, 0, ...
3612 *
3613 * If one object to be compared is a node-set and the other is a number,
3614 * then the comparison will be true if and only if there is a node in the
3615 * node-set such that the result of performing the comparison on the number
3616 * to be compared and on the result of converting the string-value of that
3617 * node to a number using the number function is true.
3618 *
3619 * Returns 0 or 1 depending on the results of the test.
3620 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003621static int
Owen Taylor3473f882001-02-23 17:55:21 +00003622xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
3623 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
3624 int i, ret = 0;
3625 xmlNodeSetPtr ns;
3626 xmlChar *str2;
3627
3628 if ((f == NULL) || (arg == NULL) ||
3629 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3630 xmlXPathFreeObject(arg);
3631 xmlXPathFreeObject(f);
3632 return(0);
3633 }
3634 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003635 if (ns != NULL) {
3636 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003637 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003638 if (str2 != NULL) {
3639 valuePush(ctxt,
3640 xmlXPathNewString(str2));
3641 xmlFree(str2);
3642 xmlXPathNumberFunction(ctxt, 1);
3643 valuePush(ctxt, xmlXPathObjectCopy(f));
3644 ret = xmlXPathCompareValues(ctxt, inf, strict);
3645 if (ret)
3646 break;
3647 }
3648 }
Owen Taylor3473f882001-02-23 17:55:21 +00003649 }
3650 xmlXPathFreeObject(arg);
3651 xmlXPathFreeObject(f);
3652 return(ret);
3653}
3654
3655/**
3656 * xmlXPathCompareNodeSetString:
3657 * @ctxt: the XPath Parser context
3658 * @inf: less than (1) or greater than (0)
3659 * @strict: is the comparison strict
3660 * @arg: the node set
3661 * @s: the value
3662 *
3663 * Implement the compare operation between a nodeset and a string
3664 * @ns < @val (1, 1, ...
3665 * @ns <= @val (1, 0, ...
3666 * @ns > @val (0, 1, ...
3667 * @ns >= @val (0, 0, ...
3668 *
3669 * If one object to be compared is a node-set and the other is a string,
3670 * then the comparison will be true if and only if there is a node in
3671 * the node-set such that the result of performing the comparison on the
3672 * string-value of the node and the other string is true.
3673 *
3674 * Returns 0 or 1 depending on the results of the test.
3675 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003676static int
Owen Taylor3473f882001-02-23 17:55:21 +00003677xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
3678 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
3679 int i, ret = 0;
3680 xmlNodeSetPtr ns;
3681 xmlChar *str2;
3682
3683 if ((s == NULL) || (arg == NULL) ||
3684 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3685 xmlXPathFreeObject(arg);
3686 xmlXPathFreeObject(s);
3687 return(0);
3688 }
3689 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003690 if (ns != NULL) {
3691 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003692 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003693 if (str2 != NULL) {
3694 valuePush(ctxt,
3695 xmlXPathNewString(str2));
3696 xmlFree(str2);
3697 valuePush(ctxt, xmlXPathObjectCopy(s));
3698 ret = xmlXPathCompareValues(ctxt, inf, strict);
3699 if (ret)
3700 break;
3701 }
3702 }
Owen Taylor3473f882001-02-23 17:55:21 +00003703 }
3704 xmlXPathFreeObject(arg);
3705 xmlXPathFreeObject(s);
3706 return(ret);
3707}
3708
3709/**
3710 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003711 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00003712 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003713 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00003714 * @arg2: the second node set object
3715 *
3716 * Implement the compare operation on nodesets:
3717 *
3718 * If both objects to be compared are node-sets, then the comparison
3719 * will be true if and only if there is a node in the first node-set
3720 * and a node in the second node-set such that the result of performing
3721 * the comparison on the string-values of the two nodes is true.
3722 * ....
3723 * When neither object to be compared is a node-set and the operator
3724 * is <=, <, >= or >, then the objects are compared by converting both
3725 * objects to numbers and comparing the numbers according to IEEE 754.
3726 * ....
3727 * The number function converts its argument to a number as follows:
3728 * - a string that consists of optional whitespace followed by an
3729 * optional minus sign followed by a Number followed by whitespace
3730 * is converted to the IEEE 754 number that is nearest (according
3731 * to the IEEE 754 round-to-nearest rule) to the mathematical value
3732 * represented by the string; any other string is converted to NaN
3733 *
3734 * Conclusion all nodes need to be converted first to their string value
3735 * and then the comparison must be done when possible
3736 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003737static int
3738xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00003739 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3740 int i, j, init = 0;
3741 double val1;
3742 double *values2;
3743 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003744 xmlNodeSetPtr ns1;
3745 xmlNodeSetPtr ns2;
3746
3747 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003748 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
3749 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003750 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003751 }
Owen Taylor3473f882001-02-23 17:55:21 +00003752 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003753 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
3754 xmlXPathFreeObject(arg1);
3755 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003756 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003757 }
Owen Taylor3473f882001-02-23 17:55:21 +00003758
3759 ns1 = arg1->nodesetval;
3760 ns2 = arg2->nodesetval;
3761
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003762 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003763 xmlXPathFreeObject(arg1);
3764 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003765 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003766 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003767 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003768 xmlXPathFreeObject(arg1);
3769 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003770 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003771 }
Owen Taylor3473f882001-02-23 17:55:21 +00003772
3773 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
3774 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003775 xmlXPathFreeObject(arg1);
3776 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003777 return(0);
3778 }
3779 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003780 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00003781 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00003782 continue;
3783 for (j = 0;j < ns2->nodeNr;j++) {
3784 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003785 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00003786 }
Daniel Veillardcda96922001-08-21 10:56:31 +00003787 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00003788 continue;
3789 if (inf && strict)
3790 ret = (val1 < values2[j]);
3791 else if (inf && !strict)
3792 ret = (val1 <= values2[j]);
3793 else if (!inf && strict)
3794 ret = (val1 > values2[j]);
3795 else if (!inf && !strict)
3796 ret = (val1 >= values2[j]);
3797 if (ret)
3798 break;
3799 }
3800 if (ret)
3801 break;
3802 init = 1;
3803 }
3804 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003805 xmlXPathFreeObject(arg1);
3806 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003807 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003808}
3809
3810/**
3811 * xmlXPathCompareNodeSetValue:
3812 * @ctxt: the XPath Parser context
3813 * @inf: less than (1) or greater than (0)
3814 * @strict: is the comparison strict
3815 * @arg: the node set
3816 * @val: the value
3817 *
3818 * Implement the compare operation between a nodeset and a value
3819 * @ns < @val (1, 1, ...
3820 * @ns <= @val (1, 0, ...
3821 * @ns > @val (0, 1, ...
3822 * @ns >= @val (0, 0, ...
3823 *
3824 * If one object to be compared is a node-set and the other is a boolean,
3825 * then the comparison will be true if and only if the result of performing
3826 * the comparison on the boolean and on the result of converting
3827 * the node-set to a boolean using the boolean function is true.
3828 *
3829 * Returns 0 or 1 depending on the results of the test.
3830 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003831static int
Owen Taylor3473f882001-02-23 17:55:21 +00003832xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
3833 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
3834 if ((val == NULL) || (arg == NULL) ||
3835 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3836 return(0);
3837
3838 switch(val->type) {
3839 case XPATH_NUMBER:
3840 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
3841 case XPATH_NODESET:
3842 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003843 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00003844 case XPATH_STRING:
3845 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
3846 case XPATH_BOOLEAN:
3847 valuePush(ctxt, arg);
3848 xmlXPathBooleanFunction(ctxt, 1);
3849 valuePush(ctxt, val);
3850 return(xmlXPathCompareValues(ctxt, inf, strict));
3851 default:
3852 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00003853 }
3854 return(0);
3855}
3856
3857/**
3858 * xmlXPathEqualNodeSetString
3859 * @arg: the nodeset object argument
3860 * @str: the string to compare to.
3861 *
3862 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3863 * If one object to be compared is a node-set and the other is a string,
3864 * then the comparison will be true if and only if there is a node in
3865 * the node-set such that the result of performing the comparison on the
3866 * string-value of the node and the other string is true.
3867 *
3868 * Returns 0 or 1 depending on the results of the test.
3869 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003870static int
Daniel Veillardf06307e2001-07-03 10:35:50 +00003871xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str)
3872{
Owen Taylor3473f882001-02-23 17:55:21 +00003873 int i;
3874 xmlNodeSetPtr ns;
3875 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003876 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00003877
3878 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00003879 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3880 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00003881 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003882 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003883 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00003884 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00003885 if (ns->nodeNr <= 0) {
3886 if (hash == 0)
3887 return(1);
3888 return(0);
3889 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003890 for (i = 0; i < ns->nodeNr; i++) {
3891 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
3892 str2 = xmlNodeGetContent(ns->nodeTab[i]);
3893 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
3894 xmlFree(str2);
3895 return (1);
3896 }
3897 if (str2 != NULL)
3898 xmlFree(str2);
3899 }
Owen Taylor3473f882001-02-23 17:55:21 +00003900 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003901 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00003902}
3903
3904/**
3905 * xmlXPathEqualNodeSetFloat
3906 * @arg: the nodeset object argument
3907 * @f: the float to compare to
3908 *
3909 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3910 * If one object to be compared is a node-set and the other is a number,
3911 * then the comparison will be true if and only if there is a node in
3912 * the node-set such that the result of performing the comparison on the
3913 * number to be compared and on the result of converting the string-value
3914 * of that node to a number using the number function is true.
3915 *
3916 * Returns 0 or 1 depending on the results of the test.
3917 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003918static int
Owen Taylor3473f882001-02-23 17:55:21 +00003919xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) {
3920 char buf[100] = "";
3921
3922 if ((arg == NULL) ||
3923 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3924 return(0);
3925
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003926 xmlXPathFormatNumber(f, buf, sizeof(buf));
Owen Taylor3473f882001-02-23 17:55:21 +00003927 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
3928}
3929
3930
3931/**
3932 * xmlXPathEqualNodeSets
3933 * @arg1: first nodeset object argument
3934 * @arg2: second nodeset object argument
3935 *
3936 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
3937 * If both objects to be compared are node-sets, then the comparison
3938 * will be true if and only if there is a node in the first node-set and
3939 * a node in the second node-set such that the result of performing the
3940 * comparison on the string-values of the two nodes is true.
3941 *
3942 * (needless to say, this is a costly operation)
3943 *
3944 * Returns 0 or 1 depending on the results of the test.
3945 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003946static int
Owen Taylor3473f882001-02-23 17:55:21 +00003947xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3948 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003949 unsigned int *hashs1;
3950 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00003951 xmlChar **values1;
3952 xmlChar **values2;
3953 int ret = 0;
3954 xmlNodeSetPtr ns1;
3955 xmlNodeSetPtr ns2;
3956
3957 if ((arg1 == NULL) ||
3958 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
3959 return(0);
3960 if ((arg2 == NULL) ||
3961 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
3962 return(0);
3963
3964 ns1 = arg1->nodesetval;
3965 ns2 = arg2->nodesetval;
3966
Daniel Veillard911f49a2001-04-07 15:39:35 +00003967 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00003968 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003969 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00003970 return(0);
3971
3972 /*
3973 * check if there is a node pertaining to both sets
3974 */
3975 for (i = 0;i < ns1->nodeNr;i++)
3976 for (j = 0;j < ns2->nodeNr;j++)
3977 if (ns1->nodeTab[i] == ns2->nodeTab[j])
3978 return(1);
3979
3980 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
3981 if (values1 == NULL)
3982 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00003983 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
3984 if (hashs1 == NULL) {
3985 xmlFree(values1);
3986 return(0);
3987 }
Owen Taylor3473f882001-02-23 17:55:21 +00003988 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
3989 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
3990 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00003991 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00003992 xmlFree(values1);
3993 return(0);
3994 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003995 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
3996 if (hashs2 == NULL) {
3997 xmlFree(hashs1);
3998 xmlFree(values1);
3999 xmlFree(values2);
4000 return(0);
4001 }
Owen Taylor3473f882001-02-23 17:55:21 +00004002 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4003 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004004 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004005 for (j = 0;j < ns2->nodeNr;j++) {
4006 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004007 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
4008 if (hashs1[i] == hashs2[j]) {
4009 if (values1[i] == NULL)
4010 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4011 if (values2[j] == NULL)
4012 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
4013 ret = xmlStrEqual(values1[i], values2[j]);
4014 if (ret)
4015 break;
4016 }
Owen Taylor3473f882001-02-23 17:55:21 +00004017 }
4018 if (ret)
4019 break;
4020 }
4021 for (i = 0;i < ns1->nodeNr;i++)
4022 if (values1[i] != NULL)
4023 xmlFree(values1[i]);
4024 for (j = 0;j < ns2->nodeNr;j++)
4025 if (values2[j] != NULL)
4026 xmlFree(values2[j]);
4027 xmlFree(values1);
4028 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004029 xmlFree(hashs1);
4030 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004031 return(ret);
4032}
4033
4034/**
4035 * xmlXPathEqualValues:
4036 * @ctxt: the XPath Parser context
4037 *
4038 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4039 *
4040 * Returns 0 or 1 depending on the results of the test.
4041 */
4042int
4043xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4044 xmlXPathObjectPtr arg1, arg2;
4045 int ret = 0;
4046
4047 arg1 = valuePop(ctxt);
4048 if (arg1 == NULL)
4049 XP_ERROR0(XPATH_INVALID_OPERAND);
4050
4051 arg2 = valuePop(ctxt);
4052 if (arg2 == NULL) {
4053 xmlXPathFreeObject(arg1);
4054 XP_ERROR0(XPATH_INVALID_OPERAND);
4055 }
4056
4057 if (arg1 == arg2) {
4058#ifdef DEBUG_EXPR
4059 xmlGenericError(xmlGenericErrorContext,
4060 "Equal: by pointer\n");
4061#endif
4062 return(1);
4063 }
4064
4065 switch (arg1->type) {
4066 case XPATH_UNDEFINED:
4067#ifdef DEBUG_EXPR
4068 xmlGenericError(xmlGenericErrorContext,
4069 "Equal: undefined\n");
4070#endif
4071 break;
4072 case XPATH_XSLT_TREE:
4073 case XPATH_NODESET:
4074 switch (arg2->type) {
4075 case XPATH_UNDEFINED:
4076#ifdef DEBUG_EXPR
4077 xmlGenericError(xmlGenericErrorContext,
4078 "Equal: undefined\n");
4079#endif
4080 break;
4081 case XPATH_XSLT_TREE:
4082 case XPATH_NODESET:
4083 ret = xmlXPathEqualNodeSets(arg1, arg2);
4084 break;
4085 case XPATH_BOOLEAN:
4086 if ((arg1->nodesetval == NULL) ||
4087 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4088 else
4089 ret = 1;
4090 ret = (ret == arg2->boolval);
4091 break;
4092 case XPATH_NUMBER:
4093 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
4094 break;
4095 case XPATH_STRING:
4096 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
4097 break;
4098 case XPATH_USERS:
4099 case XPATH_POINT:
4100 case XPATH_RANGE:
4101 case XPATH_LOCATIONSET:
4102 TODO
4103 break;
4104 }
4105 break;
4106 case XPATH_BOOLEAN:
4107 switch (arg2->type) {
4108 case XPATH_UNDEFINED:
4109#ifdef DEBUG_EXPR
4110 xmlGenericError(xmlGenericErrorContext,
4111 "Equal: undefined\n");
4112#endif
4113 break;
4114 case XPATH_NODESET:
4115 case XPATH_XSLT_TREE:
4116 if ((arg2->nodesetval == NULL) ||
4117 (arg2->nodesetval->nodeNr == 0)) ret = 0;
4118 else
4119 ret = 1;
4120 break;
4121 case XPATH_BOOLEAN:
4122#ifdef DEBUG_EXPR
4123 xmlGenericError(xmlGenericErrorContext,
4124 "Equal: %d boolean %d \n",
4125 arg1->boolval, arg2->boolval);
4126#endif
4127 ret = (arg1->boolval == arg2->boolval);
4128 break;
4129 case XPATH_NUMBER:
4130 if (arg2->floatval) ret = 1;
4131 else ret = 0;
4132 ret = (arg1->boolval == ret);
4133 break;
4134 case XPATH_STRING:
4135 if ((arg2->stringval == NULL) ||
4136 (arg2->stringval[0] == 0)) ret = 0;
4137 else
4138 ret = 1;
4139 ret = (arg1->boolval == ret);
4140 break;
4141 case XPATH_USERS:
4142 case XPATH_POINT:
4143 case XPATH_RANGE:
4144 case XPATH_LOCATIONSET:
4145 TODO
4146 break;
4147 }
4148 break;
4149 case XPATH_NUMBER:
4150 switch (arg2->type) {
4151 case XPATH_UNDEFINED:
4152#ifdef DEBUG_EXPR
4153 xmlGenericError(xmlGenericErrorContext,
4154 "Equal: undefined\n");
4155#endif
4156 break;
4157 case XPATH_NODESET:
4158 case XPATH_XSLT_TREE:
4159 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
4160 break;
4161 case XPATH_BOOLEAN:
4162 if (arg1->floatval) ret = 1;
4163 else ret = 0;
4164 ret = (arg2->boolval == ret);
4165 break;
4166 case XPATH_STRING:
4167 valuePush(ctxt, arg2);
4168 xmlXPathNumberFunction(ctxt, 1);
4169 arg2 = valuePop(ctxt);
4170 /* no break on purpose */
4171 case XPATH_NUMBER:
4172 ret = (arg1->floatval == arg2->floatval);
4173 break;
4174 case XPATH_USERS:
4175 case XPATH_POINT:
4176 case XPATH_RANGE:
4177 case XPATH_LOCATIONSET:
4178 TODO
4179 break;
4180 }
4181 break;
4182 case XPATH_STRING:
4183 switch (arg2->type) {
4184 case XPATH_UNDEFINED:
4185#ifdef DEBUG_EXPR
4186 xmlGenericError(xmlGenericErrorContext,
4187 "Equal: undefined\n");
4188#endif
4189 break;
4190 case XPATH_NODESET:
4191 case XPATH_XSLT_TREE:
4192 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
4193 break;
4194 case XPATH_BOOLEAN:
4195 if ((arg1->stringval == NULL) ||
4196 (arg1->stringval[0] == 0)) ret = 0;
4197 else
4198 ret = 1;
4199 ret = (arg2->boolval == ret);
4200 break;
4201 case XPATH_STRING:
4202 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4203 break;
4204 case XPATH_NUMBER:
4205 valuePush(ctxt, arg1);
4206 xmlXPathNumberFunction(ctxt, 1);
4207 arg1 = valuePop(ctxt);
4208 ret = (arg1->floatval == arg2->floatval);
4209 break;
4210 case XPATH_USERS:
4211 case XPATH_POINT:
4212 case XPATH_RANGE:
4213 case XPATH_LOCATIONSET:
4214 TODO
4215 break;
4216 }
4217 break;
4218 case XPATH_USERS:
4219 case XPATH_POINT:
4220 case XPATH_RANGE:
4221 case XPATH_LOCATIONSET:
4222 TODO
4223 break;
4224 }
4225 xmlXPathFreeObject(arg1);
4226 xmlXPathFreeObject(arg2);
4227 return(ret);
4228}
4229
4230
4231/**
4232 * xmlXPathCompareValues:
4233 * @ctxt: the XPath Parser context
4234 * @inf: less than (1) or greater than (0)
4235 * @strict: is the comparison strict
4236 *
4237 * Implement the compare operation on XPath objects:
4238 * @arg1 < @arg2 (1, 1, ...
4239 * @arg1 <= @arg2 (1, 0, ...
4240 * @arg1 > @arg2 (0, 1, ...
4241 * @arg1 >= @arg2 (0, 0, ...
4242 *
4243 * When neither object to be compared is a node-set and the operator is
4244 * <=, <, >=, >, then the objects are compared by converted both objects
4245 * to numbers and comparing the numbers according to IEEE 754. The <
4246 * comparison will be true if and only if the first number is less than the
4247 * second number. The <= comparison will be true if and only if the first
4248 * number is less than or equal to the second number. The > comparison
4249 * will be true if and only if the first number is greater than the second
4250 * number. The >= comparison will be true if and only if the first number
4251 * is greater than or equal to the second number.
4252 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004253 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00004254 */
4255int
4256xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
4257 int ret = 0;
4258 xmlXPathObjectPtr arg1, arg2;
4259
4260 arg2 = valuePop(ctxt);
4261 if (arg2 == NULL) {
4262 XP_ERROR0(XPATH_INVALID_OPERAND);
4263 }
4264
4265 arg1 = valuePop(ctxt);
4266 if (arg1 == NULL) {
4267 xmlXPathFreeObject(arg2);
4268 XP_ERROR0(XPATH_INVALID_OPERAND);
4269 }
4270
4271 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
4272 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004273 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004274 } else {
4275 if (arg1->type == XPATH_NODESET) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004276 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4277 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004278 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004279 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4280 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004281 }
4282 }
4283 return(ret);
4284 }
4285
4286 if (arg1->type != XPATH_NUMBER) {
4287 valuePush(ctxt, arg1);
4288 xmlXPathNumberFunction(ctxt, 1);
4289 arg1 = valuePop(ctxt);
4290 }
4291 if (arg1->type != XPATH_NUMBER) {
4292 xmlXPathFreeObject(arg1);
4293 xmlXPathFreeObject(arg2);
4294 XP_ERROR0(XPATH_INVALID_OPERAND);
4295 }
4296 if (arg2->type != XPATH_NUMBER) {
4297 valuePush(ctxt, arg2);
4298 xmlXPathNumberFunction(ctxt, 1);
4299 arg2 = valuePop(ctxt);
4300 }
4301 if (arg2->type != XPATH_NUMBER) {
4302 xmlXPathFreeObject(arg1);
4303 xmlXPathFreeObject(arg2);
4304 XP_ERROR0(XPATH_INVALID_OPERAND);
4305 }
4306 /*
4307 * Add tests for infinity and nan
4308 * => feedback on 3.4 for Inf and NaN
4309 */
4310 if (inf && strict)
4311 ret = (arg1->floatval < arg2->floatval);
4312 else if (inf && !strict)
4313 ret = (arg1->floatval <= arg2->floatval);
4314 else if (!inf && strict)
4315 ret = (arg1->floatval > arg2->floatval);
4316 else if (!inf && !strict)
4317 ret = (arg1->floatval >= arg2->floatval);
4318 xmlXPathFreeObject(arg1);
4319 xmlXPathFreeObject(arg2);
4320 return(ret);
4321}
4322
4323/**
4324 * xmlXPathValueFlipSign:
4325 * @ctxt: the XPath Parser context
4326 *
4327 * Implement the unary - operation on an XPath object
4328 * The numeric operators convert their operands to numbers as if
4329 * by calling the number function.
4330 */
4331void
4332xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004333 CAST_TO_NUMBER;
4334 CHECK_TYPE(XPATH_NUMBER);
4335 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00004336}
4337
4338/**
4339 * xmlXPathAddValues:
4340 * @ctxt: the XPath Parser context
4341 *
4342 * Implement the add operation on XPath objects:
4343 * The numeric operators convert their operands to numbers as if
4344 * by calling the number function.
4345 */
4346void
4347xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
4348 xmlXPathObjectPtr arg;
4349 double val;
4350
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004351 arg = valuePop(ctxt);
4352 if (arg == NULL)
4353 XP_ERROR(XPATH_INVALID_OPERAND);
4354 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004355 xmlXPathFreeObject(arg);
4356
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004357 CAST_TO_NUMBER;
4358 CHECK_TYPE(XPATH_NUMBER);
4359 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00004360}
4361
4362/**
4363 * xmlXPathSubValues:
4364 * @ctxt: the XPath Parser context
4365 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004366 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00004367 * The numeric operators convert their operands to numbers as if
4368 * by calling the number function.
4369 */
4370void
4371xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
4372 xmlXPathObjectPtr arg;
4373 double val;
4374
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004375 arg = valuePop(ctxt);
4376 if (arg == NULL)
4377 XP_ERROR(XPATH_INVALID_OPERAND);
4378 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004379 xmlXPathFreeObject(arg);
4380
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004381 CAST_TO_NUMBER;
4382 CHECK_TYPE(XPATH_NUMBER);
4383 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004384}
4385
4386/**
4387 * xmlXPathMultValues:
4388 * @ctxt: the XPath Parser context
4389 *
4390 * Implement the multiply operation on XPath objects:
4391 * The numeric operators convert their operands to numbers as if
4392 * by calling the number function.
4393 */
4394void
4395xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
4396 xmlXPathObjectPtr arg;
4397 double val;
4398
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004399 arg = valuePop(ctxt);
4400 if (arg == NULL)
4401 XP_ERROR(XPATH_INVALID_OPERAND);
4402 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004403 xmlXPathFreeObject(arg);
4404
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004405 CAST_TO_NUMBER;
4406 CHECK_TYPE(XPATH_NUMBER);
4407 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004408}
4409
4410/**
4411 * xmlXPathDivValues:
4412 * @ctxt: the XPath Parser context
4413 *
4414 * Implement the div operation on XPath objects @arg1 / @arg2:
4415 * The numeric operators convert their operands to numbers as if
4416 * by calling the number function.
4417 */
4418void
4419xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
4420 xmlXPathObjectPtr arg;
4421 double val;
4422
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004423 arg = valuePop(ctxt);
4424 if (arg == NULL)
4425 XP_ERROR(XPATH_INVALID_OPERAND);
4426 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004427 xmlXPathFreeObject(arg);
4428
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004429 CAST_TO_NUMBER;
4430 CHECK_TYPE(XPATH_NUMBER);
4431 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004432}
4433
4434/**
4435 * xmlXPathModValues:
4436 * @ctxt: the XPath Parser context
4437 *
4438 * Implement the mod operation on XPath objects: @arg1 / @arg2
4439 * The numeric operators convert their operands to numbers as if
4440 * by calling the number function.
4441 */
4442void
4443xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
4444 xmlXPathObjectPtr arg;
4445 int arg1, arg2;
4446
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004447 arg = valuePop(ctxt);
4448 if (arg == NULL)
4449 XP_ERROR(XPATH_INVALID_OPERAND);
4450 arg2 = (int) xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004451 xmlXPathFreeObject(arg);
4452
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004453 CAST_TO_NUMBER;
4454 CHECK_TYPE(XPATH_NUMBER);
4455 arg1 = (int) ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00004456 if (arg2 == 0)
4457 ctxt->value->floatval = xmlXPathNAN;
4458 else
4459 ctxt->value->floatval = arg1 % arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00004460}
4461
4462/************************************************************************
4463 * *
4464 * The traversal functions *
4465 * *
4466 ************************************************************************/
4467
Owen Taylor3473f882001-02-23 17:55:21 +00004468/*
4469 * A traversal function enumerates nodes along an axis.
4470 * Initially it must be called with NULL, and it indicates
4471 * termination on the axis by returning NULL.
4472 */
4473typedef xmlNodePtr (*xmlXPathTraversalFunction)
4474 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
4475
4476/**
4477 * xmlXPathNextSelf:
4478 * @ctxt: the XPath Parser context
4479 * @cur: the current node in the traversal
4480 *
4481 * Traversal function for the "self" direction
4482 * The self axis contains just the context node itself
4483 *
4484 * Returns the next element following that axis
4485 */
4486xmlNodePtr
4487xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4488 if (cur == NULL)
4489 return(ctxt->context->node);
4490 return(NULL);
4491}
4492
4493/**
4494 * xmlXPathNextChild:
4495 * @ctxt: the XPath Parser context
4496 * @cur: the current node in the traversal
4497 *
4498 * Traversal function for the "child" direction
4499 * The child axis contains the children of the context node in document order.
4500 *
4501 * Returns the next element following that axis
4502 */
4503xmlNodePtr
4504xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4505 if (cur == NULL) {
4506 if (ctxt->context->node == NULL) return(NULL);
4507 switch (ctxt->context->node->type) {
4508 case XML_ELEMENT_NODE:
4509 case XML_TEXT_NODE:
4510 case XML_CDATA_SECTION_NODE:
4511 case XML_ENTITY_REF_NODE:
4512 case XML_ENTITY_NODE:
4513 case XML_PI_NODE:
4514 case XML_COMMENT_NODE:
4515 case XML_NOTATION_NODE:
4516 case XML_DTD_NODE:
4517 return(ctxt->context->node->children);
4518 case XML_DOCUMENT_NODE:
4519 case XML_DOCUMENT_TYPE_NODE:
4520 case XML_DOCUMENT_FRAG_NODE:
4521 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004522#ifdef LIBXML_DOCB_ENABLED
4523 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004524#endif
4525 return(((xmlDocPtr) ctxt->context->node)->children);
4526 case XML_ELEMENT_DECL:
4527 case XML_ATTRIBUTE_DECL:
4528 case XML_ENTITY_DECL:
4529 case XML_ATTRIBUTE_NODE:
4530 case XML_NAMESPACE_DECL:
4531 case XML_XINCLUDE_START:
4532 case XML_XINCLUDE_END:
4533 return(NULL);
4534 }
4535 return(NULL);
4536 }
4537 if ((cur->type == XML_DOCUMENT_NODE) ||
4538 (cur->type == XML_HTML_DOCUMENT_NODE))
4539 return(NULL);
4540 return(cur->next);
4541}
4542
4543/**
4544 * xmlXPathNextDescendant:
4545 * @ctxt: the XPath Parser context
4546 * @cur: the current node in the traversal
4547 *
4548 * Traversal function for the "descendant" direction
4549 * the descendant axis contains the descendants of the context node in document
4550 * order; a descendant is a child or a child of a child and so on.
4551 *
4552 * Returns the next element following that axis
4553 */
4554xmlNodePtr
4555xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4556 if (cur == NULL) {
4557 if (ctxt->context->node == NULL)
4558 return(NULL);
4559 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4560 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4561 return(NULL);
4562
4563 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
4564 return(ctxt->context->doc->children);
4565 return(ctxt->context->node->children);
4566 }
4567
Daniel Veillard567e1b42001-08-01 15:53:47 +00004568 if (cur->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004569 if (cur->children->type != XML_ENTITY_DECL)
Daniel Veillard567e1b42001-08-01 15:53:47 +00004570 return(cur->children);
4571 }
4572
4573 if (cur == ctxt->context->node) return(NULL);
4574
Owen Taylor3473f882001-02-23 17:55:21 +00004575 if (cur->next != NULL) return(cur->next);
4576
4577 do {
4578 cur = cur->parent;
4579 if (cur == NULL) return(NULL);
4580 if (cur == ctxt->context->node) return(NULL);
4581 if (cur->next != NULL) {
4582 cur = cur->next;
4583 return(cur);
4584 }
4585 } while (cur != NULL);
4586 return(cur);
4587}
4588
4589/**
4590 * xmlXPathNextDescendantOrSelf:
4591 * @ctxt: the XPath Parser context
4592 * @cur: the current node in the traversal
4593 *
4594 * Traversal function for the "descendant-or-self" direction
4595 * the descendant-or-self axis contains the context node and the descendants
4596 * of the context node in document order; thus the context node is the first
4597 * node on the axis, and the first child of the context node is the second node
4598 * on the axis
4599 *
4600 * Returns the next element following that axis
4601 */
4602xmlNodePtr
4603xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4604 if (cur == NULL) {
4605 if (ctxt->context->node == NULL)
4606 return(NULL);
4607 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4608 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4609 return(NULL);
4610 return(ctxt->context->node);
4611 }
4612
4613 return(xmlXPathNextDescendant(ctxt, cur));
4614}
4615
4616/**
4617 * xmlXPathNextParent:
4618 * @ctxt: the XPath Parser context
4619 * @cur: the current node in the traversal
4620 *
4621 * Traversal function for the "parent" direction
4622 * The parent axis contains the parent of the context node, if there is one.
4623 *
4624 * Returns the next element following that axis
4625 */
4626xmlNodePtr
4627xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4628 /*
4629 * the parent of an attribute or namespace node is the element
4630 * to which the attribute or namespace node is attached
4631 * Namespace handling !!!
4632 */
4633 if (cur == NULL) {
4634 if (ctxt->context->node == NULL) return(NULL);
4635 switch (ctxt->context->node->type) {
4636 case XML_ELEMENT_NODE:
4637 case XML_TEXT_NODE:
4638 case XML_CDATA_SECTION_NODE:
4639 case XML_ENTITY_REF_NODE:
4640 case XML_ENTITY_NODE:
4641 case XML_PI_NODE:
4642 case XML_COMMENT_NODE:
4643 case XML_NOTATION_NODE:
4644 case XML_DTD_NODE:
4645 case XML_ELEMENT_DECL:
4646 case XML_ATTRIBUTE_DECL:
4647 case XML_XINCLUDE_START:
4648 case XML_XINCLUDE_END:
4649 case XML_ENTITY_DECL:
4650 if (ctxt->context->node->parent == NULL)
4651 return((xmlNodePtr) ctxt->context->doc);
4652 return(ctxt->context->node->parent);
4653 case XML_ATTRIBUTE_NODE: {
4654 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4655
4656 return(att->parent);
4657 }
4658 case XML_DOCUMENT_NODE:
4659 case XML_DOCUMENT_TYPE_NODE:
4660 case XML_DOCUMENT_FRAG_NODE:
4661 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004662#ifdef LIBXML_DOCB_ENABLED
4663 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004664#endif
4665 return(NULL);
4666 case XML_NAMESPACE_DECL:
4667 /*
4668 * TODO !!! may require extending struct _xmlNs with
4669 * parent field
4670 * C.f. Infoset case...
4671 */
4672 return(NULL);
4673 }
4674 }
4675 return(NULL);
4676}
4677
4678/**
4679 * xmlXPathNextAncestor:
4680 * @ctxt: the XPath Parser context
4681 * @cur: the current node in the traversal
4682 *
4683 * Traversal function for the "ancestor" direction
4684 * the ancestor axis contains the ancestors of the context node; the ancestors
4685 * of the context node consist of the parent of context node and the parent's
4686 * parent and so on; the nodes are ordered in reverse document order; thus the
4687 * parent is the first node on the axis, and the parent's parent is the second
4688 * node on the axis
4689 *
4690 * Returns the next element following that axis
4691 */
4692xmlNodePtr
4693xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4694 /*
4695 * the parent of an attribute or namespace node is the element
4696 * to which the attribute or namespace node is attached
4697 * !!!!!!!!!!!!!
4698 */
4699 if (cur == NULL) {
4700 if (ctxt->context->node == NULL) return(NULL);
4701 switch (ctxt->context->node->type) {
4702 case XML_ELEMENT_NODE:
4703 case XML_TEXT_NODE:
4704 case XML_CDATA_SECTION_NODE:
4705 case XML_ENTITY_REF_NODE:
4706 case XML_ENTITY_NODE:
4707 case XML_PI_NODE:
4708 case XML_COMMENT_NODE:
4709 case XML_DTD_NODE:
4710 case XML_ELEMENT_DECL:
4711 case XML_ATTRIBUTE_DECL:
4712 case XML_ENTITY_DECL:
4713 case XML_NOTATION_NODE:
4714 case XML_XINCLUDE_START:
4715 case XML_XINCLUDE_END:
4716 if (ctxt->context->node->parent == NULL)
4717 return((xmlNodePtr) ctxt->context->doc);
4718 return(ctxt->context->node->parent);
4719 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004720 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00004721
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004722 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00004723 }
4724 case XML_DOCUMENT_NODE:
4725 case XML_DOCUMENT_TYPE_NODE:
4726 case XML_DOCUMENT_FRAG_NODE:
4727 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004728#ifdef LIBXML_DOCB_ENABLED
4729 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004730#endif
4731 return(NULL);
4732 case XML_NAMESPACE_DECL:
4733 /*
4734 * TODO !!! may require extending struct _xmlNs with
4735 * parent field
4736 * C.f. Infoset case...
4737 */
4738 return(NULL);
4739 }
4740 return(NULL);
4741 }
4742 if (cur == ctxt->context->doc->children)
4743 return((xmlNodePtr) ctxt->context->doc);
4744 if (cur == (xmlNodePtr) ctxt->context->doc)
4745 return(NULL);
4746 switch (cur->type) {
4747 case XML_ELEMENT_NODE:
4748 case XML_TEXT_NODE:
4749 case XML_CDATA_SECTION_NODE:
4750 case XML_ENTITY_REF_NODE:
4751 case XML_ENTITY_NODE:
4752 case XML_PI_NODE:
4753 case XML_COMMENT_NODE:
4754 case XML_NOTATION_NODE:
4755 case XML_DTD_NODE:
4756 case XML_ELEMENT_DECL:
4757 case XML_ATTRIBUTE_DECL:
4758 case XML_ENTITY_DECL:
4759 case XML_XINCLUDE_START:
4760 case XML_XINCLUDE_END:
4761 return(cur->parent);
4762 case XML_ATTRIBUTE_NODE: {
4763 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4764
4765 return(att->parent);
4766 }
4767 case XML_DOCUMENT_NODE:
4768 case XML_DOCUMENT_TYPE_NODE:
4769 case XML_DOCUMENT_FRAG_NODE:
4770 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004771#ifdef LIBXML_DOCB_ENABLED
4772 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004773#endif
4774 return(NULL);
4775 case XML_NAMESPACE_DECL:
4776 /*
4777 * TODO !!! may require extending struct _xmlNs with
4778 * parent field
4779 * C.f. Infoset case...
4780 */
4781 return(NULL);
4782 }
4783 return(NULL);
4784}
4785
4786/**
4787 * xmlXPathNextAncestorOrSelf:
4788 * @ctxt: the XPath Parser context
4789 * @cur: the current node in the traversal
4790 *
4791 * Traversal function for the "ancestor-or-self" direction
4792 * he ancestor-or-self axis contains the context node and ancestors of
4793 * the context node in reverse document order; thus the context node is
4794 * the first node on the axis, and the context node's parent the second;
4795 * parent here is defined the same as with the parent axis.
4796 *
4797 * Returns the next element following that axis
4798 */
4799xmlNodePtr
4800xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4801 if (cur == NULL)
4802 return(ctxt->context->node);
4803 return(xmlXPathNextAncestor(ctxt, cur));
4804}
4805
4806/**
4807 * xmlXPathNextFollowingSibling:
4808 * @ctxt: the XPath Parser context
4809 * @cur: the current node in the traversal
4810 *
4811 * Traversal function for the "following-sibling" direction
4812 * The following-sibling axis contains the following siblings of the context
4813 * node in document order.
4814 *
4815 * Returns the next element following that axis
4816 */
4817xmlNodePtr
4818xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4819 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4820 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4821 return(NULL);
4822 if (cur == (xmlNodePtr) ctxt->context->doc)
4823 return(NULL);
4824 if (cur == NULL)
4825 return(ctxt->context->node->next);
4826 return(cur->next);
4827}
4828
4829/**
4830 * xmlXPathNextPrecedingSibling:
4831 * @ctxt: the XPath Parser context
4832 * @cur: the current node in the traversal
4833 *
4834 * Traversal function for the "preceding-sibling" direction
4835 * The preceding-sibling axis contains the preceding siblings of the context
4836 * node in reverse document order; the first preceding sibling is first on the
4837 * axis; the sibling preceding that node is the second on the axis and so on.
4838 *
4839 * Returns the next element following that axis
4840 */
4841xmlNodePtr
4842xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4843 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4844 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4845 return(NULL);
4846 if (cur == (xmlNodePtr) ctxt->context->doc)
4847 return(NULL);
4848 if (cur == NULL)
4849 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004850 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
4851 cur = cur->prev;
4852 if (cur == NULL)
4853 return(ctxt->context->node->prev);
4854 }
Owen Taylor3473f882001-02-23 17:55:21 +00004855 return(cur->prev);
4856}
4857
4858/**
4859 * xmlXPathNextFollowing:
4860 * @ctxt: the XPath Parser context
4861 * @cur: the current node in the traversal
4862 *
4863 * Traversal function for the "following" direction
4864 * The following axis contains all nodes in the same document as the context
4865 * node that are after the context node in document order, excluding any
4866 * descendants and excluding attribute nodes and namespace nodes; the nodes
4867 * are ordered in document order
4868 *
4869 * Returns the next element following that axis
4870 */
4871xmlNodePtr
4872xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4873 if (cur != NULL && cur->children != NULL)
4874 return cur->children ;
4875 if (cur == NULL) cur = ctxt->context->node;
4876 if (cur == NULL) return(NULL) ; /* ERROR */
4877 if (cur->next != NULL) return(cur->next) ;
4878 do {
4879 cur = cur->parent;
4880 if (cur == NULL) return(NULL);
4881 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
4882 if (cur->next != NULL) return(cur->next);
4883 } while (cur != NULL);
4884 return(cur);
4885}
4886
4887/*
4888 * xmlXPathIsAncestor:
4889 * @ancestor: the ancestor node
4890 * @node: the current node
4891 *
4892 * Check that @ancestor is a @node's ancestor
4893 *
4894 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
4895 */
4896static int
4897xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
4898 if ((ancestor == NULL) || (node == NULL)) return(0);
4899 /* nodes need to be in the same document */
4900 if (ancestor->doc != node->doc) return(0);
4901 /* avoid searching if ancestor or node is the root node */
4902 if (ancestor == (xmlNodePtr) node->doc) return(1);
4903 if (node == (xmlNodePtr) ancestor->doc) return(0);
4904 while (node->parent != NULL) {
4905 if (node->parent == ancestor)
4906 return(1);
4907 node = node->parent;
4908 }
4909 return(0);
4910}
4911
4912/**
4913 * xmlXPathNextPreceding:
4914 * @ctxt: the XPath Parser context
4915 * @cur: the current node in the traversal
4916 *
4917 * Traversal function for the "preceding" direction
4918 * the preceding axis contains all nodes in the same document as the context
4919 * node that are before the context node in document order, excluding any
4920 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4921 * ordered in reverse document order
4922 *
4923 * Returns the next element following that axis
4924 */
4925xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00004926xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
4927{
Owen Taylor3473f882001-02-23 17:55:21 +00004928 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004929 cur = ctxt->context->node;
4930 if (cur == NULL)
4931 return (NULL);
4932 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
4933 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00004934 do {
4935 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004936 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
4937 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004938 }
4939
4940 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004941 if (cur == NULL)
4942 return (NULL);
4943 if (cur == ctxt->context->doc->children)
4944 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004945 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00004946 return (cur);
4947}
4948
4949/**
4950 * xmlXPathNextPrecedingInternal:
4951 * @ctxt: the XPath Parser context
4952 * @cur: the current node in the traversal
4953 *
4954 * Traversal function for the "preceding" direction
4955 * the preceding axis contains all nodes in the same document as the context
4956 * node that are before the context node in document order, excluding any
4957 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4958 * ordered in reverse document order
4959 * This is a faster implementation but internal only since it requires a
4960 * state kept in the parser context: ctxt->ancestor.
4961 *
4962 * Returns the next element following that axis
4963 */
4964static xmlNodePtr
4965xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
4966 xmlNodePtr cur)
4967{
4968 if (cur == NULL) {
4969 cur = ctxt->context->node;
4970 if (cur == NULL)
4971 return (NULL);
4972 ctxt->ancestor = cur->parent;
4973 }
4974 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
4975 cur = cur->prev;
4976 while (cur->prev == NULL) {
4977 cur = cur->parent;
4978 if (cur == NULL)
4979 return (NULL);
4980 if (cur == ctxt->context->doc->children)
4981 return (NULL);
4982 if (cur != ctxt->ancestor)
4983 return (cur);
4984 ctxt->ancestor = cur->parent;
4985 }
4986 cur = cur->prev;
4987 while (cur->last != NULL)
4988 cur = cur->last;
4989 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004990}
4991
4992/**
4993 * xmlXPathNextNamespace:
4994 * @ctxt: the XPath Parser context
4995 * @cur: the current attribute in the traversal
4996 *
4997 * Traversal function for the "namespace" direction
4998 * the namespace axis contains the namespace nodes of the context node;
4999 * the order of nodes on this axis is implementation-defined; the axis will
5000 * be empty unless the context node is an element
5001 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005002 * We keep the XML namespace node at the end of the list.
5003 *
Owen Taylor3473f882001-02-23 17:55:21 +00005004 * Returns the next element following that axis
5005 */
5006xmlNodePtr
5007xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005008 xmlNodePtr ret;
5009
Owen Taylor3473f882001-02-23 17:55:21 +00005010 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005011 if (cur == (xmlNodePtr) xmlXPathXMLNamespace)
5012 return(NULL);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005013 if ((cur == NULL) || (ctxt->context->tmpNsList == NULL)) {
5014 if (ctxt->context->tmpNsList != NULL)
5015 xmlFree(ctxt->context->tmpNsList);
5016 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005017 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005018 if (ctxt->context->tmpNsList == NULL) return(NULL);
5019 ctxt->context->tmpNsNr = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005020 }
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005021 ret = (xmlNodePtr)ctxt->context->tmpNsList[ctxt->context->tmpNsNr++];
5022 if (ret == NULL) {
5023 xmlFree(ctxt->context->tmpNsList);
5024 ctxt->context->tmpNsList = NULL;
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005025 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005026 }
5027 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005028}
5029
5030/**
5031 * xmlXPathNextAttribute:
5032 * @ctxt: the XPath Parser context
5033 * @cur: the current attribute in the traversal
5034 *
5035 * Traversal function for the "attribute" direction
5036 * TODO: support DTD inherited default attributes
5037 *
5038 * Returns the next element following that axis
5039 */
5040xmlNodePtr
5041xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005042 if (ctxt->context->node == NULL)
5043 return(NULL);
5044 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5045 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005046 if (cur == NULL) {
5047 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5048 return(NULL);
5049 return((xmlNodePtr)ctxt->context->node->properties);
5050 }
5051 return((xmlNodePtr)cur->next);
5052}
5053
5054/************************************************************************
5055 * *
5056 * NodeTest Functions *
5057 * *
5058 ************************************************************************/
5059
Owen Taylor3473f882001-02-23 17:55:21 +00005060#define IS_FUNCTION 200
5061
Owen Taylor3473f882001-02-23 17:55:21 +00005062
5063/************************************************************************
5064 * *
5065 * Implicit tree core function library *
5066 * *
5067 ************************************************************************/
5068
5069/**
5070 * xmlXPathRoot:
5071 * @ctxt: the XPath Parser context
5072 *
5073 * Initialize the context to the root of the document
5074 */
5075void
5076xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5077 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5078 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5079}
5080
5081/************************************************************************
5082 * *
5083 * The explicit core function library *
5084 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5085 * *
5086 ************************************************************************/
5087
5088
5089/**
5090 * xmlXPathLastFunction:
5091 * @ctxt: the XPath Parser context
5092 * @nargs: the number of arguments
5093 *
5094 * Implement the last() XPath function
5095 * number last()
5096 * The last function returns the number of nodes in the context node list.
5097 */
5098void
5099xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5100 CHECK_ARITY(0);
5101 if (ctxt->context->contextSize >= 0) {
5102 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5103#ifdef DEBUG_EXPR
5104 xmlGenericError(xmlGenericErrorContext,
5105 "last() : %d\n", ctxt->context->contextSize);
5106#endif
5107 } else {
5108 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5109 }
5110}
5111
5112/**
5113 * xmlXPathPositionFunction:
5114 * @ctxt: the XPath Parser context
5115 * @nargs: the number of arguments
5116 *
5117 * Implement the position() XPath function
5118 * number position()
5119 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005120 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005121 * will be equal to last().
5122 */
5123void
5124xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5125 CHECK_ARITY(0);
5126 if (ctxt->context->proximityPosition >= 0) {
5127 valuePush(ctxt,
5128 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5129#ifdef DEBUG_EXPR
5130 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5131 ctxt->context->proximityPosition);
5132#endif
5133 } else {
5134 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5135 }
5136}
5137
5138/**
5139 * xmlXPathCountFunction:
5140 * @ctxt: the XPath Parser context
5141 * @nargs: the number of arguments
5142 *
5143 * Implement the count() XPath function
5144 * number count(node-set)
5145 */
5146void
5147xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5148 xmlXPathObjectPtr cur;
5149
5150 CHECK_ARITY(1);
5151 if ((ctxt->value == NULL) ||
5152 ((ctxt->value->type != XPATH_NODESET) &&
5153 (ctxt->value->type != XPATH_XSLT_TREE)))
5154 XP_ERROR(XPATH_INVALID_TYPE);
5155 cur = valuePop(ctxt);
5156
Daniel Veillard911f49a2001-04-07 15:39:35 +00005157 if ((cur == NULL) || (cur->nodesetval == NULL))
5158 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00005159 else if (cur->type == XPATH_NODESET) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005160 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005161 } else {
5162 if ((cur->nodesetval->nodeNr != 1) ||
5163 (cur->nodesetval->nodeTab == NULL)) {
5164 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5165 } else {
5166 xmlNodePtr tmp;
5167 int i = 0;
5168
5169 tmp = cur->nodesetval->nodeTab[0];
5170 if (tmp != NULL) {
5171 tmp = tmp->children;
5172 while (tmp != NULL) {
5173 tmp = tmp->next;
5174 i++;
5175 }
5176 }
5177 valuePush(ctxt, xmlXPathNewFloat((double) i));
5178 }
5179 }
Owen Taylor3473f882001-02-23 17:55:21 +00005180 xmlXPathFreeObject(cur);
5181}
5182
5183/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005184 * xmlXPathGetElementsByIds:
5185 * @doc: the document
5186 * @ids: a whitespace separated list of IDs
5187 *
5188 * Selects elements by their unique ID.
5189 *
5190 * Returns a node-set of selected elements.
5191 */
5192static xmlNodeSetPtr
5193xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5194 xmlNodeSetPtr ret;
5195 const xmlChar *cur = ids;
5196 xmlChar *ID;
5197 xmlAttrPtr attr;
5198 xmlNodePtr elem = NULL;
5199
5200 ret = xmlXPathNodeSetCreate(NULL);
5201
5202 while (IS_BLANK(*cur)) cur++;
5203 while (*cur != 0) {
5204 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
5205 (*cur == '.') || (*cur == '-') ||
5206 (*cur == '_') || (*cur == ':') ||
5207 (IS_COMBINING(*cur)) ||
5208 (IS_EXTENDER(*cur)))
5209 cur++;
5210
5211 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
5212
5213 ID = xmlStrndup(ids, cur - ids);
5214 attr = xmlGetID(doc, ID);
5215 if (attr != NULL) {
5216 elem = attr->parent;
5217 xmlXPathNodeSetAdd(ret, elem);
5218 }
5219 if (ID != NULL)
5220 xmlFree(ID);
5221
5222 while (IS_BLANK(*cur)) cur++;
5223 ids = cur;
5224 }
5225 return(ret);
5226}
5227
5228/**
Owen Taylor3473f882001-02-23 17:55:21 +00005229 * xmlXPathIdFunction:
5230 * @ctxt: the XPath Parser context
5231 * @nargs: the number of arguments
5232 *
5233 * Implement the id() XPath function
5234 * node-set id(object)
5235 * The id function selects elements by their unique ID
5236 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5237 * then the result is the union of the result of applying id to the
5238 * string value of each of the nodes in the argument node-set. When the
5239 * argument to id is of any other type, the argument is converted to a
5240 * string as if by a call to the string function; the string is split
5241 * into a whitespace-separated list of tokens (whitespace is any sequence
5242 * of characters matching the production S); the result is a node-set
5243 * containing the elements in the same document as the context node that
5244 * have a unique ID equal to any of the tokens in the list.
5245 */
5246void
5247xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005248 xmlChar *tokens;
5249 xmlNodeSetPtr ret;
5250 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00005251
5252 CHECK_ARITY(1);
5253 obj = valuePop(ctxt);
5254 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
5255 if (obj->type == XPATH_NODESET) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005256 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00005257 int i;
5258
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005259 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005260
Daniel Veillard911f49a2001-04-07 15:39:35 +00005261 if (obj->nodesetval != NULL) {
5262 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005263 tokens =
5264 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
5265 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
5266 ret = xmlXPathNodeSetMerge(ret, ns);
5267 xmlXPathFreeNodeSet(ns);
5268 if (tokens != NULL)
5269 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00005270 }
Owen Taylor3473f882001-02-23 17:55:21 +00005271 }
5272
5273 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005274 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005275 return;
5276 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005277 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00005278
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005279 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
5280 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005281
Owen Taylor3473f882001-02-23 17:55:21 +00005282 xmlXPathFreeObject(obj);
5283 return;
5284}
5285
5286/**
5287 * xmlXPathLocalNameFunction:
5288 * @ctxt: the XPath Parser context
5289 * @nargs: the number of arguments
5290 *
5291 * Implement the local-name() XPath function
5292 * string local-name(node-set?)
5293 * The local-name function returns a string containing the local part
5294 * of the name of the node in the argument node-set that is first in
5295 * document order. If the node-set is empty or the first node has no
5296 * name, an empty string is returned. If the argument is omitted it
5297 * defaults to the context node.
5298 */
5299void
5300xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5301 xmlXPathObjectPtr cur;
5302
5303 if (nargs == 0) {
5304 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5305 nargs = 1;
5306 }
5307
5308 CHECK_ARITY(1);
5309 if ((ctxt->value == NULL) ||
5310 ((ctxt->value->type != XPATH_NODESET) &&
5311 (ctxt->value->type != XPATH_XSLT_TREE)))
5312 XP_ERROR(XPATH_INVALID_TYPE);
5313 cur = valuePop(ctxt);
5314
Daniel Veillard911f49a2001-04-07 15:39:35 +00005315 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005316 valuePush(ctxt, xmlXPathNewCString(""));
5317 } else {
5318 int i = 0; /* Should be first in document order !!!!! */
5319 switch (cur->nodesetval->nodeTab[i]->type) {
5320 case XML_ELEMENT_NODE:
5321 case XML_ATTRIBUTE_NODE:
5322 case XML_PI_NODE:
5323 valuePush(ctxt,
5324 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
5325 break;
5326 case XML_NAMESPACE_DECL:
5327 valuePush(ctxt, xmlXPathNewString(
5328 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
5329 break;
5330 default:
5331 valuePush(ctxt, xmlXPathNewCString(""));
5332 }
5333 }
5334 xmlXPathFreeObject(cur);
5335}
5336
5337/**
5338 * xmlXPathNamespaceURIFunction:
5339 * @ctxt: the XPath Parser context
5340 * @nargs: the number of arguments
5341 *
5342 * Implement the namespace-uri() XPath function
5343 * string namespace-uri(node-set?)
5344 * The namespace-uri function returns a string containing the
5345 * namespace URI of the expanded name of the node in the argument
5346 * node-set that is first in document order. If the node-set is empty,
5347 * the first node has no name, or the expanded name has no namespace
5348 * URI, an empty string is returned. If the argument is omitted it
5349 * defaults to the context node.
5350 */
5351void
5352xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5353 xmlXPathObjectPtr cur;
5354
5355 if (nargs == 0) {
5356 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5357 nargs = 1;
5358 }
5359 CHECK_ARITY(1);
5360 if ((ctxt->value == NULL) ||
5361 ((ctxt->value->type != XPATH_NODESET) &&
5362 (ctxt->value->type != XPATH_XSLT_TREE)))
5363 XP_ERROR(XPATH_INVALID_TYPE);
5364 cur = valuePop(ctxt);
5365
Daniel Veillard911f49a2001-04-07 15:39:35 +00005366 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005367 valuePush(ctxt, xmlXPathNewCString(""));
5368 } else {
5369 int i = 0; /* Should be first in document order !!!!! */
5370 switch (cur->nodesetval->nodeTab[i]->type) {
5371 case XML_ELEMENT_NODE:
5372 case XML_ATTRIBUTE_NODE:
5373 if (cur->nodesetval->nodeTab[i]->ns == NULL)
5374 valuePush(ctxt, xmlXPathNewCString(""));
5375 else
5376 valuePush(ctxt, xmlXPathNewString(
5377 cur->nodesetval->nodeTab[i]->ns->href));
5378 break;
5379 default:
5380 valuePush(ctxt, xmlXPathNewCString(""));
5381 }
5382 }
5383 xmlXPathFreeObject(cur);
5384}
5385
5386/**
5387 * xmlXPathNameFunction:
5388 * @ctxt: the XPath Parser context
5389 * @nargs: the number of arguments
5390 *
5391 * Implement the name() XPath function
5392 * string name(node-set?)
5393 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005394 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00005395 * order. The QName must represent the name with respect to the namespace
5396 * declarations in effect on the node whose name is being represented.
5397 * Typically, this will be the form in which the name occurred in the XML
5398 * source. This need not be the case if there are namespace declarations
5399 * in effect on the node that associate multiple prefixes with the same
5400 * namespace. However, an implementation may include information about
5401 * the original prefix in its representation of nodes; in this case, an
5402 * implementation can ensure that the returned string is always the same
5403 * as the QName used in the XML source. If the argument it omitted it
5404 * defaults to the context node.
5405 * Libxml keep the original prefix so the "real qualified name" used is
5406 * returned.
5407 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005408static void
Daniel Veillard04383752001-07-08 14:27:15 +00005409xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
5410{
Owen Taylor3473f882001-02-23 17:55:21 +00005411 xmlXPathObjectPtr cur;
5412
5413 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00005414 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5415 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00005416 }
5417
5418 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00005419 if ((ctxt->value == NULL) ||
5420 ((ctxt->value->type != XPATH_NODESET) &&
5421 (ctxt->value->type != XPATH_XSLT_TREE)))
5422 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00005423 cur = valuePop(ctxt);
5424
Daniel Veillard911f49a2001-04-07 15:39:35 +00005425 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00005426 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00005427 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00005428 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005429
Daniel Veillard04383752001-07-08 14:27:15 +00005430 switch (cur->nodesetval->nodeTab[i]->type) {
5431 case XML_ELEMENT_NODE:
5432 case XML_ATTRIBUTE_NODE:
5433 if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
5434 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL))
5435 valuePush(ctxt,
5436 xmlXPathNewString(cur->nodesetval->
5437 nodeTab[i]->name));
5438
5439 else {
5440 char name[2000];
5441
5442 snprintf(name, sizeof(name), "%s:%s",
5443 (char *) cur->nodesetval->nodeTab[i]->ns->
5444 prefix,
5445 (char *) cur->nodesetval->nodeTab[i]->name);
5446 name[sizeof(name) - 1] = 0;
5447 valuePush(ctxt, xmlXPathNewCString(name));
5448 }
5449 break;
5450 default:
5451 valuePush(ctxt,
5452 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
5453 xmlXPathLocalNameFunction(ctxt, 1);
5454 }
Owen Taylor3473f882001-02-23 17:55:21 +00005455 }
5456 xmlXPathFreeObject(cur);
5457}
5458
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005459
5460/**
Owen Taylor3473f882001-02-23 17:55:21 +00005461 * xmlXPathStringFunction:
5462 * @ctxt: the XPath Parser context
5463 * @nargs: the number of arguments
5464 *
5465 * Implement the string() XPath function
5466 * string string(object?)
5467 * he string function converts an object to a string as follows:
5468 * - A node-set is converted to a string by returning the value of
5469 * the node in the node-set that is first in document order.
5470 * If the node-set is empty, an empty string is returned.
5471 * - A number is converted to a string as follows
5472 * + NaN is converted to the string NaN
5473 * + positive zero is converted to the string 0
5474 * + negative zero is converted to the string 0
5475 * + positive infinity is converted to the string Infinity
5476 * + negative infinity is converted to the string -Infinity
5477 * + if the number is an integer, the number is represented in
5478 * decimal form as a Number with no decimal point and no leading
5479 * zeros, preceded by a minus sign (-) if the number is negative
5480 * + otherwise, the number is represented in decimal form as a
5481 * Number including a decimal point with at least one digit
5482 * before the decimal point and at least one digit after the
5483 * decimal point, preceded by a minus sign (-) if the number
5484 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005485 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00005486 * before the decimal point; beyond the one required digit
5487 * after the decimal point there must be as many, but only as
5488 * many, more digits as are needed to uniquely distinguish the
5489 * number from all other IEEE 754 numeric values.
5490 * - The boolean false value is converted to the string false.
5491 * The boolean true value is converted to the string true.
5492 *
5493 * If the argument is omitted, it defaults to a node-set with the
5494 * context node as its only member.
5495 */
5496void
5497xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5498 xmlXPathObjectPtr cur;
5499
5500 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005501 valuePush(ctxt,
5502 xmlXPathWrapString(
5503 xmlXPathCastNodeToString(ctxt->context->node)));
5504 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005505 }
5506
5507 CHECK_ARITY(1);
5508 cur = valuePop(ctxt);
5509 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005510 cur = xmlXPathConvertString(cur);
5511 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005512}
5513
5514/**
5515 * xmlXPathStringLengthFunction:
5516 * @ctxt: the XPath Parser context
5517 * @nargs: the number of arguments
5518 *
5519 * Implement the string-length() XPath function
5520 * number string-length(string?)
5521 * The string-length returns the number of characters in the string
5522 * (see [3.6 Strings]). If the argument is omitted, it defaults to
5523 * the context node converted to a string, in other words the value
5524 * of the context node.
5525 */
5526void
5527xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5528 xmlXPathObjectPtr cur;
5529
5530 if (nargs == 0) {
5531 if (ctxt->context->node == NULL) {
5532 valuePush(ctxt, xmlXPathNewFloat(0));
5533 } else {
5534 xmlChar *content;
5535
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005536 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005537 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00005538 xmlFree(content);
5539 }
5540 return;
5541 }
5542 CHECK_ARITY(1);
5543 CAST_TO_STRING;
5544 CHECK_TYPE(XPATH_STRING);
5545 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005546 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00005547 xmlXPathFreeObject(cur);
5548}
5549
5550/**
5551 * xmlXPathConcatFunction:
5552 * @ctxt: the XPath Parser context
5553 * @nargs: the number of arguments
5554 *
5555 * Implement the concat() XPath function
5556 * string concat(string, string, string*)
5557 * The concat function returns the concatenation of its arguments.
5558 */
5559void
5560xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5561 xmlXPathObjectPtr cur, newobj;
5562 xmlChar *tmp;
5563
5564 if (nargs < 2) {
5565 CHECK_ARITY(2);
5566 }
5567
5568 CAST_TO_STRING;
5569 cur = valuePop(ctxt);
5570 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
5571 xmlXPathFreeObject(cur);
5572 return;
5573 }
5574 nargs--;
5575
5576 while (nargs > 0) {
5577 CAST_TO_STRING;
5578 newobj = valuePop(ctxt);
5579 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
5580 xmlXPathFreeObject(newobj);
5581 xmlXPathFreeObject(cur);
5582 XP_ERROR(XPATH_INVALID_TYPE);
5583 }
5584 tmp = xmlStrcat(newobj->stringval, cur->stringval);
5585 newobj->stringval = cur->stringval;
5586 cur->stringval = tmp;
5587
5588 xmlXPathFreeObject(newobj);
5589 nargs--;
5590 }
5591 valuePush(ctxt, cur);
5592}
5593
5594/**
5595 * xmlXPathContainsFunction:
5596 * @ctxt: the XPath Parser context
5597 * @nargs: the number of arguments
5598 *
5599 * Implement the contains() XPath function
5600 * boolean contains(string, string)
5601 * The contains function returns true if the first argument string
5602 * contains the second argument string, and otherwise returns false.
5603 */
5604void
5605xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5606 xmlXPathObjectPtr hay, needle;
5607
5608 CHECK_ARITY(2);
5609 CAST_TO_STRING;
5610 CHECK_TYPE(XPATH_STRING);
5611 needle = valuePop(ctxt);
5612 CAST_TO_STRING;
5613 hay = valuePop(ctxt);
5614 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5615 xmlXPathFreeObject(hay);
5616 xmlXPathFreeObject(needle);
5617 XP_ERROR(XPATH_INVALID_TYPE);
5618 }
5619 if (xmlStrstr(hay->stringval, needle->stringval))
5620 valuePush(ctxt, xmlXPathNewBoolean(1));
5621 else
5622 valuePush(ctxt, xmlXPathNewBoolean(0));
5623 xmlXPathFreeObject(hay);
5624 xmlXPathFreeObject(needle);
5625}
5626
5627/**
5628 * xmlXPathStartsWithFunction:
5629 * @ctxt: the XPath Parser context
5630 * @nargs: the number of arguments
5631 *
5632 * Implement the starts-with() XPath function
5633 * boolean starts-with(string, string)
5634 * The starts-with function returns true if the first argument string
5635 * starts with the second argument string, and otherwise returns false.
5636 */
5637void
5638xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5639 xmlXPathObjectPtr hay, needle;
5640 int n;
5641
5642 CHECK_ARITY(2);
5643 CAST_TO_STRING;
5644 CHECK_TYPE(XPATH_STRING);
5645 needle = valuePop(ctxt);
5646 CAST_TO_STRING;
5647 hay = valuePop(ctxt);
5648 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5649 xmlXPathFreeObject(hay);
5650 xmlXPathFreeObject(needle);
5651 XP_ERROR(XPATH_INVALID_TYPE);
5652 }
5653 n = xmlStrlen(needle->stringval);
5654 if (xmlStrncmp(hay->stringval, needle->stringval, n))
5655 valuePush(ctxt, xmlXPathNewBoolean(0));
5656 else
5657 valuePush(ctxt, xmlXPathNewBoolean(1));
5658 xmlXPathFreeObject(hay);
5659 xmlXPathFreeObject(needle);
5660}
5661
5662/**
5663 * xmlXPathSubstringFunction:
5664 * @ctxt: the XPath Parser context
5665 * @nargs: the number of arguments
5666 *
5667 * Implement the substring() XPath function
5668 * string substring(string, number, number?)
5669 * The substring function returns the substring of the first argument
5670 * starting at the position specified in the second argument with
5671 * length specified in the third argument. For example,
5672 * substring("12345",2,3) returns "234". If the third argument is not
5673 * specified, it returns the substring starting at the position specified
5674 * in the second argument and continuing to the end of the string. For
5675 * example, substring("12345",2) returns "2345". More precisely, each
5676 * character in the string (see [3.6 Strings]) is considered to have a
5677 * numeric position: the position of the first character is 1, the position
5678 * of the second character is 2 and so on. The returned substring contains
5679 * those characters for which the position of the character is greater than
5680 * or equal to the second argument and, if the third argument is specified,
5681 * less than the sum of the second and third arguments; the comparisons
5682 * and addition used for the above follow the standard IEEE 754 rules. Thus:
5683 * - substring("12345", 1.5, 2.6) returns "234"
5684 * - substring("12345", 0, 3) returns "12"
5685 * - substring("12345", 0 div 0, 3) returns ""
5686 * - substring("12345", 1, 0 div 0) returns ""
5687 * - substring("12345", -42, 1 div 0) returns "12345"
5688 * - substring("12345", -1 div 0, 1 div 0) returns ""
5689 */
5690void
5691xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5692 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005693 double le=0, in;
5694 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00005695 xmlChar *ret;
5696
Owen Taylor3473f882001-02-23 17:55:21 +00005697 if (nargs < 2) {
5698 CHECK_ARITY(2);
5699 }
5700 if (nargs > 3) {
5701 CHECK_ARITY(3);
5702 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005703 /*
5704 * take care of possible last (position) argument
5705 */
Owen Taylor3473f882001-02-23 17:55:21 +00005706 if (nargs == 3) {
5707 CAST_TO_NUMBER;
5708 CHECK_TYPE(XPATH_NUMBER);
5709 len = valuePop(ctxt);
5710 le = len->floatval;
5711 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00005712 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005713
Owen Taylor3473f882001-02-23 17:55:21 +00005714 CAST_TO_NUMBER;
5715 CHECK_TYPE(XPATH_NUMBER);
5716 start = valuePop(ctxt);
5717 in = start->floatval;
5718 xmlXPathFreeObject(start);
5719 CAST_TO_STRING;
5720 CHECK_TYPE(XPATH_STRING);
5721 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00005722 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005723
Daniel Veillard97ac1312001-05-30 19:14:17 +00005724 /*
5725 * If last pos not present, calculate last position
5726 */
5727 if (nargs != 3)
5728 le = m;
5729
5730 /*
5731 * To meet our requirements, initial index calculations
5732 * must be done before we convert to integer format
5733 *
5734 * First we normalize indices
5735 */
5736 in -= 1.0;
5737 le += in;
5738 if (in < 0.0)
5739 in = 0.0;
5740 if (le > (double)m)
5741 le = (double)m;
5742
5743 /*
5744 * Now we go to integer form, rounding up
5745 */
Owen Taylor3473f882001-02-23 17:55:21 +00005746 i = (int) in;
5747 if (((double)i) != in) i++;
5748
Owen Taylor3473f882001-02-23 17:55:21 +00005749 l = (int) le;
5750 if (((double)l) != le) l++;
5751
Daniel Veillard97ac1312001-05-30 19:14:17 +00005752 if (l > m) l=m;
Owen Taylor3473f882001-02-23 17:55:21 +00005753
5754 /* number of chars to copy */
5755 l -= i;
5756
Daniel Veillard97ac1312001-05-30 19:14:17 +00005757 ret = xmlUTF8Strsub(str->stringval, i, l);
Owen Taylor3473f882001-02-23 17:55:21 +00005758 if (ret == NULL)
5759 valuePush(ctxt, xmlXPathNewCString(""));
5760 else {
5761 valuePush(ctxt, xmlXPathNewString(ret));
5762 xmlFree(ret);
5763 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005764
Owen Taylor3473f882001-02-23 17:55:21 +00005765 xmlXPathFreeObject(str);
5766}
5767
5768/**
5769 * xmlXPathSubstringBeforeFunction:
5770 * @ctxt: the XPath Parser context
5771 * @nargs: the number of arguments
5772 *
5773 * Implement the substring-before() XPath function
5774 * string substring-before(string, string)
5775 * The substring-before function returns the substring of the first
5776 * argument string that precedes the first occurrence of the second
5777 * argument string in the first argument string, or the empty string
5778 * if the first argument string does not contain the second argument
5779 * string. For example, substring-before("1999/04/01","/") returns 1999.
5780 */
5781void
5782xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5783 xmlXPathObjectPtr str;
5784 xmlXPathObjectPtr find;
5785 xmlBufferPtr target;
5786 const xmlChar *point;
5787 int offset;
5788
5789 CHECK_ARITY(2);
5790 CAST_TO_STRING;
5791 find = valuePop(ctxt);
5792 CAST_TO_STRING;
5793 str = valuePop(ctxt);
5794
5795 target = xmlBufferCreate();
5796 if (target) {
5797 point = xmlStrstr(str->stringval, find->stringval);
5798 if (point) {
5799 offset = (int)(point - str->stringval);
5800 xmlBufferAdd(target, str->stringval, offset);
5801 }
5802 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5803 xmlBufferFree(target);
5804 }
5805
5806 xmlXPathFreeObject(str);
5807 xmlXPathFreeObject(find);
5808}
5809
5810/**
5811 * xmlXPathSubstringAfterFunction:
5812 * @ctxt: the XPath Parser context
5813 * @nargs: the number of arguments
5814 *
5815 * Implement the substring-after() XPath function
5816 * string substring-after(string, string)
5817 * The substring-after function returns the substring of the first
5818 * argument string that follows the first occurrence of the second
5819 * argument string in the first argument string, or the empty stringi
5820 * if the first argument string does not contain the second argument
5821 * string. For example, substring-after("1999/04/01","/") returns 04/01,
5822 * and substring-after("1999/04/01","19") returns 99/04/01.
5823 */
5824void
5825xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5826 xmlXPathObjectPtr str;
5827 xmlXPathObjectPtr find;
5828 xmlBufferPtr target;
5829 const xmlChar *point;
5830 int offset;
5831
5832 CHECK_ARITY(2);
5833 CAST_TO_STRING;
5834 find = valuePop(ctxt);
5835 CAST_TO_STRING;
5836 str = valuePop(ctxt);
5837
5838 target = xmlBufferCreate();
5839 if (target) {
5840 point = xmlStrstr(str->stringval, find->stringval);
5841 if (point) {
5842 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
5843 xmlBufferAdd(target, &str->stringval[offset],
5844 xmlStrlen(str->stringval) - offset);
5845 }
5846 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5847 xmlBufferFree(target);
5848 }
5849
5850 xmlXPathFreeObject(str);
5851 xmlXPathFreeObject(find);
5852}
5853
5854/**
5855 * xmlXPathNormalizeFunction:
5856 * @ctxt: the XPath Parser context
5857 * @nargs: the number of arguments
5858 *
5859 * Implement the normalize-space() XPath function
5860 * string normalize-space(string?)
5861 * The normalize-space function returns the argument string with white
5862 * space normalized by stripping leading and trailing whitespace
5863 * and replacing sequences of whitespace characters by a single
5864 * space. Whitespace characters are the same allowed by the S production
5865 * in XML. If the argument is omitted, it defaults to the context
5866 * node converted to a string, in other words the value of the context node.
5867 */
5868void
5869xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5870 xmlXPathObjectPtr obj = NULL;
5871 xmlChar *source = NULL;
5872 xmlBufferPtr target;
5873 xmlChar blank;
5874
5875 if (nargs == 0) {
5876 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005877 valuePush(ctxt,
5878 xmlXPathWrapString(
5879 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00005880 nargs = 1;
5881 }
5882
5883 CHECK_ARITY(1);
5884 CAST_TO_STRING;
5885 CHECK_TYPE(XPATH_STRING);
5886 obj = valuePop(ctxt);
5887 source = obj->stringval;
5888
5889 target = xmlBufferCreate();
5890 if (target && source) {
5891
5892 /* Skip leading whitespaces */
5893 while (IS_BLANK(*source))
5894 source++;
5895
5896 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
5897 blank = 0;
5898 while (*source) {
5899 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005900 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00005901 } else {
5902 if (blank) {
5903 xmlBufferAdd(target, &blank, 1);
5904 blank = 0;
5905 }
5906 xmlBufferAdd(target, source, 1);
5907 }
5908 source++;
5909 }
5910
5911 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5912 xmlBufferFree(target);
5913 }
5914 xmlXPathFreeObject(obj);
5915}
5916
5917/**
5918 * xmlXPathTranslateFunction:
5919 * @ctxt: the XPath Parser context
5920 * @nargs: the number of arguments
5921 *
5922 * Implement the translate() XPath function
5923 * string translate(string, string, string)
5924 * The translate function returns the first argument string with
5925 * occurrences of characters in the second argument string replaced
5926 * by the character at the corresponding position in the third argument
5927 * string. For example, translate("bar","abc","ABC") returns the string
5928 * BAr. If there is a character in the second argument string with no
5929 * character at a corresponding position in the third argument string
5930 * (because the second argument string is longer than the third argument
5931 * string), then occurrences of that character in the first argument
5932 * string are removed. For example, translate("--aaa--","abc-","ABC")
5933 * returns "AAA". If a character occurs more than once in second
5934 * argument string, then the first occurrence determines the replacement
5935 * character. If the third argument string is longer than the second
5936 * argument string, then excess characters are ignored.
5937 */
5938void
5939xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00005940 xmlXPathObjectPtr str;
5941 xmlXPathObjectPtr from;
5942 xmlXPathObjectPtr to;
5943 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005944 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00005945 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005946 xmlChar *point;
5947 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00005948
Daniel Veillarde043ee12001-04-16 14:08:07 +00005949 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00005950
Daniel Veillarde043ee12001-04-16 14:08:07 +00005951 CAST_TO_STRING;
5952 to = valuePop(ctxt);
5953 CAST_TO_STRING;
5954 from = valuePop(ctxt);
5955 CAST_TO_STRING;
5956 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005957
Daniel Veillarde043ee12001-04-16 14:08:07 +00005958 target = xmlBufferCreate();
5959 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005960 max = xmlUTF8Strlen(to->stringval);
5961 for (cptr = str->stringval; (ch=*cptr); ) {
5962 offset = xmlUTF8Strloc(from->stringval, cptr);
5963 if (offset >= 0) {
5964 if (offset < max) {
5965 point = xmlUTF8Strpos(to->stringval, offset);
5966 if (point)
5967 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
5968 }
5969 } else
5970 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
5971
5972 /* Step to next character in input */
5973 cptr++;
5974 if ( ch & 0x80 ) {
5975 /* if not simple ascii, verify proper format */
5976 if ( (ch & 0xc0) != 0xc0 ) {
5977 xmlGenericError(xmlGenericErrorContext,
5978 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5979 break;
5980 }
5981 /* then skip over remaining bytes for this char */
5982 while ( (ch <<= 1) & 0x80 )
5983 if ( (*cptr++ & 0xc0) != 0x80 ) {
5984 xmlGenericError(xmlGenericErrorContext,
5985 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5986 break;
5987 }
5988 if (ch & 0x80) /* must have had error encountered */
5989 break;
5990 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005991 }
Owen Taylor3473f882001-02-23 17:55:21 +00005992 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005993 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5994 xmlBufferFree(target);
5995 xmlXPathFreeObject(str);
5996 xmlXPathFreeObject(from);
5997 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00005998}
5999
6000/**
6001 * xmlXPathBooleanFunction:
6002 * @ctxt: the XPath Parser context
6003 * @nargs: the number of arguments
6004 *
6005 * Implement the boolean() XPath function
6006 * boolean boolean(object)
6007 * he boolean function converts its argument to a boolean as follows:
6008 * - a number is true if and only if it is neither positive or
6009 * negative zero nor NaN
6010 * - a node-set is true if and only if it is non-empty
6011 * - a string is true if and only if its length is non-zero
6012 */
6013void
6014xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6015 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006016
6017 CHECK_ARITY(1);
6018 cur = valuePop(ctxt);
6019 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006020 cur = xmlXPathConvertBoolean(cur);
6021 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006022}
6023
6024/**
6025 * xmlXPathNotFunction:
6026 * @ctxt: the XPath Parser context
6027 * @nargs: the number of arguments
6028 *
6029 * Implement the not() XPath function
6030 * boolean not(boolean)
6031 * The not function returns true if its argument is false,
6032 * and false otherwise.
6033 */
6034void
6035xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6036 CHECK_ARITY(1);
6037 CAST_TO_BOOLEAN;
6038 CHECK_TYPE(XPATH_BOOLEAN);
6039 ctxt->value->boolval = ! ctxt->value->boolval;
6040}
6041
6042/**
6043 * xmlXPathTrueFunction:
6044 * @ctxt: the XPath Parser context
6045 * @nargs: the number of arguments
6046 *
6047 * Implement the true() XPath function
6048 * boolean true()
6049 */
6050void
6051xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6052 CHECK_ARITY(0);
6053 valuePush(ctxt, xmlXPathNewBoolean(1));
6054}
6055
6056/**
6057 * xmlXPathFalseFunction:
6058 * @ctxt: the XPath Parser context
6059 * @nargs: the number of arguments
6060 *
6061 * Implement the false() XPath function
6062 * boolean false()
6063 */
6064void
6065xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6066 CHECK_ARITY(0);
6067 valuePush(ctxt, xmlXPathNewBoolean(0));
6068}
6069
6070/**
6071 * xmlXPathLangFunction:
6072 * @ctxt: the XPath Parser context
6073 * @nargs: the number of arguments
6074 *
6075 * Implement the lang() XPath function
6076 * boolean lang(string)
6077 * The lang function returns true or false depending on whether the
6078 * language of the context node as specified by xml:lang attributes
6079 * is the same as or is a sublanguage of the language specified by
6080 * the argument string. The language of the context node is determined
6081 * by the value of the xml:lang attribute on the context node, or, if
6082 * the context node has no xml:lang attribute, by the value of the
6083 * xml:lang attribute on the nearest ancestor of the context node that
6084 * has an xml:lang attribute. If there is no such attribute, then lang
6085 * returns false. If there is such an attribute, then lang returns
6086 * true if the attribute value is equal to the argument ignoring case,
6087 * or if there is some suffix starting with - such that the attribute
6088 * value is equal to the argument ignoring that suffix of the attribute
6089 * value and ignoring case.
6090 */
6091void
6092xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6093 xmlXPathObjectPtr val;
6094 const xmlChar *theLang;
6095 const xmlChar *lang;
6096 int ret = 0;
6097 int i;
6098
6099 CHECK_ARITY(1);
6100 CAST_TO_STRING;
6101 CHECK_TYPE(XPATH_STRING);
6102 val = valuePop(ctxt);
6103 lang = val->stringval;
6104 theLang = xmlNodeGetLang(ctxt->context->node);
6105 if ((theLang != NULL) && (lang != NULL)) {
6106 for (i = 0;lang[i] != 0;i++)
6107 if (toupper(lang[i]) != toupper(theLang[i]))
6108 goto not_equal;
6109 ret = 1;
6110 }
6111not_equal:
6112 xmlXPathFreeObject(val);
6113 valuePush(ctxt, xmlXPathNewBoolean(ret));
6114}
6115
6116/**
6117 * xmlXPathNumberFunction:
6118 * @ctxt: the XPath Parser context
6119 * @nargs: the number of arguments
6120 *
6121 * Implement the number() XPath function
6122 * number number(object?)
6123 */
6124void
6125xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6126 xmlXPathObjectPtr cur;
6127 double res;
6128
6129 if (nargs == 0) {
6130 if (ctxt->context->node == NULL) {
6131 valuePush(ctxt, xmlXPathNewFloat(0.0));
6132 } else {
6133 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6134
6135 res = xmlXPathStringEvalNumber(content);
6136 valuePush(ctxt, xmlXPathNewFloat(res));
6137 xmlFree(content);
6138 }
6139 return;
6140 }
6141
6142 CHECK_ARITY(1);
6143 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006144 cur = xmlXPathConvertNumber(cur);
6145 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006146}
6147
6148/**
6149 * xmlXPathSumFunction:
6150 * @ctxt: the XPath Parser context
6151 * @nargs: the number of arguments
6152 *
6153 * Implement the sum() XPath function
6154 * number sum(node-set)
6155 * The sum function returns the sum of the values of the nodes in
6156 * the argument node-set.
6157 */
6158void
6159xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6160 xmlXPathObjectPtr cur;
6161 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006162 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006163
6164 CHECK_ARITY(1);
6165 if ((ctxt->value == NULL) ||
6166 ((ctxt->value->type != XPATH_NODESET) &&
6167 (ctxt->value->type != XPATH_XSLT_TREE)))
6168 XP_ERROR(XPATH_INVALID_TYPE);
6169 cur = valuePop(ctxt);
6170
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006171 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006172 valuePush(ctxt, xmlXPathNewFloat(0.0));
6173 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006174 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6175 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006176 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006177 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006178 }
6179 xmlXPathFreeObject(cur);
6180}
6181
6182/**
6183 * xmlXPathFloorFunction:
6184 * @ctxt: the XPath Parser context
6185 * @nargs: the number of arguments
6186 *
6187 * Implement the floor() XPath function
6188 * number floor(number)
6189 * The floor function returns the largest (closest to positive infinity)
6190 * number that is not greater than the argument and that is an integer.
6191 */
6192void
6193xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6194 CHECK_ARITY(1);
6195 CAST_TO_NUMBER;
6196 CHECK_TYPE(XPATH_NUMBER);
6197#if 0
6198 ctxt->value->floatval = floor(ctxt->value->floatval);
6199#else
6200 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
6201 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
6202#endif
6203}
6204
6205/**
6206 * xmlXPathCeilingFunction:
6207 * @ctxt: the XPath Parser context
6208 * @nargs: the number of arguments
6209 *
6210 * Implement the ceiling() XPath function
6211 * number ceiling(number)
6212 * The ceiling function returns the smallest (closest to negative infinity)
6213 * number that is not less than the argument and that is an integer.
6214 */
6215void
6216xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6217 double f;
6218
6219 CHECK_ARITY(1);
6220 CAST_TO_NUMBER;
6221 CHECK_TYPE(XPATH_NUMBER);
6222
6223#if 0
6224 ctxt->value->floatval = ceil(ctxt->value->floatval);
6225#else
6226 f = (double)((int) ctxt->value->floatval);
6227 if (f != ctxt->value->floatval)
6228 ctxt->value->floatval = f + 1;
6229#endif
6230}
6231
6232/**
6233 * xmlXPathRoundFunction:
6234 * @ctxt: the XPath Parser context
6235 * @nargs: the number of arguments
6236 *
6237 * Implement the round() XPath function
6238 * number round(number)
6239 * The round function returns the number that is closest to the
6240 * argument and that is an integer. If there are two such numbers,
6241 * then the one that is even is returned.
6242 */
6243void
6244xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6245 double f;
6246
6247 CHECK_ARITY(1);
6248 CAST_TO_NUMBER;
6249 CHECK_TYPE(XPATH_NUMBER);
6250
Daniel Veillardcda96922001-08-21 10:56:31 +00006251 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
6252 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
6253 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00006254 (ctxt->value->floatval == 0.0))
6255 return;
6256
6257#if 0
6258 f = floor(ctxt->value->floatval);
6259#else
6260 f = (double)((int) ctxt->value->floatval);
6261#endif
6262 if (ctxt->value->floatval < f + 0.5)
6263 ctxt->value->floatval = f;
6264 else
6265 ctxt->value->floatval = f + 1;
6266}
6267
6268/************************************************************************
6269 * *
6270 * The Parser *
6271 * *
6272 ************************************************************************/
6273
6274/*
6275 * a couple of forward declarations since we use a recursive call based
6276 * implementation.
6277 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006278static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006279static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006280static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006281#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006282static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
6283#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006284#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006285static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006286#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00006287static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
6288 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00006289
6290/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00006291 * xmlXPathCurrentChar:
6292 * @ctxt: the XPath parser context
6293 * @cur: pointer to the beginning of the char
6294 * @len: pointer to the length of the char read
6295 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006296 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00006297 * bytes in the input buffer.
6298 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006299 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00006300 */
6301
6302static int
6303xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
6304 unsigned char c;
6305 unsigned int val;
6306 const xmlChar *cur;
6307
6308 if (ctxt == NULL)
6309 return(0);
6310 cur = ctxt->cur;
6311
6312 /*
6313 * We are supposed to handle UTF8, check it's valid
6314 * From rfc2044: encoding of the Unicode values on UTF-8:
6315 *
6316 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
6317 * 0000 0000-0000 007F 0xxxxxxx
6318 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
6319 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
6320 *
6321 * Check for the 0x110000 limit too
6322 */
6323 c = *cur;
6324 if (c & 0x80) {
6325 if ((cur[1] & 0xc0) != 0x80)
6326 goto encoding_error;
6327 if ((c & 0xe0) == 0xe0) {
6328
6329 if ((cur[2] & 0xc0) != 0x80)
6330 goto encoding_error;
6331 if ((c & 0xf0) == 0xf0) {
6332 if (((c & 0xf8) != 0xf0) ||
6333 ((cur[3] & 0xc0) != 0x80))
6334 goto encoding_error;
6335 /* 4-byte code */
6336 *len = 4;
6337 val = (cur[0] & 0x7) << 18;
6338 val |= (cur[1] & 0x3f) << 12;
6339 val |= (cur[2] & 0x3f) << 6;
6340 val |= cur[3] & 0x3f;
6341 } else {
6342 /* 3-byte code */
6343 *len = 3;
6344 val = (cur[0] & 0xf) << 12;
6345 val |= (cur[1] & 0x3f) << 6;
6346 val |= cur[2] & 0x3f;
6347 }
6348 } else {
6349 /* 2-byte code */
6350 *len = 2;
6351 val = (cur[0] & 0x1f) << 6;
6352 val |= cur[1] & 0x3f;
6353 }
6354 if (!IS_CHAR(val)) {
6355 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
6356 }
6357 return(val);
6358 } else {
6359 /* 1-byte code */
6360 *len = 1;
6361 return((int) *cur);
6362 }
6363encoding_error:
6364 /*
6365 * If we detect an UTF8 error that probably mean that the
6366 * input encoding didn't get properly advertized in the
6367 * declaration header. Report the error and switch the encoding
6368 * to ISO-Latin-1 (if you don't like this policy, just declare the
6369 * encoding !)
6370 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00006371 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00006372 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006373}
6374
6375/**
Owen Taylor3473f882001-02-23 17:55:21 +00006376 * xmlXPathParseNCName:
6377 * @ctxt: the XPath Parser context
6378 *
6379 * parse an XML namespace non qualified name.
6380 *
6381 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
6382 *
6383 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
6384 * CombiningChar | Extender
6385 *
6386 * Returns the namespace name or NULL
6387 */
6388
6389xmlChar *
6390xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00006391 const xmlChar *in;
6392 xmlChar *ret;
6393 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006394
Daniel Veillard2156a562001-04-28 12:24:34 +00006395 /*
6396 * Accelerator for simple ASCII names
6397 */
6398 in = ctxt->cur;
6399 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6400 ((*in >= 0x41) && (*in <= 0x5A)) ||
6401 (*in == '_')) {
6402 in++;
6403 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6404 ((*in >= 0x41) && (*in <= 0x5A)) ||
6405 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00006406 (*in == '_') || (*in == '.') ||
6407 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00006408 in++;
6409 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
6410 (*in == '[') || (*in == ']') || (*in == ':') ||
6411 (*in == '@') || (*in == '*')) {
6412 count = in - ctxt->cur;
6413 if (count == 0)
6414 return(NULL);
6415 ret = xmlStrndup(ctxt->cur, count);
6416 ctxt->cur = in;
6417 return(ret);
6418 }
6419 }
6420 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00006421}
6422
Daniel Veillard2156a562001-04-28 12:24:34 +00006423
Owen Taylor3473f882001-02-23 17:55:21 +00006424/**
6425 * xmlXPathParseQName:
6426 * @ctxt: the XPath Parser context
6427 * @prefix: a xmlChar **
6428 *
6429 * parse an XML qualified name
6430 *
6431 * [NS 5] QName ::= (Prefix ':')? LocalPart
6432 *
6433 * [NS 6] Prefix ::= NCName
6434 *
6435 * [NS 7] LocalPart ::= NCName
6436 *
6437 * Returns the function returns the local part, and prefix is updated
6438 * to get the Prefix if any.
6439 */
6440
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006441static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006442xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
6443 xmlChar *ret = NULL;
6444
6445 *prefix = NULL;
6446 ret = xmlXPathParseNCName(ctxt);
6447 if (CUR == ':') {
6448 *prefix = ret;
6449 NEXT;
6450 ret = xmlXPathParseNCName(ctxt);
6451 }
6452 return(ret);
6453}
6454
6455/**
6456 * xmlXPathParseName:
6457 * @ctxt: the XPath Parser context
6458 *
6459 * parse an XML name
6460 *
6461 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6462 * CombiningChar | Extender
6463 *
6464 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6465 *
6466 * Returns the namespace name or NULL
6467 */
6468
6469xmlChar *
6470xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006471 const xmlChar *in;
6472 xmlChar *ret;
6473 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006474
Daniel Veillard61d80a22001-04-27 17:13:01 +00006475 /*
6476 * Accelerator for simple ASCII names
6477 */
6478 in = ctxt->cur;
6479 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6480 ((*in >= 0x41) && (*in <= 0x5A)) ||
6481 (*in == '_') || (*in == ':')) {
6482 in++;
6483 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6484 ((*in >= 0x41) && (*in <= 0x5A)) ||
6485 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00006486 (*in == '_') || (*in == '-') ||
6487 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00006488 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00006489 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006490 count = in - ctxt->cur;
6491 ret = xmlStrndup(ctxt->cur, count);
6492 ctxt->cur = in;
6493 return(ret);
6494 }
6495 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006496 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00006497}
6498
Daniel Veillard61d80a22001-04-27 17:13:01 +00006499static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00006500xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006501 xmlChar buf[XML_MAX_NAMELEN + 5];
6502 int len = 0, l;
6503 int c;
6504
6505 /*
6506 * Handler for more complex cases
6507 */
6508 c = CUR_CHAR(l);
6509 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00006510 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
6511 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00006512 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00006513 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006514 return(NULL);
6515 }
6516
6517 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
6518 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
6519 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006520 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006521 (IS_COMBINING(c)) ||
6522 (IS_EXTENDER(c)))) {
6523 COPY_BUF(l,buf,len,c);
6524 NEXTL(l);
6525 c = CUR_CHAR(l);
6526 if (len >= XML_MAX_NAMELEN) {
6527 /*
6528 * Okay someone managed to make a huge name, so he's ready to pay
6529 * for the processing speed.
6530 */
6531 xmlChar *buffer;
6532 int max = len * 2;
6533
6534 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
6535 if (buffer == NULL) {
6536 XP_ERROR0(XPATH_MEMORY_ERROR);
6537 }
6538 memcpy(buffer, buf, len);
6539 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
6540 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006541 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006542 (IS_COMBINING(c)) ||
6543 (IS_EXTENDER(c))) {
6544 if (len + 10 > max) {
6545 max *= 2;
6546 buffer = (xmlChar *) xmlRealloc(buffer,
6547 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00006548 if (buffer == NULL) {
6549 XP_ERROR0(XPATH_MEMORY_ERROR);
6550 }
6551 }
6552 COPY_BUF(l,buffer,len,c);
6553 NEXTL(l);
6554 c = CUR_CHAR(l);
6555 }
6556 buffer[len] = 0;
6557 return(buffer);
6558 }
6559 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006560 if (len == 0)
6561 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006562 return(xmlStrndup(buf, len));
6563}
Owen Taylor3473f882001-02-23 17:55:21 +00006564/**
6565 * xmlXPathStringEvalNumber:
6566 * @str: A string to scan
6567 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00006568 * [30a] Float ::= Number ('e' Digits?)?
6569 *
Owen Taylor3473f882001-02-23 17:55:21 +00006570 * [30] Number ::= Digits ('.' Digits?)?
6571 * | '.' Digits
6572 * [31] Digits ::= [0-9]+
6573 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006574 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00006575 * In complement of the Number expression, this function also handles
6576 * negative values : '-' Number.
6577 *
6578 * Returns the double value.
6579 */
6580double
6581xmlXPathStringEvalNumber(const xmlChar *str) {
6582 const xmlChar *cur = str;
6583 double ret = 0.0;
6584 double mult = 1;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006585 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006586 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006587 int exponent = 0;
6588 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006589#ifdef __GNUC__
6590 unsigned long tmp = 0;
6591#endif
Bjorn Reese70a9da52001-04-21 16:57:29 +00006592
Owen Taylor3473f882001-02-23 17:55:21 +00006593 while (IS_BLANK(*cur)) cur++;
6594 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
6595 return(xmlXPathNAN);
6596 }
6597 if (*cur == '-') {
6598 isneg = 1;
6599 cur++;
6600 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00006601
6602#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006603 /*
Daniel Veillardb06c6142001-08-27 14:26:30 +00006604 * tmp is a workaround against a gcc compiler bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006605 */
Owen Taylor3473f882001-02-23 17:55:21 +00006606 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006607 tmp = tmp * 10 + (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00006608 ok = 1;
6609 cur++;
6610 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006611 ret = (double) tmp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006612#else
6613 while ((*cur >= '0') && (*cur <= '9')) {
6614 ret = ret * 10 + (*cur - '0');
6615 ok = 1;
6616 cur++;
6617 }
6618#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006619
Owen Taylor3473f882001-02-23 17:55:21 +00006620 if (*cur == '.') {
6621 cur++;
6622 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
6623 return(xmlXPathNAN);
6624 }
6625 while ((*cur >= '0') && (*cur <= '9')) {
6626 mult /= 10;
6627 ret = ret + (*cur - '0') * mult;
6628 cur++;
6629 }
6630 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006631 if ((*cur == 'e') || (*cur == 'E')) {
6632 cur++;
6633 if (*cur == '-') {
6634 is_exponent_negative = 1;
6635 cur++;
6636 }
6637 while ((*cur >= '0') && (*cur <= '9')) {
6638 exponent = exponent * 10 + (*cur - '0');
6639 cur++;
6640 }
6641 }
Owen Taylor3473f882001-02-23 17:55:21 +00006642 while (IS_BLANK(*cur)) cur++;
6643 if (*cur != 0) return(xmlXPathNAN);
6644 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006645 if (is_exponent_negative) exponent = -exponent;
6646 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00006647 return(ret);
6648}
6649
6650/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006651 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00006652 * @ctxt: the XPath Parser context
6653 *
6654 * [30] Number ::= Digits ('.' Digits?)?
6655 * | '.' Digits
6656 * [31] Digits ::= [0-9]+
6657 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006658 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00006659 *
6660 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006661static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006662xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
6663{
Owen Taylor3473f882001-02-23 17:55:21 +00006664 double ret = 0.0;
6665 double mult = 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006666 int ok = 0, tmp = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006667 int exponent = 0;
6668 int is_exponent_negative = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006669
6670 CHECK_ERROR;
6671 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
6672 XP_ERROR(XPATH_NUMBER_ERROR);
6673 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006674 /*
6675 * Try to work around a gcc optimizer bug
6676 */
Owen Taylor3473f882001-02-23 17:55:21 +00006677 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006678 tmp = tmp * 10 + (CUR - '0');
6679 ok = 1;
6680 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +00006681 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006682 ret = (double) tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00006683 if (CUR == '.') {
6684 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006685 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
6686 XP_ERROR(XPATH_NUMBER_ERROR);
6687 }
6688 while ((CUR >= '0') && (CUR <= '9')) {
6689 mult /= 10;
6690 ret = ret + (CUR - '0') * mult;
6691 NEXT;
6692 }
Owen Taylor3473f882001-02-23 17:55:21 +00006693 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006694 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006695 NEXT;
6696 if (CUR == '-') {
6697 is_exponent_negative = 1;
6698 NEXT;
6699 }
6700 while ((CUR >= '0') && (CUR <= '9')) {
6701 exponent = exponent * 10 + (CUR - '0');
6702 NEXT;
6703 }
6704 if (is_exponent_negative)
6705 exponent = -exponent;
6706 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006707 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006708 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006709 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006710}
6711
6712/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006713 * xmlXPathParseLiteral:
6714 * @ctxt: the XPath Parser context
6715 *
6716 * Parse a Literal
6717 *
6718 * [29] Literal ::= '"' [^"]* '"'
6719 * | "'" [^']* "'"
6720 *
6721 * Returns the value found or NULL in case of error
6722 */
6723static xmlChar *
6724xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
6725 const xmlChar *q;
6726 xmlChar *ret = NULL;
6727
6728 if (CUR == '"') {
6729 NEXT;
6730 q = CUR_PTR;
6731 while ((IS_CHAR(CUR)) && (CUR != '"'))
6732 NEXT;
6733 if (!IS_CHAR(CUR)) {
6734 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6735 } else {
6736 ret = xmlStrndup(q, CUR_PTR - q);
6737 NEXT;
6738 }
6739 } else if (CUR == '\'') {
6740 NEXT;
6741 q = CUR_PTR;
6742 while ((IS_CHAR(CUR)) && (CUR != '\''))
6743 NEXT;
6744 if (!IS_CHAR(CUR)) {
6745 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6746 } else {
6747 ret = xmlStrndup(q, CUR_PTR - q);
6748 NEXT;
6749 }
6750 } else {
6751 XP_ERROR0(XPATH_START_LITERAL_ERROR);
6752 }
6753 return(ret);
6754}
6755
6756/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006757 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00006758 * @ctxt: the XPath Parser context
6759 *
6760 * Parse a Literal and push it on the stack.
6761 *
6762 * [29] Literal ::= '"' [^"]* '"'
6763 * | "'" [^']* "'"
6764 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006765 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00006766 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006767static void
6768xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006769 const xmlChar *q;
6770 xmlChar *ret = NULL;
6771
6772 if (CUR == '"') {
6773 NEXT;
6774 q = CUR_PTR;
6775 while ((IS_CHAR(CUR)) && (CUR != '"'))
6776 NEXT;
6777 if (!IS_CHAR(CUR)) {
6778 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
6779 } else {
6780 ret = xmlStrndup(q, CUR_PTR - q);
6781 NEXT;
6782 }
6783 } else if (CUR == '\'') {
6784 NEXT;
6785 q = CUR_PTR;
6786 while ((IS_CHAR(CUR)) && (CUR != '\''))
6787 NEXT;
6788 if (!IS_CHAR(CUR)) {
6789 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
6790 } else {
6791 ret = xmlStrndup(q, CUR_PTR - q);
6792 NEXT;
6793 }
6794 } else {
6795 XP_ERROR(XPATH_START_LITERAL_ERROR);
6796 }
6797 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006798 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
6799 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006800 xmlFree(ret);
6801}
6802
6803/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006804 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00006805 * @ctxt: the XPath Parser context
6806 *
6807 * Parse a VariableReference, evaluate it and push it on the stack.
6808 *
6809 * The variable bindings consist of a mapping from variable names
6810 * to variable values. The value of a variable is an object, which
6811 * of any of the types that are possible for the value of an expression,
6812 * and may also be of additional types not specified here.
6813 *
6814 * Early evaluation is possible since:
6815 * The variable bindings [...] used to evaluate a subexpression are
6816 * always the same as those used to evaluate the containing expression.
6817 *
6818 * [36] VariableReference ::= '$' QName
6819 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006820static void
6821xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006822 xmlChar *name;
6823 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006824
6825 SKIP_BLANKS;
6826 if (CUR != '$') {
6827 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
6828 }
6829 NEXT;
6830 name = xmlXPathParseQName(ctxt, &prefix);
6831 if (name == NULL) {
6832 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
6833 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006834 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006835 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
6836 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006837 SKIP_BLANKS;
6838}
6839
6840/**
6841 * xmlXPathIsNodeType:
6842 * @ctxt: the XPath Parser context
6843 * @name: a name string
6844 *
6845 * Is the name given a NodeType one.
6846 *
6847 * [38] NodeType ::= 'comment'
6848 * | 'text'
6849 * | 'processing-instruction'
6850 * | 'node'
6851 *
6852 * Returns 1 if true 0 otherwise
6853 */
6854int
6855xmlXPathIsNodeType(const xmlChar *name) {
6856 if (name == NULL)
6857 return(0);
6858
6859 if (xmlStrEqual(name, BAD_CAST "comment"))
6860 return(1);
6861 if (xmlStrEqual(name, BAD_CAST "text"))
6862 return(1);
6863 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
6864 return(1);
6865 if (xmlStrEqual(name, BAD_CAST "node"))
6866 return(1);
6867 return(0);
6868}
6869
6870/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006871 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00006872 * @ctxt: the XPath Parser context
6873 *
6874 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
6875 * [17] Argument ::= Expr
6876 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006877 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00006878 * pushed on the stack
6879 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006880static void
6881xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006882 xmlChar *name;
6883 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006884 int nbargs = 0;
6885
6886 name = xmlXPathParseQName(ctxt, &prefix);
6887 if (name == NULL) {
6888 XP_ERROR(XPATH_EXPR_ERROR);
6889 }
6890 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006891#ifdef DEBUG_EXPR
6892 if (prefix == NULL)
6893 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
6894 name);
6895 else
6896 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
6897 prefix, name);
6898#endif
6899
Owen Taylor3473f882001-02-23 17:55:21 +00006900 if (CUR != '(') {
6901 XP_ERROR(XPATH_EXPR_ERROR);
6902 }
6903 NEXT;
6904 SKIP_BLANKS;
6905
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006906 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006907 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006908 int op1 = ctxt->comp->last;
6909 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006910 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006911 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006912 nbargs++;
6913 if (CUR == ')') break;
6914 if (CUR != ',') {
6915 XP_ERROR(XPATH_EXPR_ERROR);
6916 }
6917 NEXT;
6918 SKIP_BLANKS;
6919 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006920 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
6921 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006922 NEXT;
6923 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006924}
6925
6926/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006927 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006928 * @ctxt: the XPath Parser context
6929 *
6930 * [15] PrimaryExpr ::= VariableReference
6931 * | '(' Expr ')'
6932 * | Literal
6933 * | Number
6934 * | FunctionCall
6935 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006936 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006937 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006938static void
6939xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006940 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006941 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006942 else if (CUR == '(') {
6943 NEXT;
6944 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006945 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006946 if (CUR != ')') {
6947 XP_ERROR(XPATH_EXPR_ERROR);
6948 }
6949 NEXT;
6950 SKIP_BLANKS;
6951 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006952 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006953 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006954 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006955 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006956 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006957 }
6958 SKIP_BLANKS;
6959}
6960
6961/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006962 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006963 * @ctxt: the XPath Parser context
6964 *
6965 * [20] FilterExpr ::= PrimaryExpr
6966 * | FilterExpr Predicate
6967 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006968 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006969 * Square brackets are used to filter expressions in the same way that
6970 * they are used in location paths. It is an error if the expression to
6971 * be filtered does not evaluate to a node-set. The context node list
6972 * used for evaluating the expression in square brackets is the node-set
6973 * to be filtered listed in document order.
6974 */
6975
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006976static void
6977xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
6978 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006979 CHECK_ERROR;
6980 SKIP_BLANKS;
6981
6982 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006983 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00006984 SKIP_BLANKS;
6985 }
6986
6987
6988}
6989
6990/**
6991 * xmlXPathScanName:
6992 * @ctxt: the XPath Parser context
6993 *
6994 * Trickery: parse an XML name but without consuming the input flow
6995 * Needed to avoid insanity in the parser state.
6996 *
6997 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6998 * CombiningChar | Extender
6999 *
7000 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7001 *
7002 * [6] Names ::= Name (S Name)*
7003 *
7004 * Returns the Name parsed or NULL
7005 */
7006
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007007static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007008xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7009 xmlChar buf[XML_MAX_NAMELEN];
7010 int len = 0;
7011
7012 SKIP_BLANKS;
7013 if (!IS_LETTER(CUR) && (CUR != '_') &&
7014 (CUR != ':')) {
7015 return(NULL);
7016 }
7017
7018 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7019 (NXT(len) == '.') || (NXT(len) == '-') ||
7020 (NXT(len) == '_') || (NXT(len) == ':') ||
7021 (IS_COMBINING(NXT(len))) ||
7022 (IS_EXTENDER(NXT(len)))) {
7023 buf[len] = NXT(len);
7024 len++;
7025 if (len >= XML_MAX_NAMELEN) {
7026 xmlGenericError(xmlGenericErrorContext,
7027 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7028 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7029 (NXT(len) == '.') || (NXT(len) == '-') ||
7030 (NXT(len) == '_') || (NXT(len) == ':') ||
7031 (IS_COMBINING(NXT(len))) ||
7032 (IS_EXTENDER(NXT(len))))
7033 len++;
7034 break;
7035 }
7036 }
7037 return(xmlStrndup(buf, len));
7038}
7039
7040/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007041 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007042 * @ctxt: the XPath Parser context
7043 *
7044 * [19] PathExpr ::= LocationPath
7045 * | FilterExpr
7046 * | FilterExpr '/' RelativeLocationPath
7047 * | FilterExpr '//' RelativeLocationPath
7048 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007049 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007050 * The / operator and // operators combine an arbitrary expression
7051 * and a relative location path. It is an error if the expression
7052 * does not evaluate to a node-set.
7053 * The / operator does composition in the same way as when / is
7054 * used in a location path. As in location paths, // is short for
7055 * /descendant-or-self::node()/.
7056 */
7057
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007058static void
7059xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007060 int lc = 1; /* Should we branch to LocationPath ? */
7061 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7062
7063 SKIP_BLANKS;
7064 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
7065 (CUR == '\'') || (CUR == '"')) {
7066 lc = 0;
7067 } else if (CUR == '*') {
7068 /* relative or absolute location path */
7069 lc = 1;
7070 } else if (CUR == '/') {
7071 /* relative or absolute location path */
7072 lc = 1;
7073 } else if (CUR == '@') {
7074 /* relative abbreviated attribute location path */
7075 lc = 1;
7076 } else if (CUR == '.') {
7077 /* relative abbreviated attribute location path */
7078 lc = 1;
7079 } else {
7080 /*
7081 * Problem is finding if we have a name here whether it's:
7082 * - a nodetype
7083 * - a function call in which case it's followed by '('
7084 * - an axis in which case it's followed by ':'
7085 * - a element name
7086 * We do an a priori analysis here rather than having to
7087 * maintain parsed token content through the recursive function
7088 * calls. This looks uglier but makes the code quite easier to
7089 * read/write/debug.
7090 */
7091 SKIP_BLANKS;
7092 name = xmlXPathScanName(ctxt);
7093 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7094#ifdef DEBUG_STEP
7095 xmlGenericError(xmlGenericErrorContext,
7096 "PathExpr: Axis\n");
7097#endif
7098 lc = 1;
7099 xmlFree(name);
7100 } else if (name != NULL) {
7101 int len =xmlStrlen(name);
7102 int blank = 0;
7103
7104
7105 while (NXT(len) != 0) {
7106 if (NXT(len) == '/') {
7107 /* element name */
7108#ifdef DEBUG_STEP
7109 xmlGenericError(xmlGenericErrorContext,
7110 "PathExpr: AbbrRelLocation\n");
7111#endif
7112 lc = 1;
7113 break;
7114 } else if (IS_BLANK(NXT(len))) {
7115 /* skip to next */
7116 blank = 1;
7117 } else if (NXT(len) == ':') {
7118#ifdef DEBUG_STEP
7119 xmlGenericError(xmlGenericErrorContext,
7120 "PathExpr: AbbrRelLocation\n");
7121#endif
7122 lc = 1;
7123 break;
7124 } else if ((NXT(len) == '(')) {
7125 /* Note Type or Function */
7126 if (xmlXPathIsNodeType(name)) {
7127#ifdef DEBUG_STEP
7128 xmlGenericError(xmlGenericErrorContext,
7129 "PathExpr: Type search\n");
7130#endif
7131 lc = 1;
7132 } else {
7133#ifdef DEBUG_STEP
7134 xmlGenericError(xmlGenericErrorContext,
7135 "PathExpr: function call\n");
7136#endif
7137 lc = 0;
7138 }
7139 break;
7140 } else if ((NXT(len) == '[')) {
7141 /* element name */
7142#ifdef DEBUG_STEP
7143 xmlGenericError(xmlGenericErrorContext,
7144 "PathExpr: AbbrRelLocation\n");
7145#endif
7146 lc = 1;
7147 break;
7148 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7149 (NXT(len) == '=')) {
7150 lc = 1;
7151 break;
7152 } else {
7153 lc = 1;
7154 break;
7155 }
7156 len++;
7157 }
7158 if (NXT(len) == 0) {
7159#ifdef DEBUG_STEP
7160 xmlGenericError(xmlGenericErrorContext,
7161 "PathExpr: AbbrRelLocation\n");
7162#endif
7163 /* element name */
7164 lc = 1;
7165 }
7166 xmlFree(name);
7167 } else {
7168 /* make sure all cases are covered explicitely */
7169 XP_ERROR(XPATH_EXPR_ERROR);
7170 }
7171 }
7172
7173 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007174 if (CUR == '/') {
7175 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7176 } else {
7177 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007178 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007179 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007180 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007181 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007182 CHECK_ERROR;
7183 if ((CUR == '/') && (NXT(1) == '/')) {
7184 SKIP(2);
7185 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007186
7187 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7188 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7189 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7190
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007191 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007192 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007193 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007194 }
7195 }
7196 SKIP_BLANKS;
7197}
7198
7199/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007200 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007201 * @ctxt: the XPath Parser context
7202 *
7203 * [18] UnionExpr ::= PathExpr
7204 * | UnionExpr '|' PathExpr
7205 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007206 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007207 */
7208
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007209static void
7210xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7211 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007212 CHECK_ERROR;
7213 SKIP_BLANKS;
7214 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007215 int op1 = ctxt->comp->last;
7216 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007217
7218 NEXT;
7219 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007220 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007221
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007222 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
7223
Owen Taylor3473f882001-02-23 17:55:21 +00007224 SKIP_BLANKS;
7225 }
Owen Taylor3473f882001-02-23 17:55:21 +00007226}
7227
7228/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007229 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007230 * @ctxt: the XPath Parser context
7231 *
7232 * [27] UnaryExpr ::= UnionExpr
7233 * | '-' UnaryExpr
7234 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007235 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007236 */
7237
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007238static void
7239xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007240 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007241 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007242
7243 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00007244 while (CUR == '-') {
7245 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007246 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007247 NEXT;
7248 SKIP_BLANKS;
7249 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007250
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007251 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007252 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007253 if (found) {
7254 if (minus)
7255 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
7256 else
7257 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007258 }
7259}
7260
7261/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007262 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007263 * @ctxt: the XPath Parser context
7264 *
7265 * [26] MultiplicativeExpr ::= UnaryExpr
7266 * | MultiplicativeExpr MultiplyOperator UnaryExpr
7267 * | MultiplicativeExpr 'div' UnaryExpr
7268 * | MultiplicativeExpr 'mod' UnaryExpr
7269 * [34] MultiplyOperator ::= '*'
7270 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007271 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007272 */
7273
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007274static void
7275xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
7276 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007277 CHECK_ERROR;
7278 SKIP_BLANKS;
7279 while ((CUR == '*') ||
7280 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
7281 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
7282 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007283 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007284
7285 if (CUR == '*') {
7286 op = 0;
7287 NEXT;
7288 } else if (CUR == 'd') {
7289 op = 1;
7290 SKIP(3);
7291 } else if (CUR == 'm') {
7292 op = 2;
7293 SKIP(3);
7294 }
7295 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007296 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007297 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007298 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007299 SKIP_BLANKS;
7300 }
7301}
7302
7303/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007304 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007305 * @ctxt: the XPath Parser context
7306 *
7307 * [25] AdditiveExpr ::= MultiplicativeExpr
7308 * | AdditiveExpr '+' MultiplicativeExpr
7309 * | AdditiveExpr '-' MultiplicativeExpr
7310 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007311 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007312 */
7313
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007314static void
7315xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007316
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007317 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007318 CHECK_ERROR;
7319 SKIP_BLANKS;
7320 while ((CUR == '+') || (CUR == '-')) {
7321 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007322 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007323
7324 if (CUR == '+') plus = 1;
7325 else plus = 0;
7326 NEXT;
7327 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007328 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007329 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007330 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007331 SKIP_BLANKS;
7332 }
7333}
7334
7335/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007336 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007337 * @ctxt: the XPath Parser context
7338 *
7339 * [24] RelationalExpr ::= AdditiveExpr
7340 * | RelationalExpr '<' AdditiveExpr
7341 * | RelationalExpr '>' AdditiveExpr
7342 * | RelationalExpr '<=' AdditiveExpr
7343 * | RelationalExpr '>=' AdditiveExpr
7344 *
7345 * A <= B > C is allowed ? Answer from James, yes with
7346 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
7347 * which is basically what got implemented.
7348 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007349 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00007350 * on the stack
7351 */
7352
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007353static void
7354xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
7355 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007356 CHECK_ERROR;
7357 SKIP_BLANKS;
7358 while ((CUR == '<') ||
7359 (CUR == '>') ||
7360 ((CUR == '<') && (NXT(1) == '=')) ||
7361 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007362 int inf, strict;
7363 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007364
7365 if (CUR == '<') inf = 1;
7366 else inf = 0;
7367 if (NXT(1) == '=') strict = 0;
7368 else strict = 1;
7369 NEXT;
7370 if (!strict) NEXT;
7371 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007372 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007373 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007374 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00007375 SKIP_BLANKS;
7376 }
7377}
7378
7379/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007380 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007381 * @ctxt: the XPath Parser context
7382 *
7383 * [23] EqualityExpr ::= RelationalExpr
7384 * | EqualityExpr '=' RelationalExpr
7385 * | EqualityExpr '!=' RelationalExpr
7386 *
7387 * A != B != C is allowed ? Answer from James, yes with
7388 * (RelationalExpr = RelationalExpr) = RelationalExpr
7389 * (RelationalExpr != RelationalExpr) != RelationalExpr
7390 * which is basically what got implemented.
7391 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007392 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007393 *
7394 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007395static void
7396xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
7397 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007398 CHECK_ERROR;
7399 SKIP_BLANKS;
7400 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007401 int eq;
7402 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007403
7404 if (CUR == '=') eq = 1;
7405 else eq = 0;
7406 NEXT;
7407 if (!eq) NEXT;
7408 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007409 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007410 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007411 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007412 SKIP_BLANKS;
7413 }
7414}
7415
7416/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007417 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007418 * @ctxt: the XPath Parser context
7419 *
7420 * [22] AndExpr ::= EqualityExpr
7421 * | AndExpr 'and' EqualityExpr
7422 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007423 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007424 *
7425 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007426static void
7427xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
7428 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007429 CHECK_ERROR;
7430 SKIP_BLANKS;
7431 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007432 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007433 SKIP(3);
7434 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007435 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007436 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007437 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007438 SKIP_BLANKS;
7439 }
7440}
7441
7442/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007443 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007444 * @ctxt: the XPath Parser context
7445 *
7446 * [14] Expr ::= OrExpr
7447 * [21] OrExpr ::= AndExpr
7448 * | OrExpr 'or' AndExpr
7449 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007450 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00007451 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007452static void
7453xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
7454 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007455 CHECK_ERROR;
7456 SKIP_BLANKS;
7457 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007458 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007459 SKIP(2);
7460 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007461 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007462 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007463 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
7464 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00007465 SKIP_BLANKS;
7466 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007467 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
7468 /* more ops could be optimized too */
7469 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
7470 }
Owen Taylor3473f882001-02-23 17:55:21 +00007471}
7472
7473/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007474 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00007475 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007476 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00007477 *
7478 * [8] Predicate ::= '[' PredicateExpr ']'
7479 * [9] PredicateExpr ::= Expr
7480 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007481 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00007482 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007483static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007484xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007485 int op1 = ctxt->comp->last;
7486
7487 SKIP_BLANKS;
7488 if (CUR != '[') {
7489 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7490 }
7491 NEXT;
7492 SKIP_BLANKS;
7493
7494 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007495 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007496 CHECK_ERROR;
7497
7498 if (CUR != ']') {
7499 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7500 }
7501
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007502 if (filter)
7503 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
7504 else
7505 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007506
7507 NEXT;
7508 SKIP_BLANKS;
7509}
7510
7511/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007512 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00007513 * @ctxt: the XPath Parser context
7514 * @test: pointer to a xmlXPathTestVal
7515 * @type: pointer to a xmlXPathTypeVal
7516 * @prefix: placeholder for a possible name prefix
7517 *
7518 * [7] NodeTest ::= NameTest
7519 * | NodeType '(' ')'
7520 * | 'processing-instruction' '(' Literal ')'
7521 *
7522 * [37] NameTest ::= '*'
7523 * | NCName ':' '*'
7524 * | QName
7525 * [38] NodeType ::= 'comment'
7526 * | 'text'
7527 * | 'processing-instruction'
7528 * | 'node'
7529 *
7530 * Returns the name found and update @test, @type and @prefix appropriately
7531 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007532static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007533xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
7534 xmlXPathTypeVal *type, const xmlChar **prefix,
7535 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00007536 int blanks;
7537
7538 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
7539 STRANGE;
7540 return(NULL);
7541 }
7542 *type = 0;
7543 *test = 0;
7544 *prefix = NULL;
7545 SKIP_BLANKS;
7546
7547 if ((name == NULL) && (CUR == '*')) {
7548 /*
7549 * All elements
7550 */
7551 NEXT;
7552 *test = NODE_TEST_ALL;
7553 return(NULL);
7554 }
7555
7556 if (name == NULL)
7557 name = xmlXPathParseNCName(ctxt);
7558 if (name == NULL) {
7559 XP_ERROR0(XPATH_EXPR_ERROR);
7560 }
7561
7562 blanks = IS_BLANK(CUR);
7563 SKIP_BLANKS;
7564 if (CUR == '(') {
7565 NEXT;
7566 /*
7567 * NodeType or PI search
7568 */
7569 if (xmlStrEqual(name, BAD_CAST "comment"))
7570 *type = NODE_TYPE_COMMENT;
7571 else if (xmlStrEqual(name, BAD_CAST "node"))
7572 *type = NODE_TYPE_NODE;
7573 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
7574 *type = NODE_TYPE_PI;
7575 else if (xmlStrEqual(name, BAD_CAST "text"))
7576 *type = NODE_TYPE_TEXT;
7577 else {
7578 if (name != NULL)
7579 xmlFree(name);
7580 XP_ERROR0(XPATH_EXPR_ERROR);
7581 }
7582
7583 *test = NODE_TEST_TYPE;
7584
7585 SKIP_BLANKS;
7586 if (*type == NODE_TYPE_PI) {
7587 /*
7588 * Specific case: search a PI by name.
7589 */
Owen Taylor3473f882001-02-23 17:55:21 +00007590 if (name != NULL)
7591 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00007592 name = NULL;
7593 if (CUR != ')') {
7594 name = xmlXPathParseLiteral(ctxt);
7595 CHECK_ERROR 0;
7596 SKIP_BLANKS;
7597 }
Owen Taylor3473f882001-02-23 17:55:21 +00007598 }
7599 if (CUR != ')') {
7600 if (name != NULL)
7601 xmlFree(name);
7602 XP_ERROR0(XPATH_UNCLOSED_ERROR);
7603 }
7604 NEXT;
7605 return(name);
7606 }
7607 *test = NODE_TEST_NAME;
7608 if ((!blanks) && (CUR == ':')) {
7609 NEXT;
7610
7611 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007612 * Since currently the parser context don't have a
7613 * namespace list associated:
7614 * The namespace name for this prefix can be computed
7615 * only at evaluation time. The compilation is done
7616 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00007617 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007618#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00007619 *prefix = xmlXPathNsLookup(ctxt->context, name);
7620 if (name != NULL)
7621 xmlFree(name);
7622 if (*prefix == NULL) {
7623 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
7624 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007625#else
7626 *prefix = name;
7627#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007628
7629 if (CUR == '*') {
7630 /*
7631 * All elements
7632 */
7633 NEXT;
7634 *test = NODE_TEST_ALL;
7635 return(NULL);
7636 }
7637
7638 name = xmlXPathParseNCName(ctxt);
7639 if (name == NULL) {
7640 XP_ERROR0(XPATH_EXPR_ERROR);
7641 }
7642 }
7643 return(name);
7644}
7645
7646/**
7647 * xmlXPathIsAxisName:
7648 * @name: a preparsed name token
7649 *
7650 * [6] AxisName ::= 'ancestor'
7651 * | 'ancestor-or-self'
7652 * | 'attribute'
7653 * | 'child'
7654 * | 'descendant'
7655 * | 'descendant-or-self'
7656 * | 'following'
7657 * | 'following-sibling'
7658 * | 'namespace'
7659 * | 'parent'
7660 * | 'preceding'
7661 * | 'preceding-sibling'
7662 * | 'self'
7663 *
7664 * Returns the axis or 0
7665 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007666static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00007667xmlXPathIsAxisName(const xmlChar *name) {
7668 xmlXPathAxisVal ret = 0;
7669 switch (name[0]) {
7670 case 'a':
7671 if (xmlStrEqual(name, BAD_CAST "ancestor"))
7672 ret = AXIS_ANCESTOR;
7673 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
7674 ret = AXIS_ANCESTOR_OR_SELF;
7675 if (xmlStrEqual(name, BAD_CAST "attribute"))
7676 ret = AXIS_ATTRIBUTE;
7677 break;
7678 case 'c':
7679 if (xmlStrEqual(name, BAD_CAST "child"))
7680 ret = AXIS_CHILD;
7681 break;
7682 case 'd':
7683 if (xmlStrEqual(name, BAD_CAST "descendant"))
7684 ret = AXIS_DESCENDANT;
7685 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
7686 ret = AXIS_DESCENDANT_OR_SELF;
7687 break;
7688 case 'f':
7689 if (xmlStrEqual(name, BAD_CAST "following"))
7690 ret = AXIS_FOLLOWING;
7691 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
7692 ret = AXIS_FOLLOWING_SIBLING;
7693 break;
7694 case 'n':
7695 if (xmlStrEqual(name, BAD_CAST "namespace"))
7696 ret = AXIS_NAMESPACE;
7697 break;
7698 case 'p':
7699 if (xmlStrEqual(name, BAD_CAST "parent"))
7700 ret = AXIS_PARENT;
7701 if (xmlStrEqual(name, BAD_CAST "preceding"))
7702 ret = AXIS_PRECEDING;
7703 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
7704 ret = AXIS_PRECEDING_SIBLING;
7705 break;
7706 case 's':
7707 if (xmlStrEqual(name, BAD_CAST "self"))
7708 ret = AXIS_SELF;
7709 break;
7710 }
7711 return(ret);
7712}
7713
7714/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007715 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00007716 * @ctxt: the XPath Parser context
7717 *
7718 * [4] Step ::= AxisSpecifier NodeTest Predicate*
7719 * | AbbreviatedStep
7720 *
7721 * [12] AbbreviatedStep ::= '.' | '..'
7722 *
7723 * [5] AxisSpecifier ::= AxisName '::'
7724 * | AbbreviatedAxisSpecifier
7725 *
7726 * [13] AbbreviatedAxisSpecifier ::= '@'?
7727 *
7728 * Modified for XPtr range support as:
7729 *
7730 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
7731 * | AbbreviatedStep
7732 * | 'range-to' '(' Expr ')' Predicate*
7733 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007734 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00007735 * A location step of . is short for self::node(). This is
7736 * particularly useful in conjunction with //. For example, the
7737 * location path .//para is short for
7738 * self::node()/descendant-or-self::node()/child::para
7739 * and so will select all para descendant elements of the context
7740 * node.
7741 * Similarly, a location step of .. is short for parent::node().
7742 * For example, ../title is short for parent::node()/child::title
7743 * and so will select the title children of the parent of the context
7744 * node.
7745 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007746static void
7747xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007748#ifdef LIBXML_XPTR_ENABLED
7749 int rangeto = 0;
7750 int op2 = -1;
7751#endif
7752
Owen Taylor3473f882001-02-23 17:55:21 +00007753 SKIP_BLANKS;
7754 if ((CUR == '.') && (NXT(1) == '.')) {
7755 SKIP(2);
7756 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007757 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
7758 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007759 } else if (CUR == '.') {
7760 NEXT;
7761 SKIP_BLANKS;
7762 } else {
7763 xmlChar *name = NULL;
7764 const xmlChar *prefix = NULL;
7765 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007766 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007767 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007768 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00007769
7770 /*
7771 * The modification needed for XPointer change to the production
7772 */
7773#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007774 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00007775 name = xmlXPathParseNCName(ctxt);
7776 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007777 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007778 xmlFree(name);
7779 SKIP_BLANKS;
7780 if (CUR != '(') {
7781 XP_ERROR(XPATH_EXPR_ERROR);
7782 }
7783 NEXT;
7784 SKIP_BLANKS;
7785
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007786 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007787 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00007788 CHECK_ERROR;
7789
7790 SKIP_BLANKS;
7791 if (CUR != ')') {
7792 XP_ERROR(XPATH_EXPR_ERROR);
7793 }
7794 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007795 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007796 goto eval_predicates;
7797 }
7798 }
7799#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00007800 if (CUR == '*') {
7801 axis = AXIS_CHILD;
7802 } else {
7803 if (name == NULL)
7804 name = xmlXPathParseNCName(ctxt);
7805 if (name != NULL) {
7806 axis = xmlXPathIsAxisName(name);
7807 if (axis != 0) {
7808 SKIP_BLANKS;
7809 if ((CUR == ':') && (NXT(1) == ':')) {
7810 SKIP(2);
7811 xmlFree(name);
7812 name = NULL;
7813 } else {
7814 /* an element name can conflict with an axis one :-\ */
7815 axis = AXIS_CHILD;
7816 }
Owen Taylor3473f882001-02-23 17:55:21 +00007817 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00007818 axis = AXIS_CHILD;
7819 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007820 } else if (CUR == '@') {
7821 NEXT;
7822 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00007823 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00007824 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00007825 }
Owen Taylor3473f882001-02-23 17:55:21 +00007826 }
7827
7828 CHECK_ERROR;
7829
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007830 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00007831 if (test == 0)
7832 return;
7833
7834#ifdef DEBUG_STEP
7835 xmlGenericError(xmlGenericErrorContext,
7836 "Basis : computing new set\n");
7837#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007838
Owen Taylor3473f882001-02-23 17:55:21 +00007839#ifdef DEBUG_STEP
7840 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007841 if (ctxt->value == NULL)
7842 xmlGenericError(xmlGenericErrorContext, "no value\n");
7843 else if (ctxt->value->nodesetval == NULL)
7844 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7845 else
7846 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007847#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007848
7849eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007850 op1 = ctxt->comp->last;
7851 ctxt->comp->last = -1;
7852
Owen Taylor3473f882001-02-23 17:55:21 +00007853 SKIP_BLANKS;
7854 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007855 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007856 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007857
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007858#ifdef LIBXML_XPTR_ENABLED
7859 if (rangeto) {
7860 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
7861 } else
7862#endif
7863 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
7864 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007865
Owen Taylor3473f882001-02-23 17:55:21 +00007866 }
7867#ifdef DEBUG_STEP
7868 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007869 if (ctxt->value == NULL)
7870 xmlGenericError(xmlGenericErrorContext, "no value\n");
7871 else if (ctxt->value->nodesetval == NULL)
7872 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7873 else
7874 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
7875 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007876#endif
7877}
7878
7879/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007880 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007881 * @ctxt: the XPath Parser context
7882 *
7883 * [3] RelativeLocationPath ::= Step
7884 * | RelativeLocationPath '/' Step
7885 * | AbbreviatedRelativeLocationPath
7886 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
7887 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007888 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00007889 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007890static void
Owen Taylor3473f882001-02-23 17:55:21 +00007891#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007892xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007893#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007894xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007895#endif
7896(xmlXPathParserContextPtr ctxt) {
7897 SKIP_BLANKS;
7898 if ((CUR == '/') && (NXT(1) == '/')) {
7899 SKIP(2);
7900 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007901 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7902 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007903 } else if (CUR == '/') {
7904 NEXT;
7905 SKIP_BLANKS;
7906 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007907 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007908 SKIP_BLANKS;
7909 while (CUR == '/') {
7910 if ((CUR == '/') && (NXT(1) == '/')) {
7911 SKIP(2);
7912 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007913 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00007914 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007915 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007916 } else if (CUR == '/') {
7917 NEXT;
7918 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007919 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007920 }
7921 SKIP_BLANKS;
7922 }
7923}
7924
7925/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007926 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007927 * @ctxt: the XPath Parser context
7928 *
7929 * [1] LocationPath ::= RelativeLocationPath
7930 * | AbsoluteLocationPath
7931 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
7932 * | AbbreviatedAbsoluteLocationPath
7933 * [10] AbbreviatedAbsoluteLocationPath ::=
7934 * '//' RelativeLocationPath
7935 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007936 * Compile a location path
7937 *
Owen Taylor3473f882001-02-23 17:55:21 +00007938 * // is short for /descendant-or-self::node()/. For example,
7939 * //para is short for /descendant-or-self::node()/child::para and
7940 * so will select any para element in the document (even a para element
7941 * that is a document element will be selected by //para since the
7942 * document element node is a child of the root node); div//para is
7943 * short for div/descendant-or-self::node()/child::para and so will
7944 * select all para descendants of div children.
7945 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007946static void
7947xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007948 SKIP_BLANKS;
7949 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007950 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007951 } else {
7952 while (CUR == '/') {
7953 if ((CUR == '/') && (NXT(1) == '/')) {
7954 SKIP(2);
7955 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007956 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7957 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007958 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007959 } else if (CUR == '/') {
7960 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00007961 SKIP_BLANKS;
7962 if ((CUR != 0 ) &&
7963 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
7964 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007965 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007966 }
7967 }
7968 }
7969}
7970
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007971/************************************************************************
7972 * *
7973 * XPath precompiled expression evaluation *
7974 * *
7975 ************************************************************************/
7976
Daniel Veillardf06307e2001-07-03 10:35:50 +00007977static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007978xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
7979
7980/**
7981 * xmlXPathNodeCollectAndTest:
7982 * @ctxt: the XPath Parser context
7983 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00007984 * @first: pointer to the first element in document order
7985 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007986 *
7987 * This is the function implementing a step: based on the current list
7988 * of nodes, it builds up a new list, looking at all nodes under that
7989 * axis and selecting them it also do the predicate filtering
7990 *
7991 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00007992 *
7993 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007994 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00007995static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007996xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00007997 xmlXPathStepOpPtr op,
7998 xmlNodePtr * first, xmlNodePtr * last)
7999{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008000 xmlXPathAxisVal axis = op->value;
8001 xmlXPathTestVal test = op->value2;
8002 xmlXPathTypeVal type = op->value3;
8003 const xmlChar *prefix = op->value4;
8004 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008005 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008006
8007#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008008 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008009#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008010 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008011 xmlNodeSetPtr ret, list;
8012 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008013 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008014 xmlNodePtr cur = NULL;
8015 xmlXPathObjectPtr obj;
8016 xmlNodeSetPtr nodelist;
8017 xmlNodePtr tmp;
8018
Daniel Veillardf06307e2001-07-03 10:35:50 +00008019 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008020 obj = valuePop(ctxt);
8021 addNode = xmlXPathNodeSetAdd;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008022 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008023 URI = xmlXPathNsLookup(ctxt->context, prefix);
8024 if (URI == NULL)
8025 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008026 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008027#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008028 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008029#endif
8030 switch (axis) {
8031 case AXIS_ANCESTOR:
8032#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008033 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008034#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008035 first = NULL;
8036 next = xmlXPathNextAncestor;
8037 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008038 case AXIS_ANCESTOR_OR_SELF:
8039#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008040 xmlGenericError(xmlGenericErrorContext,
8041 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008042#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008043 first = NULL;
8044 next = xmlXPathNextAncestorOrSelf;
8045 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008046 case AXIS_ATTRIBUTE:
8047#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008048 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008049#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008050 first = NULL;
8051 last = NULL;
8052 next = xmlXPathNextAttribute;
8053 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008054 case AXIS_CHILD:
8055#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008056 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008057#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008058 last = NULL;
8059 next = xmlXPathNextChild;
8060 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008061 case AXIS_DESCENDANT:
8062#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008063 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008064#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008065 last = NULL;
8066 next = xmlXPathNextDescendant;
8067 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008068 case AXIS_DESCENDANT_OR_SELF:
8069#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008070 xmlGenericError(xmlGenericErrorContext,
8071 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008072#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008073 last = NULL;
8074 next = xmlXPathNextDescendantOrSelf;
8075 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008076 case AXIS_FOLLOWING:
8077#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008078 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008079#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008080 last = NULL;
8081 next = xmlXPathNextFollowing;
8082 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008083 case AXIS_FOLLOWING_SIBLING:
8084#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008085 xmlGenericError(xmlGenericErrorContext,
8086 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008087#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008088 last = NULL;
8089 next = xmlXPathNextFollowingSibling;
8090 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008091 case AXIS_NAMESPACE:
8092#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008093 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008094#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008095 first = NULL;
8096 last = NULL;
8097 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8098 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008099 case AXIS_PARENT:
8100#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008101 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008102#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008103 first = NULL;
8104 next = xmlXPathNextParent;
8105 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008106 case AXIS_PRECEDING:
8107#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008108 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008109#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008110 first = NULL;
8111 next = xmlXPathNextPrecedingInternal;
8112 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008113 case AXIS_PRECEDING_SIBLING:
8114#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008115 xmlGenericError(xmlGenericErrorContext,
8116 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008117#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008118 first = NULL;
8119 next = xmlXPathNextPrecedingSibling;
8120 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008121 case AXIS_SELF:
8122#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008123 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008124#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008125 first = NULL;
8126 last = NULL;
8127 next = xmlXPathNextSelf;
8128 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008129 }
8130 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008131 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008132
8133 nodelist = obj->nodesetval;
8134 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008135 xmlXPathFreeObject(obj);
8136 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8137 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008138 }
8139 addNode = xmlXPathNodeSetAddUnique;
8140 ret = NULL;
8141#ifdef DEBUG_STEP
8142 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008143 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008144 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008145 case NODE_TEST_NONE:
8146 xmlGenericError(xmlGenericErrorContext,
8147 " searching for none !!!\n");
8148 break;
8149 case NODE_TEST_TYPE:
8150 xmlGenericError(xmlGenericErrorContext,
8151 " searching for type %d\n", type);
8152 break;
8153 case NODE_TEST_PI:
8154 xmlGenericError(xmlGenericErrorContext,
8155 " searching for PI !!!\n");
8156 break;
8157 case NODE_TEST_ALL:
8158 xmlGenericError(xmlGenericErrorContext,
8159 " searching for *\n");
8160 break;
8161 case NODE_TEST_NS:
8162 xmlGenericError(xmlGenericErrorContext,
8163 " searching for namespace %s\n",
8164 prefix);
8165 break;
8166 case NODE_TEST_NAME:
8167 xmlGenericError(xmlGenericErrorContext,
8168 " searching for name %s\n", name);
8169 if (prefix != NULL)
8170 xmlGenericError(xmlGenericErrorContext,
8171 " with namespace %s\n", prefix);
8172 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008173 }
8174 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8175#endif
8176 /*
8177 * 2.3 Node Tests
8178 * - For the attribute axis, the principal node type is attribute.
8179 * - For the namespace axis, the principal node type is namespace.
8180 * - For other axes, the principal node type is element.
8181 *
8182 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008183 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008184 * select all element children of the context node
8185 */
8186 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008187 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008188 ctxt->context->node = nodelist->nodeTab[i];
8189
Daniel Veillardf06307e2001-07-03 10:35:50 +00008190 cur = NULL;
8191 list = xmlXPathNodeSetCreate(NULL);
8192 do {
8193 cur = next(ctxt, cur);
8194 if (cur == NULL)
8195 break;
8196 if ((first != NULL) && (*first == cur))
8197 break;
8198 if (((t % 256) == 0) &&
8199 (first != NULL) && (*first != NULL) &&
8200 (xmlXPathCmpNodes(*first, cur) >= 0))
8201 break;
8202 if ((last != NULL) && (*last == cur))
8203 break;
8204 if (((t % 256) == 0) &&
8205 (last != NULL) && (*last != NULL) &&
8206 (xmlXPathCmpNodes(cur, *last) >= 0))
8207 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008208 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008209#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008210 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8211#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008212 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008213 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008214 ctxt->context->node = tmp;
8215 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008216 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008217 if ((cur->type == type) ||
8218 ((type == NODE_TYPE_NODE) &&
8219 ((cur->type == XML_DOCUMENT_NODE) ||
8220 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8221 (cur->type == XML_ELEMENT_NODE) ||
8222 (cur->type == XML_PI_NODE) ||
8223 (cur->type == XML_COMMENT_NODE) ||
8224 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00008225 (cur->type == XML_TEXT_NODE))) ||
8226 ((type == NODE_TYPE_TEXT) &&
8227 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008228#ifdef DEBUG_STEP
8229 n++;
8230#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008231 addNode(list, cur);
8232 }
8233 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008234 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008235 if (cur->type == XML_PI_NODE) {
8236 if ((name != NULL) &&
8237 (!xmlStrEqual(name, cur->name)))
8238 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008239#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008240 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008241#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008242 addNode(list, cur);
8243 }
8244 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008245 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008246 if (axis == AXIS_ATTRIBUTE) {
8247 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008248#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008249 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008250#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008251 addNode(list, cur);
8252 }
8253 } else if (axis == AXIS_NAMESPACE) {
8254 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008255#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008256 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008257#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008258 addNode(list, cur);
8259 }
8260 } else {
8261 if (cur->type == XML_ELEMENT_NODE) {
8262 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008263#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008264 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008265#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008266 addNode(list, cur);
8267 } else if ((cur->ns != NULL) &&
8268 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008269#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008270 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008271#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008272 addNode(list, cur);
8273 }
8274 }
8275 }
8276 break;
8277 case NODE_TEST_NS:{
8278 TODO;
8279 break;
8280 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008281 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008282 switch (cur->type) {
8283 case XML_ELEMENT_NODE:
8284 if (xmlStrEqual(name, cur->name)) {
8285 if (prefix == NULL) {
8286 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008287#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008288 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008289#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008290 addNode(list, cur);
8291 }
8292 } else {
8293 if ((cur->ns != NULL) &&
8294 (xmlStrEqual(URI,
8295 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008296#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008297 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008298#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008299 addNode(list, cur);
8300 }
8301 }
8302 }
8303 break;
8304 case XML_ATTRIBUTE_NODE:{
8305 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008306
Daniel Veillardf06307e2001-07-03 10:35:50 +00008307 if (xmlStrEqual(name, attr->name)) {
8308 if (prefix == NULL) {
8309 if ((attr->ns == NULL) ||
8310 (attr->ns->prefix == NULL)) {
8311#ifdef DEBUG_STEP
8312 n++;
8313#endif
8314 addNode(list,
8315 (xmlNodePtr) attr);
8316 }
8317 } else {
8318 if ((attr->ns != NULL) &&
8319 (xmlStrEqual(URI,
8320 attr->ns->
8321 href))) {
8322#ifdef DEBUG_STEP
8323 n++;
8324#endif
8325 addNode(list,
8326 (xmlNodePtr) attr);
8327 }
8328 }
8329 }
8330 break;
8331 }
8332 case XML_NAMESPACE_DECL:
8333 if (cur->type == XML_NAMESPACE_DECL) {
8334 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008335
Daniel Veillardf06307e2001-07-03 10:35:50 +00008336 if ((ns->prefix != NULL) && (name != NULL)
8337 && (xmlStrEqual(ns->prefix, name))) {
8338#ifdef DEBUG_STEP
8339 n++;
8340#endif
8341 addNode(list, cur);
8342 }
8343 }
8344 break;
8345 default:
8346 break;
8347 }
8348 break;
8349 break;
8350 }
8351 } while (cur != NULL);
8352
8353 /*
8354 * If there is some predicate filtering do it now
8355 */
8356 if (op->ch2 != -1) {
8357 xmlXPathObjectPtr obj2;
8358
8359 valuePush(ctxt, xmlXPathWrapNodeSet(list));
8360 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
8361 CHECK_TYPE0(XPATH_NODESET);
8362 obj2 = valuePop(ctxt);
8363 list = obj2->nodesetval;
8364 obj2->nodesetval = NULL;
8365 xmlXPathFreeObject(obj2);
8366 }
8367 if (ret == NULL) {
8368 ret = list;
8369 } else {
8370 ret = xmlXPathNodeSetMerge(ret, list);
8371 xmlXPathFreeNodeSet(list);
8372 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008373 }
8374 ctxt->context->node = tmp;
8375#ifdef DEBUG_STEP
8376 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008377 "\nExamined %d nodes, found %d nodes at that step\n",
8378 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008379#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008380 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00008381 if ((obj->boolval) && (obj->user != NULL)) {
8382 ctxt->value->boolval = 1;
8383 ctxt->value->user = obj->user;
8384 obj->user = NULL;
8385 obj->boolval = 0;
8386 }
8387 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008388 return(t);
8389}
8390
8391/**
8392 * xmlXPathNodeCollectAndTestNth:
8393 * @ctxt: the XPath Parser context
8394 * @op: the XPath precompiled step operation
8395 * @indx: the index to collect
8396 * @first: pointer to the first element in document order
8397 * @last: pointer to the last element in document order
8398 *
8399 * This is the function implementing a step: based on the current list
8400 * of nodes, it builds up a new list, looking at all nodes under that
8401 * axis and selecting them it also do the predicate filtering
8402 *
8403 * Pushes the new NodeSet resulting from the search.
8404 * Returns the number of node traversed
8405 */
8406static int
8407xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
8408 xmlXPathStepOpPtr op, int indx,
8409 xmlNodePtr * first, xmlNodePtr * last)
8410{
8411 xmlXPathAxisVal axis = op->value;
8412 xmlXPathTestVal test = op->value2;
8413 xmlXPathTypeVal type = op->value3;
8414 const xmlChar *prefix = op->value4;
8415 const xmlChar *name = op->value5;
8416 const xmlChar *URI = NULL;
8417 int n = 0, t = 0;
8418
8419 int i;
8420 xmlNodeSetPtr list;
8421 xmlXPathTraversalFunction next = NULL;
8422 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
8423 xmlNodePtr cur = NULL;
8424 xmlXPathObjectPtr obj;
8425 xmlNodeSetPtr nodelist;
8426 xmlNodePtr tmp;
8427
8428 CHECK_TYPE0(XPATH_NODESET);
8429 obj = valuePop(ctxt);
8430 addNode = xmlXPathNodeSetAdd;
8431 if (prefix != NULL) {
8432 URI = xmlXPathNsLookup(ctxt->context, prefix);
8433 if (URI == NULL)
8434 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8435 }
8436#ifdef DEBUG_STEP_NTH
8437 xmlGenericError(xmlGenericErrorContext, "new step : ");
8438 if (first != NULL) {
8439 if (*first != NULL)
8440 xmlGenericError(xmlGenericErrorContext, "first = %s ",
8441 (*first)->name);
8442 else
8443 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
8444 }
8445 if (last != NULL) {
8446 if (*last != NULL)
8447 xmlGenericError(xmlGenericErrorContext, "last = %s ",
8448 (*last)->name);
8449 else
8450 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
8451 }
8452#endif
8453 switch (axis) {
8454 case AXIS_ANCESTOR:
8455#ifdef DEBUG_STEP_NTH
8456 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
8457#endif
8458 first = NULL;
8459 next = xmlXPathNextAncestor;
8460 break;
8461 case AXIS_ANCESTOR_OR_SELF:
8462#ifdef DEBUG_STEP_NTH
8463 xmlGenericError(xmlGenericErrorContext,
8464 "axis 'ancestors-or-self' ");
8465#endif
8466 first = NULL;
8467 next = xmlXPathNextAncestorOrSelf;
8468 break;
8469 case AXIS_ATTRIBUTE:
8470#ifdef DEBUG_STEP_NTH
8471 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
8472#endif
8473 first = NULL;
8474 last = NULL;
8475 next = xmlXPathNextAttribute;
8476 break;
8477 case AXIS_CHILD:
8478#ifdef DEBUG_STEP_NTH
8479 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
8480#endif
8481 last = NULL;
8482 next = xmlXPathNextChild;
8483 break;
8484 case AXIS_DESCENDANT:
8485#ifdef DEBUG_STEP_NTH
8486 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
8487#endif
8488 last = NULL;
8489 next = xmlXPathNextDescendant;
8490 break;
8491 case AXIS_DESCENDANT_OR_SELF:
8492#ifdef DEBUG_STEP_NTH
8493 xmlGenericError(xmlGenericErrorContext,
8494 "axis 'descendant-or-self' ");
8495#endif
8496 last = NULL;
8497 next = xmlXPathNextDescendantOrSelf;
8498 break;
8499 case AXIS_FOLLOWING:
8500#ifdef DEBUG_STEP_NTH
8501 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
8502#endif
8503 last = NULL;
8504 next = xmlXPathNextFollowing;
8505 break;
8506 case AXIS_FOLLOWING_SIBLING:
8507#ifdef DEBUG_STEP_NTH
8508 xmlGenericError(xmlGenericErrorContext,
8509 "axis 'following-siblings' ");
8510#endif
8511 last = NULL;
8512 next = xmlXPathNextFollowingSibling;
8513 break;
8514 case AXIS_NAMESPACE:
8515#ifdef DEBUG_STEP_NTH
8516 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
8517#endif
8518 last = NULL;
8519 first = NULL;
8520 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8521 break;
8522 case AXIS_PARENT:
8523#ifdef DEBUG_STEP_NTH
8524 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
8525#endif
8526 first = NULL;
8527 next = xmlXPathNextParent;
8528 break;
8529 case AXIS_PRECEDING:
8530#ifdef DEBUG_STEP_NTH
8531 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
8532#endif
8533 first = NULL;
8534 next = xmlXPathNextPrecedingInternal;
8535 break;
8536 case AXIS_PRECEDING_SIBLING:
8537#ifdef DEBUG_STEP_NTH
8538 xmlGenericError(xmlGenericErrorContext,
8539 "axis 'preceding-sibling' ");
8540#endif
8541 first = NULL;
8542 next = xmlXPathNextPrecedingSibling;
8543 break;
8544 case AXIS_SELF:
8545#ifdef DEBUG_STEP_NTH
8546 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
8547#endif
8548 first = NULL;
8549 last = NULL;
8550 next = xmlXPathNextSelf;
8551 break;
8552 }
8553 if (next == NULL)
8554 return(0);
8555
8556 nodelist = obj->nodesetval;
8557 if (nodelist == NULL) {
8558 xmlXPathFreeObject(obj);
8559 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8560 return(0);
8561 }
8562 addNode = xmlXPathNodeSetAddUnique;
8563#ifdef DEBUG_STEP_NTH
8564 xmlGenericError(xmlGenericErrorContext,
8565 " context contains %d nodes\n", nodelist->nodeNr);
8566 switch (test) {
8567 case NODE_TEST_NONE:
8568 xmlGenericError(xmlGenericErrorContext,
8569 " searching for none !!!\n");
8570 break;
8571 case NODE_TEST_TYPE:
8572 xmlGenericError(xmlGenericErrorContext,
8573 " searching for type %d\n", type);
8574 break;
8575 case NODE_TEST_PI:
8576 xmlGenericError(xmlGenericErrorContext,
8577 " searching for PI !!!\n");
8578 break;
8579 case NODE_TEST_ALL:
8580 xmlGenericError(xmlGenericErrorContext,
8581 " searching for *\n");
8582 break;
8583 case NODE_TEST_NS:
8584 xmlGenericError(xmlGenericErrorContext,
8585 " searching for namespace %s\n",
8586 prefix);
8587 break;
8588 case NODE_TEST_NAME:
8589 xmlGenericError(xmlGenericErrorContext,
8590 " searching for name %s\n", name);
8591 if (prefix != NULL)
8592 xmlGenericError(xmlGenericErrorContext,
8593 " with namespace %s\n", prefix);
8594 break;
8595 }
8596 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8597#endif
8598 /*
8599 * 2.3 Node Tests
8600 * - For the attribute axis, the principal node type is attribute.
8601 * - For the namespace axis, the principal node type is namespace.
8602 * - For other axes, the principal node type is element.
8603 *
8604 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008605 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00008606 * select all element children of the context node
8607 */
8608 tmp = ctxt->context->node;
8609 list = xmlXPathNodeSetCreate(NULL);
8610 for (i = 0; i < nodelist->nodeNr; i++) {
8611 ctxt->context->node = nodelist->nodeTab[i];
8612
8613 cur = NULL;
8614 n = 0;
8615 do {
8616 cur = next(ctxt, cur);
8617 if (cur == NULL)
8618 break;
8619 if ((first != NULL) && (*first == cur))
8620 break;
8621 if (((t % 256) == 0) &&
8622 (first != NULL) && (*first != NULL) &&
8623 (xmlXPathCmpNodes(*first, cur) >= 0))
8624 break;
8625 if ((last != NULL) && (*last == cur))
8626 break;
8627 if (((t % 256) == 0) &&
8628 (last != NULL) && (*last != NULL) &&
8629 (xmlXPathCmpNodes(cur, *last) >= 0))
8630 break;
8631 t++;
8632 switch (test) {
8633 case NODE_TEST_NONE:
8634 ctxt->context->node = tmp;
8635 STRANGE return(0);
8636 case NODE_TEST_TYPE:
8637 if ((cur->type == type) ||
8638 ((type == NODE_TYPE_NODE) &&
8639 ((cur->type == XML_DOCUMENT_NODE) ||
8640 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8641 (cur->type == XML_ELEMENT_NODE) ||
8642 (cur->type == XML_PI_NODE) ||
8643 (cur->type == XML_COMMENT_NODE) ||
8644 (cur->type == XML_CDATA_SECTION_NODE) ||
8645 (cur->type == XML_TEXT_NODE)))) {
8646 n++;
8647 if (n == indx)
8648 addNode(list, cur);
8649 }
8650 break;
8651 case NODE_TEST_PI:
8652 if (cur->type == XML_PI_NODE) {
8653 if ((name != NULL) &&
8654 (!xmlStrEqual(name, cur->name)))
8655 break;
8656 n++;
8657 if (n == indx)
8658 addNode(list, cur);
8659 }
8660 break;
8661 case NODE_TEST_ALL:
8662 if (axis == AXIS_ATTRIBUTE) {
8663 if (cur->type == XML_ATTRIBUTE_NODE) {
8664 n++;
8665 if (n == indx)
8666 addNode(list, cur);
8667 }
8668 } else if (axis == AXIS_NAMESPACE) {
8669 if (cur->type == XML_NAMESPACE_DECL) {
8670 n++;
8671 if (n == indx)
8672 addNode(list, cur);
8673 }
8674 } else {
8675 if (cur->type == XML_ELEMENT_NODE) {
8676 if (prefix == NULL) {
8677 n++;
8678 if (n == indx)
8679 addNode(list, cur);
8680 } else if ((cur->ns != NULL) &&
8681 (xmlStrEqual(URI, cur->ns->href))) {
8682 n++;
8683 if (n == indx)
8684 addNode(list, cur);
8685 }
8686 }
8687 }
8688 break;
8689 case NODE_TEST_NS:{
8690 TODO;
8691 break;
8692 }
8693 case NODE_TEST_NAME:
8694 switch (cur->type) {
8695 case XML_ELEMENT_NODE:
8696 if (xmlStrEqual(name, cur->name)) {
8697 if (prefix == NULL) {
8698 if (cur->ns == NULL) {
8699 n++;
8700 if (n == indx)
8701 addNode(list, cur);
8702 }
8703 } else {
8704 if ((cur->ns != NULL) &&
8705 (xmlStrEqual(URI,
8706 cur->ns->href))) {
8707 n++;
8708 if (n == indx)
8709 addNode(list, cur);
8710 }
8711 }
8712 }
8713 break;
8714 case XML_ATTRIBUTE_NODE:{
8715 xmlAttrPtr attr = (xmlAttrPtr) cur;
8716
8717 if (xmlStrEqual(name, attr->name)) {
8718 if (prefix == NULL) {
8719 if ((attr->ns == NULL) ||
8720 (attr->ns->prefix == NULL)) {
8721 n++;
8722 if (n == indx)
8723 addNode(list, cur);
8724 }
8725 } else {
8726 if ((attr->ns != NULL) &&
8727 (xmlStrEqual(URI,
8728 attr->ns->
8729 href))) {
8730 n++;
8731 if (n == indx)
8732 addNode(list, cur);
8733 }
8734 }
8735 }
8736 break;
8737 }
8738 case XML_NAMESPACE_DECL:
8739 if (cur->type == XML_NAMESPACE_DECL) {
8740 xmlNsPtr ns = (xmlNsPtr) cur;
8741
8742 if ((ns->prefix != NULL) && (name != NULL)
8743 && (xmlStrEqual(ns->prefix, name))) {
8744 n++;
8745 if (n == indx)
8746 addNode(list, cur);
8747 }
8748 }
8749 break;
8750 default:
8751 break;
8752 }
8753 break;
8754 break;
8755 }
8756 } while (n < indx);
8757 }
8758 ctxt->context->node = tmp;
8759#ifdef DEBUG_STEP_NTH
8760 xmlGenericError(xmlGenericErrorContext,
8761 "\nExamined %d nodes, found %d nodes at that step\n",
8762 t, list->nodeNr);
8763#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008764 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00008765 if ((obj->boolval) && (obj->user != NULL)) {
8766 ctxt->value->boolval = 1;
8767 ctxt->value->user = obj->user;
8768 obj->user = NULL;
8769 obj->boolval = 0;
8770 }
8771 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008772 return(t);
8773}
8774
8775/**
8776 * xmlXPathCompOpEvalFirst:
8777 * @ctxt: the XPath parser context with the compiled expression
8778 * @op: an XPath compiled operation
8779 * @first: the first elem found so far
8780 *
8781 * Evaluate the Precompiled XPath operation searching only the first
8782 * element in document order
8783 *
8784 * Returns the number of examined objects.
8785 */
8786static int
8787xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
8788 xmlXPathStepOpPtr op, xmlNodePtr * first)
8789{
8790 int total = 0, cur;
8791 xmlXPathCompExprPtr comp;
8792 xmlXPathObjectPtr arg1, arg2;
8793
Daniel Veillard556c6682001-10-06 09:59:51 +00008794 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008795 comp = ctxt->comp;
8796 switch (op->op) {
8797 case XPATH_OP_END:
8798 return (0);
8799 case XPATH_OP_UNION:
8800 total =
8801 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
8802 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00008803 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008804 if ((ctxt->value != NULL)
8805 && (ctxt->value->type == XPATH_NODESET)
8806 && (ctxt->value->nodesetval != NULL)
8807 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8808 /*
8809 * limit tree traversing to first node in the result
8810 */
8811 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8812 *first = ctxt->value->nodesetval->nodeTab[0];
8813 }
8814 cur =
8815 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
8816 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00008817 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008818 CHECK_TYPE0(XPATH_NODESET);
8819 arg2 = valuePop(ctxt);
8820
8821 CHECK_TYPE0(XPATH_NODESET);
8822 arg1 = valuePop(ctxt);
8823
8824 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8825 arg2->nodesetval);
8826 valuePush(ctxt, arg1);
8827 xmlXPathFreeObject(arg2);
8828 /* optimizer */
8829 if (total > cur)
8830 xmlXPathCompSwap(op);
8831 return (total + cur);
8832 case XPATH_OP_ROOT:
8833 xmlXPathRoot(ctxt);
8834 return (0);
8835 case XPATH_OP_NODE:
8836 if (op->ch1 != -1)
8837 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008838 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008839 if (op->ch2 != -1)
8840 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008841 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008842 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8843 return (total);
8844 case XPATH_OP_RESET:
8845 if (op->ch1 != -1)
8846 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008847 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008848 if (op->ch2 != -1)
8849 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008850 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008851 ctxt->context->node = NULL;
8852 return (total);
8853 case XPATH_OP_COLLECT:{
8854 if (op->ch1 == -1)
8855 return (total);
8856
8857 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008858 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008859
8860 /*
8861 * Optimization for [n] selection where n is a number
8862 */
8863 if ((op->ch2 != -1) &&
8864 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8865 (comp->steps[op->ch2].ch1 == -1) &&
8866 (comp->steps[op->ch2].ch2 != -1) &&
8867 (comp->steps[comp->steps[op->ch2].ch2].op ==
8868 XPATH_OP_VALUE)) {
8869 xmlXPathObjectPtr val;
8870
8871 val = comp->steps[comp->steps[op->ch2].ch2].value4;
8872 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
8873 int indx = (int) val->floatval;
8874
8875 if (val->floatval == (float) indx) {
8876 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
8877 first, NULL);
8878 return (total);
8879 }
8880 }
8881 }
8882 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
8883 return (total);
8884 }
8885 case XPATH_OP_VALUE:
8886 valuePush(ctxt,
8887 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
8888 return (0);
8889 case XPATH_OP_SORT:
8890 if (op->ch1 != -1)
8891 total +=
8892 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
8893 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00008894 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008895 if ((ctxt->value != NULL)
8896 && (ctxt->value->type == XPATH_NODESET)
8897 && (ctxt->value->nodesetval != NULL))
8898 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8899 return (total);
8900 default:
8901 return (xmlXPathCompOpEval(ctxt, op));
8902 }
8903}
8904
8905/**
8906 * xmlXPathCompOpEvalLast:
8907 * @ctxt: the XPath parser context with the compiled expression
8908 * @op: an XPath compiled operation
8909 * @last: the last elem found so far
8910 *
8911 * Evaluate the Precompiled XPath operation searching only the last
8912 * element in document order
8913 *
8914 * Returns the number of node traversed
8915 */
8916static int
8917xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
8918 xmlNodePtr * last)
8919{
8920 int total = 0, cur;
8921 xmlXPathCompExprPtr comp;
8922 xmlXPathObjectPtr arg1, arg2;
8923
Daniel Veillard556c6682001-10-06 09:59:51 +00008924 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008925 comp = ctxt->comp;
8926 switch (op->op) {
8927 case XPATH_OP_END:
8928 return (0);
8929 case XPATH_OP_UNION:
8930 total =
8931 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00008932 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008933 if ((ctxt->value != NULL)
8934 && (ctxt->value->type == XPATH_NODESET)
8935 && (ctxt->value->nodesetval != NULL)
8936 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8937 /*
8938 * limit tree traversing to first node in the result
8939 */
8940 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8941 *last =
8942 ctxt->value->nodesetval->nodeTab[ctxt->value->
8943 nodesetval->nodeNr -
8944 1];
8945 }
8946 cur =
8947 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00008948 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008949 if ((ctxt->value != NULL)
8950 && (ctxt->value->type == XPATH_NODESET)
8951 && (ctxt->value->nodesetval != NULL)
8952 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8953 }
8954 CHECK_TYPE0(XPATH_NODESET);
8955 arg2 = valuePop(ctxt);
8956
8957 CHECK_TYPE0(XPATH_NODESET);
8958 arg1 = valuePop(ctxt);
8959
8960 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8961 arg2->nodesetval);
8962 valuePush(ctxt, arg1);
8963 xmlXPathFreeObject(arg2);
8964 /* optimizer */
8965 if (total > cur)
8966 xmlXPathCompSwap(op);
8967 return (total + cur);
8968 case XPATH_OP_ROOT:
8969 xmlXPathRoot(ctxt);
8970 return (0);
8971 case XPATH_OP_NODE:
8972 if (op->ch1 != -1)
8973 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008974 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008975 if (op->ch2 != -1)
8976 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008977 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008978 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8979 return (total);
8980 case XPATH_OP_RESET:
8981 if (op->ch1 != -1)
8982 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008983 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008984 if (op->ch2 != -1)
8985 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008986 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008987 ctxt->context->node = NULL;
8988 return (total);
8989 case XPATH_OP_COLLECT:{
8990 if (op->ch1 == -1)
8991 return (0);
8992
8993 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008994 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008995
8996 /*
8997 * Optimization for [n] selection where n is a number
8998 */
8999 if ((op->ch2 != -1) &&
9000 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9001 (comp->steps[op->ch2].ch1 == -1) &&
9002 (comp->steps[op->ch2].ch2 != -1) &&
9003 (comp->steps[comp->steps[op->ch2].ch2].op ==
9004 XPATH_OP_VALUE)) {
9005 xmlXPathObjectPtr val;
9006
9007 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9008 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9009 int indx = (int) val->floatval;
9010
9011 if (val->floatval == (float) indx) {
9012 total +=
9013 xmlXPathNodeCollectAndTestNth(ctxt, op,
9014 indx, NULL,
9015 last);
9016 return (total);
9017 }
9018 }
9019 }
9020 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9021 return (total);
9022 }
9023 case XPATH_OP_VALUE:
9024 valuePush(ctxt,
9025 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9026 return (0);
9027 case XPATH_OP_SORT:
9028 if (op->ch1 != -1)
9029 total +=
9030 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9031 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009032 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009033 if ((ctxt->value != NULL)
9034 && (ctxt->value->type == XPATH_NODESET)
9035 && (ctxt->value->nodesetval != NULL))
9036 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9037 return (total);
9038 default:
9039 return (xmlXPathCompOpEval(ctxt, op));
9040 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009041}
9042
Owen Taylor3473f882001-02-23 17:55:21 +00009043/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009044 * xmlXPathCompOpEval:
9045 * @ctxt: the XPath parser context with the compiled expression
9046 * @op: an XPath compiled operation
9047 *
9048 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009049 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009050 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009051static int
9052xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9053{
9054 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009055 int equal, ret;
9056 xmlXPathCompExprPtr comp;
9057 xmlXPathObjectPtr arg1, arg2;
9058
Daniel Veillard556c6682001-10-06 09:59:51 +00009059 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009060 comp = ctxt->comp;
9061 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009062 case XPATH_OP_END:
9063 return (0);
9064 case XPATH_OP_AND:
9065 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009066 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009067 xmlXPathBooleanFunction(ctxt, 1);
9068 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9069 return (total);
9070 arg2 = valuePop(ctxt);
9071 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009072 if (ctxt->error) {
9073 xmlXPathFreeObject(arg2);
9074 return(0);
9075 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009076 xmlXPathBooleanFunction(ctxt, 1);
9077 arg1 = valuePop(ctxt);
9078 arg1->boolval &= arg2->boolval;
9079 valuePush(ctxt, arg1);
9080 xmlXPathFreeObject(arg2);
9081 return (total);
9082 case XPATH_OP_OR:
9083 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009084 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009085 xmlXPathBooleanFunction(ctxt, 1);
9086 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9087 return (total);
9088 arg2 = valuePop(ctxt);
9089 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009090 if (ctxt->error) {
9091 xmlXPathFreeObject(arg2);
9092 return(0);
9093 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009094 xmlXPathBooleanFunction(ctxt, 1);
9095 arg1 = valuePop(ctxt);
9096 arg1->boolval |= arg2->boolval;
9097 valuePush(ctxt, arg1);
9098 xmlXPathFreeObject(arg2);
9099 return (total);
9100 case XPATH_OP_EQUAL:
9101 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009102 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009103 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009104 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009105 equal = xmlXPathEqualValues(ctxt);
9106 if (op->value)
9107 valuePush(ctxt, xmlXPathNewBoolean(equal));
9108 else
9109 valuePush(ctxt, xmlXPathNewBoolean(!equal));
9110 return (total);
9111 case XPATH_OP_CMP:
9112 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009113 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009114 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009115 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009116 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9117 valuePush(ctxt, xmlXPathNewBoolean(ret));
9118 return (total);
9119 case XPATH_OP_PLUS:
9120 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009121 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009122 if (op->ch2 != -1)
9123 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009124 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009125 if (op->value == 0)
9126 xmlXPathSubValues(ctxt);
9127 else if (op->value == 1)
9128 xmlXPathAddValues(ctxt);
9129 else if (op->value == 2)
9130 xmlXPathValueFlipSign(ctxt);
9131 else if (op->value == 3) {
9132 CAST_TO_NUMBER;
9133 CHECK_TYPE0(XPATH_NUMBER);
9134 }
9135 return (total);
9136 case XPATH_OP_MULT:
9137 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009138 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009139 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009140 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009141 if (op->value == 0)
9142 xmlXPathMultValues(ctxt);
9143 else if (op->value == 1)
9144 xmlXPathDivValues(ctxt);
9145 else if (op->value == 2)
9146 xmlXPathModValues(ctxt);
9147 return (total);
9148 case XPATH_OP_UNION:
9149 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009150 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009151 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009152 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009153 CHECK_TYPE0(XPATH_NODESET);
9154 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009155
Daniel Veillardf06307e2001-07-03 10:35:50 +00009156 CHECK_TYPE0(XPATH_NODESET);
9157 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009158
Daniel Veillardf06307e2001-07-03 10:35:50 +00009159 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9160 arg2->nodesetval);
9161 valuePush(ctxt, arg1);
9162 xmlXPathFreeObject(arg2);
9163 return (total);
9164 case XPATH_OP_ROOT:
9165 xmlXPathRoot(ctxt);
9166 return (total);
9167 case XPATH_OP_NODE:
9168 if (op->ch1 != -1)
9169 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009170 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009171 if (op->ch2 != -1)
9172 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009173 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009174 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9175 return (total);
9176 case XPATH_OP_RESET:
9177 if (op->ch1 != -1)
9178 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009179 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009180 if (op->ch2 != -1)
9181 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009182 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009183 ctxt->context->node = NULL;
9184 return (total);
9185 case XPATH_OP_COLLECT:{
9186 if (op->ch1 == -1)
9187 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009188
Daniel Veillardf06307e2001-07-03 10:35:50 +00009189 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009190 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009191
Daniel Veillardf06307e2001-07-03 10:35:50 +00009192 /*
9193 * Optimization for [n] selection where n is a number
9194 */
9195 if ((op->ch2 != -1) &&
9196 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9197 (comp->steps[op->ch2].ch1 == -1) &&
9198 (comp->steps[op->ch2].ch2 != -1) &&
9199 (comp->steps[comp->steps[op->ch2].ch2].op ==
9200 XPATH_OP_VALUE)) {
9201 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00009202
Daniel Veillardf06307e2001-07-03 10:35:50 +00009203 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9204 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9205 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009206
Daniel Veillardf06307e2001-07-03 10:35:50 +00009207 if (val->floatval == (float) indx) {
9208 total +=
9209 xmlXPathNodeCollectAndTestNth(ctxt, op,
9210 indx, NULL,
9211 NULL);
9212 return (total);
9213 }
9214 }
9215 }
9216 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
9217 return (total);
9218 }
9219 case XPATH_OP_VALUE:
9220 valuePush(ctxt,
9221 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9222 return (total);
9223 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +00009224 xmlXPathObjectPtr val;
9225
Daniel Veillardf06307e2001-07-03 10:35:50 +00009226 if (op->ch1 != -1)
9227 total +=
9228 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009229 if (op->value5 == NULL) {
9230 val = xmlXPathVariableLookup(ctxt->context, op->value4);
9231 if (val == NULL) {
9232 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9233 return(0);
9234 }
9235 valuePush(ctxt, val);
9236 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009237 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009238
Daniel Veillardf06307e2001-07-03 10:35:50 +00009239 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9240 if (URI == NULL) {
9241 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009242 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009243 op->value4, op->value5);
9244 return (total);
9245 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009246 val = xmlXPathVariableLookupNS(ctxt->context,
9247 op->value4, URI);
9248 if (val == NULL) {
9249 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9250 return(0);
9251 }
9252 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009253 }
9254 return (total);
9255 }
9256 case XPATH_OP_FUNCTION:{
9257 xmlXPathFunction func;
9258 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +00009259 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009260
9261 if (op->ch1 != -1)
9262 total +=
9263 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009264 if (ctxt->valueNr < op->value) {
9265 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009266 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +00009267 ctxt->error = XPATH_INVALID_OPERAND;
9268 return (total);
9269 }
9270 for (i = 0; i < op->value; i++)
9271 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
9272 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009273 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +00009274 ctxt->error = XPATH_INVALID_OPERAND;
9275 return (total);
9276 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009277 if (op->cache != NULL)
9278 func = (xmlXPathFunction) op->cache;
9279 else {
9280 const xmlChar *URI = NULL;
9281
9282 if (op->value5 == NULL)
9283 func =
9284 xmlXPathFunctionLookup(ctxt->context,
9285 op->value4);
9286 else {
9287 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9288 if (URI == NULL) {
9289 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009290 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009291 op->value4, op->value5);
9292 return (total);
9293 }
9294 func = xmlXPathFunctionLookupNS(ctxt->context,
9295 op->value4, URI);
9296 }
9297 if (func == NULL) {
9298 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009299 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009300 op->value4);
9301 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009302 }
9303 op->cache = (void *) func;
9304 op->cacheURI = (void *) URI;
9305 }
9306 oldFunc = ctxt->context->function;
9307 oldFuncURI = ctxt->context->functionURI;
9308 ctxt->context->function = op->value4;
9309 ctxt->context->functionURI = op->cacheURI;
9310 func(ctxt, op->value);
9311 ctxt->context->function = oldFunc;
9312 ctxt->context->functionURI = oldFuncURI;
9313 return (total);
9314 }
9315 case XPATH_OP_ARG:
9316 if (op->ch1 != -1)
9317 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009318 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009319 if (op->ch2 != -1)
9320 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009321 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009322 return (total);
9323 case XPATH_OP_PREDICATE:
9324 case XPATH_OP_FILTER:{
9325 xmlXPathObjectPtr res;
9326 xmlXPathObjectPtr obj, tmp;
9327 xmlNodeSetPtr newset = NULL;
9328 xmlNodeSetPtr oldset;
9329 xmlNodePtr oldnode;
9330 int i;
9331
9332 /*
9333 * Optimization for ()[1] selection i.e. the first elem
9334 */
9335 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9336 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9337 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
9338 xmlXPathObjectPtr val;
9339
9340 val = comp->steps[op->ch2].value4;
9341 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
9342 (val->floatval == 1.0)) {
9343 xmlNodePtr first = NULL;
9344
9345 total +=
9346 xmlXPathCompOpEvalFirst(ctxt,
9347 &comp->steps[op->ch1],
9348 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009349 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009350 /*
9351 * The nodeset should be in document order,
9352 * Keep only the first value
9353 */
9354 if ((ctxt->value != NULL) &&
9355 (ctxt->value->type == XPATH_NODESET) &&
9356 (ctxt->value->nodesetval != NULL) &&
9357 (ctxt->value->nodesetval->nodeNr > 1))
9358 ctxt->value->nodesetval->nodeNr = 1;
9359 return (total);
9360 }
9361 }
9362 /*
9363 * Optimization for ()[last()] selection i.e. the last elem
9364 */
9365 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9366 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9367 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
9368 int f = comp->steps[op->ch2].ch1;
9369
9370 if ((f != -1) &&
9371 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
9372 (comp->steps[f].value5 == NULL) &&
9373 (comp->steps[f].value == 0) &&
9374 (comp->steps[f].value4 != NULL) &&
9375 (xmlStrEqual
9376 (comp->steps[f].value4, BAD_CAST "last"))) {
9377 xmlNodePtr last = NULL;
9378
9379 total +=
9380 xmlXPathCompOpEvalLast(ctxt,
9381 &comp->steps[op->ch1],
9382 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009383 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009384 /*
9385 * The nodeset should be in document order,
9386 * Keep only the last value
9387 */
9388 if ((ctxt->value != NULL) &&
9389 (ctxt->value->type == XPATH_NODESET) &&
9390 (ctxt->value->nodesetval != NULL) &&
9391 (ctxt->value->nodesetval->nodeTab != NULL) &&
9392 (ctxt->value->nodesetval->nodeNr > 1)) {
9393 ctxt->value->nodesetval->nodeTab[0] =
9394 ctxt->value->nodesetval->nodeTab[ctxt->
9395 value->
9396 nodesetval->
9397 nodeNr -
9398 1];
9399 ctxt->value->nodesetval->nodeNr = 1;
9400 }
9401 return (total);
9402 }
9403 }
9404
9405 if (op->ch1 != -1)
9406 total +=
9407 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009408 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009409 if (op->ch2 == -1)
9410 return (total);
9411 if (ctxt->value == NULL)
9412 return (total);
9413
9414 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009415
9416#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009417 /*
9418 * Hum are we filtering the result of an XPointer expression
9419 */
9420 if (ctxt->value->type == XPATH_LOCATIONSET) {
9421 xmlLocationSetPtr newlocset = NULL;
9422 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009423
Daniel Veillardf06307e2001-07-03 10:35:50 +00009424 /*
9425 * Extract the old locset, and then evaluate the result of the
9426 * expression for all the element in the locset. use it to grow
9427 * up a new locset.
9428 */
9429 CHECK_TYPE0(XPATH_LOCATIONSET);
9430 obj = valuePop(ctxt);
9431 oldlocset = obj->user;
9432 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009433
Daniel Veillardf06307e2001-07-03 10:35:50 +00009434 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
9435 ctxt->context->contextSize = 0;
9436 ctxt->context->proximityPosition = 0;
9437 if (op->ch2 != -1)
9438 total +=
9439 xmlXPathCompOpEval(ctxt,
9440 &comp->steps[op->ch2]);
9441 res = valuePop(ctxt);
9442 if (res != NULL)
9443 xmlXPathFreeObject(res);
9444 valuePush(ctxt, obj);
9445 CHECK_ERROR0;
9446 return (total);
9447 }
9448 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009449
Daniel Veillardf06307e2001-07-03 10:35:50 +00009450 for (i = 0; i < oldlocset->locNr; i++) {
9451 /*
9452 * Run the evaluation with a node list made of a
9453 * single item in the nodelocset.
9454 */
9455 ctxt->context->node = oldlocset->locTab[i]->user;
9456 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9457 valuePush(ctxt, tmp);
9458 ctxt->context->contextSize = oldlocset->locNr;
9459 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009460
Daniel Veillardf06307e2001-07-03 10:35:50 +00009461 if (op->ch2 != -1)
9462 total +=
9463 xmlXPathCompOpEval(ctxt,
9464 &comp->steps[op->ch2]);
9465 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009466
Daniel Veillardf06307e2001-07-03 10:35:50 +00009467 /*
9468 * The result of the evaluation need to be tested to
9469 * decided whether the filter succeeded or not
9470 */
9471 res = valuePop(ctxt);
9472 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9473 xmlXPtrLocationSetAdd(newlocset,
9474 xmlXPathObjectCopy
9475 (oldlocset->locTab[i]));
9476 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009477
Daniel Veillardf06307e2001-07-03 10:35:50 +00009478 /*
9479 * Cleanup
9480 */
9481 if (res != NULL)
9482 xmlXPathFreeObject(res);
9483 if (ctxt->value == tmp) {
9484 res = valuePop(ctxt);
9485 xmlXPathFreeObject(res);
9486 }
9487
9488 ctxt->context->node = NULL;
9489 }
9490
9491 /*
9492 * The result is used as the new evaluation locset.
9493 */
9494 xmlXPathFreeObject(obj);
9495 ctxt->context->node = NULL;
9496 ctxt->context->contextSize = -1;
9497 ctxt->context->proximityPosition = -1;
9498 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
9499 ctxt->context->node = oldnode;
9500 return (total);
9501 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009502#endif /* LIBXML_XPTR_ENABLED */
9503
Daniel Veillardf06307e2001-07-03 10:35:50 +00009504 /*
9505 * Extract the old set, and then evaluate the result of the
9506 * expression for all the element in the set. use it to grow
9507 * up a new set.
9508 */
9509 CHECK_TYPE0(XPATH_NODESET);
9510 obj = valuePop(ctxt);
9511 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00009512
Daniel Veillardf06307e2001-07-03 10:35:50 +00009513 oldnode = ctxt->context->node;
9514 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009515
Daniel Veillardf06307e2001-07-03 10:35:50 +00009516 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
9517 ctxt->context->contextSize = 0;
9518 ctxt->context->proximityPosition = 0;
9519 if (op->ch2 != -1)
9520 total +=
9521 xmlXPathCompOpEval(ctxt,
9522 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009523 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009524 res = valuePop(ctxt);
9525 if (res != NULL)
9526 xmlXPathFreeObject(res);
9527 valuePush(ctxt, obj);
9528 ctxt->context->node = oldnode;
9529 CHECK_ERROR0;
9530 } else {
9531 /*
9532 * Initialize the new set.
9533 */
9534 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009535
Daniel Veillardf06307e2001-07-03 10:35:50 +00009536 for (i = 0; i < oldset->nodeNr; i++) {
9537 /*
9538 * Run the evaluation with a node list made of
9539 * a single item in the nodeset.
9540 */
9541 ctxt->context->node = oldset->nodeTab[i];
9542 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9543 valuePush(ctxt, tmp);
9544 ctxt->context->contextSize = oldset->nodeNr;
9545 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009546
Daniel Veillardf06307e2001-07-03 10:35:50 +00009547 if (op->ch2 != -1)
9548 total +=
9549 xmlXPathCompOpEval(ctxt,
9550 &comp->steps[op->ch2]);
9551 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009552
Daniel Veillardf06307e2001-07-03 10:35:50 +00009553 /*
9554 * The result of the evaluation need to be tested to
9555 * decided whether the filter succeeded or not
9556 */
9557 res = valuePop(ctxt);
9558 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9559 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
9560 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009561
Daniel Veillardf06307e2001-07-03 10:35:50 +00009562 /*
9563 * Cleanup
9564 */
9565 if (res != NULL)
9566 xmlXPathFreeObject(res);
9567 if (ctxt->value == tmp) {
9568 res = valuePop(ctxt);
9569 xmlXPathFreeObject(res);
9570 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009571
Daniel Veillardf06307e2001-07-03 10:35:50 +00009572 ctxt->context->node = NULL;
9573 }
9574
9575 /*
9576 * The result is used as the new evaluation set.
9577 */
9578 xmlXPathFreeObject(obj);
9579 ctxt->context->node = NULL;
9580 ctxt->context->contextSize = -1;
9581 ctxt->context->proximityPosition = -1;
9582 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
9583 }
9584 ctxt->context->node = oldnode;
9585 return (total);
9586 }
9587 case XPATH_OP_SORT:
9588 if (op->ch1 != -1)
9589 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009590 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009591 if ((ctxt->value != NULL) &&
9592 (ctxt->value->type == XPATH_NODESET) &&
9593 (ctxt->value->nodesetval != NULL))
9594 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9595 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009596#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009597 case XPATH_OP_RANGETO:{
9598 xmlXPathObjectPtr range;
9599 xmlXPathObjectPtr res, obj;
9600 xmlXPathObjectPtr tmp;
9601 xmlLocationSetPtr newset = NULL;
9602 xmlNodeSetPtr oldset;
9603 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009604
Daniel Veillardf06307e2001-07-03 10:35:50 +00009605 if (op->ch1 != -1)
9606 total +=
9607 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9608 if (op->ch2 == -1)
9609 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009610
Daniel Veillardf06307e2001-07-03 10:35:50 +00009611 CHECK_TYPE0(XPATH_NODESET);
9612 obj = valuePop(ctxt);
9613 oldset = obj->nodesetval;
9614 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009615
Daniel Veillardf06307e2001-07-03 10:35:50 +00009616 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009617
Daniel Veillardf06307e2001-07-03 10:35:50 +00009618 if (oldset != NULL) {
9619 for (i = 0; i < oldset->nodeNr; i++) {
9620 /*
9621 * Run the evaluation with a node list made of a single item
9622 * in the nodeset.
9623 */
9624 ctxt->context->node = oldset->nodeTab[i];
9625 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9626 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009627
Daniel Veillardf06307e2001-07-03 10:35:50 +00009628 if (op->ch2 != -1)
9629 total +=
9630 xmlXPathCompOpEval(ctxt,
9631 &comp->steps[op->ch2]);
9632 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009633
Daniel Veillardf06307e2001-07-03 10:35:50 +00009634 /*
9635 * The result of the evaluation need to be tested to
9636 * decided whether the filter succeeded or not
9637 */
9638 res = valuePop(ctxt);
9639 range =
9640 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
9641 res);
9642 if (range != NULL) {
9643 xmlXPtrLocationSetAdd(newset, range);
9644 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009645
Daniel Veillardf06307e2001-07-03 10:35:50 +00009646 /*
9647 * Cleanup
9648 */
9649 if (res != NULL)
9650 xmlXPathFreeObject(res);
9651 if (ctxt->value == tmp) {
9652 res = valuePop(ctxt);
9653 xmlXPathFreeObject(res);
9654 }
9655
9656 ctxt->context->node = NULL;
9657 }
9658 }
9659
9660 /*
9661 * The result is used as the new evaluation set.
9662 */
9663 xmlXPathFreeObject(obj);
9664 ctxt->context->node = NULL;
9665 ctxt->context->contextSize = -1;
9666 ctxt->context->proximityPosition = -1;
9667 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
9668 return (total);
9669 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009670#endif /* LIBXML_XPTR_ENABLED */
9671 }
9672 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009673 "XPath: unknown precompiled operation %d\n", op->op);
9674 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009675}
9676
9677/**
9678 * xmlXPathRunEval:
9679 * @ctxt: the XPath parser context with the compiled expression
9680 *
9681 * Evaluate the Precompiled XPath expression in the given context.
9682 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009683static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009684xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
9685 xmlXPathCompExprPtr comp;
9686
9687 if ((ctxt == NULL) || (ctxt->comp == NULL))
9688 return;
9689
9690 if (ctxt->valueTab == NULL) {
9691 /* Allocate the value stack */
9692 ctxt->valueTab = (xmlXPathObjectPtr *)
9693 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
9694 if (ctxt->valueTab == NULL) {
9695 xmlFree(ctxt);
9696 xmlGenericError(xmlGenericErrorContext,
9697 "xmlXPathRunEval: out of memory\n");
9698 return;
9699 }
9700 ctxt->valueNr = 0;
9701 ctxt->valueMax = 10;
9702 ctxt->value = NULL;
9703 }
9704 comp = ctxt->comp;
9705 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
9706}
9707
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009708/************************************************************************
9709 * *
9710 * Public interfaces *
9711 * *
9712 ************************************************************************/
9713
9714/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009715 * xmlXPathEvalPredicate:
9716 * @ctxt: the XPath context
9717 * @res: the Predicate Expression evaluation result
9718 *
9719 * Evaluate a predicate result for the current node.
9720 * A PredicateExpr is evaluated by evaluating the Expr and converting
9721 * the result to a boolean. If the result is a number, the result will
9722 * be converted to true if the number is equal to the position of the
9723 * context node in the context node list (as returned by the position
9724 * function) and will be converted to false otherwise; if the result
9725 * is not a number, then the result will be converted as if by a call
9726 * to the boolean function.
9727 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009728 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009729 */
9730int
9731xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
9732 if (res == NULL) return(0);
9733 switch (res->type) {
9734 case XPATH_BOOLEAN:
9735 return(res->boolval);
9736 case XPATH_NUMBER:
9737 return(res->floatval == ctxt->proximityPosition);
9738 case XPATH_NODESET:
9739 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009740 if (res->nodesetval == NULL)
9741 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009742 return(res->nodesetval->nodeNr != 0);
9743 case XPATH_STRING:
9744 return((res->stringval != NULL) &&
9745 (xmlStrlen(res->stringval) != 0));
9746 default:
9747 STRANGE
9748 }
9749 return(0);
9750}
9751
9752/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009753 * xmlXPathEvaluatePredicateResult:
9754 * @ctxt: the XPath Parser context
9755 * @res: the Predicate Expression evaluation result
9756 *
9757 * Evaluate a predicate result for the current node.
9758 * A PredicateExpr is evaluated by evaluating the Expr and converting
9759 * the result to a boolean. If the result is a number, the result will
9760 * be converted to true if the number is equal to the position of the
9761 * context node in the context node list (as returned by the position
9762 * function) and will be converted to false otherwise; if the result
9763 * is not a number, then the result will be converted as if by a call
9764 * to the boolean function.
9765 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009766 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009767 */
9768int
9769xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
9770 xmlXPathObjectPtr res) {
9771 if (res == NULL) return(0);
9772 switch (res->type) {
9773 case XPATH_BOOLEAN:
9774 return(res->boolval);
9775 case XPATH_NUMBER:
9776 return(res->floatval == ctxt->context->proximityPosition);
9777 case XPATH_NODESET:
9778 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +00009779 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +00009780 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009781 return(res->nodesetval->nodeNr != 0);
9782 case XPATH_STRING:
9783 return((res->stringval != NULL) &&
9784 (xmlStrlen(res->stringval) != 0));
9785 default:
9786 STRANGE
9787 }
9788 return(0);
9789}
9790
9791/**
9792 * xmlXPathCompile:
9793 * @str: the XPath expression
9794 *
9795 * Compile an XPath expression
9796 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009797 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009798 * the caller has to free the object.
9799 */
9800xmlXPathCompExprPtr
9801xmlXPathCompile(const xmlChar *str) {
9802 xmlXPathParserContextPtr ctxt;
9803 xmlXPathCompExprPtr comp;
9804
9805 xmlXPathInit();
9806
9807 ctxt = xmlXPathNewParserContext(str, NULL);
9808 xmlXPathCompileExpr(ctxt);
9809
Daniel Veillard40af6492001-04-22 08:50:55 +00009810 if (*ctxt->cur != 0) {
9811 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9812 comp = NULL;
9813 } else {
9814 comp = ctxt->comp;
9815 ctxt->comp = NULL;
9816 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009817 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009818#ifdef DEBUG_EVAL_COUNTS
9819 if (comp != NULL) {
9820 comp->string = xmlStrdup(str);
9821 comp->nb = 0;
9822 }
9823#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009824 return(comp);
9825}
9826
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009827/**
9828 * xmlXPathCompiledEval:
9829 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +00009830 * @ctx: the XPath context
9831 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009832 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +00009833 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009834 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +00009835 * the caller has to free the object.
9836 */
9837xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009838xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +00009839 xmlXPathParserContextPtr ctxt;
9840 xmlXPathObjectPtr res, tmp, init = NULL;
9841 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +00009842#ifndef LIBXML_THREAD_ENABLED
9843 static int reentance = 0;
9844#endif
Owen Taylor3473f882001-02-23 17:55:21 +00009845
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009846 if ((comp == NULL) || (ctx == NULL))
9847 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00009848 xmlXPathInit();
9849
9850 CHECK_CONTEXT(ctx)
9851
Daniel Veillard81463942001-10-16 12:34:39 +00009852#ifndef LIBXML_THREAD_ENABLED
9853 reentance++;
9854 if (reentance > 1)
9855 xmlXPathDisableOptimizer = 1;
9856#endif
9857
Daniel Veillardf06307e2001-07-03 10:35:50 +00009858#ifdef DEBUG_EVAL_COUNTS
9859 comp->nb++;
9860 if ((comp->string != NULL) && (comp->nb > 100)) {
9861 fprintf(stderr, "100 x %s\n", comp->string);
9862 comp->nb = 0;
9863 }
9864#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009865 ctxt = xmlXPathCompParserContext(comp, ctx);
9866 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009867
9868 if (ctxt->value == NULL) {
9869 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009870 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00009871 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009872 } else {
9873 res = valuePop(ctxt);
9874 }
9875
Daniel Veillardf06307e2001-07-03 10:35:50 +00009876
Owen Taylor3473f882001-02-23 17:55:21 +00009877 do {
9878 tmp = valuePop(ctxt);
9879 if (tmp != NULL) {
9880 if (tmp != init)
9881 stack++;
9882 xmlXPathFreeObject(tmp);
9883 }
9884 } while (tmp != NULL);
9885 if ((stack != 0) && (res != NULL)) {
9886 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009887 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +00009888 stack);
9889 }
9890 if (ctxt->error != XPATH_EXPRESSION_OK) {
9891 xmlXPathFreeObject(res);
9892 res = NULL;
9893 }
9894
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009895
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009896 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009897 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +00009898#ifndef LIBXML_THREAD_ENABLED
9899 reentance--;
9900#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009901 return(res);
9902}
9903
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009904/**
9905 * xmlXPathEvalExpr:
9906 * @ctxt: the XPath Parser context
9907 *
9908 * Parse and evaluate an XPath expression in the given context,
9909 * then push the result on the context stack
9910 */
9911void
9912xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
9913 xmlXPathCompileExpr(ctxt);
9914 xmlXPathRunEval(ctxt);
9915}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009916
9917/**
9918 * xmlXPathEval:
9919 * @str: the XPath expression
9920 * @ctx: the XPath context
9921 *
9922 * Evaluate the XPath Location Path in the given context.
9923 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009924 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009925 * the caller has to free the object.
9926 */
9927xmlXPathObjectPtr
9928xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
9929 xmlXPathParserContextPtr ctxt;
9930 xmlXPathObjectPtr res, tmp, init = NULL;
9931 int stack = 0;
9932
9933 xmlXPathInit();
9934
9935 CHECK_CONTEXT(ctx)
9936
9937 ctxt = xmlXPathNewParserContext(str, ctx);
9938 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009939
9940 if (ctxt->value == NULL) {
9941 xmlGenericError(xmlGenericErrorContext,
9942 "xmlXPathEval: evaluation failed\n");
9943 res = NULL;
9944 } else if (*ctxt->cur != 0) {
9945 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9946 res = NULL;
9947 } else {
9948 res = valuePop(ctxt);
9949 }
9950
9951 do {
9952 tmp = valuePop(ctxt);
9953 if (tmp != NULL) {
9954 if (tmp != init)
9955 stack++;
9956 xmlXPathFreeObject(tmp);
9957 }
9958 } while (tmp != NULL);
9959 if ((stack != 0) && (res != NULL)) {
9960 xmlGenericError(xmlGenericErrorContext,
9961 "xmlXPathEval: %d object left on the stack\n",
9962 stack);
9963 }
9964 if (ctxt->error != XPATH_EXPRESSION_OK) {
9965 xmlXPathFreeObject(res);
9966 res = NULL;
9967 }
9968
Owen Taylor3473f882001-02-23 17:55:21 +00009969 xmlXPathFreeParserContext(ctxt);
9970 return(res);
9971}
9972
9973/**
9974 * xmlXPathEvalExpression:
9975 * @str: the XPath expression
9976 * @ctxt: the XPath context
9977 *
9978 * Evaluate the XPath expression in the given context.
9979 *
9980 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
9981 * the caller has to free the object.
9982 */
9983xmlXPathObjectPtr
9984xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
9985 xmlXPathParserContextPtr pctxt;
9986 xmlXPathObjectPtr res, tmp;
9987 int stack = 0;
9988
9989 xmlXPathInit();
9990
9991 CHECK_CONTEXT(ctxt)
9992
9993 pctxt = xmlXPathNewParserContext(str, ctxt);
9994 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009995
9996 if (*pctxt->cur != 0) {
9997 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9998 res = NULL;
9999 } else {
10000 res = valuePop(pctxt);
10001 }
10002 do {
10003 tmp = valuePop(pctxt);
10004 if (tmp != NULL) {
10005 xmlXPathFreeObject(tmp);
10006 stack++;
10007 }
10008 } while (tmp != NULL);
10009 if ((stack != 0) && (res != NULL)) {
10010 xmlGenericError(xmlGenericErrorContext,
10011 "xmlXPathEvalExpression: %d object left on the stack\n",
10012 stack);
10013 }
10014 xmlXPathFreeParserContext(pctxt);
10015 return(res);
10016}
10017
10018/**
10019 * xmlXPathRegisterAllFunctions:
10020 * @ctxt: the XPath context
10021 *
10022 * Registers all default XPath functions in this context
10023 */
10024void
10025xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
10026{
10027 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
10028 xmlXPathBooleanFunction);
10029 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
10030 xmlXPathCeilingFunction);
10031 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
10032 xmlXPathCountFunction);
10033 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
10034 xmlXPathConcatFunction);
10035 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
10036 xmlXPathContainsFunction);
10037 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
10038 xmlXPathIdFunction);
10039 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
10040 xmlXPathFalseFunction);
10041 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
10042 xmlXPathFloorFunction);
10043 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
10044 xmlXPathLastFunction);
10045 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
10046 xmlXPathLangFunction);
10047 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
10048 xmlXPathLocalNameFunction);
10049 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
10050 xmlXPathNotFunction);
10051 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
10052 xmlXPathNameFunction);
10053 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
10054 xmlXPathNamespaceURIFunction);
10055 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
10056 xmlXPathNormalizeFunction);
10057 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
10058 xmlXPathNumberFunction);
10059 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
10060 xmlXPathPositionFunction);
10061 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
10062 xmlXPathRoundFunction);
10063 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
10064 xmlXPathStringFunction);
10065 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
10066 xmlXPathStringLengthFunction);
10067 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
10068 xmlXPathStartsWithFunction);
10069 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
10070 xmlXPathSubstringFunction);
10071 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
10072 xmlXPathSubstringBeforeFunction);
10073 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
10074 xmlXPathSubstringAfterFunction);
10075 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
10076 xmlXPathSumFunction);
10077 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
10078 xmlXPathTrueFunction);
10079 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
10080 xmlXPathTranslateFunction);
10081}
10082
10083#endif /* LIBXML_XPATH_ENABLED */