blob: 8e3adb67407f172e3efa35d522ff3cac1af2e496 [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;
2294
2295 ret = ((xmlXPathFuncLookupFunc) ctxt->funcLookupFunc)
2296 (ctxt->funcLookupData, name, NULL);
2297 if (ret != NULL)
2298 return(ret);
2299 }
Owen Taylor3473f882001-02-23 17:55:21 +00002300 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2301}
2302
2303/**
2304 * xmlXPathFunctionLookupNS:
2305 * @ctxt: the XPath context
2306 * @name: the function name
2307 * @ns_uri: the function namespace URI
2308 *
2309 * Search in the Function array of the context for the given
2310 * function.
2311 *
2312 * Returns the xmlXPathFunction or NULL if not found
2313 */
2314xmlXPathFunction
2315xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2316 const xmlChar *ns_uri) {
2317 if (ctxt == NULL)
2318 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002319 if (name == NULL)
2320 return(NULL);
2321
Thomas Broyerba4ad322001-07-26 16:55:21 +00002322 if (ctxt->funcLookupFunc != NULL) {
2323 xmlXPathFunction ret;
2324
2325 ret = ((xmlXPathFuncLookupFunc) ctxt->funcLookupFunc)
2326 (ctxt->funcLookupData, name, ns_uri);
2327 if (ret != NULL)
2328 return(ret);
2329 }
2330
2331 if (ctxt->funcHash == NULL)
2332 return(NULL);
2333
Owen Taylor3473f882001-02-23 17:55:21 +00002334 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2335}
2336
2337/**
2338 * xmlXPathRegisteredFuncsCleanup:
2339 * @ctxt: the XPath context
2340 *
2341 * Cleanup the XPath context data associated to registered functions
2342 */
2343void
2344xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2345 if (ctxt == NULL)
2346 return;
2347
2348 xmlHashFree(ctxt->funcHash, NULL);
2349 ctxt->funcHash = NULL;
2350}
2351
2352/************************************************************************
2353 * *
2354 * Routines to handle Variable *
2355 * *
2356 ************************************************************************/
2357
2358/**
2359 * xmlXPathRegisterVariable:
2360 * @ctxt: the XPath context
2361 * @name: the variable name
2362 * @value: the variable value or NULL
2363 *
2364 * Register a new variable value. If @value is NULL it unregisters
2365 * the variable
2366 *
2367 * Returns 0 in case of success, -1 in case of error
2368 */
2369int
2370xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2371 xmlXPathObjectPtr value) {
2372 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2373}
2374
2375/**
2376 * xmlXPathRegisterVariableNS:
2377 * @ctxt: the XPath context
2378 * @name: the variable name
2379 * @ns_uri: the variable namespace URI
2380 * @value: the variable value or NULL
2381 *
2382 * Register a new variable value. If @value is NULL it unregisters
2383 * the variable
2384 *
2385 * Returns 0 in case of success, -1 in case of error
2386 */
2387int
2388xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2389 const xmlChar *ns_uri,
2390 xmlXPathObjectPtr value) {
2391 if (ctxt == NULL)
2392 return(-1);
2393 if (name == NULL)
2394 return(-1);
2395
2396 if (ctxt->varHash == NULL)
2397 ctxt->varHash = xmlHashCreate(0);
2398 if (ctxt->varHash == NULL)
2399 return(-1);
2400 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2401 (void *) value,
2402 (xmlHashDeallocator)xmlXPathFreeObject));
2403}
2404
2405/**
2406 * xmlXPathRegisterVariableLookup:
2407 * @ctxt: the XPath context
2408 * @f: the lookup function
2409 * @data: the lookup data
2410 *
2411 * register an external mechanism to do variable lookup
2412 */
2413void
2414xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2415 xmlXPathVariableLookupFunc f, void *data) {
2416 if (ctxt == NULL)
2417 return;
2418 ctxt->varLookupFunc = (void *) f;
2419 ctxt->varLookupData = data;
2420}
2421
2422/**
2423 * xmlXPathVariableLookup:
2424 * @ctxt: the XPath context
2425 * @name: the variable name
2426 *
2427 * Search in the Variable array of the context for the given
2428 * variable value.
2429 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002430 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002431 */
2432xmlXPathObjectPtr
2433xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2434 if (ctxt == NULL)
2435 return(NULL);
2436
2437 if (ctxt->varLookupFunc != NULL) {
2438 xmlXPathObjectPtr ret;
2439
2440 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2441 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002442 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002443 }
2444 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2445}
2446
2447/**
2448 * xmlXPathVariableLookupNS:
2449 * @ctxt: the XPath context
2450 * @name: the variable name
2451 * @ns_uri: the variable namespace URI
2452 *
2453 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002454 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002455 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002456 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002457 */
2458xmlXPathObjectPtr
2459xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2460 const xmlChar *ns_uri) {
2461 if (ctxt == NULL)
2462 return(NULL);
2463
2464 if (ctxt->varLookupFunc != NULL) {
2465 xmlXPathObjectPtr ret;
2466
2467 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2468 (ctxt->varLookupData, name, ns_uri);
2469 if (ret != NULL) return(ret);
2470 }
2471
2472 if (ctxt->varHash == NULL)
2473 return(NULL);
2474 if (name == NULL)
2475 return(NULL);
2476
Daniel Veillard8c357d52001-07-03 23:43:33 +00002477 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2478 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002479}
2480
2481/**
2482 * xmlXPathRegisteredVariablesCleanup:
2483 * @ctxt: the XPath context
2484 *
2485 * Cleanup the XPath context data associated to registered variables
2486 */
2487void
2488xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2489 if (ctxt == NULL)
2490 return;
2491
Daniel Veillard76d66f42001-05-16 21:05:17 +00002492 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002493 ctxt->varHash = NULL;
2494}
2495
2496/**
2497 * xmlXPathRegisterNs:
2498 * @ctxt: the XPath context
2499 * @prefix: the namespace prefix
2500 * @ns_uri: the namespace name
2501 *
2502 * Register a new namespace. If @ns_uri is NULL it unregisters
2503 * the namespace
2504 *
2505 * Returns 0 in case of success, -1 in case of error
2506 */
2507int
2508xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2509 const xmlChar *ns_uri) {
2510 if (ctxt == NULL)
2511 return(-1);
2512 if (prefix == NULL)
2513 return(-1);
2514
2515 if (ctxt->nsHash == NULL)
2516 ctxt->nsHash = xmlHashCreate(10);
2517 if (ctxt->nsHash == NULL)
2518 return(-1);
2519 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) ns_uri,
2520 (xmlHashDeallocator)xmlFree));
2521}
2522
2523/**
2524 * xmlXPathNsLookup:
2525 * @ctxt: the XPath context
2526 * @prefix: the namespace prefix value
2527 *
2528 * Search in the namespace declaration array of the context for the given
2529 * namespace name associated to the given prefix
2530 *
2531 * Returns the value or NULL if not found
2532 */
2533const xmlChar *
2534xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2535 if (ctxt == NULL)
2536 return(NULL);
2537 if (prefix == NULL)
2538 return(NULL);
2539
2540#ifdef XML_XML_NAMESPACE
2541 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
2542 return(XML_XML_NAMESPACE);
2543#endif
2544
Daniel Veillardc8f620b2001-04-30 20:31:33 +00002545 if (ctxt->namespaces != NULL) {
2546 int i;
2547
2548 for (i = 0;i < ctxt->nsNr;i++) {
2549 if ((ctxt->namespaces[i] != NULL) &&
2550 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
2551 return(ctxt->namespaces[i]->href);
2552 }
2553 }
Owen Taylor3473f882001-02-23 17:55:21 +00002554
2555 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
2556}
2557
2558/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002559 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00002560 * @ctxt: the XPath context
2561 *
2562 * Cleanup the XPath context data associated to registered variables
2563 */
2564void
2565xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2566 if (ctxt == NULL)
2567 return;
2568
2569 xmlHashFree(ctxt->nsHash, NULL);
2570 ctxt->nsHash = NULL;
2571}
2572
2573/************************************************************************
2574 * *
2575 * Routines to handle Values *
2576 * *
2577 ************************************************************************/
2578
2579/* Allocations are terrible, one need to optimize all this !!! */
2580
2581/**
2582 * xmlXPathNewFloat:
2583 * @val: the double value
2584 *
2585 * Create a new xmlXPathObjectPtr of type double and of value @val
2586 *
2587 * Returns the newly created object.
2588 */
2589xmlXPathObjectPtr
2590xmlXPathNewFloat(double val) {
2591 xmlXPathObjectPtr ret;
2592
2593 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2594 if (ret == NULL) {
2595 xmlGenericError(xmlGenericErrorContext,
2596 "xmlXPathNewFloat: out of memory\n");
2597 return(NULL);
2598 }
2599 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2600 ret->type = XPATH_NUMBER;
2601 ret->floatval = val;
2602 return(ret);
2603}
2604
2605/**
2606 * xmlXPathNewBoolean:
2607 * @val: the boolean value
2608 *
2609 * Create a new xmlXPathObjectPtr of type boolean and of value @val
2610 *
2611 * Returns the newly created object.
2612 */
2613xmlXPathObjectPtr
2614xmlXPathNewBoolean(int val) {
2615 xmlXPathObjectPtr ret;
2616
2617 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2618 if (ret == NULL) {
2619 xmlGenericError(xmlGenericErrorContext,
2620 "xmlXPathNewBoolean: out of memory\n");
2621 return(NULL);
2622 }
2623 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2624 ret->type = XPATH_BOOLEAN;
2625 ret->boolval = (val != 0);
2626 return(ret);
2627}
2628
2629/**
2630 * xmlXPathNewString:
2631 * @val: the xmlChar * value
2632 *
2633 * Create a new xmlXPathObjectPtr of type string and of value @val
2634 *
2635 * Returns the newly created object.
2636 */
2637xmlXPathObjectPtr
2638xmlXPathNewString(const xmlChar *val) {
2639 xmlXPathObjectPtr ret;
2640
2641 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2642 if (ret == NULL) {
2643 xmlGenericError(xmlGenericErrorContext,
2644 "xmlXPathNewString: out of memory\n");
2645 return(NULL);
2646 }
2647 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2648 ret->type = XPATH_STRING;
2649 if (val != NULL)
2650 ret->stringval = xmlStrdup(val);
2651 else
2652 ret->stringval = xmlStrdup((const xmlChar *)"");
2653 return(ret);
2654}
2655
2656/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002657 * xmlXPathWrapString:
2658 * @val: the xmlChar * value
2659 *
2660 * Wraps the @val string into an XPath object.
2661 *
2662 * Returns the newly created object.
2663 */
2664xmlXPathObjectPtr
2665xmlXPathWrapString (xmlChar *val) {
2666 xmlXPathObjectPtr ret;
2667
2668 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2669 if (ret == NULL) {
2670 xmlGenericError(xmlGenericErrorContext,
2671 "xmlXPathWrapString: out of memory\n");
2672 return(NULL);
2673 }
2674 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2675 ret->type = XPATH_STRING;
2676 ret->stringval = val;
2677 return(ret);
2678}
2679
2680/**
Owen Taylor3473f882001-02-23 17:55:21 +00002681 * xmlXPathNewCString:
2682 * @val: the char * value
2683 *
2684 * Create a new xmlXPathObjectPtr of type string and of value @val
2685 *
2686 * Returns the newly created object.
2687 */
2688xmlXPathObjectPtr
2689xmlXPathNewCString(const char *val) {
2690 xmlXPathObjectPtr ret;
2691
2692 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2693 if (ret == NULL) {
2694 xmlGenericError(xmlGenericErrorContext,
2695 "xmlXPathNewCString: out of memory\n");
2696 return(NULL);
2697 }
2698 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2699 ret->type = XPATH_STRING;
2700 ret->stringval = xmlStrdup(BAD_CAST val);
2701 return(ret);
2702}
2703
2704/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002705 * xmlXPathWrapCString:
2706 * @val: the char * value
2707 *
2708 * Wraps a string into an XPath object.
2709 *
2710 * Returns the newly created object.
2711 */
2712xmlXPathObjectPtr
2713xmlXPathWrapCString (char * val) {
2714 return(xmlXPathWrapString((xmlChar *)(val)));
2715}
2716
2717/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002718 * xmlXPathWrapExternal:
2719 * @val: the user data
2720 *
2721 * Wraps the @val data into an XPath object.
2722 *
2723 * Returns the newly created object.
2724 */
2725xmlXPathObjectPtr
2726xmlXPathWrapExternal (void *val) {
2727 xmlXPathObjectPtr ret;
2728
2729 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2730 if (ret == NULL) {
2731 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002732 "xmlXPathWrapExternal: out of memory\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002733 return(NULL);
2734 }
2735 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2736 ret->type = XPATH_USERS;
2737 ret->user = val;
2738 return(ret);
2739}
2740
2741/**
Owen Taylor3473f882001-02-23 17:55:21 +00002742 * xmlXPathObjectCopy:
2743 * @val: the original object
2744 *
2745 * allocate a new copy of a given object
2746 *
2747 * Returns the newly created object.
2748 */
2749xmlXPathObjectPtr
2750xmlXPathObjectCopy(xmlXPathObjectPtr val) {
2751 xmlXPathObjectPtr ret;
2752
2753 if (val == NULL)
2754 return(NULL);
2755
2756 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2757 if (ret == NULL) {
2758 xmlGenericError(xmlGenericErrorContext,
2759 "xmlXPathObjectCopy: out of memory\n");
2760 return(NULL);
2761 }
2762 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
2763 switch (val->type) {
2764 case XPATH_BOOLEAN:
2765 case XPATH_NUMBER:
2766 case XPATH_POINT:
2767 case XPATH_RANGE:
2768 break;
2769 case XPATH_STRING:
2770 ret->stringval = xmlStrdup(val->stringval);
2771 break;
2772 case XPATH_XSLT_TREE:
2773 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002774 (val->nodesetval->nodeTab != NULL)) {
2775 ret->boolval = 1;
Daniel Veillard6ab38382001-10-06 13:08:27 +00002776 ret->user = xmlDocCopyNode(val->nodesetval->nodeTab[0],
2777 val->nodesetval->nodeTab[0]->doc, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00002778 ret->nodesetval = xmlXPathNodeSetCreate(
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002779 (xmlNodePtr) ret->user);
2780 } else
Owen Taylor3473f882001-02-23 17:55:21 +00002781 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002782 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00002783 break;
2784 case XPATH_NODESET:
2785 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002786 /* Do not deallocate the copied tree value */
2787 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002788 break;
2789 case XPATH_LOCATIONSET:
2790#ifdef LIBXML_XPTR_ENABLED
2791 {
2792 xmlLocationSetPtr loc = val->user;
2793 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
2794 break;
2795 }
2796#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00002797 case XPATH_USERS:
2798 ret->user = val->user;
2799 break;
2800 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00002801 xmlGenericError(xmlGenericErrorContext,
2802 "xmlXPathObjectCopy: unsupported type %d\n",
2803 val->type);
2804 break;
2805 }
2806 return(ret);
2807}
2808
2809/**
2810 * xmlXPathFreeObject:
2811 * @obj: the object to free
2812 *
2813 * Free up an xmlXPathObjectPtr object.
2814 */
2815void
2816xmlXPathFreeObject(xmlXPathObjectPtr obj) {
2817 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002818 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00002819 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002820 if (obj->user != NULL) {
2821 xmlFreeNodeList((xmlNodePtr) obj->user);
2822 xmlXPathFreeNodeSet(obj->nodesetval);
2823 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00002824 xmlXPathFreeValueTree(obj->nodesetval);
2825 } else {
2826 if (obj->nodesetval != NULL)
2827 xmlXPathFreeNodeSet(obj->nodesetval);
2828 }
Owen Taylor3473f882001-02-23 17:55:21 +00002829#ifdef LIBXML_XPTR_ENABLED
2830 } else if (obj->type == XPATH_LOCATIONSET) {
2831 if (obj->user != NULL)
2832 xmlXPtrFreeLocationSet(obj->user);
2833#endif
2834 } else if (obj->type == XPATH_STRING) {
2835 if (obj->stringval != NULL)
2836 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00002837 }
2838
Owen Taylor3473f882001-02-23 17:55:21 +00002839 xmlFree(obj);
2840}
2841
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002842
2843/************************************************************************
2844 * *
2845 * Type Casting Routines *
2846 * *
2847 ************************************************************************/
2848
2849/**
2850 * xmlXPathCastBooleanToString:
2851 * @val: a boolean
2852 *
2853 * Converts a boolean to its string value.
2854 *
2855 * Returns a newly allocated string.
2856 */
2857xmlChar *
2858xmlXPathCastBooleanToString (int val) {
2859 xmlChar *ret;
2860 if (val)
2861 ret = xmlStrdup((const xmlChar *) "true");
2862 else
2863 ret = xmlStrdup((const xmlChar *) "false");
2864 return(ret);
2865}
2866
2867/**
2868 * xmlXPathCastNumberToString:
2869 * @val: a number
2870 *
2871 * Converts a number to its string value.
2872 *
2873 * Returns a newly allocated string.
2874 */
2875xmlChar *
2876xmlXPathCastNumberToString (double val) {
2877 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00002878 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002879 case 1:
2880 ret = xmlStrdup((const xmlChar *) "+Infinity");
2881 break;
2882 case -1:
2883 ret = xmlStrdup((const xmlChar *) "-Infinity");
2884 break;
2885 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00002886 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002887 ret = xmlStrdup((const xmlChar *) "NaN");
2888 } else {
2889 /* could be improved */
2890 char buf[100];
2891 xmlXPathFormatNumber(val, buf, 100);
2892 ret = xmlStrdup((const xmlChar *) buf);
2893 }
2894 }
2895 return(ret);
2896}
2897
2898/**
2899 * xmlXPathCastNodeToString:
2900 * @node: a node
2901 *
2902 * Converts a node to its string value.
2903 *
2904 * Returns a newly allocated string.
2905 */
2906xmlChar *
2907xmlXPathCastNodeToString (xmlNodePtr node) {
2908 return(xmlNodeGetContent(node));
2909}
2910
2911/**
2912 * xmlXPathCastNodeSetToString:
2913 * @ns: a node-set
2914 *
2915 * Converts a node-set to its string value.
2916 *
2917 * Returns a newly allocated string.
2918 */
2919xmlChar *
2920xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
2921 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
2922 return(xmlStrdup((const xmlChar *) ""));
2923
2924 xmlXPathNodeSetSort(ns);
2925 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
2926}
2927
2928/**
2929 * xmlXPathCastToString:
2930 * @val: an XPath object
2931 *
2932 * Converts an existing object to its string() equivalent
2933 *
2934 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002935 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002936 * string object).
2937 */
2938xmlChar *
2939xmlXPathCastToString(xmlXPathObjectPtr val) {
2940 xmlChar *ret = NULL;
2941
2942 if (val == NULL)
2943 return(xmlStrdup((const xmlChar *) ""));
2944 switch (val->type) {
2945 case XPATH_UNDEFINED:
2946#ifdef DEBUG_EXPR
2947 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
2948#endif
2949 ret = xmlStrdup((const xmlChar *) "");
2950 break;
2951 case XPATH_XSLT_TREE:
2952 case XPATH_NODESET:
2953 ret = xmlXPathCastNodeSetToString(val->nodesetval);
2954 break;
2955 case XPATH_STRING:
2956 return(val->stringval);
2957 case XPATH_BOOLEAN:
2958 ret = xmlXPathCastBooleanToString(val->boolval);
2959 break;
2960 case XPATH_NUMBER: {
2961 ret = xmlXPathCastNumberToString(val->floatval);
2962 break;
2963 }
2964 case XPATH_USERS:
2965 case XPATH_POINT:
2966 case XPATH_RANGE:
2967 case XPATH_LOCATIONSET:
2968 TODO
2969 ret = xmlStrdup((const xmlChar *) "");
2970 break;
2971 }
2972 return(ret);
2973}
2974
2975/**
2976 * xmlXPathConvertString:
2977 * @val: an XPath object
2978 *
2979 * Converts an existing object to its string() equivalent
2980 *
2981 * Returns the new object, the old one is freed (or the operation
2982 * is done directly on @val)
2983 */
2984xmlXPathObjectPtr
2985xmlXPathConvertString(xmlXPathObjectPtr val) {
2986 xmlChar *res = NULL;
2987
2988 if (val == NULL)
2989 return(xmlXPathNewCString(""));
2990
2991 switch (val->type) {
2992 case XPATH_UNDEFINED:
2993#ifdef DEBUG_EXPR
2994 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2995#endif
2996 break;
2997 case XPATH_XSLT_TREE:
2998 case XPATH_NODESET:
2999 res = xmlXPathCastNodeSetToString(val->nodesetval);
3000 break;
3001 case XPATH_STRING:
3002 return(val);
3003 case XPATH_BOOLEAN:
3004 res = xmlXPathCastBooleanToString(val->boolval);
3005 break;
3006 case XPATH_NUMBER:
3007 res = xmlXPathCastNumberToString(val->floatval);
3008 break;
3009 case XPATH_USERS:
3010 case XPATH_POINT:
3011 case XPATH_RANGE:
3012 case XPATH_LOCATIONSET:
3013 TODO;
3014 break;
3015 }
3016 xmlXPathFreeObject(val);
3017 if (res == NULL)
3018 return(xmlXPathNewCString(""));
3019 return(xmlXPathWrapString(res));
3020}
3021
3022/**
3023 * xmlXPathCastBooleanToNumber:
3024 * @val: a boolean
3025 *
3026 * Converts a boolean to its number value
3027 *
3028 * Returns the number value
3029 */
3030double
3031xmlXPathCastBooleanToNumber(int val) {
3032 if (val)
3033 return(1.0);
3034 return(0.0);
3035}
3036
3037/**
3038 * xmlXPathCastStringToNumber:
3039 * @val: a string
3040 *
3041 * Converts a string to its number value
3042 *
3043 * Returns the number value
3044 */
3045double
3046xmlXPathCastStringToNumber(const xmlChar * val) {
3047 return(xmlXPathStringEvalNumber(val));
3048}
3049
3050/**
3051 * xmlXPathCastNodeToNumber:
3052 * @node: a node
3053 *
3054 * Converts a node to its number value
3055 *
3056 * Returns the number value
3057 */
3058double
3059xmlXPathCastNodeToNumber (xmlNodePtr node) {
3060 xmlChar *strval;
3061 double ret;
3062
3063 if (node == NULL)
3064 return(xmlXPathNAN);
3065 strval = xmlXPathCastNodeToString(node);
3066 if (strval == NULL)
3067 return(xmlXPathNAN);
3068 ret = xmlXPathCastStringToNumber(strval);
3069 xmlFree(strval);
3070
3071 return(ret);
3072}
3073
3074/**
3075 * xmlXPathCastNodeSetToNumber:
3076 * @ns: a node-set
3077 *
3078 * Converts a node-set to its number value
3079 *
3080 * Returns the number value
3081 */
3082double
3083xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3084 xmlChar *str;
3085 double ret;
3086
3087 if (ns == NULL)
3088 return(xmlXPathNAN);
3089 str = xmlXPathCastNodeSetToString(ns);
3090 ret = xmlXPathCastStringToNumber(str);
3091 xmlFree(str);
3092 return(ret);
3093}
3094
3095/**
3096 * xmlXPathCastToNumber:
3097 * @val: an XPath object
3098 *
3099 * Converts an XPath object to its number value
3100 *
3101 * Returns the number value
3102 */
3103double
3104xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3105 double ret = 0.0;
3106
3107 if (val == NULL)
3108 return(xmlXPathNAN);
3109 switch (val->type) {
3110 case XPATH_UNDEFINED:
3111#ifdef DEGUB_EXPR
3112 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3113#endif
3114 ret = xmlXPathNAN;
3115 break;
3116 case XPATH_XSLT_TREE:
3117 case XPATH_NODESET:
3118 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3119 break;
3120 case XPATH_STRING:
3121 ret = xmlXPathCastStringToNumber(val->stringval);
3122 break;
3123 case XPATH_NUMBER:
3124 ret = val->floatval;
3125 break;
3126 case XPATH_BOOLEAN:
3127 ret = xmlXPathCastBooleanToNumber(val->boolval);
3128 break;
3129 case XPATH_USERS:
3130 case XPATH_POINT:
3131 case XPATH_RANGE:
3132 case XPATH_LOCATIONSET:
3133 TODO;
3134 ret = xmlXPathNAN;
3135 break;
3136 }
3137 return(ret);
3138}
3139
3140/**
3141 * xmlXPathConvertNumber:
3142 * @val: an XPath object
3143 *
3144 * Converts an existing object to its number() equivalent
3145 *
3146 * Returns the new object, the old one is freed (or the operation
3147 * is done directly on @val)
3148 */
3149xmlXPathObjectPtr
3150xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3151 xmlXPathObjectPtr ret;
3152
3153 if (val == NULL)
3154 return(xmlXPathNewFloat(0.0));
3155 if (val->type == XPATH_NUMBER)
3156 return(val);
3157 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3158 xmlXPathFreeObject(val);
3159 return(ret);
3160}
3161
3162/**
3163 * xmlXPathCastNumberToBoolean:
3164 * @val: a number
3165 *
3166 * Converts a number to its boolean value
3167 *
3168 * Returns the boolean value
3169 */
3170int
3171xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003172 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003173 return(0);
3174 return(1);
3175}
3176
3177/**
3178 * xmlXPathCastStringToBoolean:
3179 * @val: a string
3180 *
3181 * Converts a string to its boolean value
3182 *
3183 * Returns the boolean value
3184 */
3185int
3186xmlXPathCastStringToBoolean (const xmlChar *val) {
3187 if ((val == NULL) || (xmlStrlen(val) == 0))
3188 return(0);
3189 return(1);
3190}
3191
3192/**
3193 * xmlXPathCastNodeSetToBoolean:
3194 * @ns: a node-set
3195 *
3196 * Converts a node-set to its boolean value
3197 *
3198 * Returns the boolean value
3199 */
3200int
3201xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3202 if ((ns == NULL) || (ns->nodeNr == 0))
3203 return(0);
3204 return(1);
3205}
3206
3207/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003208 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003209 * @val: an XPath object
3210 *
3211 * Converts an XPath object to its boolean value
3212 *
3213 * Returns the boolean value
3214 */
3215int
3216xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3217 int ret = 0;
3218
3219 if (val == NULL)
3220 return(0);
3221 switch (val->type) {
3222 case XPATH_UNDEFINED:
3223#ifdef DEBUG_EXPR
3224 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3225#endif
3226 ret = 0;
3227 break;
3228 case XPATH_XSLT_TREE:
3229 case XPATH_NODESET:
3230 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3231 break;
3232 case XPATH_STRING:
3233 ret = xmlXPathCastStringToBoolean(val->stringval);
3234 break;
3235 case XPATH_NUMBER:
3236 ret = xmlXPathCastNumberToBoolean(val->floatval);
3237 break;
3238 case XPATH_BOOLEAN:
3239 ret = val->boolval;
3240 break;
3241 case XPATH_USERS:
3242 case XPATH_POINT:
3243 case XPATH_RANGE:
3244 case XPATH_LOCATIONSET:
3245 TODO;
3246 ret = 0;
3247 break;
3248 }
3249 return(ret);
3250}
3251
3252
3253/**
3254 * xmlXPathConvertBoolean:
3255 * @val: an XPath object
3256 *
3257 * Converts an existing object to its boolean() equivalent
3258 *
3259 * Returns the new object, the old one is freed (or the operation
3260 * is done directly on @val)
3261 */
3262xmlXPathObjectPtr
3263xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3264 xmlXPathObjectPtr ret;
3265
3266 if (val == NULL)
3267 return(xmlXPathNewBoolean(0));
3268 if (val->type == XPATH_BOOLEAN)
3269 return(val);
3270 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3271 xmlXPathFreeObject(val);
3272 return(ret);
3273}
3274
Owen Taylor3473f882001-02-23 17:55:21 +00003275/************************************************************************
3276 * *
3277 * Routines to handle XPath contexts *
3278 * *
3279 ************************************************************************/
3280
3281/**
3282 * xmlXPathNewContext:
3283 * @doc: the XML document
3284 *
3285 * Create a new xmlXPathContext
3286 *
3287 * Returns the xmlXPathContext just allocated.
3288 */
3289xmlXPathContextPtr
3290xmlXPathNewContext(xmlDocPtr doc) {
3291 xmlXPathContextPtr ret;
3292
3293 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3294 if (ret == NULL) {
3295 xmlGenericError(xmlGenericErrorContext,
3296 "xmlXPathNewContext: out of memory\n");
3297 return(NULL);
3298 }
3299 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3300 ret->doc = doc;
3301 ret->node = NULL;
3302
3303 ret->varHash = NULL;
3304
3305 ret->nb_types = 0;
3306 ret->max_types = 0;
3307 ret->types = NULL;
3308
3309 ret->funcHash = xmlHashCreate(0);
3310
3311 ret->nb_axis = 0;
3312 ret->max_axis = 0;
3313 ret->axis = NULL;
3314
3315 ret->nsHash = NULL;
3316 ret->user = NULL;
3317
3318 ret->contextSize = -1;
3319 ret->proximityPosition = -1;
3320
3321 xmlXPathRegisterAllFunctions(ret);
3322
3323 return(ret);
3324}
3325
3326/**
3327 * xmlXPathFreeContext:
3328 * @ctxt: the context to free
3329 *
3330 * Free up an xmlXPathContext
3331 */
3332void
3333xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3334 xmlXPathRegisteredNsCleanup(ctxt);
3335 xmlXPathRegisteredFuncsCleanup(ctxt);
3336 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003337 xmlFree(ctxt);
3338}
3339
3340/************************************************************************
3341 * *
3342 * Routines to handle XPath parser contexts *
3343 * *
3344 ************************************************************************/
3345
3346#define CHECK_CTXT(ctxt) \
3347 if (ctxt == NULL) { \
3348 xmlGenericError(xmlGenericErrorContext, \
3349 "%s:%d Internal error: ctxt == NULL\n", \
3350 __FILE__, __LINE__); \
3351 } \
3352
3353
3354#define CHECK_CONTEXT(ctxt) \
3355 if (ctxt == NULL) { \
3356 xmlGenericError(xmlGenericErrorContext, \
3357 "%s:%d Internal error: no context\n", \
3358 __FILE__, __LINE__); \
3359 } \
3360 else if (ctxt->doc == NULL) { \
3361 xmlGenericError(xmlGenericErrorContext, \
3362 "%s:%d Internal error: no document\n", \
3363 __FILE__, __LINE__); \
3364 } \
3365 else if (ctxt->doc->children == NULL) { \
3366 xmlGenericError(xmlGenericErrorContext, \
3367 "%s:%d Internal error: document without root\n", \
3368 __FILE__, __LINE__); \
3369 } \
3370
3371
3372/**
3373 * xmlXPathNewParserContext:
3374 * @str: the XPath expression
3375 * @ctxt: the XPath context
3376 *
3377 * Create a new xmlXPathParserContext
3378 *
3379 * Returns the xmlXPathParserContext just allocated.
3380 */
3381xmlXPathParserContextPtr
3382xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3383 xmlXPathParserContextPtr ret;
3384
3385 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3386 if (ret == NULL) {
3387 xmlGenericError(xmlGenericErrorContext,
3388 "xmlXPathNewParserContext: out of memory\n");
3389 return(NULL);
3390 }
3391 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3392 ret->cur = ret->base = str;
3393 ret->context = ctxt;
3394
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003395 ret->comp = xmlXPathNewCompExpr();
3396 if (ret->comp == NULL) {
3397 xmlFree(ret->valueTab);
3398 xmlFree(ret);
3399 return(NULL);
3400 }
3401
3402 return(ret);
3403}
3404
3405/**
3406 * xmlXPathCompParserContext:
3407 * @comp: the XPath compiled expression
3408 * @ctxt: the XPath context
3409 *
3410 * Create a new xmlXPathParserContext when processing a compiled expression
3411 *
3412 * Returns the xmlXPathParserContext just allocated.
3413 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003414static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003415xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3416 xmlXPathParserContextPtr ret;
3417
3418 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3419 if (ret == NULL) {
3420 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003421 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003422 return(NULL);
3423 }
3424 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3425
Owen Taylor3473f882001-02-23 17:55:21 +00003426 /* Allocate the value stack */
3427 ret->valueTab = (xmlXPathObjectPtr *)
3428 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003429 if (ret->valueTab == NULL) {
3430 xmlFree(ret);
3431 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003432 "xmlXPathCompParserContext: out of memory\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003433 return(NULL);
3434 }
Owen Taylor3473f882001-02-23 17:55:21 +00003435 ret->valueNr = 0;
3436 ret->valueMax = 10;
3437 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003438
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003439 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003440 ret->comp = comp;
3441
Owen Taylor3473f882001-02-23 17:55:21 +00003442 return(ret);
3443}
3444
3445/**
3446 * xmlXPathFreeParserContext:
3447 * @ctxt: the context to free
3448 *
3449 * Free up an xmlXPathParserContext
3450 */
3451void
3452xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3453 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003454 xmlFree(ctxt->valueTab);
3455 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003456 if (ctxt->comp)
3457 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003458 xmlFree(ctxt);
3459}
3460
3461/************************************************************************
3462 * *
3463 * The implicit core function library *
3464 * *
3465 ************************************************************************/
3466
Owen Taylor3473f882001-02-23 17:55:21 +00003467/**
Daniel Veillardf06307e2001-07-03 10:35:50 +00003468 * xmlXPathNodeStringHash:
3469 * @node: a node pointer
3470 *
3471 * Function computing the beginning of the string value of the node,
3472 * used to speed up comparisons
3473 *
3474 * Returns an int usable as a hash
3475 */
3476static unsigned int
3477xmlXPathNodeValHash(xmlNodePtr node) {
3478 int len = 2;
3479 const xmlChar * string = NULL;
3480 xmlNodePtr tmp = NULL;
3481 unsigned int ret = 0;
3482
3483 if (node == NULL)
3484 return(0);
3485
3486
3487 switch (node->type) {
3488 case XML_COMMENT_NODE:
3489 case XML_PI_NODE:
3490 case XML_CDATA_SECTION_NODE:
3491 case XML_TEXT_NODE:
3492 string = node->content;
3493 if (string == NULL)
3494 return(0);
3495 if (string[0] == 0)
3496 return(0);
3497 return(((unsigned int) string[0]) +
3498 (((unsigned int) string[1]) << 8));
3499 case XML_NAMESPACE_DECL:
3500 string = ((xmlNsPtr)node)->href;
3501 if (string == NULL)
3502 return(0);
3503 if (string[0] == 0)
3504 return(0);
3505 return(((unsigned int) string[0]) +
3506 (((unsigned int) string[1]) << 8));
3507 case XML_ATTRIBUTE_NODE:
3508 tmp = ((xmlAttrPtr) node)->children;
3509 break;
3510 case XML_ELEMENT_NODE:
3511 tmp = node->children;
3512 break;
3513 default:
3514 return(0);
3515 }
3516 while (tmp != NULL) {
3517 switch (tmp->type) {
3518 case XML_COMMENT_NODE:
3519 case XML_PI_NODE:
3520 case XML_CDATA_SECTION_NODE:
3521 case XML_TEXT_NODE:
3522 string = tmp->content;
3523 break;
3524 case XML_NAMESPACE_DECL:
3525 string = ((xmlNsPtr)tmp)->href;
3526 break;
3527 default:
3528 break;
3529 }
3530 if ((string != NULL) && (string[0] != 0)) {
3531 if (string[0] == 0)
3532 return(0);
3533 if (len == 1) {
3534 return(ret + (((unsigned int) string[0]) << 8));
3535 }
3536 if (string[1] == 0) {
3537 len = 1;
3538 ret = (unsigned int) string[0];
3539 } else {
3540 return(((unsigned int) string[0]) +
3541 (((unsigned int) string[1]) << 8));
3542 }
3543 }
3544 /*
3545 * Skip to next node
3546 */
3547 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
3548 if (tmp->children->type != XML_ENTITY_DECL) {
3549 tmp = tmp->children;
3550 continue;
3551 }
3552 }
3553 if (tmp == node)
3554 break;
3555
3556 if (tmp->next != NULL) {
3557 tmp = tmp->next;
3558 continue;
3559 }
3560
3561 do {
3562 tmp = tmp->parent;
3563 if (tmp == NULL)
3564 break;
3565 if (tmp == node) {
3566 tmp = NULL;
3567 break;
3568 }
3569 if (tmp->next != NULL) {
3570 tmp = tmp->next;
3571 break;
3572 }
3573 } while (tmp != NULL);
3574 }
3575 return(ret);
3576}
3577
3578/**
3579 * xmlXPathStringHash:
3580 * @string: a string
3581 *
3582 * Function computing the beginning of the string value of the node,
3583 * used to speed up comparisons
3584 *
3585 * Returns an int usable as a hash
3586 */
3587static unsigned int
3588xmlXPathStringHash(const xmlChar * string) {
3589 if (string == NULL)
3590 return((unsigned int) 0);
3591 if (string[0] == 0)
3592 return(0);
3593 return(((unsigned int) string[0]) +
3594 (((unsigned int) string[1]) << 8));
3595}
3596
3597/**
Owen Taylor3473f882001-02-23 17:55:21 +00003598 * xmlXPathCompareNodeSetFloat:
3599 * @ctxt: the XPath Parser context
3600 * @inf: less than (1) or greater than (0)
3601 * @strict: is the comparison strict
3602 * @arg: the node set
3603 * @f: the value
3604 *
3605 * Implement the compare operation between a nodeset and a number
3606 * @ns < @val (1, 1, ...
3607 * @ns <= @val (1, 0, ...
3608 * @ns > @val (0, 1, ...
3609 * @ns >= @val (0, 0, ...
3610 *
3611 * If one object to be compared is a node-set and the other is a number,
3612 * then the comparison will be true if and only if there is a node in the
3613 * node-set such that the result of performing the comparison on the number
3614 * to be compared and on the result of converting the string-value of that
3615 * node to a number using the number function is true.
3616 *
3617 * Returns 0 or 1 depending on the results of the test.
3618 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003619static int
Owen Taylor3473f882001-02-23 17:55:21 +00003620xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
3621 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
3622 int i, ret = 0;
3623 xmlNodeSetPtr ns;
3624 xmlChar *str2;
3625
3626 if ((f == NULL) || (arg == NULL) ||
3627 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3628 xmlXPathFreeObject(arg);
3629 xmlXPathFreeObject(f);
3630 return(0);
3631 }
3632 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003633 if (ns != NULL) {
3634 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003635 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003636 if (str2 != NULL) {
3637 valuePush(ctxt,
3638 xmlXPathNewString(str2));
3639 xmlFree(str2);
3640 xmlXPathNumberFunction(ctxt, 1);
3641 valuePush(ctxt, xmlXPathObjectCopy(f));
3642 ret = xmlXPathCompareValues(ctxt, inf, strict);
3643 if (ret)
3644 break;
3645 }
3646 }
Owen Taylor3473f882001-02-23 17:55:21 +00003647 }
3648 xmlXPathFreeObject(arg);
3649 xmlXPathFreeObject(f);
3650 return(ret);
3651}
3652
3653/**
3654 * xmlXPathCompareNodeSetString:
3655 * @ctxt: the XPath Parser context
3656 * @inf: less than (1) or greater than (0)
3657 * @strict: is the comparison strict
3658 * @arg: the node set
3659 * @s: the value
3660 *
3661 * Implement the compare operation between a nodeset and a string
3662 * @ns < @val (1, 1, ...
3663 * @ns <= @val (1, 0, ...
3664 * @ns > @val (0, 1, ...
3665 * @ns >= @val (0, 0, ...
3666 *
3667 * If one object to be compared is a node-set and the other is a string,
3668 * then the comparison will be true if and only if there is a node in
3669 * the node-set such that the result of performing the comparison on the
3670 * string-value of the node and the other string is true.
3671 *
3672 * Returns 0 or 1 depending on the results of the test.
3673 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003674static int
Owen Taylor3473f882001-02-23 17:55:21 +00003675xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
3676 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
3677 int i, ret = 0;
3678 xmlNodeSetPtr ns;
3679 xmlChar *str2;
3680
3681 if ((s == NULL) || (arg == NULL) ||
3682 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3683 xmlXPathFreeObject(arg);
3684 xmlXPathFreeObject(s);
3685 return(0);
3686 }
3687 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003688 if (ns != NULL) {
3689 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003690 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003691 if (str2 != NULL) {
3692 valuePush(ctxt,
3693 xmlXPathNewString(str2));
3694 xmlFree(str2);
3695 valuePush(ctxt, xmlXPathObjectCopy(s));
3696 ret = xmlXPathCompareValues(ctxt, inf, strict);
3697 if (ret)
3698 break;
3699 }
3700 }
Owen Taylor3473f882001-02-23 17:55:21 +00003701 }
3702 xmlXPathFreeObject(arg);
3703 xmlXPathFreeObject(s);
3704 return(ret);
3705}
3706
3707/**
3708 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003709 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00003710 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003711 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00003712 * @arg2: the second node set object
3713 *
3714 * Implement the compare operation on nodesets:
3715 *
3716 * If both objects to be compared are node-sets, then the comparison
3717 * will be true if and only if there is a node in the first node-set
3718 * and a node in the second node-set such that the result of performing
3719 * the comparison on the string-values of the two nodes is true.
3720 * ....
3721 * When neither object to be compared is a node-set and the operator
3722 * is <=, <, >= or >, then the objects are compared by converting both
3723 * objects to numbers and comparing the numbers according to IEEE 754.
3724 * ....
3725 * The number function converts its argument to a number as follows:
3726 * - a string that consists of optional whitespace followed by an
3727 * optional minus sign followed by a Number followed by whitespace
3728 * is converted to the IEEE 754 number that is nearest (according
3729 * to the IEEE 754 round-to-nearest rule) to the mathematical value
3730 * represented by the string; any other string is converted to NaN
3731 *
3732 * Conclusion all nodes need to be converted first to their string value
3733 * and then the comparison must be done when possible
3734 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003735static int
3736xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00003737 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3738 int i, j, init = 0;
3739 double val1;
3740 double *values2;
3741 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003742 xmlNodeSetPtr ns1;
3743 xmlNodeSetPtr ns2;
3744
3745 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003746 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
3747 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003748 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003749 }
Owen Taylor3473f882001-02-23 17:55:21 +00003750 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003751 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
3752 xmlXPathFreeObject(arg1);
3753 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003754 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003755 }
Owen Taylor3473f882001-02-23 17:55:21 +00003756
3757 ns1 = arg1->nodesetval;
3758 ns2 = arg2->nodesetval;
3759
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003760 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003761 xmlXPathFreeObject(arg1);
3762 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003763 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003764 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003765 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003766 xmlXPathFreeObject(arg1);
3767 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003768 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003769 }
Owen Taylor3473f882001-02-23 17:55:21 +00003770
3771 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
3772 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003773 xmlXPathFreeObject(arg1);
3774 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003775 return(0);
3776 }
3777 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003778 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00003779 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00003780 continue;
3781 for (j = 0;j < ns2->nodeNr;j++) {
3782 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003783 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00003784 }
Daniel Veillardcda96922001-08-21 10:56:31 +00003785 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00003786 continue;
3787 if (inf && strict)
3788 ret = (val1 < values2[j]);
3789 else 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 if (ret)
3796 break;
3797 }
3798 if (ret)
3799 break;
3800 init = 1;
3801 }
3802 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003803 xmlXPathFreeObject(arg1);
3804 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003805 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003806}
3807
3808/**
3809 * xmlXPathCompareNodeSetValue:
3810 * @ctxt: the XPath Parser context
3811 * @inf: less than (1) or greater than (0)
3812 * @strict: is the comparison strict
3813 * @arg: the node set
3814 * @val: the value
3815 *
3816 * Implement the compare operation between a nodeset and a value
3817 * @ns < @val (1, 1, ...
3818 * @ns <= @val (1, 0, ...
3819 * @ns > @val (0, 1, ...
3820 * @ns >= @val (0, 0, ...
3821 *
3822 * If one object to be compared is a node-set and the other is a boolean,
3823 * then the comparison will be true if and only if the result of performing
3824 * the comparison on the boolean and on the result of converting
3825 * the node-set to a boolean using the boolean function is true.
3826 *
3827 * Returns 0 or 1 depending on the results of the test.
3828 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003829static int
Owen Taylor3473f882001-02-23 17:55:21 +00003830xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
3831 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
3832 if ((val == NULL) || (arg == NULL) ||
3833 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3834 return(0);
3835
3836 switch(val->type) {
3837 case XPATH_NUMBER:
3838 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
3839 case XPATH_NODESET:
3840 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003841 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00003842 case XPATH_STRING:
3843 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
3844 case XPATH_BOOLEAN:
3845 valuePush(ctxt, arg);
3846 xmlXPathBooleanFunction(ctxt, 1);
3847 valuePush(ctxt, val);
3848 return(xmlXPathCompareValues(ctxt, inf, strict));
3849 default:
3850 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00003851 }
3852 return(0);
3853}
3854
3855/**
3856 * xmlXPathEqualNodeSetString
3857 * @arg: the nodeset object argument
3858 * @str: the string to compare to.
3859 *
3860 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3861 * If one object to be compared is a node-set and the other is a string,
3862 * then the comparison will be true if and only if there is a node in
3863 * the node-set such that the result of performing the comparison on the
3864 * string-value of the node and the other string is true.
3865 *
3866 * Returns 0 or 1 depending on the results of the test.
3867 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003868static int
Daniel Veillardf06307e2001-07-03 10:35:50 +00003869xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str)
3870{
Owen Taylor3473f882001-02-23 17:55:21 +00003871 int i;
3872 xmlNodeSetPtr ns;
3873 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003874 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00003875
3876 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00003877 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3878 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00003879 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003880 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003881 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00003882 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00003883 if (ns->nodeNr <= 0) {
3884 if (hash == 0)
3885 return(1);
3886 return(0);
3887 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003888 for (i = 0; i < ns->nodeNr; i++) {
3889 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
3890 str2 = xmlNodeGetContent(ns->nodeTab[i]);
3891 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
3892 xmlFree(str2);
3893 return (1);
3894 }
3895 if (str2 != NULL)
3896 xmlFree(str2);
3897 }
Owen Taylor3473f882001-02-23 17:55:21 +00003898 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003899 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00003900}
3901
3902/**
3903 * xmlXPathEqualNodeSetFloat
3904 * @arg: the nodeset object argument
3905 * @f: the float to compare to
3906 *
3907 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3908 * If one object to be compared is a node-set and the other is a number,
3909 * then the comparison will be true if and only if there is a node in
3910 * the node-set such that the result of performing the comparison on the
3911 * number to be compared and on the result of converting the string-value
3912 * of that node to a number using the number function is true.
3913 *
3914 * Returns 0 or 1 depending on the results of the test.
3915 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003916static int
Owen Taylor3473f882001-02-23 17:55:21 +00003917xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) {
3918 char buf[100] = "";
3919
3920 if ((arg == NULL) ||
3921 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3922 return(0);
3923
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003924 xmlXPathFormatNumber(f, buf, sizeof(buf));
Owen Taylor3473f882001-02-23 17:55:21 +00003925 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
3926}
3927
3928
3929/**
3930 * xmlXPathEqualNodeSets
3931 * @arg1: first nodeset object argument
3932 * @arg2: second nodeset object argument
3933 *
3934 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
3935 * If both objects to be compared are node-sets, then the comparison
3936 * will be true if and only if there is a node in the first node-set and
3937 * a node in the second node-set such that the result of performing the
3938 * comparison on the string-values of the two nodes is true.
3939 *
3940 * (needless to say, this is a costly operation)
3941 *
3942 * Returns 0 or 1 depending on the results of the test.
3943 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003944static int
Owen Taylor3473f882001-02-23 17:55:21 +00003945xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3946 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003947 unsigned int *hashs1;
3948 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00003949 xmlChar **values1;
3950 xmlChar **values2;
3951 int ret = 0;
3952 xmlNodeSetPtr ns1;
3953 xmlNodeSetPtr ns2;
3954
3955 if ((arg1 == NULL) ||
3956 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
3957 return(0);
3958 if ((arg2 == NULL) ||
3959 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
3960 return(0);
3961
3962 ns1 = arg1->nodesetval;
3963 ns2 = arg2->nodesetval;
3964
Daniel Veillard911f49a2001-04-07 15:39:35 +00003965 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00003966 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003967 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00003968 return(0);
3969
3970 /*
3971 * check if there is a node pertaining to both sets
3972 */
3973 for (i = 0;i < ns1->nodeNr;i++)
3974 for (j = 0;j < ns2->nodeNr;j++)
3975 if (ns1->nodeTab[i] == ns2->nodeTab[j])
3976 return(1);
3977
3978 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
3979 if (values1 == NULL)
3980 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00003981 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
3982 if (hashs1 == NULL) {
3983 xmlFree(values1);
3984 return(0);
3985 }
Owen Taylor3473f882001-02-23 17:55:21 +00003986 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
3987 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
3988 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00003989 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00003990 xmlFree(values1);
3991 return(0);
3992 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003993 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
3994 if (hashs2 == NULL) {
3995 xmlFree(hashs1);
3996 xmlFree(values1);
3997 xmlFree(values2);
3998 return(0);
3999 }
Owen Taylor3473f882001-02-23 17:55:21 +00004000 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4001 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004002 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004003 for (j = 0;j < ns2->nodeNr;j++) {
4004 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004005 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
4006 if (hashs1[i] == hashs2[j]) {
4007 if (values1[i] == NULL)
4008 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4009 if (values2[j] == NULL)
4010 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
4011 ret = xmlStrEqual(values1[i], values2[j]);
4012 if (ret)
4013 break;
4014 }
Owen Taylor3473f882001-02-23 17:55:21 +00004015 }
4016 if (ret)
4017 break;
4018 }
4019 for (i = 0;i < ns1->nodeNr;i++)
4020 if (values1[i] != NULL)
4021 xmlFree(values1[i]);
4022 for (j = 0;j < ns2->nodeNr;j++)
4023 if (values2[j] != NULL)
4024 xmlFree(values2[j]);
4025 xmlFree(values1);
4026 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004027 xmlFree(hashs1);
4028 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004029 return(ret);
4030}
4031
4032/**
4033 * xmlXPathEqualValues:
4034 * @ctxt: the XPath Parser context
4035 *
4036 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4037 *
4038 * Returns 0 or 1 depending on the results of the test.
4039 */
4040int
4041xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4042 xmlXPathObjectPtr arg1, arg2;
4043 int ret = 0;
4044
4045 arg1 = valuePop(ctxt);
4046 if (arg1 == NULL)
4047 XP_ERROR0(XPATH_INVALID_OPERAND);
4048
4049 arg2 = valuePop(ctxt);
4050 if (arg2 == NULL) {
4051 xmlXPathFreeObject(arg1);
4052 XP_ERROR0(XPATH_INVALID_OPERAND);
4053 }
4054
4055 if (arg1 == arg2) {
4056#ifdef DEBUG_EXPR
4057 xmlGenericError(xmlGenericErrorContext,
4058 "Equal: by pointer\n");
4059#endif
4060 return(1);
4061 }
4062
4063 switch (arg1->type) {
4064 case XPATH_UNDEFINED:
4065#ifdef DEBUG_EXPR
4066 xmlGenericError(xmlGenericErrorContext,
4067 "Equal: undefined\n");
4068#endif
4069 break;
4070 case XPATH_XSLT_TREE:
4071 case XPATH_NODESET:
4072 switch (arg2->type) {
4073 case XPATH_UNDEFINED:
4074#ifdef DEBUG_EXPR
4075 xmlGenericError(xmlGenericErrorContext,
4076 "Equal: undefined\n");
4077#endif
4078 break;
4079 case XPATH_XSLT_TREE:
4080 case XPATH_NODESET:
4081 ret = xmlXPathEqualNodeSets(arg1, arg2);
4082 break;
4083 case XPATH_BOOLEAN:
4084 if ((arg1->nodesetval == NULL) ||
4085 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4086 else
4087 ret = 1;
4088 ret = (ret == arg2->boolval);
4089 break;
4090 case XPATH_NUMBER:
4091 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
4092 break;
4093 case XPATH_STRING:
4094 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
4095 break;
4096 case XPATH_USERS:
4097 case XPATH_POINT:
4098 case XPATH_RANGE:
4099 case XPATH_LOCATIONSET:
4100 TODO
4101 break;
4102 }
4103 break;
4104 case XPATH_BOOLEAN:
4105 switch (arg2->type) {
4106 case XPATH_UNDEFINED:
4107#ifdef DEBUG_EXPR
4108 xmlGenericError(xmlGenericErrorContext,
4109 "Equal: undefined\n");
4110#endif
4111 break;
4112 case XPATH_NODESET:
4113 case XPATH_XSLT_TREE:
4114 if ((arg2->nodesetval == NULL) ||
4115 (arg2->nodesetval->nodeNr == 0)) ret = 0;
4116 else
4117 ret = 1;
4118 break;
4119 case XPATH_BOOLEAN:
4120#ifdef DEBUG_EXPR
4121 xmlGenericError(xmlGenericErrorContext,
4122 "Equal: %d boolean %d \n",
4123 arg1->boolval, arg2->boolval);
4124#endif
4125 ret = (arg1->boolval == arg2->boolval);
4126 break;
4127 case XPATH_NUMBER:
4128 if (arg2->floatval) ret = 1;
4129 else ret = 0;
4130 ret = (arg1->boolval == ret);
4131 break;
4132 case XPATH_STRING:
4133 if ((arg2->stringval == NULL) ||
4134 (arg2->stringval[0] == 0)) ret = 0;
4135 else
4136 ret = 1;
4137 ret = (arg1->boolval == ret);
4138 break;
4139 case XPATH_USERS:
4140 case XPATH_POINT:
4141 case XPATH_RANGE:
4142 case XPATH_LOCATIONSET:
4143 TODO
4144 break;
4145 }
4146 break;
4147 case XPATH_NUMBER:
4148 switch (arg2->type) {
4149 case XPATH_UNDEFINED:
4150#ifdef DEBUG_EXPR
4151 xmlGenericError(xmlGenericErrorContext,
4152 "Equal: undefined\n");
4153#endif
4154 break;
4155 case XPATH_NODESET:
4156 case XPATH_XSLT_TREE:
4157 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
4158 break;
4159 case XPATH_BOOLEAN:
4160 if (arg1->floatval) ret = 1;
4161 else ret = 0;
4162 ret = (arg2->boolval == ret);
4163 break;
4164 case XPATH_STRING:
4165 valuePush(ctxt, arg2);
4166 xmlXPathNumberFunction(ctxt, 1);
4167 arg2 = valuePop(ctxt);
4168 /* no break on purpose */
4169 case XPATH_NUMBER:
4170 ret = (arg1->floatval == arg2->floatval);
4171 break;
4172 case XPATH_USERS:
4173 case XPATH_POINT:
4174 case XPATH_RANGE:
4175 case XPATH_LOCATIONSET:
4176 TODO
4177 break;
4178 }
4179 break;
4180 case XPATH_STRING:
4181 switch (arg2->type) {
4182 case XPATH_UNDEFINED:
4183#ifdef DEBUG_EXPR
4184 xmlGenericError(xmlGenericErrorContext,
4185 "Equal: undefined\n");
4186#endif
4187 break;
4188 case XPATH_NODESET:
4189 case XPATH_XSLT_TREE:
4190 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
4191 break;
4192 case XPATH_BOOLEAN:
4193 if ((arg1->stringval == NULL) ||
4194 (arg1->stringval[0] == 0)) ret = 0;
4195 else
4196 ret = 1;
4197 ret = (arg2->boolval == ret);
4198 break;
4199 case XPATH_STRING:
4200 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4201 break;
4202 case XPATH_NUMBER:
4203 valuePush(ctxt, arg1);
4204 xmlXPathNumberFunction(ctxt, 1);
4205 arg1 = valuePop(ctxt);
4206 ret = (arg1->floatval == arg2->floatval);
4207 break;
4208 case XPATH_USERS:
4209 case XPATH_POINT:
4210 case XPATH_RANGE:
4211 case XPATH_LOCATIONSET:
4212 TODO
4213 break;
4214 }
4215 break;
4216 case XPATH_USERS:
4217 case XPATH_POINT:
4218 case XPATH_RANGE:
4219 case XPATH_LOCATIONSET:
4220 TODO
4221 break;
4222 }
4223 xmlXPathFreeObject(arg1);
4224 xmlXPathFreeObject(arg2);
4225 return(ret);
4226}
4227
4228
4229/**
4230 * xmlXPathCompareValues:
4231 * @ctxt: the XPath Parser context
4232 * @inf: less than (1) or greater than (0)
4233 * @strict: is the comparison strict
4234 *
4235 * Implement the compare operation on XPath objects:
4236 * @arg1 < @arg2 (1, 1, ...
4237 * @arg1 <= @arg2 (1, 0, ...
4238 * @arg1 > @arg2 (0, 1, ...
4239 * @arg1 >= @arg2 (0, 0, ...
4240 *
4241 * When neither object to be compared is a node-set and the operator is
4242 * <=, <, >=, >, then the objects are compared by converted both objects
4243 * to numbers and comparing the numbers according to IEEE 754. The <
4244 * comparison will be true if and only if the first number is less than the
4245 * second number. The <= comparison will be true if and only if the first
4246 * number is less than or equal to the second number. The > comparison
4247 * will be true if and only if the first number is greater than the second
4248 * number. The >= comparison will be true if and only if the first number
4249 * is greater than or equal to the second number.
4250 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004251 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00004252 */
4253int
4254xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
4255 int ret = 0;
4256 xmlXPathObjectPtr arg1, arg2;
4257
4258 arg2 = valuePop(ctxt);
4259 if (arg2 == NULL) {
4260 XP_ERROR0(XPATH_INVALID_OPERAND);
4261 }
4262
4263 arg1 = valuePop(ctxt);
4264 if (arg1 == NULL) {
4265 xmlXPathFreeObject(arg2);
4266 XP_ERROR0(XPATH_INVALID_OPERAND);
4267 }
4268
4269 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
4270 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004271 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004272 } else {
4273 if (arg1->type == XPATH_NODESET) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004274 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4275 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004276 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004277 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4278 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004279 }
4280 }
4281 return(ret);
4282 }
4283
4284 if (arg1->type != XPATH_NUMBER) {
4285 valuePush(ctxt, arg1);
4286 xmlXPathNumberFunction(ctxt, 1);
4287 arg1 = valuePop(ctxt);
4288 }
4289 if (arg1->type != XPATH_NUMBER) {
4290 xmlXPathFreeObject(arg1);
4291 xmlXPathFreeObject(arg2);
4292 XP_ERROR0(XPATH_INVALID_OPERAND);
4293 }
4294 if (arg2->type != XPATH_NUMBER) {
4295 valuePush(ctxt, arg2);
4296 xmlXPathNumberFunction(ctxt, 1);
4297 arg2 = valuePop(ctxt);
4298 }
4299 if (arg2->type != XPATH_NUMBER) {
4300 xmlXPathFreeObject(arg1);
4301 xmlXPathFreeObject(arg2);
4302 XP_ERROR0(XPATH_INVALID_OPERAND);
4303 }
4304 /*
4305 * Add tests for infinity and nan
4306 * => feedback on 3.4 for Inf and NaN
4307 */
4308 if (inf && strict)
4309 ret = (arg1->floatval < arg2->floatval);
4310 else 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 xmlXPathFreeObject(arg1);
4317 xmlXPathFreeObject(arg2);
4318 return(ret);
4319}
4320
4321/**
4322 * xmlXPathValueFlipSign:
4323 * @ctxt: the XPath Parser context
4324 *
4325 * Implement the unary - operation on an XPath object
4326 * The numeric operators convert their operands to numbers as if
4327 * by calling the number function.
4328 */
4329void
4330xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004331 CAST_TO_NUMBER;
4332 CHECK_TYPE(XPATH_NUMBER);
4333 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00004334}
4335
4336/**
4337 * xmlXPathAddValues:
4338 * @ctxt: the XPath Parser context
4339 *
4340 * Implement the add operation on XPath objects:
4341 * The numeric operators convert their operands to numbers as if
4342 * by calling the number function.
4343 */
4344void
4345xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
4346 xmlXPathObjectPtr arg;
4347 double val;
4348
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004349 arg = valuePop(ctxt);
4350 if (arg == NULL)
4351 XP_ERROR(XPATH_INVALID_OPERAND);
4352 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004353 xmlXPathFreeObject(arg);
4354
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004355 CAST_TO_NUMBER;
4356 CHECK_TYPE(XPATH_NUMBER);
4357 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00004358}
4359
4360/**
4361 * xmlXPathSubValues:
4362 * @ctxt: the XPath Parser context
4363 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004364 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00004365 * The numeric operators convert their operands to numbers as if
4366 * by calling the number function.
4367 */
4368void
4369xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
4370 xmlXPathObjectPtr arg;
4371 double val;
4372
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004373 arg = valuePop(ctxt);
4374 if (arg == NULL)
4375 XP_ERROR(XPATH_INVALID_OPERAND);
4376 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004377 xmlXPathFreeObject(arg);
4378
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004379 CAST_TO_NUMBER;
4380 CHECK_TYPE(XPATH_NUMBER);
4381 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004382}
4383
4384/**
4385 * xmlXPathMultValues:
4386 * @ctxt: the XPath Parser context
4387 *
4388 * Implement the multiply operation on XPath objects:
4389 * The numeric operators convert their operands to numbers as if
4390 * by calling the number function.
4391 */
4392void
4393xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
4394 xmlXPathObjectPtr arg;
4395 double val;
4396
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004397 arg = valuePop(ctxt);
4398 if (arg == NULL)
4399 XP_ERROR(XPATH_INVALID_OPERAND);
4400 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004401 xmlXPathFreeObject(arg);
4402
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004403 CAST_TO_NUMBER;
4404 CHECK_TYPE(XPATH_NUMBER);
4405 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004406}
4407
4408/**
4409 * xmlXPathDivValues:
4410 * @ctxt: the XPath Parser context
4411 *
4412 * Implement the div operation on XPath objects @arg1 / @arg2:
4413 * The numeric operators convert their operands to numbers as if
4414 * by calling the number function.
4415 */
4416void
4417xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
4418 xmlXPathObjectPtr arg;
4419 double val;
4420
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004421 arg = valuePop(ctxt);
4422 if (arg == NULL)
4423 XP_ERROR(XPATH_INVALID_OPERAND);
4424 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004425 xmlXPathFreeObject(arg);
4426
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004427 CAST_TO_NUMBER;
4428 CHECK_TYPE(XPATH_NUMBER);
4429 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004430}
4431
4432/**
4433 * xmlXPathModValues:
4434 * @ctxt: the XPath Parser context
4435 *
4436 * Implement the mod operation on XPath objects: @arg1 / @arg2
4437 * The numeric operators convert their operands to numbers as if
4438 * by calling the number function.
4439 */
4440void
4441xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
4442 xmlXPathObjectPtr arg;
4443 int arg1, arg2;
4444
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004445 arg = valuePop(ctxt);
4446 if (arg == NULL)
4447 XP_ERROR(XPATH_INVALID_OPERAND);
4448 arg2 = (int) xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004449 xmlXPathFreeObject(arg);
4450
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004451 CAST_TO_NUMBER;
4452 CHECK_TYPE(XPATH_NUMBER);
4453 arg1 = (int) ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00004454 if (arg2 == 0)
4455 ctxt->value->floatval = xmlXPathNAN;
4456 else
4457 ctxt->value->floatval = arg1 % arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00004458}
4459
4460/************************************************************************
4461 * *
4462 * The traversal functions *
4463 * *
4464 ************************************************************************/
4465
Owen Taylor3473f882001-02-23 17:55:21 +00004466/*
4467 * A traversal function enumerates nodes along an axis.
4468 * Initially it must be called with NULL, and it indicates
4469 * termination on the axis by returning NULL.
4470 */
4471typedef xmlNodePtr (*xmlXPathTraversalFunction)
4472 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
4473
4474/**
4475 * xmlXPathNextSelf:
4476 * @ctxt: the XPath Parser context
4477 * @cur: the current node in the traversal
4478 *
4479 * Traversal function for the "self" direction
4480 * The self axis contains just the context node itself
4481 *
4482 * Returns the next element following that axis
4483 */
4484xmlNodePtr
4485xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4486 if (cur == NULL)
4487 return(ctxt->context->node);
4488 return(NULL);
4489}
4490
4491/**
4492 * xmlXPathNextChild:
4493 * @ctxt: the XPath Parser context
4494 * @cur: the current node in the traversal
4495 *
4496 * Traversal function for the "child" direction
4497 * The child axis contains the children of the context node in document order.
4498 *
4499 * Returns the next element following that axis
4500 */
4501xmlNodePtr
4502xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4503 if (cur == NULL) {
4504 if (ctxt->context->node == NULL) return(NULL);
4505 switch (ctxt->context->node->type) {
4506 case XML_ELEMENT_NODE:
4507 case XML_TEXT_NODE:
4508 case XML_CDATA_SECTION_NODE:
4509 case XML_ENTITY_REF_NODE:
4510 case XML_ENTITY_NODE:
4511 case XML_PI_NODE:
4512 case XML_COMMENT_NODE:
4513 case XML_NOTATION_NODE:
4514 case XML_DTD_NODE:
4515 return(ctxt->context->node->children);
4516 case XML_DOCUMENT_NODE:
4517 case XML_DOCUMENT_TYPE_NODE:
4518 case XML_DOCUMENT_FRAG_NODE:
4519 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004520#ifdef LIBXML_DOCB_ENABLED
4521 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004522#endif
4523 return(((xmlDocPtr) ctxt->context->node)->children);
4524 case XML_ELEMENT_DECL:
4525 case XML_ATTRIBUTE_DECL:
4526 case XML_ENTITY_DECL:
4527 case XML_ATTRIBUTE_NODE:
4528 case XML_NAMESPACE_DECL:
4529 case XML_XINCLUDE_START:
4530 case XML_XINCLUDE_END:
4531 return(NULL);
4532 }
4533 return(NULL);
4534 }
4535 if ((cur->type == XML_DOCUMENT_NODE) ||
4536 (cur->type == XML_HTML_DOCUMENT_NODE))
4537 return(NULL);
4538 return(cur->next);
4539}
4540
4541/**
4542 * xmlXPathNextDescendant:
4543 * @ctxt: the XPath Parser context
4544 * @cur: the current node in the traversal
4545 *
4546 * Traversal function for the "descendant" direction
4547 * the descendant axis contains the descendants of the context node in document
4548 * order; a descendant is a child or a child of a child and so on.
4549 *
4550 * Returns the next element following that axis
4551 */
4552xmlNodePtr
4553xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4554 if (cur == NULL) {
4555 if (ctxt->context->node == NULL)
4556 return(NULL);
4557 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4558 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4559 return(NULL);
4560
4561 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
4562 return(ctxt->context->doc->children);
4563 return(ctxt->context->node->children);
4564 }
4565
Daniel Veillard567e1b42001-08-01 15:53:47 +00004566 if (cur->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004567 if (cur->children->type != XML_ENTITY_DECL)
Daniel Veillard567e1b42001-08-01 15:53:47 +00004568 return(cur->children);
4569 }
4570
4571 if (cur == ctxt->context->node) return(NULL);
4572
Owen Taylor3473f882001-02-23 17:55:21 +00004573 if (cur->next != NULL) return(cur->next);
4574
4575 do {
4576 cur = cur->parent;
4577 if (cur == NULL) return(NULL);
4578 if (cur == ctxt->context->node) return(NULL);
4579 if (cur->next != NULL) {
4580 cur = cur->next;
4581 return(cur);
4582 }
4583 } while (cur != NULL);
4584 return(cur);
4585}
4586
4587/**
4588 * xmlXPathNextDescendantOrSelf:
4589 * @ctxt: the XPath Parser context
4590 * @cur: the current node in the traversal
4591 *
4592 * Traversal function for the "descendant-or-self" direction
4593 * the descendant-or-self axis contains the context node and the descendants
4594 * of the context node in document order; thus the context node is the first
4595 * node on the axis, and the first child of the context node is the second node
4596 * on the axis
4597 *
4598 * Returns the next element following that axis
4599 */
4600xmlNodePtr
4601xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4602 if (cur == NULL) {
4603 if (ctxt->context->node == NULL)
4604 return(NULL);
4605 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4606 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4607 return(NULL);
4608 return(ctxt->context->node);
4609 }
4610
4611 return(xmlXPathNextDescendant(ctxt, cur));
4612}
4613
4614/**
4615 * xmlXPathNextParent:
4616 * @ctxt: the XPath Parser context
4617 * @cur: the current node in the traversal
4618 *
4619 * Traversal function for the "parent" direction
4620 * The parent axis contains the parent of the context node, if there is one.
4621 *
4622 * Returns the next element following that axis
4623 */
4624xmlNodePtr
4625xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4626 /*
4627 * the parent of an attribute or namespace node is the element
4628 * to which the attribute or namespace node is attached
4629 * Namespace handling !!!
4630 */
4631 if (cur == NULL) {
4632 if (ctxt->context->node == NULL) return(NULL);
4633 switch (ctxt->context->node->type) {
4634 case XML_ELEMENT_NODE:
4635 case XML_TEXT_NODE:
4636 case XML_CDATA_SECTION_NODE:
4637 case XML_ENTITY_REF_NODE:
4638 case XML_ENTITY_NODE:
4639 case XML_PI_NODE:
4640 case XML_COMMENT_NODE:
4641 case XML_NOTATION_NODE:
4642 case XML_DTD_NODE:
4643 case XML_ELEMENT_DECL:
4644 case XML_ATTRIBUTE_DECL:
4645 case XML_XINCLUDE_START:
4646 case XML_XINCLUDE_END:
4647 case XML_ENTITY_DECL:
4648 if (ctxt->context->node->parent == NULL)
4649 return((xmlNodePtr) ctxt->context->doc);
4650 return(ctxt->context->node->parent);
4651 case XML_ATTRIBUTE_NODE: {
4652 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4653
4654 return(att->parent);
4655 }
4656 case XML_DOCUMENT_NODE:
4657 case XML_DOCUMENT_TYPE_NODE:
4658 case XML_DOCUMENT_FRAG_NODE:
4659 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004660#ifdef LIBXML_DOCB_ENABLED
4661 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004662#endif
4663 return(NULL);
4664 case XML_NAMESPACE_DECL:
4665 /*
4666 * TODO !!! may require extending struct _xmlNs with
4667 * parent field
4668 * C.f. Infoset case...
4669 */
4670 return(NULL);
4671 }
4672 }
4673 return(NULL);
4674}
4675
4676/**
4677 * xmlXPathNextAncestor:
4678 * @ctxt: the XPath Parser context
4679 * @cur: the current node in the traversal
4680 *
4681 * Traversal function for the "ancestor" direction
4682 * the ancestor axis contains the ancestors of the context node; the ancestors
4683 * of the context node consist of the parent of context node and the parent's
4684 * parent and so on; the nodes are ordered in reverse document order; thus the
4685 * parent is the first node on the axis, and the parent's parent is the second
4686 * node on the axis
4687 *
4688 * Returns the next element following that axis
4689 */
4690xmlNodePtr
4691xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4692 /*
4693 * the parent of an attribute or namespace node is the element
4694 * to which the attribute or namespace node is attached
4695 * !!!!!!!!!!!!!
4696 */
4697 if (cur == NULL) {
4698 if (ctxt->context->node == NULL) return(NULL);
4699 switch (ctxt->context->node->type) {
4700 case XML_ELEMENT_NODE:
4701 case XML_TEXT_NODE:
4702 case XML_CDATA_SECTION_NODE:
4703 case XML_ENTITY_REF_NODE:
4704 case XML_ENTITY_NODE:
4705 case XML_PI_NODE:
4706 case XML_COMMENT_NODE:
4707 case XML_DTD_NODE:
4708 case XML_ELEMENT_DECL:
4709 case XML_ATTRIBUTE_DECL:
4710 case XML_ENTITY_DECL:
4711 case XML_NOTATION_NODE:
4712 case XML_XINCLUDE_START:
4713 case XML_XINCLUDE_END:
4714 if (ctxt->context->node->parent == NULL)
4715 return((xmlNodePtr) ctxt->context->doc);
4716 return(ctxt->context->node->parent);
4717 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004718 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00004719
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004720 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00004721 }
4722 case XML_DOCUMENT_NODE:
4723 case XML_DOCUMENT_TYPE_NODE:
4724 case XML_DOCUMENT_FRAG_NODE:
4725 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004726#ifdef LIBXML_DOCB_ENABLED
4727 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004728#endif
4729 return(NULL);
4730 case XML_NAMESPACE_DECL:
4731 /*
4732 * TODO !!! may require extending struct _xmlNs with
4733 * parent field
4734 * C.f. Infoset case...
4735 */
4736 return(NULL);
4737 }
4738 return(NULL);
4739 }
4740 if (cur == ctxt->context->doc->children)
4741 return((xmlNodePtr) ctxt->context->doc);
4742 if (cur == (xmlNodePtr) ctxt->context->doc)
4743 return(NULL);
4744 switch (cur->type) {
4745 case XML_ELEMENT_NODE:
4746 case XML_TEXT_NODE:
4747 case XML_CDATA_SECTION_NODE:
4748 case XML_ENTITY_REF_NODE:
4749 case XML_ENTITY_NODE:
4750 case XML_PI_NODE:
4751 case XML_COMMENT_NODE:
4752 case XML_NOTATION_NODE:
4753 case XML_DTD_NODE:
4754 case XML_ELEMENT_DECL:
4755 case XML_ATTRIBUTE_DECL:
4756 case XML_ENTITY_DECL:
4757 case XML_XINCLUDE_START:
4758 case XML_XINCLUDE_END:
4759 return(cur->parent);
4760 case XML_ATTRIBUTE_NODE: {
4761 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4762
4763 return(att->parent);
4764 }
4765 case XML_DOCUMENT_NODE:
4766 case XML_DOCUMENT_TYPE_NODE:
4767 case XML_DOCUMENT_FRAG_NODE:
4768 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004769#ifdef LIBXML_DOCB_ENABLED
4770 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004771#endif
4772 return(NULL);
4773 case XML_NAMESPACE_DECL:
4774 /*
4775 * TODO !!! may require extending struct _xmlNs with
4776 * parent field
4777 * C.f. Infoset case...
4778 */
4779 return(NULL);
4780 }
4781 return(NULL);
4782}
4783
4784/**
4785 * xmlXPathNextAncestorOrSelf:
4786 * @ctxt: the XPath Parser context
4787 * @cur: the current node in the traversal
4788 *
4789 * Traversal function for the "ancestor-or-self" direction
4790 * he ancestor-or-self axis contains the context node and ancestors of
4791 * the context node in reverse document order; thus the context node is
4792 * the first node on the axis, and the context node's parent the second;
4793 * parent here is defined the same as with the parent axis.
4794 *
4795 * Returns the next element following that axis
4796 */
4797xmlNodePtr
4798xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4799 if (cur == NULL)
4800 return(ctxt->context->node);
4801 return(xmlXPathNextAncestor(ctxt, cur));
4802}
4803
4804/**
4805 * xmlXPathNextFollowingSibling:
4806 * @ctxt: the XPath Parser context
4807 * @cur: the current node in the traversal
4808 *
4809 * Traversal function for the "following-sibling" direction
4810 * The following-sibling axis contains the following siblings of the context
4811 * node in document order.
4812 *
4813 * Returns the next element following that axis
4814 */
4815xmlNodePtr
4816xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4817 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4818 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4819 return(NULL);
4820 if (cur == (xmlNodePtr) ctxt->context->doc)
4821 return(NULL);
4822 if (cur == NULL)
4823 return(ctxt->context->node->next);
4824 return(cur->next);
4825}
4826
4827/**
4828 * xmlXPathNextPrecedingSibling:
4829 * @ctxt: the XPath Parser context
4830 * @cur: the current node in the traversal
4831 *
4832 * Traversal function for the "preceding-sibling" direction
4833 * The preceding-sibling axis contains the preceding siblings of the context
4834 * node in reverse document order; the first preceding sibling is first on the
4835 * axis; the sibling preceding that node is the second on the axis and so on.
4836 *
4837 * Returns the next element following that axis
4838 */
4839xmlNodePtr
4840xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4841 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4842 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4843 return(NULL);
4844 if (cur == (xmlNodePtr) ctxt->context->doc)
4845 return(NULL);
4846 if (cur == NULL)
4847 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004848 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
4849 cur = cur->prev;
4850 if (cur == NULL)
4851 return(ctxt->context->node->prev);
4852 }
Owen Taylor3473f882001-02-23 17:55:21 +00004853 return(cur->prev);
4854}
4855
4856/**
4857 * xmlXPathNextFollowing:
4858 * @ctxt: the XPath Parser context
4859 * @cur: the current node in the traversal
4860 *
4861 * Traversal function for the "following" direction
4862 * The following axis contains all nodes in the same document as the context
4863 * node that are after the context node in document order, excluding any
4864 * descendants and excluding attribute nodes and namespace nodes; the nodes
4865 * are ordered in document order
4866 *
4867 * Returns the next element following that axis
4868 */
4869xmlNodePtr
4870xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4871 if (cur != NULL && cur->children != NULL)
4872 return cur->children ;
4873 if (cur == NULL) cur = ctxt->context->node;
4874 if (cur == NULL) return(NULL) ; /* ERROR */
4875 if (cur->next != NULL) return(cur->next) ;
4876 do {
4877 cur = cur->parent;
4878 if (cur == NULL) return(NULL);
4879 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
4880 if (cur->next != NULL) return(cur->next);
4881 } while (cur != NULL);
4882 return(cur);
4883}
4884
4885/*
4886 * xmlXPathIsAncestor:
4887 * @ancestor: the ancestor node
4888 * @node: the current node
4889 *
4890 * Check that @ancestor is a @node's ancestor
4891 *
4892 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
4893 */
4894static int
4895xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
4896 if ((ancestor == NULL) || (node == NULL)) return(0);
4897 /* nodes need to be in the same document */
4898 if (ancestor->doc != node->doc) return(0);
4899 /* avoid searching if ancestor or node is the root node */
4900 if (ancestor == (xmlNodePtr) node->doc) return(1);
4901 if (node == (xmlNodePtr) ancestor->doc) return(0);
4902 while (node->parent != NULL) {
4903 if (node->parent == ancestor)
4904 return(1);
4905 node = node->parent;
4906 }
4907 return(0);
4908}
4909
4910/**
4911 * xmlXPathNextPreceding:
4912 * @ctxt: the XPath Parser context
4913 * @cur: the current node in the traversal
4914 *
4915 * Traversal function for the "preceding" direction
4916 * the preceding axis contains all nodes in the same document as the context
4917 * node that are before the context node in document order, excluding any
4918 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4919 * ordered in reverse document order
4920 *
4921 * Returns the next element following that axis
4922 */
4923xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00004924xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
4925{
Owen Taylor3473f882001-02-23 17:55:21 +00004926 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004927 cur = ctxt->context->node;
4928 if (cur == NULL)
4929 return (NULL);
4930 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
4931 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00004932 do {
4933 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004934 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
4935 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004936 }
4937
4938 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004939 if (cur == NULL)
4940 return (NULL);
4941 if (cur == ctxt->context->doc->children)
4942 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004943 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00004944 return (cur);
4945}
4946
4947/**
4948 * xmlXPathNextPrecedingInternal:
4949 * @ctxt: the XPath Parser context
4950 * @cur: the current node in the traversal
4951 *
4952 * Traversal function for the "preceding" direction
4953 * the preceding axis contains all nodes in the same document as the context
4954 * node that are before the context node in document order, excluding any
4955 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4956 * ordered in reverse document order
4957 * This is a faster implementation but internal only since it requires a
4958 * state kept in the parser context: ctxt->ancestor.
4959 *
4960 * Returns the next element following that axis
4961 */
4962static xmlNodePtr
4963xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
4964 xmlNodePtr cur)
4965{
4966 if (cur == NULL) {
4967 cur = ctxt->context->node;
4968 if (cur == NULL)
4969 return (NULL);
4970 ctxt->ancestor = cur->parent;
4971 }
4972 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
4973 cur = cur->prev;
4974 while (cur->prev == NULL) {
4975 cur = cur->parent;
4976 if (cur == NULL)
4977 return (NULL);
4978 if (cur == ctxt->context->doc->children)
4979 return (NULL);
4980 if (cur != ctxt->ancestor)
4981 return (cur);
4982 ctxt->ancestor = cur->parent;
4983 }
4984 cur = cur->prev;
4985 while (cur->last != NULL)
4986 cur = cur->last;
4987 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004988}
4989
4990/**
4991 * xmlXPathNextNamespace:
4992 * @ctxt: the XPath Parser context
4993 * @cur: the current attribute in the traversal
4994 *
4995 * Traversal function for the "namespace" direction
4996 * the namespace axis contains the namespace nodes of the context node;
4997 * the order of nodes on this axis is implementation-defined; the axis will
4998 * be empty unless the context node is an element
4999 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005000 * We keep the XML namespace node at the end of the list.
5001 *
Owen Taylor3473f882001-02-23 17:55:21 +00005002 * Returns the next element following that axis
5003 */
5004xmlNodePtr
5005xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005006 xmlNodePtr ret;
5007
Owen Taylor3473f882001-02-23 17:55:21 +00005008 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005009 if (cur == (xmlNodePtr) xmlXPathXMLNamespace)
5010 return(NULL);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005011 if ((cur == NULL) || (ctxt->context->tmpNsList == NULL)) {
5012 if (ctxt->context->tmpNsList != NULL)
5013 xmlFree(ctxt->context->tmpNsList);
5014 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005015 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005016 if (ctxt->context->tmpNsList == NULL) return(NULL);
5017 ctxt->context->tmpNsNr = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005018 }
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005019 ret = (xmlNodePtr)ctxt->context->tmpNsList[ctxt->context->tmpNsNr++];
5020 if (ret == NULL) {
5021 xmlFree(ctxt->context->tmpNsList);
5022 ctxt->context->tmpNsList = NULL;
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005023 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005024 }
5025 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005026}
5027
5028/**
5029 * xmlXPathNextAttribute:
5030 * @ctxt: the XPath Parser context
5031 * @cur: the current attribute in the traversal
5032 *
5033 * Traversal function for the "attribute" direction
5034 * TODO: support DTD inherited default attributes
5035 *
5036 * Returns the next element following that axis
5037 */
5038xmlNodePtr
5039xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005040 if (ctxt->context->node == NULL)
5041 return(NULL);
5042 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5043 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005044 if (cur == NULL) {
5045 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5046 return(NULL);
5047 return((xmlNodePtr)ctxt->context->node->properties);
5048 }
5049 return((xmlNodePtr)cur->next);
5050}
5051
5052/************************************************************************
5053 * *
5054 * NodeTest Functions *
5055 * *
5056 ************************************************************************/
5057
Owen Taylor3473f882001-02-23 17:55:21 +00005058#define IS_FUNCTION 200
5059
Owen Taylor3473f882001-02-23 17:55:21 +00005060
5061/************************************************************************
5062 * *
5063 * Implicit tree core function library *
5064 * *
5065 ************************************************************************/
5066
5067/**
5068 * xmlXPathRoot:
5069 * @ctxt: the XPath Parser context
5070 *
5071 * Initialize the context to the root of the document
5072 */
5073void
5074xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5075 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5076 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5077}
5078
5079/************************************************************************
5080 * *
5081 * The explicit core function library *
5082 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5083 * *
5084 ************************************************************************/
5085
5086
5087/**
5088 * xmlXPathLastFunction:
5089 * @ctxt: the XPath Parser context
5090 * @nargs: the number of arguments
5091 *
5092 * Implement the last() XPath function
5093 * number last()
5094 * The last function returns the number of nodes in the context node list.
5095 */
5096void
5097xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5098 CHECK_ARITY(0);
5099 if (ctxt->context->contextSize >= 0) {
5100 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5101#ifdef DEBUG_EXPR
5102 xmlGenericError(xmlGenericErrorContext,
5103 "last() : %d\n", ctxt->context->contextSize);
5104#endif
5105 } else {
5106 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5107 }
5108}
5109
5110/**
5111 * xmlXPathPositionFunction:
5112 * @ctxt: the XPath Parser context
5113 * @nargs: the number of arguments
5114 *
5115 * Implement the position() XPath function
5116 * number position()
5117 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005118 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005119 * will be equal to last().
5120 */
5121void
5122xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5123 CHECK_ARITY(0);
5124 if (ctxt->context->proximityPosition >= 0) {
5125 valuePush(ctxt,
5126 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5127#ifdef DEBUG_EXPR
5128 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5129 ctxt->context->proximityPosition);
5130#endif
5131 } else {
5132 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5133 }
5134}
5135
5136/**
5137 * xmlXPathCountFunction:
5138 * @ctxt: the XPath Parser context
5139 * @nargs: the number of arguments
5140 *
5141 * Implement the count() XPath function
5142 * number count(node-set)
5143 */
5144void
5145xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5146 xmlXPathObjectPtr cur;
5147
5148 CHECK_ARITY(1);
5149 if ((ctxt->value == NULL) ||
5150 ((ctxt->value->type != XPATH_NODESET) &&
5151 (ctxt->value->type != XPATH_XSLT_TREE)))
5152 XP_ERROR(XPATH_INVALID_TYPE);
5153 cur = valuePop(ctxt);
5154
Daniel Veillard911f49a2001-04-07 15:39:35 +00005155 if ((cur == NULL) || (cur->nodesetval == NULL))
5156 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00005157 else if (cur->type == XPATH_NODESET) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005158 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005159 } else {
5160 if ((cur->nodesetval->nodeNr != 1) ||
5161 (cur->nodesetval->nodeTab == NULL)) {
5162 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5163 } else {
5164 xmlNodePtr tmp;
5165 int i = 0;
5166
5167 tmp = cur->nodesetval->nodeTab[0];
5168 if (tmp != NULL) {
5169 tmp = tmp->children;
5170 while (tmp != NULL) {
5171 tmp = tmp->next;
5172 i++;
5173 }
5174 }
5175 valuePush(ctxt, xmlXPathNewFloat((double) i));
5176 }
5177 }
Owen Taylor3473f882001-02-23 17:55:21 +00005178 xmlXPathFreeObject(cur);
5179}
5180
5181/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005182 * xmlXPathGetElementsByIds:
5183 * @doc: the document
5184 * @ids: a whitespace separated list of IDs
5185 *
5186 * Selects elements by their unique ID.
5187 *
5188 * Returns a node-set of selected elements.
5189 */
5190static xmlNodeSetPtr
5191xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5192 xmlNodeSetPtr ret;
5193 const xmlChar *cur = ids;
5194 xmlChar *ID;
5195 xmlAttrPtr attr;
5196 xmlNodePtr elem = NULL;
5197
5198 ret = xmlXPathNodeSetCreate(NULL);
5199
5200 while (IS_BLANK(*cur)) cur++;
5201 while (*cur != 0) {
5202 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
5203 (*cur == '.') || (*cur == '-') ||
5204 (*cur == '_') || (*cur == ':') ||
5205 (IS_COMBINING(*cur)) ||
5206 (IS_EXTENDER(*cur)))
5207 cur++;
5208
5209 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
5210
5211 ID = xmlStrndup(ids, cur - ids);
5212 attr = xmlGetID(doc, ID);
5213 if (attr != NULL) {
5214 elem = attr->parent;
5215 xmlXPathNodeSetAdd(ret, elem);
5216 }
5217 if (ID != NULL)
5218 xmlFree(ID);
5219
5220 while (IS_BLANK(*cur)) cur++;
5221 ids = cur;
5222 }
5223 return(ret);
5224}
5225
5226/**
Owen Taylor3473f882001-02-23 17:55:21 +00005227 * xmlXPathIdFunction:
5228 * @ctxt: the XPath Parser context
5229 * @nargs: the number of arguments
5230 *
5231 * Implement the id() XPath function
5232 * node-set id(object)
5233 * The id function selects elements by their unique ID
5234 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5235 * then the result is the union of the result of applying id to the
5236 * string value of each of the nodes in the argument node-set. When the
5237 * argument to id is of any other type, the argument is converted to a
5238 * string as if by a call to the string function; the string is split
5239 * into a whitespace-separated list of tokens (whitespace is any sequence
5240 * of characters matching the production S); the result is a node-set
5241 * containing the elements in the same document as the context node that
5242 * have a unique ID equal to any of the tokens in the list.
5243 */
5244void
5245xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005246 xmlChar *tokens;
5247 xmlNodeSetPtr ret;
5248 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00005249
5250 CHECK_ARITY(1);
5251 obj = valuePop(ctxt);
5252 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
5253 if (obj->type == XPATH_NODESET) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005254 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00005255 int i;
5256
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005257 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005258
Daniel Veillard911f49a2001-04-07 15:39:35 +00005259 if (obj->nodesetval != NULL) {
5260 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005261 tokens =
5262 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
5263 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
5264 ret = xmlXPathNodeSetMerge(ret, ns);
5265 xmlXPathFreeNodeSet(ns);
5266 if (tokens != NULL)
5267 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00005268 }
Owen Taylor3473f882001-02-23 17:55:21 +00005269 }
5270
5271 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005272 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005273 return;
5274 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005275 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00005276
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005277 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
5278 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005279
Owen Taylor3473f882001-02-23 17:55:21 +00005280 xmlXPathFreeObject(obj);
5281 return;
5282}
5283
5284/**
5285 * xmlXPathLocalNameFunction:
5286 * @ctxt: the XPath Parser context
5287 * @nargs: the number of arguments
5288 *
5289 * Implement the local-name() XPath function
5290 * string local-name(node-set?)
5291 * The local-name function returns a string containing the local part
5292 * of the name of the node in the argument node-set that is first in
5293 * document order. If the node-set is empty or the first node has no
5294 * name, an empty string is returned. If the argument is omitted it
5295 * defaults to the context node.
5296 */
5297void
5298xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5299 xmlXPathObjectPtr cur;
5300
5301 if (nargs == 0) {
5302 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5303 nargs = 1;
5304 }
5305
5306 CHECK_ARITY(1);
5307 if ((ctxt->value == NULL) ||
5308 ((ctxt->value->type != XPATH_NODESET) &&
5309 (ctxt->value->type != XPATH_XSLT_TREE)))
5310 XP_ERROR(XPATH_INVALID_TYPE);
5311 cur = valuePop(ctxt);
5312
Daniel Veillard911f49a2001-04-07 15:39:35 +00005313 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005314 valuePush(ctxt, xmlXPathNewCString(""));
5315 } else {
5316 int i = 0; /* Should be first in document order !!!!! */
5317 switch (cur->nodesetval->nodeTab[i]->type) {
5318 case XML_ELEMENT_NODE:
5319 case XML_ATTRIBUTE_NODE:
5320 case XML_PI_NODE:
5321 valuePush(ctxt,
5322 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
5323 break;
5324 case XML_NAMESPACE_DECL:
5325 valuePush(ctxt, xmlXPathNewString(
5326 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
5327 break;
5328 default:
5329 valuePush(ctxt, xmlXPathNewCString(""));
5330 }
5331 }
5332 xmlXPathFreeObject(cur);
5333}
5334
5335/**
5336 * xmlXPathNamespaceURIFunction:
5337 * @ctxt: the XPath Parser context
5338 * @nargs: the number of arguments
5339 *
5340 * Implement the namespace-uri() XPath function
5341 * string namespace-uri(node-set?)
5342 * The namespace-uri function returns a string containing the
5343 * namespace URI of the expanded name of the node in the argument
5344 * node-set that is first in document order. If the node-set is empty,
5345 * the first node has no name, or the expanded name has no namespace
5346 * URI, an empty string is returned. If the argument is omitted it
5347 * defaults to the context node.
5348 */
5349void
5350xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5351 xmlXPathObjectPtr cur;
5352
5353 if (nargs == 0) {
5354 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5355 nargs = 1;
5356 }
5357 CHECK_ARITY(1);
5358 if ((ctxt->value == NULL) ||
5359 ((ctxt->value->type != XPATH_NODESET) &&
5360 (ctxt->value->type != XPATH_XSLT_TREE)))
5361 XP_ERROR(XPATH_INVALID_TYPE);
5362 cur = valuePop(ctxt);
5363
Daniel Veillard911f49a2001-04-07 15:39:35 +00005364 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005365 valuePush(ctxt, xmlXPathNewCString(""));
5366 } else {
5367 int i = 0; /* Should be first in document order !!!!! */
5368 switch (cur->nodesetval->nodeTab[i]->type) {
5369 case XML_ELEMENT_NODE:
5370 case XML_ATTRIBUTE_NODE:
5371 if (cur->nodesetval->nodeTab[i]->ns == NULL)
5372 valuePush(ctxt, xmlXPathNewCString(""));
5373 else
5374 valuePush(ctxt, xmlXPathNewString(
5375 cur->nodesetval->nodeTab[i]->ns->href));
5376 break;
5377 default:
5378 valuePush(ctxt, xmlXPathNewCString(""));
5379 }
5380 }
5381 xmlXPathFreeObject(cur);
5382}
5383
5384/**
5385 * xmlXPathNameFunction:
5386 * @ctxt: the XPath Parser context
5387 * @nargs: the number of arguments
5388 *
5389 * Implement the name() XPath function
5390 * string name(node-set?)
5391 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005392 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00005393 * order. The QName must represent the name with respect to the namespace
5394 * declarations in effect on the node whose name is being represented.
5395 * Typically, this will be the form in which the name occurred in the XML
5396 * source. This need not be the case if there are namespace declarations
5397 * in effect on the node that associate multiple prefixes with the same
5398 * namespace. However, an implementation may include information about
5399 * the original prefix in its representation of nodes; in this case, an
5400 * implementation can ensure that the returned string is always the same
5401 * as the QName used in the XML source. If the argument it omitted it
5402 * defaults to the context node.
5403 * Libxml keep the original prefix so the "real qualified name" used is
5404 * returned.
5405 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005406static void
Daniel Veillard04383752001-07-08 14:27:15 +00005407xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
5408{
Owen Taylor3473f882001-02-23 17:55:21 +00005409 xmlXPathObjectPtr cur;
5410
5411 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00005412 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5413 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00005414 }
5415
5416 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00005417 if ((ctxt->value == NULL) ||
5418 ((ctxt->value->type != XPATH_NODESET) &&
5419 (ctxt->value->type != XPATH_XSLT_TREE)))
5420 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00005421 cur = valuePop(ctxt);
5422
Daniel Veillard911f49a2001-04-07 15:39:35 +00005423 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00005424 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00005425 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00005426 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005427
Daniel Veillard04383752001-07-08 14:27:15 +00005428 switch (cur->nodesetval->nodeTab[i]->type) {
5429 case XML_ELEMENT_NODE:
5430 case XML_ATTRIBUTE_NODE:
5431 if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
5432 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL))
5433 valuePush(ctxt,
5434 xmlXPathNewString(cur->nodesetval->
5435 nodeTab[i]->name));
5436
5437 else {
5438 char name[2000];
5439
5440 snprintf(name, sizeof(name), "%s:%s",
5441 (char *) cur->nodesetval->nodeTab[i]->ns->
5442 prefix,
5443 (char *) cur->nodesetval->nodeTab[i]->name);
5444 name[sizeof(name) - 1] = 0;
5445 valuePush(ctxt, xmlXPathNewCString(name));
5446 }
5447 break;
5448 default:
5449 valuePush(ctxt,
5450 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
5451 xmlXPathLocalNameFunction(ctxt, 1);
5452 }
Owen Taylor3473f882001-02-23 17:55:21 +00005453 }
5454 xmlXPathFreeObject(cur);
5455}
5456
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005457
5458/**
Owen Taylor3473f882001-02-23 17:55:21 +00005459 * xmlXPathStringFunction:
5460 * @ctxt: the XPath Parser context
5461 * @nargs: the number of arguments
5462 *
5463 * Implement the string() XPath function
5464 * string string(object?)
5465 * he string function converts an object to a string as follows:
5466 * - A node-set is converted to a string by returning the value of
5467 * the node in the node-set that is first in document order.
5468 * If the node-set is empty, an empty string is returned.
5469 * - A number is converted to a string as follows
5470 * + NaN is converted to the string NaN
5471 * + positive zero is converted to the string 0
5472 * + negative zero is converted to the string 0
5473 * + positive infinity is converted to the string Infinity
5474 * + negative infinity is converted to the string -Infinity
5475 * + if the number is an integer, the number is represented in
5476 * decimal form as a Number with no decimal point and no leading
5477 * zeros, preceded by a minus sign (-) if the number is negative
5478 * + otherwise, the number is represented in decimal form as a
5479 * Number including a decimal point with at least one digit
5480 * before the decimal point and at least one digit after the
5481 * decimal point, preceded by a minus sign (-) if the number
5482 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005483 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00005484 * before the decimal point; beyond the one required digit
5485 * after the decimal point there must be as many, but only as
5486 * many, more digits as are needed to uniquely distinguish the
5487 * number from all other IEEE 754 numeric values.
5488 * - The boolean false value is converted to the string false.
5489 * The boolean true value is converted to the string true.
5490 *
5491 * If the argument is omitted, it defaults to a node-set with the
5492 * context node as its only member.
5493 */
5494void
5495xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5496 xmlXPathObjectPtr cur;
5497
5498 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005499 valuePush(ctxt,
5500 xmlXPathWrapString(
5501 xmlXPathCastNodeToString(ctxt->context->node)));
5502 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005503 }
5504
5505 CHECK_ARITY(1);
5506 cur = valuePop(ctxt);
5507 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005508 cur = xmlXPathConvertString(cur);
5509 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005510}
5511
5512/**
5513 * xmlXPathStringLengthFunction:
5514 * @ctxt: the XPath Parser context
5515 * @nargs: the number of arguments
5516 *
5517 * Implement the string-length() XPath function
5518 * number string-length(string?)
5519 * The string-length returns the number of characters in the string
5520 * (see [3.6 Strings]). If the argument is omitted, it defaults to
5521 * the context node converted to a string, in other words the value
5522 * of the context node.
5523 */
5524void
5525xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5526 xmlXPathObjectPtr cur;
5527
5528 if (nargs == 0) {
5529 if (ctxt->context->node == NULL) {
5530 valuePush(ctxt, xmlXPathNewFloat(0));
5531 } else {
5532 xmlChar *content;
5533
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005534 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005535 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00005536 xmlFree(content);
5537 }
5538 return;
5539 }
5540 CHECK_ARITY(1);
5541 CAST_TO_STRING;
5542 CHECK_TYPE(XPATH_STRING);
5543 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005544 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00005545 xmlXPathFreeObject(cur);
5546}
5547
5548/**
5549 * xmlXPathConcatFunction:
5550 * @ctxt: the XPath Parser context
5551 * @nargs: the number of arguments
5552 *
5553 * Implement the concat() XPath function
5554 * string concat(string, string, string*)
5555 * The concat function returns the concatenation of its arguments.
5556 */
5557void
5558xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5559 xmlXPathObjectPtr cur, newobj;
5560 xmlChar *tmp;
5561
5562 if (nargs < 2) {
5563 CHECK_ARITY(2);
5564 }
5565
5566 CAST_TO_STRING;
5567 cur = valuePop(ctxt);
5568 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
5569 xmlXPathFreeObject(cur);
5570 return;
5571 }
5572 nargs--;
5573
5574 while (nargs > 0) {
5575 CAST_TO_STRING;
5576 newobj = valuePop(ctxt);
5577 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
5578 xmlXPathFreeObject(newobj);
5579 xmlXPathFreeObject(cur);
5580 XP_ERROR(XPATH_INVALID_TYPE);
5581 }
5582 tmp = xmlStrcat(newobj->stringval, cur->stringval);
5583 newobj->stringval = cur->stringval;
5584 cur->stringval = tmp;
5585
5586 xmlXPathFreeObject(newobj);
5587 nargs--;
5588 }
5589 valuePush(ctxt, cur);
5590}
5591
5592/**
5593 * xmlXPathContainsFunction:
5594 * @ctxt: the XPath Parser context
5595 * @nargs: the number of arguments
5596 *
5597 * Implement the contains() XPath function
5598 * boolean contains(string, string)
5599 * The contains function returns true if the first argument string
5600 * contains the second argument string, and otherwise returns false.
5601 */
5602void
5603xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5604 xmlXPathObjectPtr hay, needle;
5605
5606 CHECK_ARITY(2);
5607 CAST_TO_STRING;
5608 CHECK_TYPE(XPATH_STRING);
5609 needle = valuePop(ctxt);
5610 CAST_TO_STRING;
5611 hay = valuePop(ctxt);
5612 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5613 xmlXPathFreeObject(hay);
5614 xmlXPathFreeObject(needle);
5615 XP_ERROR(XPATH_INVALID_TYPE);
5616 }
5617 if (xmlStrstr(hay->stringval, needle->stringval))
5618 valuePush(ctxt, xmlXPathNewBoolean(1));
5619 else
5620 valuePush(ctxt, xmlXPathNewBoolean(0));
5621 xmlXPathFreeObject(hay);
5622 xmlXPathFreeObject(needle);
5623}
5624
5625/**
5626 * xmlXPathStartsWithFunction:
5627 * @ctxt: the XPath Parser context
5628 * @nargs: the number of arguments
5629 *
5630 * Implement the starts-with() XPath function
5631 * boolean starts-with(string, string)
5632 * The starts-with function returns true if the first argument string
5633 * starts with the second argument string, and otherwise returns false.
5634 */
5635void
5636xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5637 xmlXPathObjectPtr hay, needle;
5638 int n;
5639
5640 CHECK_ARITY(2);
5641 CAST_TO_STRING;
5642 CHECK_TYPE(XPATH_STRING);
5643 needle = valuePop(ctxt);
5644 CAST_TO_STRING;
5645 hay = valuePop(ctxt);
5646 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5647 xmlXPathFreeObject(hay);
5648 xmlXPathFreeObject(needle);
5649 XP_ERROR(XPATH_INVALID_TYPE);
5650 }
5651 n = xmlStrlen(needle->stringval);
5652 if (xmlStrncmp(hay->stringval, needle->stringval, n))
5653 valuePush(ctxt, xmlXPathNewBoolean(0));
5654 else
5655 valuePush(ctxt, xmlXPathNewBoolean(1));
5656 xmlXPathFreeObject(hay);
5657 xmlXPathFreeObject(needle);
5658}
5659
5660/**
5661 * xmlXPathSubstringFunction:
5662 * @ctxt: the XPath Parser context
5663 * @nargs: the number of arguments
5664 *
5665 * Implement the substring() XPath function
5666 * string substring(string, number, number?)
5667 * The substring function returns the substring of the first argument
5668 * starting at the position specified in the second argument with
5669 * length specified in the third argument. For example,
5670 * substring("12345",2,3) returns "234". If the third argument is not
5671 * specified, it returns the substring starting at the position specified
5672 * in the second argument and continuing to the end of the string. For
5673 * example, substring("12345",2) returns "2345". More precisely, each
5674 * character in the string (see [3.6 Strings]) is considered to have a
5675 * numeric position: the position of the first character is 1, the position
5676 * of the second character is 2 and so on. The returned substring contains
5677 * those characters for which the position of the character is greater than
5678 * or equal to the second argument and, if the third argument is specified,
5679 * less than the sum of the second and third arguments; the comparisons
5680 * and addition used for the above follow the standard IEEE 754 rules. Thus:
5681 * - substring("12345", 1.5, 2.6) returns "234"
5682 * - substring("12345", 0, 3) returns "12"
5683 * - substring("12345", 0 div 0, 3) returns ""
5684 * - substring("12345", 1, 0 div 0) returns ""
5685 * - substring("12345", -42, 1 div 0) returns "12345"
5686 * - substring("12345", -1 div 0, 1 div 0) returns ""
5687 */
5688void
5689xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5690 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005691 double le=0, in;
5692 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00005693 xmlChar *ret;
5694
Owen Taylor3473f882001-02-23 17:55:21 +00005695 if (nargs < 2) {
5696 CHECK_ARITY(2);
5697 }
5698 if (nargs > 3) {
5699 CHECK_ARITY(3);
5700 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005701 /*
5702 * take care of possible last (position) argument
5703 */
Owen Taylor3473f882001-02-23 17:55:21 +00005704 if (nargs == 3) {
5705 CAST_TO_NUMBER;
5706 CHECK_TYPE(XPATH_NUMBER);
5707 len = valuePop(ctxt);
5708 le = len->floatval;
5709 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00005710 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005711
Owen Taylor3473f882001-02-23 17:55:21 +00005712 CAST_TO_NUMBER;
5713 CHECK_TYPE(XPATH_NUMBER);
5714 start = valuePop(ctxt);
5715 in = start->floatval;
5716 xmlXPathFreeObject(start);
5717 CAST_TO_STRING;
5718 CHECK_TYPE(XPATH_STRING);
5719 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00005720 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005721
Daniel Veillard97ac1312001-05-30 19:14:17 +00005722 /*
5723 * If last pos not present, calculate last position
5724 */
5725 if (nargs != 3)
5726 le = m;
5727
5728 /*
5729 * To meet our requirements, initial index calculations
5730 * must be done before we convert to integer format
5731 *
5732 * First we normalize indices
5733 */
5734 in -= 1.0;
5735 le += in;
5736 if (in < 0.0)
5737 in = 0.0;
5738 if (le > (double)m)
5739 le = (double)m;
5740
5741 /*
5742 * Now we go to integer form, rounding up
5743 */
Owen Taylor3473f882001-02-23 17:55:21 +00005744 i = (int) in;
5745 if (((double)i) != in) i++;
5746
Owen Taylor3473f882001-02-23 17:55:21 +00005747 l = (int) le;
5748 if (((double)l) != le) l++;
5749
Daniel Veillard97ac1312001-05-30 19:14:17 +00005750 if (l > m) l=m;
Owen Taylor3473f882001-02-23 17:55:21 +00005751
5752 /* number of chars to copy */
5753 l -= i;
5754
Daniel Veillard97ac1312001-05-30 19:14:17 +00005755 ret = xmlUTF8Strsub(str->stringval, i, l);
Owen Taylor3473f882001-02-23 17:55:21 +00005756 if (ret == NULL)
5757 valuePush(ctxt, xmlXPathNewCString(""));
5758 else {
5759 valuePush(ctxt, xmlXPathNewString(ret));
5760 xmlFree(ret);
5761 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005762
Owen Taylor3473f882001-02-23 17:55:21 +00005763 xmlXPathFreeObject(str);
5764}
5765
5766/**
5767 * xmlXPathSubstringBeforeFunction:
5768 * @ctxt: the XPath Parser context
5769 * @nargs: the number of arguments
5770 *
5771 * Implement the substring-before() XPath function
5772 * string substring-before(string, string)
5773 * The substring-before function returns the substring of the first
5774 * argument string that precedes the first occurrence of the second
5775 * argument string in the first argument string, or the empty string
5776 * if the first argument string does not contain the second argument
5777 * string. For example, substring-before("1999/04/01","/") returns 1999.
5778 */
5779void
5780xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5781 xmlXPathObjectPtr str;
5782 xmlXPathObjectPtr find;
5783 xmlBufferPtr target;
5784 const xmlChar *point;
5785 int offset;
5786
5787 CHECK_ARITY(2);
5788 CAST_TO_STRING;
5789 find = valuePop(ctxt);
5790 CAST_TO_STRING;
5791 str = valuePop(ctxt);
5792
5793 target = xmlBufferCreate();
5794 if (target) {
5795 point = xmlStrstr(str->stringval, find->stringval);
5796 if (point) {
5797 offset = (int)(point - str->stringval);
5798 xmlBufferAdd(target, str->stringval, offset);
5799 }
5800 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5801 xmlBufferFree(target);
5802 }
5803
5804 xmlXPathFreeObject(str);
5805 xmlXPathFreeObject(find);
5806}
5807
5808/**
5809 * xmlXPathSubstringAfterFunction:
5810 * @ctxt: the XPath Parser context
5811 * @nargs: the number of arguments
5812 *
5813 * Implement the substring-after() XPath function
5814 * string substring-after(string, string)
5815 * The substring-after function returns the substring of the first
5816 * argument string that follows the first occurrence of the second
5817 * argument string in the first argument string, or the empty stringi
5818 * if the first argument string does not contain the second argument
5819 * string. For example, substring-after("1999/04/01","/") returns 04/01,
5820 * and substring-after("1999/04/01","19") returns 99/04/01.
5821 */
5822void
5823xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5824 xmlXPathObjectPtr str;
5825 xmlXPathObjectPtr find;
5826 xmlBufferPtr target;
5827 const xmlChar *point;
5828 int offset;
5829
5830 CHECK_ARITY(2);
5831 CAST_TO_STRING;
5832 find = valuePop(ctxt);
5833 CAST_TO_STRING;
5834 str = valuePop(ctxt);
5835
5836 target = xmlBufferCreate();
5837 if (target) {
5838 point = xmlStrstr(str->stringval, find->stringval);
5839 if (point) {
5840 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
5841 xmlBufferAdd(target, &str->stringval[offset],
5842 xmlStrlen(str->stringval) - offset);
5843 }
5844 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5845 xmlBufferFree(target);
5846 }
5847
5848 xmlXPathFreeObject(str);
5849 xmlXPathFreeObject(find);
5850}
5851
5852/**
5853 * xmlXPathNormalizeFunction:
5854 * @ctxt: the XPath Parser context
5855 * @nargs: the number of arguments
5856 *
5857 * Implement the normalize-space() XPath function
5858 * string normalize-space(string?)
5859 * The normalize-space function returns the argument string with white
5860 * space normalized by stripping leading and trailing whitespace
5861 * and replacing sequences of whitespace characters by a single
5862 * space. Whitespace characters are the same allowed by the S production
5863 * in XML. If the argument is omitted, it defaults to the context
5864 * node converted to a string, in other words the value of the context node.
5865 */
5866void
5867xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5868 xmlXPathObjectPtr obj = NULL;
5869 xmlChar *source = NULL;
5870 xmlBufferPtr target;
5871 xmlChar blank;
5872
5873 if (nargs == 0) {
5874 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005875 valuePush(ctxt,
5876 xmlXPathWrapString(
5877 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00005878 nargs = 1;
5879 }
5880
5881 CHECK_ARITY(1);
5882 CAST_TO_STRING;
5883 CHECK_TYPE(XPATH_STRING);
5884 obj = valuePop(ctxt);
5885 source = obj->stringval;
5886
5887 target = xmlBufferCreate();
5888 if (target && source) {
5889
5890 /* Skip leading whitespaces */
5891 while (IS_BLANK(*source))
5892 source++;
5893
5894 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
5895 blank = 0;
5896 while (*source) {
5897 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005898 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00005899 } else {
5900 if (blank) {
5901 xmlBufferAdd(target, &blank, 1);
5902 blank = 0;
5903 }
5904 xmlBufferAdd(target, source, 1);
5905 }
5906 source++;
5907 }
5908
5909 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5910 xmlBufferFree(target);
5911 }
5912 xmlXPathFreeObject(obj);
5913}
5914
5915/**
5916 * xmlXPathTranslateFunction:
5917 * @ctxt: the XPath Parser context
5918 * @nargs: the number of arguments
5919 *
5920 * Implement the translate() XPath function
5921 * string translate(string, string, string)
5922 * The translate function returns the first argument string with
5923 * occurrences of characters in the second argument string replaced
5924 * by the character at the corresponding position in the third argument
5925 * string. For example, translate("bar","abc","ABC") returns the string
5926 * BAr. If there is a character in the second argument string with no
5927 * character at a corresponding position in the third argument string
5928 * (because the second argument string is longer than the third argument
5929 * string), then occurrences of that character in the first argument
5930 * string are removed. For example, translate("--aaa--","abc-","ABC")
5931 * returns "AAA". If a character occurs more than once in second
5932 * argument string, then the first occurrence determines the replacement
5933 * character. If the third argument string is longer than the second
5934 * argument string, then excess characters are ignored.
5935 */
5936void
5937xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00005938 xmlXPathObjectPtr str;
5939 xmlXPathObjectPtr from;
5940 xmlXPathObjectPtr to;
5941 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005942 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00005943 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005944 xmlChar *point;
5945 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00005946
Daniel Veillarde043ee12001-04-16 14:08:07 +00005947 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00005948
Daniel Veillarde043ee12001-04-16 14:08:07 +00005949 CAST_TO_STRING;
5950 to = valuePop(ctxt);
5951 CAST_TO_STRING;
5952 from = valuePop(ctxt);
5953 CAST_TO_STRING;
5954 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005955
Daniel Veillarde043ee12001-04-16 14:08:07 +00005956 target = xmlBufferCreate();
5957 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005958 max = xmlUTF8Strlen(to->stringval);
5959 for (cptr = str->stringval; (ch=*cptr); ) {
5960 offset = xmlUTF8Strloc(from->stringval, cptr);
5961 if (offset >= 0) {
5962 if (offset < max) {
5963 point = xmlUTF8Strpos(to->stringval, offset);
5964 if (point)
5965 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
5966 }
5967 } else
5968 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
5969
5970 /* Step to next character in input */
5971 cptr++;
5972 if ( ch & 0x80 ) {
5973 /* if not simple ascii, verify proper format */
5974 if ( (ch & 0xc0) != 0xc0 ) {
5975 xmlGenericError(xmlGenericErrorContext,
5976 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5977 break;
5978 }
5979 /* then skip over remaining bytes for this char */
5980 while ( (ch <<= 1) & 0x80 )
5981 if ( (*cptr++ & 0xc0) != 0x80 ) {
5982 xmlGenericError(xmlGenericErrorContext,
5983 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5984 break;
5985 }
5986 if (ch & 0x80) /* must have had error encountered */
5987 break;
5988 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005989 }
Owen Taylor3473f882001-02-23 17:55:21 +00005990 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005991 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5992 xmlBufferFree(target);
5993 xmlXPathFreeObject(str);
5994 xmlXPathFreeObject(from);
5995 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00005996}
5997
5998/**
5999 * xmlXPathBooleanFunction:
6000 * @ctxt: the XPath Parser context
6001 * @nargs: the number of arguments
6002 *
6003 * Implement the boolean() XPath function
6004 * boolean boolean(object)
6005 * he boolean function converts its argument to a boolean as follows:
6006 * - a number is true if and only if it is neither positive or
6007 * negative zero nor NaN
6008 * - a node-set is true if and only if it is non-empty
6009 * - a string is true if and only if its length is non-zero
6010 */
6011void
6012xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6013 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006014
6015 CHECK_ARITY(1);
6016 cur = valuePop(ctxt);
6017 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006018 cur = xmlXPathConvertBoolean(cur);
6019 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006020}
6021
6022/**
6023 * xmlXPathNotFunction:
6024 * @ctxt: the XPath Parser context
6025 * @nargs: the number of arguments
6026 *
6027 * Implement the not() XPath function
6028 * boolean not(boolean)
6029 * The not function returns true if its argument is false,
6030 * and false otherwise.
6031 */
6032void
6033xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6034 CHECK_ARITY(1);
6035 CAST_TO_BOOLEAN;
6036 CHECK_TYPE(XPATH_BOOLEAN);
6037 ctxt->value->boolval = ! ctxt->value->boolval;
6038}
6039
6040/**
6041 * xmlXPathTrueFunction:
6042 * @ctxt: the XPath Parser context
6043 * @nargs: the number of arguments
6044 *
6045 * Implement the true() XPath function
6046 * boolean true()
6047 */
6048void
6049xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6050 CHECK_ARITY(0);
6051 valuePush(ctxt, xmlXPathNewBoolean(1));
6052}
6053
6054/**
6055 * xmlXPathFalseFunction:
6056 * @ctxt: the XPath Parser context
6057 * @nargs: the number of arguments
6058 *
6059 * Implement the false() XPath function
6060 * boolean false()
6061 */
6062void
6063xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6064 CHECK_ARITY(0);
6065 valuePush(ctxt, xmlXPathNewBoolean(0));
6066}
6067
6068/**
6069 * xmlXPathLangFunction:
6070 * @ctxt: the XPath Parser context
6071 * @nargs: the number of arguments
6072 *
6073 * Implement the lang() XPath function
6074 * boolean lang(string)
6075 * The lang function returns true or false depending on whether the
6076 * language of the context node as specified by xml:lang attributes
6077 * is the same as or is a sublanguage of the language specified by
6078 * the argument string. The language of the context node is determined
6079 * by the value of the xml:lang attribute on the context node, or, if
6080 * the context node has no xml:lang attribute, by the value of the
6081 * xml:lang attribute on the nearest ancestor of the context node that
6082 * has an xml:lang attribute. If there is no such attribute, then lang
6083 * returns false. If there is such an attribute, then lang returns
6084 * true if the attribute value is equal to the argument ignoring case,
6085 * or if there is some suffix starting with - such that the attribute
6086 * value is equal to the argument ignoring that suffix of the attribute
6087 * value and ignoring case.
6088 */
6089void
6090xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6091 xmlXPathObjectPtr val;
6092 const xmlChar *theLang;
6093 const xmlChar *lang;
6094 int ret = 0;
6095 int i;
6096
6097 CHECK_ARITY(1);
6098 CAST_TO_STRING;
6099 CHECK_TYPE(XPATH_STRING);
6100 val = valuePop(ctxt);
6101 lang = val->stringval;
6102 theLang = xmlNodeGetLang(ctxt->context->node);
6103 if ((theLang != NULL) && (lang != NULL)) {
6104 for (i = 0;lang[i] != 0;i++)
6105 if (toupper(lang[i]) != toupper(theLang[i]))
6106 goto not_equal;
6107 ret = 1;
6108 }
6109not_equal:
6110 xmlXPathFreeObject(val);
6111 valuePush(ctxt, xmlXPathNewBoolean(ret));
6112}
6113
6114/**
6115 * xmlXPathNumberFunction:
6116 * @ctxt: the XPath Parser context
6117 * @nargs: the number of arguments
6118 *
6119 * Implement the number() XPath function
6120 * number number(object?)
6121 */
6122void
6123xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6124 xmlXPathObjectPtr cur;
6125 double res;
6126
6127 if (nargs == 0) {
6128 if (ctxt->context->node == NULL) {
6129 valuePush(ctxt, xmlXPathNewFloat(0.0));
6130 } else {
6131 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6132
6133 res = xmlXPathStringEvalNumber(content);
6134 valuePush(ctxt, xmlXPathNewFloat(res));
6135 xmlFree(content);
6136 }
6137 return;
6138 }
6139
6140 CHECK_ARITY(1);
6141 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006142 cur = xmlXPathConvertNumber(cur);
6143 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006144}
6145
6146/**
6147 * xmlXPathSumFunction:
6148 * @ctxt: the XPath Parser context
6149 * @nargs: the number of arguments
6150 *
6151 * Implement the sum() XPath function
6152 * number sum(node-set)
6153 * The sum function returns the sum of the values of the nodes in
6154 * the argument node-set.
6155 */
6156void
6157xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6158 xmlXPathObjectPtr cur;
6159 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006160 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006161
6162 CHECK_ARITY(1);
6163 if ((ctxt->value == NULL) ||
6164 ((ctxt->value->type != XPATH_NODESET) &&
6165 (ctxt->value->type != XPATH_XSLT_TREE)))
6166 XP_ERROR(XPATH_INVALID_TYPE);
6167 cur = valuePop(ctxt);
6168
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006169 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006170 valuePush(ctxt, xmlXPathNewFloat(0.0));
6171 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006172 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6173 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006174 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006175 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006176 }
6177 xmlXPathFreeObject(cur);
6178}
6179
6180/**
6181 * xmlXPathFloorFunction:
6182 * @ctxt: the XPath Parser context
6183 * @nargs: the number of arguments
6184 *
6185 * Implement the floor() XPath function
6186 * number floor(number)
6187 * The floor function returns the largest (closest to positive infinity)
6188 * number that is not greater than the argument and that is an integer.
6189 */
6190void
6191xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6192 CHECK_ARITY(1);
6193 CAST_TO_NUMBER;
6194 CHECK_TYPE(XPATH_NUMBER);
6195#if 0
6196 ctxt->value->floatval = floor(ctxt->value->floatval);
6197#else
6198 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
6199 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
6200#endif
6201}
6202
6203/**
6204 * xmlXPathCeilingFunction:
6205 * @ctxt: the XPath Parser context
6206 * @nargs: the number of arguments
6207 *
6208 * Implement the ceiling() XPath function
6209 * number ceiling(number)
6210 * The ceiling function returns the smallest (closest to negative infinity)
6211 * number that is not less than the argument and that is an integer.
6212 */
6213void
6214xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6215 double f;
6216
6217 CHECK_ARITY(1);
6218 CAST_TO_NUMBER;
6219 CHECK_TYPE(XPATH_NUMBER);
6220
6221#if 0
6222 ctxt->value->floatval = ceil(ctxt->value->floatval);
6223#else
6224 f = (double)((int) ctxt->value->floatval);
6225 if (f != ctxt->value->floatval)
6226 ctxt->value->floatval = f + 1;
6227#endif
6228}
6229
6230/**
6231 * xmlXPathRoundFunction:
6232 * @ctxt: the XPath Parser context
6233 * @nargs: the number of arguments
6234 *
6235 * Implement the round() XPath function
6236 * number round(number)
6237 * The round function returns the number that is closest to the
6238 * argument and that is an integer. If there are two such numbers,
6239 * then the one that is even is returned.
6240 */
6241void
6242xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6243 double f;
6244
6245 CHECK_ARITY(1);
6246 CAST_TO_NUMBER;
6247 CHECK_TYPE(XPATH_NUMBER);
6248
Daniel Veillardcda96922001-08-21 10:56:31 +00006249 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
6250 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
6251 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00006252 (ctxt->value->floatval == 0.0))
6253 return;
6254
6255#if 0
6256 f = floor(ctxt->value->floatval);
6257#else
6258 f = (double)((int) ctxt->value->floatval);
6259#endif
6260 if (ctxt->value->floatval < f + 0.5)
6261 ctxt->value->floatval = f;
6262 else
6263 ctxt->value->floatval = f + 1;
6264}
6265
6266/************************************************************************
6267 * *
6268 * The Parser *
6269 * *
6270 ************************************************************************/
6271
6272/*
6273 * a couple of forward declarations since we use a recursive call based
6274 * implementation.
6275 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006276static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006277static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006278static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006279#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006280static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
6281#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006282#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006283static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006284#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00006285static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
6286 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00006287
6288/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00006289 * xmlXPathCurrentChar:
6290 * @ctxt: the XPath parser context
6291 * @cur: pointer to the beginning of the char
6292 * @len: pointer to the length of the char read
6293 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006294 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00006295 * bytes in the input buffer.
6296 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006297 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00006298 */
6299
6300static int
6301xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
6302 unsigned char c;
6303 unsigned int val;
6304 const xmlChar *cur;
6305
6306 if (ctxt == NULL)
6307 return(0);
6308 cur = ctxt->cur;
6309
6310 /*
6311 * We are supposed to handle UTF8, check it's valid
6312 * From rfc2044: encoding of the Unicode values on UTF-8:
6313 *
6314 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
6315 * 0000 0000-0000 007F 0xxxxxxx
6316 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
6317 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
6318 *
6319 * Check for the 0x110000 limit too
6320 */
6321 c = *cur;
6322 if (c & 0x80) {
6323 if ((cur[1] & 0xc0) != 0x80)
6324 goto encoding_error;
6325 if ((c & 0xe0) == 0xe0) {
6326
6327 if ((cur[2] & 0xc0) != 0x80)
6328 goto encoding_error;
6329 if ((c & 0xf0) == 0xf0) {
6330 if (((c & 0xf8) != 0xf0) ||
6331 ((cur[3] & 0xc0) != 0x80))
6332 goto encoding_error;
6333 /* 4-byte code */
6334 *len = 4;
6335 val = (cur[0] & 0x7) << 18;
6336 val |= (cur[1] & 0x3f) << 12;
6337 val |= (cur[2] & 0x3f) << 6;
6338 val |= cur[3] & 0x3f;
6339 } else {
6340 /* 3-byte code */
6341 *len = 3;
6342 val = (cur[0] & 0xf) << 12;
6343 val |= (cur[1] & 0x3f) << 6;
6344 val |= cur[2] & 0x3f;
6345 }
6346 } else {
6347 /* 2-byte code */
6348 *len = 2;
6349 val = (cur[0] & 0x1f) << 6;
6350 val |= cur[1] & 0x3f;
6351 }
6352 if (!IS_CHAR(val)) {
6353 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
6354 }
6355 return(val);
6356 } else {
6357 /* 1-byte code */
6358 *len = 1;
6359 return((int) *cur);
6360 }
6361encoding_error:
6362 /*
6363 * If we detect an UTF8 error that probably mean that the
6364 * input encoding didn't get properly advertized in the
6365 * declaration header. Report the error and switch the encoding
6366 * to ISO-Latin-1 (if you don't like this policy, just declare the
6367 * encoding !)
6368 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00006369 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00006370 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006371}
6372
6373/**
Owen Taylor3473f882001-02-23 17:55:21 +00006374 * xmlXPathParseNCName:
6375 * @ctxt: the XPath Parser context
6376 *
6377 * parse an XML namespace non qualified name.
6378 *
6379 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
6380 *
6381 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
6382 * CombiningChar | Extender
6383 *
6384 * Returns the namespace name or NULL
6385 */
6386
6387xmlChar *
6388xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00006389 const xmlChar *in;
6390 xmlChar *ret;
6391 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006392
Daniel Veillard2156a562001-04-28 12:24:34 +00006393 /*
6394 * Accelerator for simple ASCII names
6395 */
6396 in = ctxt->cur;
6397 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6398 ((*in >= 0x41) && (*in <= 0x5A)) ||
6399 (*in == '_')) {
6400 in++;
6401 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6402 ((*in >= 0x41) && (*in <= 0x5A)) ||
6403 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00006404 (*in == '_') || (*in == '.') ||
6405 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00006406 in++;
6407 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
6408 (*in == '[') || (*in == ']') || (*in == ':') ||
6409 (*in == '@') || (*in == '*')) {
6410 count = in - ctxt->cur;
6411 if (count == 0)
6412 return(NULL);
6413 ret = xmlStrndup(ctxt->cur, count);
6414 ctxt->cur = in;
6415 return(ret);
6416 }
6417 }
6418 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00006419}
6420
Daniel Veillard2156a562001-04-28 12:24:34 +00006421
Owen Taylor3473f882001-02-23 17:55:21 +00006422/**
6423 * xmlXPathParseQName:
6424 * @ctxt: the XPath Parser context
6425 * @prefix: a xmlChar **
6426 *
6427 * parse an XML qualified name
6428 *
6429 * [NS 5] QName ::= (Prefix ':')? LocalPart
6430 *
6431 * [NS 6] Prefix ::= NCName
6432 *
6433 * [NS 7] LocalPart ::= NCName
6434 *
6435 * Returns the function returns the local part, and prefix is updated
6436 * to get the Prefix if any.
6437 */
6438
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006439static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006440xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
6441 xmlChar *ret = NULL;
6442
6443 *prefix = NULL;
6444 ret = xmlXPathParseNCName(ctxt);
6445 if (CUR == ':') {
6446 *prefix = ret;
6447 NEXT;
6448 ret = xmlXPathParseNCName(ctxt);
6449 }
6450 return(ret);
6451}
6452
6453/**
6454 * xmlXPathParseName:
6455 * @ctxt: the XPath Parser context
6456 *
6457 * parse an XML name
6458 *
6459 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6460 * CombiningChar | Extender
6461 *
6462 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6463 *
6464 * Returns the namespace name or NULL
6465 */
6466
6467xmlChar *
6468xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006469 const xmlChar *in;
6470 xmlChar *ret;
6471 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006472
Daniel Veillard61d80a22001-04-27 17:13:01 +00006473 /*
6474 * Accelerator for simple ASCII names
6475 */
6476 in = ctxt->cur;
6477 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6478 ((*in >= 0x41) && (*in <= 0x5A)) ||
6479 (*in == '_') || (*in == ':')) {
6480 in++;
6481 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6482 ((*in >= 0x41) && (*in <= 0x5A)) ||
6483 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00006484 (*in == '_') || (*in == '-') ||
6485 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00006486 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00006487 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006488 count = in - ctxt->cur;
6489 ret = xmlStrndup(ctxt->cur, count);
6490 ctxt->cur = in;
6491 return(ret);
6492 }
6493 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006494 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00006495}
6496
Daniel Veillard61d80a22001-04-27 17:13:01 +00006497static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00006498xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006499 xmlChar buf[XML_MAX_NAMELEN + 5];
6500 int len = 0, l;
6501 int c;
6502
6503 /*
6504 * Handler for more complex cases
6505 */
6506 c = CUR_CHAR(l);
6507 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00006508 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
6509 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00006510 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00006511 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006512 return(NULL);
6513 }
6514
6515 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
6516 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
6517 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006518 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006519 (IS_COMBINING(c)) ||
6520 (IS_EXTENDER(c)))) {
6521 COPY_BUF(l,buf,len,c);
6522 NEXTL(l);
6523 c = CUR_CHAR(l);
6524 if (len >= XML_MAX_NAMELEN) {
6525 /*
6526 * Okay someone managed to make a huge name, so he's ready to pay
6527 * for the processing speed.
6528 */
6529 xmlChar *buffer;
6530 int max = len * 2;
6531
6532 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
6533 if (buffer == NULL) {
6534 XP_ERROR0(XPATH_MEMORY_ERROR);
6535 }
6536 memcpy(buffer, buf, len);
6537 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
6538 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006539 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006540 (IS_COMBINING(c)) ||
6541 (IS_EXTENDER(c))) {
6542 if (len + 10 > max) {
6543 max *= 2;
6544 buffer = (xmlChar *) xmlRealloc(buffer,
6545 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00006546 if (buffer == NULL) {
6547 XP_ERROR0(XPATH_MEMORY_ERROR);
6548 }
6549 }
6550 COPY_BUF(l,buffer,len,c);
6551 NEXTL(l);
6552 c = CUR_CHAR(l);
6553 }
6554 buffer[len] = 0;
6555 return(buffer);
6556 }
6557 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006558 if (len == 0)
6559 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006560 return(xmlStrndup(buf, len));
6561}
Owen Taylor3473f882001-02-23 17:55:21 +00006562/**
6563 * xmlXPathStringEvalNumber:
6564 * @str: A string to scan
6565 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00006566 * [30a] Float ::= Number ('e' Digits?)?
6567 *
Owen Taylor3473f882001-02-23 17:55:21 +00006568 * [30] Number ::= Digits ('.' Digits?)?
6569 * | '.' Digits
6570 * [31] Digits ::= [0-9]+
6571 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006572 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00006573 * In complement of the Number expression, this function also handles
6574 * negative values : '-' Number.
6575 *
6576 * Returns the double value.
6577 */
6578double
6579xmlXPathStringEvalNumber(const xmlChar *str) {
6580 const xmlChar *cur = str;
6581 double ret = 0.0;
6582 double mult = 1;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006583 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006584 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006585 int exponent = 0;
6586 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006587#ifdef __GNUC__
6588 unsigned long tmp = 0;
6589#endif
Bjorn Reese70a9da52001-04-21 16:57:29 +00006590
Owen Taylor3473f882001-02-23 17:55:21 +00006591 while (IS_BLANK(*cur)) cur++;
6592 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
6593 return(xmlXPathNAN);
6594 }
6595 if (*cur == '-') {
6596 isneg = 1;
6597 cur++;
6598 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00006599
6600#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006601 /*
Daniel Veillardb06c6142001-08-27 14:26:30 +00006602 * tmp is a workaround against a gcc compiler bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006603 */
Owen Taylor3473f882001-02-23 17:55:21 +00006604 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006605 tmp = tmp * 10 + (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00006606 ok = 1;
6607 cur++;
6608 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006609 ret = (double) tmp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006610#else
6611 while ((*cur >= '0') && (*cur <= '9')) {
6612 ret = ret * 10 + (*cur - '0');
6613 ok = 1;
6614 cur++;
6615 }
6616#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006617
Owen Taylor3473f882001-02-23 17:55:21 +00006618 if (*cur == '.') {
6619 cur++;
6620 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
6621 return(xmlXPathNAN);
6622 }
6623 while ((*cur >= '0') && (*cur <= '9')) {
6624 mult /= 10;
6625 ret = ret + (*cur - '0') * mult;
6626 cur++;
6627 }
6628 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006629 if ((*cur == 'e') || (*cur == 'E')) {
6630 cur++;
6631 if (*cur == '-') {
6632 is_exponent_negative = 1;
6633 cur++;
6634 }
6635 while ((*cur >= '0') && (*cur <= '9')) {
6636 exponent = exponent * 10 + (*cur - '0');
6637 cur++;
6638 }
6639 }
Owen Taylor3473f882001-02-23 17:55:21 +00006640 while (IS_BLANK(*cur)) cur++;
6641 if (*cur != 0) return(xmlXPathNAN);
6642 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006643 if (is_exponent_negative) exponent = -exponent;
6644 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00006645 return(ret);
6646}
6647
6648/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006649 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00006650 * @ctxt: the XPath Parser context
6651 *
6652 * [30] Number ::= Digits ('.' Digits?)?
6653 * | '.' Digits
6654 * [31] Digits ::= [0-9]+
6655 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006656 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00006657 *
6658 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006659static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006660xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
6661{
Owen Taylor3473f882001-02-23 17:55:21 +00006662 double ret = 0.0;
6663 double mult = 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006664 int ok = 0, tmp = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006665 int exponent = 0;
6666 int is_exponent_negative = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006667
6668 CHECK_ERROR;
6669 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
6670 XP_ERROR(XPATH_NUMBER_ERROR);
6671 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006672 /*
6673 * Try to work around a gcc optimizer bug
6674 */
Owen Taylor3473f882001-02-23 17:55:21 +00006675 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006676 tmp = tmp * 10 + (CUR - '0');
6677 ok = 1;
6678 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +00006679 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006680 ret = (double) tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00006681 if (CUR == '.') {
6682 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006683 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
6684 XP_ERROR(XPATH_NUMBER_ERROR);
6685 }
6686 while ((CUR >= '0') && (CUR <= '9')) {
6687 mult /= 10;
6688 ret = ret + (CUR - '0') * mult;
6689 NEXT;
6690 }
Owen Taylor3473f882001-02-23 17:55:21 +00006691 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006692 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006693 NEXT;
6694 if (CUR == '-') {
6695 is_exponent_negative = 1;
6696 NEXT;
6697 }
6698 while ((CUR >= '0') && (CUR <= '9')) {
6699 exponent = exponent * 10 + (CUR - '0');
6700 NEXT;
6701 }
6702 if (is_exponent_negative)
6703 exponent = -exponent;
6704 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006705 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006706 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006707 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006708}
6709
6710/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006711 * xmlXPathParseLiteral:
6712 * @ctxt: the XPath Parser context
6713 *
6714 * Parse a Literal
6715 *
6716 * [29] Literal ::= '"' [^"]* '"'
6717 * | "'" [^']* "'"
6718 *
6719 * Returns the value found or NULL in case of error
6720 */
6721static xmlChar *
6722xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
6723 const xmlChar *q;
6724 xmlChar *ret = NULL;
6725
6726 if (CUR == '"') {
6727 NEXT;
6728 q = CUR_PTR;
6729 while ((IS_CHAR(CUR)) && (CUR != '"'))
6730 NEXT;
6731 if (!IS_CHAR(CUR)) {
6732 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6733 } else {
6734 ret = xmlStrndup(q, CUR_PTR - q);
6735 NEXT;
6736 }
6737 } else if (CUR == '\'') {
6738 NEXT;
6739 q = CUR_PTR;
6740 while ((IS_CHAR(CUR)) && (CUR != '\''))
6741 NEXT;
6742 if (!IS_CHAR(CUR)) {
6743 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6744 } else {
6745 ret = xmlStrndup(q, CUR_PTR - q);
6746 NEXT;
6747 }
6748 } else {
6749 XP_ERROR0(XPATH_START_LITERAL_ERROR);
6750 }
6751 return(ret);
6752}
6753
6754/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006755 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00006756 * @ctxt: the XPath Parser context
6757 *
6758 * Parse a Literal and push it on the stack.
6759 *
6760 * [29] Literal ::= '"' [^"]* '"'
6761 * | "'" [^']* "'"
6762 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006763 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00006764 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006765static void
6766xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006767 const xmlChar *q;
6768 xmlChar *ret = NULL;
6769
6770 if (CUR == '"') {
6771 NEXT;
6772 q = CUR_PTR;
6773 while ((IS_CHAR(CUR)) && (CUR != '"'))
6774 NEXT;
6775 if (!IS_CHAR(CUR)) {
6776 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
6777 } else {
6778 ret = xmlStrndup(q, CUR_PTR - q);
6779 NEXT;
6780 }
6781 } else if (CUR == '\'') {
6782 NEXT;
6783 q = CUR_PTR;
6784 while ((IS_CHAR(CUR)) && (CUR != '\''))
6785 NEXT;
6786 if (!IS_CHAR(CUR)) {
6787 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
6788 } else {
6789 ret = xmlStrndup(q, CUR_PTR - q);
6790 NEXT;
6791 }
6792 } else {
6793 XP_ERROR(XPATH_START_LITERAL_ERROR);
6794 }
6795 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006796 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
6797 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006798 xmlFree(ret);
6799}
6800
6801/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006802 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00006803 * @ctxt: the XPath Parser context
6804 *
6805 * Parse a VariableReference, evaluate it and push it on the stack.
6806 *
6807 * The variable bindings consist of a mapping from variable names
6808 * to variable values. The value of a variable is an object, which
6809 * of any of the types that are possible for the value of an expression,
6810 * and may also be of additional types not specified here.
6811 *
6812 * Early evaluation is possible since:
6813 * The variable bindings [...] used to evaluate a subexpression are
6814 * always the same as those used to evaluate the containing expression.
6815 *
6816 * [36] VariableReference ::= '$' QName
6817 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006818static void
6819xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006820 xmlChar *name;
6821 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006822
6823 SKIP_BLANKS;
6824 if (CUR != '$') {
6825 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
6826 }
6827 NEXT;
6828 name = xmlXPathParseQName(ctxt, &prefix);
6829 if (name == NULL) {
6830 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
6831 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006832 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006833 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
6834 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006835 SKIP_BLANKS;
6836}
6837
6838/**
6839 * xmlXPathIsNodeType:
6840 * @ctxt: the XPath Parser context
6841 * @name: a name string
6842 *
6843 * Is the name given a NodeType one.
6844 *
6845 * [38] NodeType ::= 'comment'
6846 * | 'text'
6847 * | 'processing-instruction'
6848 * | 'node'
6849 *
6850 * Returns 1 if true 0 otherwise
6851 */
6852int
6853xmlXPathIsNodeType(const xmlChar *name) {
6854 if (name == NULL)
6855 return(0);
6856
6857 if (xmlStrEqual(name, BAD_CAST "comment"))
6858 return(1);
6859 if (xmlStrEqual(name, BAD_CAST "text"))
6860 return(1);
6861 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
6862 return(1);
6863 if (xmlStrEqual(name, BAD_CAST "node"))
6864 return(1);
6865 return(0);
6866}
6867
6868/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006869 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00006870 * @ctxt: the XPath Parser context
6871 *
6872 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
6873 * [17] Argument ::= Expr
6874 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006875 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00006876 * pushed on the stack
6877 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006878static void
6879xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006880 xmlChar *name;
6881 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006882 int nbargs = 0;
6883
6884 name = xmlXPathParseQName(ctxt, &prefix);
6885 if (name == NULL) {
6886 XP_ERROR(XPATH_EXPR_ERROR);
6887 }
6888 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006889#ifdef DEBUG_EXPR
6890 if (prefix == NULL)
6891 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
6892 name);
6893 else
6894 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
6895 prefix, name);
6896#endif
6897
Owen Taylor3473f882001-02-23 17:55:21 +00006898 if (CUR != '(') {
6899 XP_ERROR(XPATH_EXPR_ERROR);
6900 }
6901 NEXT;
6902 SKIP_BLANKS;
6903
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006904 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006905 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006906 int op1 = ctxt->comp->last;
6907 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006908 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006909 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006910 nbargs++;
6911 if (CUR == ')') break;
6912 if (CUR != ',') {
6913 XP_ERROR(XPATH_EXPR_ERROR);
6914 }
6915 NEXT;
6916 SKIP_BLANKS;
6917 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006918 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
6919 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006920 NEXT;
6921 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006922}
6923
6924/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006925 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006926 * @ctxt: the XPath Parser context
6927 *
6928 * [15] PrimaryExpr ::= VariableReference
6929 * | '(' Expr ')'
6930 * | Literal
6931 * | Number
6932 * | FunctionCall
6933 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006934 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006935 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006936static void
6937xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006938 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006939 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006940 else if (CUR == '(') {
6941 NEXT;
6942 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006943 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006944 if (CUR != ')') {
6945 XP_ERROR(XPATH_EXPR_ERROR);
6946 }
6947 NEXT;
6948 SKIP_BLANKS;
6949 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006950 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006951 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006952 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006953 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006954 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006955 }
6956 SKIP_BLANKS;
6957}
6958
6959/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006960 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006961 * @ctxt: the XPath Parser context
6962 *
6963 * [20] FilterExpr ::= PrimaryExpr
6964 * | FilterExpr Predicate
6965 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006966 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006967 * Square brackets are used to filter expressions in the same way that
6968 * they are used in location paths. It is an error if the expression to
6969 * be filtered does not evaluate to a node-set. The context node list
6970 * used for evaluating the expression in square brackets is the node-set
6971 * to be filtered listed in document order.
6972 */
6973
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006974static void
6975xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
6976 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006977 CHECK_ERROR;
6978 SKIP_BLANKS;
6979
6980 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006981 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00006982 SKIP_BLANKS;
6983 }
6984
6985
6986}
6987
6988/**
6989 * xmlXPathScanName:
6990 * @ctxt: the XPath Parser context
6991 *
6992 * Trickery: parse an XML name but without consuming the input flow
6993 * Needed to avoid insanity in the parser state.
6994 *
6995 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6996 * CombiningChar | Extender
6997 *
6998 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6999 *
7000 * [6] Names ::= Name (S Name)*
7001 *
7002 * Returns the Name parsed or NULL
7003 */
7004
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007005static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007006xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7007 xmlChar buf[XML_MAX_NAMELEN];
7008 int len = 0;
7009
7010 SKIP_BLANKS;
7011 if (!IS_LETTER(CUR) && (CUR != '_') &&
7012 (CUR != ':')) {
7013 return(NULL);
7014 }
7015
7016 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7017 (NXT(len) == '.') || (NXT(len) == '-') ||
7018 (NXT(len) == '_') || (NXT(len) == ':') ||
7019 (IS_COMBINING(NXT(len))) ||
7020 (IS_EXTENDER(NXT(len)))) {
7021 buf[len] = NXT(len);
7022 len++;
7023 if (len >= XML_MAX_NAMELEN) {
7024 xmlGenericError(xmlGenericErrorContext,
7025 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7026 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7027 (NXT(len) == '.') || (NXT(len) == '-') ||
7028 (NXT(len) == '_') || (NXT(len) == ':') ||
7029 (IS_COMBINING(NXT(len))) ||
7030 (IS_EXTENDER(NXT(len))))
7031 len++;
7032 break;
7033 }
7034 }
7035 return(xmlStrndup(buf, len));
7036}
7037
7038/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007039 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007040 * @ctxt: the XPath Parser context
7041 *
7042 * [19] PathExpr ::= LocationPath
7043 * | FilterExpr
7044 * | FilterExpr '/' RelativeLocationPath
7045 * | FilterExpr '//' RelativeLocationPath
7046 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007047 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007048 * The / operator and // operators combine an arbitrary expression
7049 * and a relative location path. It is an error if the expression
7050 * does not evaluate to a node-set.
7051 * The / operator does composition in the same way as when / is
7052 * used in a location path. As in location paths, // is short for
7053 * /descendant-or-self::node()/.
7054 */
7055
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007056static void
7057xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007058 int lc = 1; /* Should we branch to LocationPath ? */
7059 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7060
7061 SKIP_BLANKS;
7062 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
7063 (CUR == '\'') || (CUR == '"')) {
7064 lc = 0;
7065 } else if (CUR == '*') {
7066 /* relative or absolute location path */
7067 lc = 1;
7068 } else if (CUR == '/') {
7069 /* relative or absolute location path */
7070 lc = 1;
7071 } else if (CUR == '@') {
7072 /* relative abbreviated attribute location path */
7073 lc = 1;
7074 } else if (CUR == '.') {
7075 /* relative abbreviated attribute location path */
7076 lc = 1;
7077 } else {
7078 /*
7079 * Problem is finding if we have a name here whether it's:
7080 * - a nodetype
7081 * - a function call in which case it's followed by '('
7082 * - an axis in which case it's followed by ':'
7083 * - a element name
7084 * We do an a priori analysis here rather than having to
7085 * maintain parsed token content through the recursive function
7086 * calls. This looks uglier but makes the code quite easier to
7087 * read/write/debug.
7088 */
7089 SKIP_BLANKS;
7090 name = xmlXPathScanName(ctxt);
7091 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7092#ifdef DEBUG_STEP
7093 xmlGenericError(xmlGenericErrorContext,
7094 "PathExpr: Axis\n");
7095#endif
7096 lc = 1;
7097 xmlFree(name);
7098 } else if (name != NULL) {
7099 int len =xmlStrlen(name);
7100 int blank = 0;
7101
7102
7103 while (NXT(len) != 0) {
7104 if (NXT(len) == '/') {
7105 /* element name */
7106#ifdef DEBUG_STEP
7107 xmlGenericError(xmlGenericErrorContext,
7108 "PathExpr: AbbrRelLocation\n");
7109#endif
7110 lc = 1;
7111 break;
7112 } else if (IS_BLANK(NXT(len))) {
7113 /* skip to next */
7114 blank = 1;
7115 } else if (NXT(len) == ':') {
7116#ifdef DEBUG_STEP
7117 xmlGenericError(xmlGenericErrorContext,
7118 "PathExpr: AbbrRelLocation\n");
7119#endif
7120 lc = 1;
7121 break;
7122 } else if ((NXT(len) == '(')) {
7123 /* Note Type or Function */
7124 if (xmlXPathIsNodeType(name)) {
7125#ifdef DEBUG_STEP
7126 xmlGenericError(xmlGenericErrorContext,
7127 "PathExpr: Type search\n");
7128#endif
7129 lc = 1;
7130 } else {
7131#ifdef DEBUG_STEP
7132 xmlGenericError(xmlGenericErrorContext,
7133 "PathExpr: function call\n");
7134#endif
7135 lc = 0;
7136 }
7137 break;
7138 } else if ((NXT(len) == '[')) {
7139 /* element name */
7140#ifdef DEBUG_STEP
7141 xmlGenericError(xmlGenericErrorContext,
7142 "PathExpr: AbbrRelLocation\n");
7143#endif
7144 lc = 1;
7145 break;
7146 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7147 (NXT(len) == '=')) {
7148 lc = 1;
7149 break;
7150 } else {
7151 lc = 1;
7152 break;
7153 }
7154 len++;
7155 }
7156 if (NXT(len) == 0) {
7157#ifdef DEBUG_STEP
7158 xmlGenericError(xmlGenericErrorContext,
7159 "PathExpr: AbbrRelLocation\n");
7160#endif
7161 /* element name */
7162 lc = 1;
7163 }
7164 xmlFree(name);
7165 } else {
7166 /* make sure all cases are covered explicitely */
7167 XP_ERROR(XPATH_EXPR_ERROR);
7168 }
7169 }
7170
7171 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007172 if (CUR == '/') {
7173 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7174 } else {
7175 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007176 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007177 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007178 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007179 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007180 CHECK_ERROR;
7181 if ((CUR == '/') && (NXT(1) == '/')) {
7182 SKIP(2);
7183 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007184
7185 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7186 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7187 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7188
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007189 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007190 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007191 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007192 }
7193 }
7194 SKIP_BLANKS;
7195}
7196
7197/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007198 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007199 * @ctxt: the XPath Parser context
7200 *
7201 * [18] UnionExpr ::= PathExpr
7202 * | UnionExpr '|' PathExpr
7203 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007204 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007205 */
7206
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007207static void
7208xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7209 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007210 CHECK_ERROR;
7211 SKIP_BLANKS;
7212 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007213 int op1 = ctxt->comp->last;
7214 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007215
7216 NEXT;
7217 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007218 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007219
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007220 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
7221
Owen Taylor3473f882001-02-23 17:55:21 +00007222 SKIP_BLANKS;
7223 }
Owen Taylor3473f882001-02-23 17:55:21 +00007224}
7225
7226/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007227 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007228 * @ctxt: the XPath Parser context
7229 *
7230 * [27] UnaryExpr ::= UnionExpr
7231 * | '-' UnaryExpr
7232 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007233 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007234 */
7235
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007236static void
7237xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007238 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007239 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007240
7241 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00007242 while (CUR == '-') {
7243 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007244 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007245 NEXT;
7246 SKIP_BLANKS;
7247 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007248
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007249 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007250 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007251 if (found) {
7252 if (minus)
7253 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
7254 else
7255 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007256 }
7257}
7258
7259/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007260 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007261 * @ctxt: the XPath Parser context
7262 *
7263 * [26] MultiplicativeExpr ::= UnaryExpr
7264 * | MultiplicativeExpr MultiplyOperator UnaryExpr
7265 * | MultiplicativeExpr 'div' UnaryExpr
7266 * | MultiplicativeExpr 'mod' UnaryExpr
7267 * [34] MultiplyOperator ::= '*'
7268 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007269 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007270 */
7271
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007272static void
7273xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
7274 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007275 CHECK_ERROR;
7276 SKIP_BLANKS;
7277 while ((CUR == '*') ||
7278 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
7279 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
7280 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007281 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007282
7283 if (CUR == '*') {
7284 op = 0;
7285 NEXT;
7286 } else if (CUR == 'd') {
7287 op = 1;
7288 SKIP(3);
7289 } else if (CUR == 'm') {
7290 op = 2;
7291 SKIP(3);
7292 }
7293 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007294 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007295 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007296 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007297 SKIP_BLANKS;
7298 }
7299}
7300
7301/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007302 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007303 * @ctxt: the XPath Parser context
7304 *
7305 * [25] AdditiveExpr ::= MultiplicativeExpr
7306 * | AdditiveExpr '+' MultiplicativeExpr
7307 * | AdditiveExpr '-' MultiplicativeExpr
7308 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007309 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007310 */
7311
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007312static void
7313xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007314
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007315 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007316 CHECK_ERROR;
7317 SKIP_BLANKS;
7318 while ((CUR == '+') || (CUR == '-')) {
7319 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007320 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007321
7322 if (CUR == '+') plus = 1;
7323 else plus = 0;
7324 NEXT;
7325 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007326 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007327 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007328 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007329 SKIP_BLANKS;
7330 }
7331}
7332
7333/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007334 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007335 * @ctxt: the XPath Parser context
7336 *
7337 * [24] RelationalExpr ::= AdditiveExpr
7338 * | RelationalExpr '<' AdditiveExpr
7339 * | RelationalExpr '>' AdditiveExpr
7340 * | RelationalExpr '<=' AdditiveExpr
7341 * | RelationalExpr '>=' AdditiveExpr
7342 *
7343 * A <= B > C is allowed ? Answer from James, yes with
7344 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
7345 * which is basically what got implemented.
7346 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007347 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00007348 * on the stack
7349 */
7350
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007351static void
7352xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
7353 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007354 CHECK_ERROR;
7355 SKIP_BLANKS;
7356 while ((CUR == '<') ||
7357 (CUR == '>') ||
7358 ((CUR == '<') && (NXT(1) == '=')) ||
7359 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007360 int inf, strict;
7361 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007362
7363 if (CUR == '<') inf = 1;
7364 else inf = 0;
7365 if (NXT(1) == '=') strict = 0;
7366 else strict = 1;
7367 NEXT;
7368 if (!strict) NEXT;
7369 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007370 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007371 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007372 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00007373 SKIP_BLANKS;
7374 }
7375}
7376
7377/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007378 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007379 * @ctxt: the XPath Parser context
7380 *
7381 * [23] EqualityExpr ::= RelationalExpr
7382 * | EqualityExpr '=' RelationalExpr
7383 * | EqualityExpr '!=' RelationalExpr
7384 *
7385 * A != B != C is allowed ? Answer from James, yes with
7386 * (RelationalExpr = RelationalExpr) = RelationalExpr
7387 * (RelationalExpr != RelationalExpr) != RelationalExpr
7388 * which is basically what got implemented.
7389 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007390 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007391 *
7392 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007393static void
7394xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
7395 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007396 CHECK_ERROR;
7397 SKIP_BLANKS;
7398 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007399 int eq;
7400 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007401
7402 if (CUR == '=') eq = 1;
7403 else eq = 0;
7404 NEXT;
7405 if (!eq) NEXT;
7406 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007407 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007408 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007409 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007410 SKIP_BLANKS;
7411 }
7412}
7413
7414/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007415 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007416 * @ctxt: the XPath Parser context
7417 *
7418 * [22] AndExpr ::= EqualityExpr
7419 * | AndExpr 'and' EqualityExpr
7420 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007421 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007422 *
7423 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007424static void
7425xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
7426 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007427 CHECK_ERROR;
7428 SKIP_BLANKS;
7429 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007430 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007431 SKIP(3);
7432 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007433 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007434 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007435 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007436 SKIP_BLANKS;
7437 }
7438}
7439
7440/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007441 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007442 * @ctxt: the XPath Parser context
7443 *
7444 * [14] Expr ::= OrExpr
7445 * [21] OrExpr ::= AndExpr
7446 * | OrExpr 'or' AndExpr
7447 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007448 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00007449 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007450static void
7451xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
7452 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007453 CHECK_ERROR;
7454 SKIP_BLANKS;
7455 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007456 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007457 SKIP(2);
7458 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007459 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007460 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007461 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
7462 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00007463 SKIP_BLANKS;
7464 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007465 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
7466 /* more ops could be optimized too */
7467 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
7468 }
Owen Taylor3473f882001-02-23 17:55:21 +00007469}
7470
7471/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007472 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00007473 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007474 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00007475 *
7476 * [8] Predicate ::= '[' PredicateExpr ']'
7477 * [9] PredicateExpr ::= Expr
7478 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007479 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00007480 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007481static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007482xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007483 int op1 = ctxt->comp->last;
7484
7485 SKIP_BLANKS;
7486 if (CUR != '[') {
7487 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7488 }
7489 NEXT;
7490 SKIP_BLANKS;
7491
7492 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007493 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007494 CHECK_ERROR;
7495
7496 if (CUR != ']') {
7497 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7498 }
7499
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007500 if (filter)
7501 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
7502 else
7503 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007504
7505 NEXT;
7506 SKIP_BLANKS;
7507}
7508
7509/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007510 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00007511 * @ctxt: the XPath Parser context
7512 * @test: pointer to a xmlXPathTestVal
7513 * @type: pointer to a xmlXPathTypeVal
7514 * @prefix: placeholder for a possible name prefix
7515 *
7516 * [7] NodeTest ::= NameTest
7517 * | NodeType '(' ')'
7518 * | 'processing-instruction' '(' Literal ')'
7519 *
7520 * [37] NameTest ::= '*'
7521 * | NCName ':' '*'
7522 * | QName
7523 * [38] NodeType ::= 'comment'
7524 * | 'text'
7525 * | 'processing-instruction'
7526 * | 'node'
7527 *
7528 * Returns the name found and update @test, @type and @prefix appropriately
7529 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007530static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007531xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
7532 xmlXPathTypeVal *type, const xmlChar **prefix,
7533 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00007534 int blanks;
7535
7536 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
7537 STRANGE;
7538 return(NULL);
7539 }
7540 *type = 0;
7541 *test = 0;
7542 *prefix = NULL;
7543 SKIP_BLANKS;
7544
7545 if ((name == NULL) && (CUR == '*')) {
7546 /*
7547 * All elements
7548 */
7549 NEXT;
7550 *test = NODE_TEST_ALL;
7551 return(NULL);
7552 }
7553
7554 if (name == NULL)
7555 name = xmlXPathParseNCName(ctxt);
7556 if (name == NULL) {
7557 XP_ERROR0(XPATH_EXPR_ERROR);
7558 }
7559
7560 blanks = IS_BLANK(CUR);
7561 SKIP_BLANKS;
7562 if (CUR == '(') {
7563 NEXT;
7564 /*
7565 * NodeType or PI search
7566 */
7567 if (xmlStrEqual(name, BAD_CAST "comment"))
7568 *type = NODE_TYPE_COMMENT;
7569 else if (xmlStrEqual(name, BAD_CAST "node"))
7570 *type = NODE_TYPE_NODE;
7571 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
7572 *type = NODE_TYPE_PI;
7573 else if (xmlStrEqual(name, BAD_CAST "text"))
7574 *type = NODE_TYPE_TEXT;
7575 else {
7576 if (name != NULL)
7577 xmlFree(name);
7578 XP_ERROR0(XPATH_EXPR_ERROR);
7579 }
7580
7581 *test = NODE_TEST_TYPE;
7582
7583 SKIP_BLANKS;
7584 if (*type == NODE_TYPE_PI) {
7585 /*
7586 * Specific case: search a PI by name.
7587 */
Owen Taylor3473f882001-02-23 17:55:21 +00007588 if (name != NULL)
7589 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00007590 name = NULL;
7591 if (CUR != ')') {
7592 name = xmlXPathParseLiteral(ctxt);
7593 CHECK_ERROR 0;
7594 SKIP_BLANKS;
7595 }
Owen Taylor3473f882001-02-23 17:55:21 +00007596 }
7597 if (CUR != ')') {
7598 if (name != NULL)
7599 xmlFree(name);
7600 XP_ERROR0(XPATH_UNCLOSED_ERROR);
7601 }
7602 NEXT;
7603 return(name);
7604 }
7605 *test = NODE_TEST_NAME;
7606 if ((!blanks) && (CUR == ':')) {
7607 NEXT;
7608
7609 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007610 * Since currently the parser context don't have a
7611 * namespace list associated:
7612 * The namespace name for this prefix can be computed
7613 * only at evaluation time. The compilation is done
7614 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00007615 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007616#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00007617 *prefix = xmlXPathNsLookup(ctxt->context, name);
7618 if (name != NULL)
7619 xmlFree(name);
7620 if (*prefix == NULL) {
7621 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
7622 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007623#else
7624 *prefix = name;
7625#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007626
7627 if (CUR == '*') {
7628 /*
7629 * All elements
7630 */
7631 NEXT;
7632 *test = NODE_TEST_ALL;
7633 return(NULL);
7634 }
7635
7636 name = xmlXPathParseNCName(ctxt);
7637 if (name == NULL) {
7638 XP_ERROR0(XPATH_EXPR_ERROR);
7639 }
7640 }
7641 return(name);
7642}
7643
7644/**
7645 * xmlXPathIsAxisName:
7646 * @name: a preparsed name token
7647 *
7648 * [6] AxisName ::= 'ancestor'
7649 * | 'ancestor-or-self'
7650 * | 'attribute'
7651 * | 'child'
7652 * | 'descendant'
7653 * | 'descendant-or-self'
7654 * | 'following'
7655 * | 'following-sibling'
7656 * | 'namespace'
7657 * | 'parent'
7658 * | 'preceding'
7659 * | 'preceding-sibling'
7660 * | 'self'
7661 *
7662 * Returns the axis or 0
7663 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007664static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00007665xmlXPathIsAxisName(const xmlChar *name) {
7666 xmlXPathAxisVal ret = 0;
7667 switch (name[0]) {
7668 case 'a':
7669 if (xmlStrEqual(name, BAD_CAST "ancestor"))
7670 ret = AXIS_ANCESTOR;
7671 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
7672 ret = AXIS_ANCESTOR_OR_SELF;
7673 if (xmlStrEqual(name, BAD_CAST "attribute"))
7674 ret = AXIS_ATTRIBUTE;
7675 break;
7676 case 'c':
7677 if (xmlStrEqual(name, BAD_CAST "child"))
7678 ret = AXIS_CHILD;
7679 break;
7680 case 'd':
7681 if (xmlStrEqual(name, BAD_CAST "descendant"))
7682 ret = AXIS_DESCENDANT;
7683 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
7684 ret = AXIS_DESCENDANT_OR_SELF;
7685 break;
7686 case 'f':
7687 if (xmlStrEqual(name, BAD_CAST "following"))
7688 ret = AXIS_FOLLOWING;
7689 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
7690 ret = AXIS_FOLLOWING_SIBLING;
7691 break;
7692 case 'n':
7693 if (xmlStrEqual(name, BAD_CAST "namespace"))
7694 ret = AXIS_NAMESPACE;
7695 break;
7696 case 'p':
7697 if (xmlStrEqual(name, BAD_CAST "parent"))
7698 ret = AXIS_PARENT;
7699 if (xmlStrEqual(name, BAD_CAST "preceding"))
7700 ret = AXIS_PRECEDING;
7701 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
7702 ret = AXIS_PRECEDING_SIBLING;
7703 break;
7704 case 's':
7705 if (xmlStrEqual(name, BAD_CAST "self"))
7706 ret = AXIS_SELF;
7707 break;
7708 }
7709 return(ret);
7710}
7711
7712/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007713 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00007714 * @ctxt: the XPath Parser context
7715 *
7716 * [4] Step ::= AxisSpecifier NodeTest Predicate*
7717 * | AbbreviatedStep
7718 *
7719 * [12] AbbreviatedStep ::= '.' | '..'
7720 *
7721 * [5] AxisSpecifier ::= AxisName '::'
7722 * | AbbreviatedAxisSpecifier
7723 *
7724 * [13] AbbreviatedAxisSpecifier ::= '@'?
7725 *
7726 * Modified for XPtr range support as:
7727 *
7728 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
7729 * | AbbreviatedStep
7730 * | 'range-to' '(' Expr ')' Predicate*
7731 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007732 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00007733 * A location step of . is short for self::node(). This is
7734 * particularly useful in conjunction with //. For example, the
7735 * location path .//para is short for
7736 * self::node()/descendant-or-self::node()/child::para
7737 * and so will select all para descendant elements of the context
7738 * node.
7739 * Similarly, a location step of .. is short for parent::node().
7740 * For example, ../title is short for parent::node()/child::title
7741 * and so will select the title children of the parent of the context
7742 * node.
7743 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007744static void
7745xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007746#ifdef LIBXML_XPTR_ENABLED
7747 int rangeto = 0;
7748 int op2 = -1;
7749#endif
7750
Owen Taylor3473f882001-02-23 17:55:21 +00007751 SKIP_BLANKS;
7752 if ((CUR == '.') && (NXT(1) == '.')) {
7753 SKIP(2);
7754 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007755 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
7756 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007757 } else if (CUR == '.') {
7758 NEXT;
7759 SKIP_BLANKS;
7760 } else {
7761 xmlChar *name = NULL;
7762 const xmlChar *prefix = NULL;
7763 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007764 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007765 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007766 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00007767
7768 /*
7769 * The modification needed for XPointer change to the production
7770 */
7771#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007772 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00007773 name = xmlXPathParseNCName(ctxt);
7774 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007775 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007776 xmlFree(name);
7777 SKIP_BLANKS;
7778 if (CUR != '(') {
7779 XP_ERROR(XPATH_EXPR_ERROR);
7780 }
7781 NEXT;
7782 SKIP_BLANKS;
7783
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007784 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007785 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00007786 CHECK_ERROR;
7787
7788 SKIP_BLANKS;
7789 if (CUR != ')') {
7790 XP_ERROR(XPATH_EXPR_ERROR);
7791 }
7792 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007793 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007794 goto eval_predicates;
7795 }
7796 }
7797#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00007798 if (CUR == '*') {
7799 axis = AXIS_CHILD;
7800 } else {
7801 if (name == NULL)
7802 name = xmlXPathParseNCName(ctxt);
7803 if (name != NULL) {
7804 axis = xmlXPathIsAxisName(name);
7805 if (axis != 0) {
7806 SKIP_BLANKS;
7807 if ((CUR == ':') && (NXT(1) == ':')) {
7808 SKIP(2);
7809 xmlFree(name);
7810 name = NULL;
7811 } else {
7812 /* an element name can conflict with an axis one :-\ */
7813 axis = AXIS_CHILD;
7814 }
Owen Taylor3473f882001-02-23 17:55:21 +00007815 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00007816 axis = AXIS_CHILD;
7817 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007818 } else if (CUR == '@') {
7819 NEXT;
7820 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00007821 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00007822 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00007823 }
Owen Taylor3473f882001-02-23 17:55:21 +00007824 }
7825
7826 CHECK_ERROR;
7827
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007828 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00007829 if (test == 0)
7830 return;
7831
7832#ifdef DEBUG_STEP
7833 xmlGenericError(xmlGenericErrorContext,
7834 "Basis : computing new set\n");
7835#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007836
Owen Taylor3473f882001-02-23 17:55:21 +00007837#ifdef DEBUG_STEP
7838 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007839 if (ctxt->value == NULL)
7840 xmlGenericError(xmlGenericErrorContext, "no value\n");
7841 else if (ctxt->value->nodesetval == NULL)
7842 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7843 else
7844 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007845#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007846
7847eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007848 op1 = ctxt->comp->last;
7849 ctxt->comp->last = -1;
7850
Owen Taylor3473f882001-02-23 17:55:21 +00007851 SKIP_BLANKS;
7852 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007853 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007854 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007855
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007856#ifdef LIBXML_XPTR_ENABLED
7857 if (rangeto) {
7858 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
7859 } else
7860#endif
7861 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
7862 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007863
Owen Taylor3473f882001-02-23 17:55:21 +00007864 }
7865#ifdef DEBUG_STEP
7866 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007867 if (ctxt->value == NULL)
7868 xmlGenericError(xmlGenericErrorContext, "no value\n");
7869 else if (ctxt->value->nodesetval == NULL)
7870 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7871 else
7872 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
7873 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007874#endif
7875}
7876
7877/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007878 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007879 * @ctxt: the XPath Parser context
7880 *
7881 * [3] RelativeLocationPath ::= Step
7882 * | RelativeLocationPath '/' Step
7883 * | AbbreviatedRelativeLocationPath
7884 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
7885 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007886 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00007887 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007888static void
Owen Taylor3473f882001-02-23 17:55:21 +00007889#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007890xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007891#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007892xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007893#endif
7894(xmlXPathParserContextPtr ctxt) {
7895 SKIP_BLANKS;
7896 if ((CUR == '/') && (NXT(1) == '/')) {
7897 SKIP(2);
7898 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007899 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7900 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007901 } else if (CUR == '/') {
7902 NEXT;
7903 SKIP_BLANKS;
7904 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007905 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007906 SKIP_BLANKS;
7907 while (CUR == '/') {
7908 if ((CUR == '/') && (NXT(1) == '/')) {
7909 SKIP(2);
7910 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007911 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00007912 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007913 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007914 } else if (CUR == '/') {
7915 NEXT;
7916 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007917 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007918 }
7919 SKIP_BLANKS;
7920 }
7921}
7922
7923/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007924 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007925 * @ctxt: the XPath Parser context
7926 *
7927 * [1] LocationPath ::= RelativeLocationPath
7928 * | AbsoluteLocationPath
7929 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
7930 * | AbbreviatedAbsoluteLocationPath
7931 * [10] AbbreviatedAbsoluteLocationPath ::=
7932 * '//' RelativeLocationPath
7933 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007934 * Compile a location path
7935 *
Owen Taylor3473f882001-02-23 17:55:21 +00007936 * // is short for /descendant-or-self::node()/. For example,
7937 * //para is short for /descendant-or-self::node()/child::para and
7938 * so will select any para element in the document (even a para element
7939 * that is a document element will be selected by //para since the
7940 * document element node is a child of the root node); div//para is
7941 * short for div/descendant-or-self::node()/child::para and so will
7942 * select all para descendants of div children.
7943 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007944static void
7945xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007946 SKIP_BLANKS;
7947 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007948 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007949 } else {
7950 while (CUR == '/') {
7951 if ((CUR == '/') && (NXT(1) == '/')) {
7952 SKIP(2);
7953 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007954 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7955 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007956 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007957 } else if (CUR == '/') {
7958 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00007959 SKIP_BLANKS;
7960 if ((CUR != 0 ) &&
7961 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
7962 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007963 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007964 }
7965 }
7966 }
7967}
7968
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007969/************************************************************************
7970 * *
7971 * XPath precompiled expression evaluation *
7972 * *
7973 ************************************************************************/
7974
Daniel Veillardf06307e2001-07-03 10:35:50 +00007975static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007976xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
7977
7978/**
7979 * xmlXPathNodeCollectAndTest:
7980 * @ctxt: the XPath Parser context
7981 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00007982 * @first: pointer to the first element in document order
7983 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007984 *
7985 * This is the function implementing a step: based on the current list
7986 * of nodes, it builds up a new list, looking at all nodes under that
7987 * axis and selecting them it also do the predicate filtering
7988 *
7989 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00007990 *
7991 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007992 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00007993static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007994xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00007995 xmlXPathStepOpPtr op,
7996 xmlNodePtr * first, xmlNodePtr * last)
7997{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007998 xmlXPathAxisVal axis = op->value;
7999 xmlXPathTestVal test = op->value2;
8000 xmlXPathTypeVal type = op->value3;
8001 const xmlChar *prefix = op->value4;
8002 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008003 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008004
8005#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008006 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008007#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008008 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008009 xmlNodeSetPtr ret, list;
8010 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008011 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008012 xmlNodePtr cur = NULL;
8013 xmlXPathObjectPtr obj;
8014 xmlNodeSetPtr nodelist;
8015 xmlNodePtr tmp;
8016
Daniel Veillardf06307e2001-07-03 10:35:50 +00008017 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008018 obj = valuePop(ctxt);
8019 addNode = xmlXPathNodeSetAdd;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008020 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008021 URI = xmlXPathNsLookup(ctxt->context, prefix);
8022 if (URI == NULL)
8023 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008024 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008025#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008026 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008027#endif
8028 switch (axis) {
8029 case AXIS_ANCESTOR:
8030#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008031 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008032#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008033 first = NULL;
8034 next = xmlXPathNextAncestor;
8035 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008036 case AXIS_ANCESTOR_OR_SELF:
8037#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008038 xmlGenericError(xmlGenericErrorContext,
8039 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008040#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008041 first = NULL;
8042 next = xmlXPathNextAncestorOrSelf;
8043 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008044 case AXIS_ATTRIBUTE:
8045#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008046 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008047#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008048 first = NULL;
8049 last = NULL;
8050 next = xmlXPathNextAttribute;
8051 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008052 case AXIS_CHILD:
8053#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008054 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008055#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008056 last = NULL;
8057 next = xmlXPathNextChild;
8058 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008059 case AXIS_DESCENDANT:
8060#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008061 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008062#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008063 last = NULL;
8064 next = xmlXPathNextDescendant;
8065 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008066 case AXIS_DESCENDANT_OR_SELF:
8067#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008068 xmlGenericError(xmlGenericErrorContext,
8069 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008070#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008071 last = NULL;
8072 next = xmlXPathNextDescendantOrSelf;
8073 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008074 case AXIS_FOLLOWING:
8075#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008076 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008077#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008078 last = NULL;
8079 next = xmlXPathNextFollowing;
8080 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008081 case AXIS_FOLLOWING_SIBLING:
8082#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008083 xmlGenericError(xmlGenericErrorContext,
8084 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008085#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008086 last = NULL;
8087 next = xmlXPathNextFollowingSibling;
8088 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008089 case AXIS_NAMESPACE:
8090#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008091 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008092#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008093 first = NULL;
8094 last = NULL;
8095 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8096 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008097 case AXIS_PARENT:
8098#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008099 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008100#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008101 first = NULL;
8102 next = xmlXPathNextParent;
8103 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008104 case AXIS_PRECEDING:
8105#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008106 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008107#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008108 first = NULL;
8109 next = xmlXPathNextPrecedingInternal;
8110 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008111 case AXIS_PRECEDING_SIBLING:
8112#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008113 xmlGenericError(xmlGenericErrorContext,
8114 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008115#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008116 first = NULL;
8117 next = xmlXPathNextPrecedingSibling;
8118 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008119 case AXIS_SELF:
8120#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008121 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008122#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008123 first = NULL;
8124 last = NULL;
8125 next = xmlXPathNextSelf;
8126 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008127 }
8128 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008129 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008130
8131 nodelist = obj->nodesetval;
8132 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008133 xmlXPathFreeObject(obj);
8134 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8135 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008136 }
8137 addNode = xmlXPathNodeSetAddUnique;
8138 ret = NULL;
8139#ifdef DEBUG_STEP
8140 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008141 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008142 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008143 case NODE_TEST_NONE:
8144 xmlGenericError(xmlGenericErrorContext,
8145 " searching for none !!!\n");
8146 break;
8147 case NODE_TEST_TYPE:
8148 xmlGenericError(xmlGenericErrorContext,
8149 " searching for type %d\n", type);
8150 break;
8151 case NODE_TEST_PI:
8152 xmlGenericError(xmlGenericErrorContext,
8153 " searching for PI !!!\n");
8154 break;
8155 case NODE_TEST_ALL:
8156 xmlGenericError(xmlGenericErrorContext,
8157 " searching for *\n");
8158 break;
8159 case NODE_TEST_NS:
8160 xmlGenericError(xmlGenericErrorContext,
8161 " searching for namespace %s\n",
8162 prefix);
8163 break;
8164 case NODE_TEST_NAME:
8165 xmlGenericError(xmlGenericErrorContext,
8166 " searching for name %s\n", name);
8167 if (prefix != NULL)
8168 xmlGenericError(xmlGenericErrorContext,
8169 " with namespace %s\n", prefix);
8170 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008171 }
8172 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8173#endif
8174 /*
8175 * 2.3 Node Tests
8176 * - For the attribute axis, the principal node type is attribute.
8177 * - For the namespace axis, the principal node type is namespace.
8178 * - For other axes, the principal node type is element.
8179 *
8180 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008181 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008182 * select all element children of the context node
8183 */
8184 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008185 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008186 ctxt->context->node = nodelist->nodeTab[i];
8187
Daniel Veillardf06307e2001-07-03 10:35:50 +00008188 cur = NULL;
8189 list = xmlXPathNodeSetCreate(NULL);
8190 do {
8191 cur = next(ctxt, cur);
8192 if (cur == NULL)
8193 break;
8194 if ((first != NULL) && (*first == cur))
8195 break;
8196 if (((t % 256) == 0) &&
8197 (first != NULL) && (*first != NULL) &&
8198 (xmlXPathCmpNodes(*first, cur) >= 0))
8199 break;
8200 if ((last != NULL) && (*last == cur))
8201 break;
8202 if (((t % 256) == 0) &&
8203 (last != NULL) && (*last != NULL) &&
8204 (xmlXPathCmpNodes(cur, *last) >= 0))
8205 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008206 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008207#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008208 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8209#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008210 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008211 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008212 ctxt->context->node = tmp;
8213 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008214 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008215 if ((cur->type == type) ||
8216 ((type == NODE_TYPE_NODE) &&
8217 ((cur->type == XML_DOCUMENT_NODE) ||
8218 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8219 (cur->type == XML_ELEMENT_NODE) ||
8220 (cur->type == XML_PI_NODE) ||
8221 (cur->type == XML_COMMENT_NODE) ||
8222 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00008223 (cur->type == XML_TEXT_NODE))) ||
8224 ((type == NODE_TYPE_TEXT) &&
8225 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008226#ifdef DEBUG_STEP
8227 n++;
8228#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008229 addNode(list, cur);
8230 }
8231 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008232 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008233 if (cur->type == XML_PI_NODE) {
8234 if ((name != NULL) &&
8235 (!xmlStrEqual(name, cur->name)))
8236 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008237#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008238 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008239#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008240 addNode(list, cur);
8241 }
8242 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008243 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008244 if (axis == AXIS_ATTRIBUTE) {
8245 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008246#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008247 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008248#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008249 addNode(list, cur);
8250 }
8251 } else if (axis == AXIS_NAMESPACE) {
8252 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008253#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008254 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008255#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008256 addNode(list, cur);
8257 }
8258 } else {
8259 if (cur->type == XML_ELEMENT_NODE) {
8260 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008261#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008262 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008263#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008264 addNode(list, cur);
8265 } else if ((cur->ns != NULL) &&
8266 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008267#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008268 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008269#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008270 addNode(list, cur);
8271 }
8272 }
8273 }
8274 break;
8275 case NODE_TEST_NS:{
8276 TODO;
8277 break;
8278 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008279 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008280 switch (cur->type) {
8281 case XML_ELEMENT_NODE:
8282 if (xmlStrEqual(name, cur->name)) {
8283 if (prefix == NULL) {
8284 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008285#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008286 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008287#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008288 addNode(list, cur);
8289 }
8290 } else {
8291 if ((cur->ns != NULL) &&
8292 (xmlStrEqual(URI,
8293 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008294#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008295 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008296#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008297 addNode(list, cur);
8298 }
8299 }
8300 }
8301 break;
8302 case XML_ATTRIBUTE_NODE:{
8303 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008304
Daniel Veillardf06307e2001-07-03 10:35:50 +00008305 if (xmlStrEqual(name, attr->name)) {
8306 if (prefix == NULL) {
8307 if ((attr->ns == NULL) ||
8308 (attr->ns->prefix == NULL)) {
8309#ifdef DEBUG_STEP
8310 n++;
8311#endif
8312 addNode(list,
8313 (xmlNodePtr) attr);
8314 }
8315 } else {
8316 if ((attr->ns != NULL) &&
8317 (xmlStrEqual(URI,
8318 attr->ns->
8319 href))) {
8320#ifdef DEBUG_STEP
8321 n++;
8322#endif
8323 addNode(list,
8324 (xmlNodePtr) attr);
8325 }
8326 }
8327 }
8328 break;
8329 }
8330 case XML_NAMESPACE_DECL:
8331 if (cur->type == XML_NAMESPACE_DECL) {
8332 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008333
Daniel Veillardf06307e2001-07-03 10:35:50 +00008334 if ((ns->prefix != NULL) && (name != NULL)
8335 && (xmlStrEqual(ns->prefix, name))) {
8336#ifdef DEBUG_STEP
8337 n++;
8338#endif
8339 addNode(list, cur);
8340 }
8341 }
8342 break;
8343 default:
8344 break;
8345 }
8346 break;
8347 break;
8348 }
8349 } while (cur != NULL);
8350
8351 /*
8352 * If there is some predicate filtering do it now
8353 */
8354 if (op->ch2 != -1) {
8355 xmlXPathObjectPtr obj2;
8356
8357 valuePush(ctxt, xmlXPathWrapNodeSet(list));
8358 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
8359 CHECK_TYPE0(XPATH_NODESET);
8360 obj2 = valuePop(ctxt);
8361 list = obj2->nodesetval;
8362 obj2->nodesetval = NULL;
8363 xmlXPathFreeObject(obj2);
8364 }
8365 if (ret == NULL) {
8366 ret = list;
8367 } else {
8368 ret = xmlXPathNodeSetMerge(ret, list);
8369 xmlXPathFreeNodeSet(list);
8370 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008371 }
8372 ctxt->context->node = tmp;
8373#ifdef DEBUG_STEP
8374 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008375 "\nExamined %d nodes, found %d nodes at that step\n",
8376 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008377#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008378 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00008379 if ((obj->boolval) && (obj->user != NULL)) {
8380 ctxt->value->boolval = 1;
8381 ctxt->value->user = obj->user;
8382 obj->user = NULL;
8383 obj->boolval = 0;
8384 }
8385 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008386 return(t);
8387}
8388
8389/**
8390 * xmlXPathNodeCollectAndTestNth:
8391 * @ctxt: the XPath Parser context
8392 * @op: the XPath precompiled step operation
8393 * @indx: the index to collect
8394 * @first: pointer to the first element in document order
8395 * @last: pointer to the last element in document order
8396 *
8397 * This is the function implementing a step: based on the current list
8398 * of nodes, it builds up a new list, looking at all nodes under that
8399 * axis and selecting them it also do the predicate filtering
8400 *
8401 * Pushes the new NodeSet resulting from the search.
8402 * Returns the number of node traversed
8403 */
8404static int
8405xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
8406 xmlXPathStepOpPtr op, int indx,
8407 xmlNodePtr * first, xmlNodePtr * last)
8408{
8409 xmlXPathAxisVal axis = op->value;
8410 xmlXPathTestVal test = op->value2;
8411 xmlXPathTypeVal type = op->value3;
8412 const xmlChar *prefix = op->value4;
8413 const xmlChar *name = op->value5;
8414 const xmlChar *URI = NULL;
8415 int n = 0, t = 0;
8416
8417 int i;
8418 xmlNodeSetPtr list;
8419 xmlXPathTraversalFunction next = NULL;
8420 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
8421 xmlNodePtr cur = NULL;
8422 xmlXPathObjectPtr obj;
8423 xmlNodeSetPtr nodelist;
8424 xmlNodePtr tmp;
8425
8426 CHECK_TYPE0(XPATH_NODESET);
8427 obj = valuePop(ctxt);
8428 addNode = xmlXPathNodeSetAdd;
8429 if (prefix != NULL) {
8430 URI = xmlXPathNsLookup(ctxt->context, prefix);
8431 if (URI == NULL)
8432 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8433 }
8434#ifdef DEBUG_STEP_NTH
8435 xmlGenericError(xmlGenericErrorContext, "new step : ");
8436 if (first != NULL) {
8437 if (*first != NULL)
8438 xmlGenericError(xmlGenericErrorContext, "first = %s ",
8439 (*first)->name);
8440 else
8441 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
8442 }
8443 if (last != NULL) {
8444 if (*last != NULL)
8445 xmlGenericError(xmlGenericErrorContext, "last = %s ",
8446 (*last)->name);
8447 else
8448 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
8449 }
8450#endif
8451 switch (axis) {
8452 case AXIS_ANCESTOR:
8453#ifdef DEBUG_STEP_NTH
8454 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
8455#endif
8456 first = NULL;
8457 next = xmlXPathNextAncestor;
8458 break;
8459 case AXIS_ANCESTOR_OR_SELF:
8460#ifdef DEBUG_STEP_NTH
8461 xmlGenericError(xmlGenericErrorContext,
8462 "axis 'ancestors-or-self' ");
8463#endif
8464 first = NULL;
8465 next = xmlXPathNextAncestorOrSelf;
8466 break;
8467 case AXIS_ATTRIBUTE:
8468#ifdef DEBUG_STEP_NTH
8469 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
8470#endif
8471 first = NULL;
8472 last = NULL;
8473 next = xmlXPathNextAttribute;
8474 break;
8475 case AXIS_CHILD:
8476#ifdef DEBUG_STEP_NTH
8477 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
8478#endif
8479 last = NULL;
8480 next = xmlXPathNextChild;
8481 break;
8482 case AXIS_DESCENDANT:
8483#ifdef DEBUG_STEP_NTH
8484 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
8485#endif
8486 last = NULL;
8487 next = xmlXPathNextDescendant;
8488 break;
8489 case AXIS_DESCENDANT_OR_SELF:
8490#ifdef DEBUG_STEP_NTH
8491 xmlGenericError(xmlGenericErrorContext,
8492 "axis 'descendant-or-self' ");
8493#endif
8494 last = NULL;
8495 next = xmlXPathNextDescendantOrSelf;
8496 break;
8497 case AXIS_FOLLOWING:
8498#ifdef DEBUG_STEP_NTH
8499 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
8500#endif
8501 last = NULL;
8502 next = xmlXPathNextFollowing;
8503 break;
8504 case AXIS_FOLLOWING_SIBLING:
8505#ifdef DEBUG_STEP_NTH
8506 xmlGenericError(xmlGenericErrorContext,
8507 "axis 'following-siblings' ");
8508#endif
8509 last = NULL;
8510 next = xmlXPathNextFollowingSibling;
8511 break;
8512 case AXIS_NAMESPACE:
8513#ifdef DEBUG_STEP_NTH
8514 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
8515#endif
8516 last = NULL;
8517 first = NULL;
8518 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8519 break;
8520 case AXIS_PARENT:
8521#ifdef DEBUG_STEP_NTH
8522 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
8523#endif
8524 first = NULL;
8525 next = xmlXPathNextParent;
8526 break;
8527 case AXIS_PRECEDING:
8528#ifdef DEBUG_STEP_NTH
8529 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
8530#endif
8531 first = NULL;
8532 next = xmlXPathNextPrecedingInternal;
8533 break;
8534 case AXIS_PRECEDING_SIBLING:
8535#ifdef DEBUG_STEP_NTH
8536 xmlGenericError(xmlGenericErrorContext,
8537 "axis 'preceding-sibling' ");
8538#endif
8539 first = NULL;
8540 next = xmlXPathNextPrecedingSibling;
8541 break;
8542 case AXIS_SELF:
8543#ifdef DEBUG_STEP_NTH
8544 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
8545#endif
8546 first = NULL;
8547 last = NULL;
8548 next = xmlXPathNextSelf;
8549 break;
8550 }
8551 if (next == NULL)
8552 return(0);
8553
8554 nodelist = obj->nodesetval;
8555 if (nodelist == NULL) {
8556 xmlXPathFreeObject(obj);
8557 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8558 return(0);
8559 }
8560 addNode = xmlXPathNodeSetAddUnique;
8561#ifdef DEBUG_STEP_NTH
8562 xmlGenericError(xmlGenericErrorContext,
8563 " context contains %d nodes\n", nodelist->nodeNr);
8564 switch (test) {
8565 case NODE_TEST_NONE:
8566 xmlGenericError(xmlGenericErrorContext,
8567 " searching for none !!!\n");
8568 break;
8569 case NODE_TEST_TYPE:
8570 xmlGenericError(xmlGenericErrorContext,
8571 " searching for type %d\n", type);
8572 break;
8573 case NODE_TEST_PI:
8574 xmlGenericError(xmlGenericErrorContext,
8575 " searching for PI !!!\n");
8576 break;
8577 case NODE_TEST_ALL:
8578 xmlGenericError(xmlGenericErrorContext,
8579 " searching for *\n");
8580 break;
8581 case NODE_TEST_NS:
8582 xmlGenericError(xmlGenericErrorContext,
8583 " searching for namespace %s\n",
8584 prefix);
8585 break;
8586 case NODE_TEST_NAME:
8587 xmlGenericError(xmlGenericErrorContext,
8588 " searching for name %s\n", name);
8589 if (prefix != NULL)
8590 xmlGenericError(xmlGenericErrorContext,
8591 " with namespace %s\n", prefix);
8592 break;
8593 }
8594 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8595#endif
8596 /*
8597 * 2.3 Node Tests
8598 * - For the attribute axis, the principal node type is attribute.
8599 * - For the namespace axis, the principal node type is namespace.
8600 * - For other axes, the principal node type is element.
8601 *
8602 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008603 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00008604 * select all element children of the context node
8605 */
8606 tmp = ctxt->context->node;
8607 list = xmlXPathNodeSetCreate(NULL);
8608 for (i = 0; i < nodelist->nodeNr; i++) {
8609 ctxt->context->node = nodelist->nodeTab[i];
8610
8611 cur = NULL;
8612 n = 0;
8613 do {
8614 cur = next(ctxt, cur);
8615 if (cur == NULL)
8616 break;
8617 if ((first != NULL) && (*first == cur))
8618 break;
8619 if (((t % 256) == 0) &&
8620 (first != NULL) && (*first != NULL) &&
8621 (xmlXPathCmpNodes(*first, cur) >= 0))
8622 break;
8623 if ((last != NULL) && (*last == cur))
8624 break;
8625 if (((t % 256) == 0) &&
8626 (last != NULL) && (*last != NULL) &&
8627 (xmlXPathCmpNodes(cur, *last) >= 0))
8628 break;
8629 t++;
8630 switch (test) {
8631 case NODE_TEST_NONE:
8632 ctxt->context->node = tmp;
8633 STRANGE return(0);
8634 case NODE_TEST_TYPE:
8635 if ((cur->type == type) ||
8636 ((type == NODE_TYPE_NODE) &&
8637 ((cur->type == XML_DOCUMENT_NODE) ||
8638 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8639 (cur->type == XML_ELEMENT_NODE) ||
8640 (cur->type == XML_PI_NODE) ||
8641 (cur->type == XML_COMMENT_NODE) ||
8642 (cur->type == XML_CDATA_SECTION_NODE) ||
8643 (cur->type == XML_TEXT_NODE)))) {
8644 n++;
8645 if (n == indx)
8646 addNode(list, cur);
8647 }
8648 break;
8649 case NODE_TEST_PI:
8650 if (cur->type == XML_PI_NODE) {
8651 if ((name != NULL) &&
8652 (!xmlStrEqual(name, cur->name)))
8653 break;
8654 n++;
8655 if (n == indx)
8656 addNode(list, cur);
8657 }
8658 break;
8659 case NODE_TEST_ALL:
8660 if (axis == AXIS_ATTRIBUTE) {
8661 if (cur->type == XML_ATTRIBUTE_NODE) {
8662 n++;
8663 if (n == indx)
8664 addNode(list, cur);
8665 }
8666 } else if (axis == AXIS_NAMESPACE) {
8667 if (cur->type == XML_NAMESPACE_DECL) {
8668 n++;
8669 if (n == indx)
8670 addNode(list, cur);
8671 }
8672 } else {
8673 if (cur->type == XML_ELEMENT_NODE) {
8674 if (prefix == NULL) {
8675 n++;
8676 if (n == indx)
8677 addNode(list, cur);
8678 } else if ((cur->ns != NULL) &&
8679 (xmlStrEqual(URI, cur->ns->href))) {
8680 n++;
8681 if (n == indx)
8682 addNode(list, cur);
8683 }
8684 }
8685 }
8686 break;
8687 case NODE_TEST_NS:{
8688 TODO;
8689 break;
8690 }
8691 case NODE_TEST_NAME:
8692 switch (cur->type) {
8693 case XML_ELEMENT_NODE:
8694 if (xmlStrEqual(name, cur->name)) {
8695 if (prefix == NULL) {
8696 if (cur->ns == NULL) {
8697 n++;
8698 if (n == indx)
8699 addNode(list, cur);
8700 }
8701 } else {
8702 if ((cur->ns != NULL) &&
8703 (xmlStrEqual(URI,
8704 cur->ns->href))) {
8705 n++;
8706 if (n == indx)
8707 addNode(list, cur);
8708 }
8709 }
8710 }
8711 break;
8712 case XML_ATTRIBUTE_NODE:{
8713 xmlAttrPtr attr = (xmlAttrPtr) cur;
8714
8715 if (xmlStrEqual(name, attr->name)) {
8716 if (prefix == NULL) {
8717 if ((attr->ns == NULL) ||
8718 (attr->ns->prefix == NULL)) {
8719 n++;
8720 if (n == indx)
8721 addNode(list, cur);
8722 }
8723 } else {
8724 if ((attr->ns != NULL) &&
8725 (xmlStrEqual(URI,
8726 attr->ns->
8727 href))) {
8728 n++;
8729 if (n == indx)
8730 addNode(list, cur);
8731 }
8732 }
8733 }
8734 break;
8735 }
8736 case XML_NAMESPACE_DECL:
8737 if (cur->type == XML_NAMESPACE_DECL) {
8738 xmlNsPtr ns = (xmlNsPtr) cur;
8739
8740 if ((ns->prefix != NULL) && (name != NULL)
8741 && (xmlStrEqual(ns->prefix, name))) {
8742 n++;
8743 if (n == indx)
8744 addNode(list, cur);
8745 }
8746 }
8747 break;
8748 default:
8749 break;
8750 }
8751 break;
8752 break;
8753 }
8754 } while (n < indx);
8755 }
8756 ctxt->context->node = tmp;
8757#ifdef DEBUG_STEP_NTH
8758 xmlGenericError(xmlGenericErrorContext,
8759 "\nExamined %d nodes, found %d nodes at that step\n",
8760 t, list->nodeNr);
8761#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008762 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00008763 if ((obj->boolval) && (obj->user != NULL)) {
8764 ctxt->value->boolval = 1;
8765 ctxt->value->user = obj->user;
8766 obj->user = NULL;
8767 obj->boolval = 0;
8768 }
8769 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008770 return(t);
8771}
8772
8773/**
8774 * xmlXPathCompOpEvalFirst:
8775 * @ctxt: the XPath parser context with the compiled expression
8776 * @op: an XPath compiled operation
8777 * @first: the first elem found so far
8778 *
8779 * Evaluate the Precompiled XPath operation searching only the first
8780 * element in document order
8781 *
8782 * Returns the number of examined objects.
8783 */
8784static int
8785xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
8786 xmlXPathStepOpPtr op, xmlNodePtr * first)
8787{
8788 int total = 0, cur;
8789 xmlXPathCompExprPtr comp;
8790 xmlXPathObjectPtr arg1, arg2;
8791
Daniel Veillard556c6682001-10-06 09:59:51 +00008792 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008793 comp = ctxt->comp;
8794 switch (op->op) {
8795 case XPATH_OP_END:
8796 return (0);
8797 case XPATH_OP_UNION:
8798 total =
8799 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
8800 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00008801 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008802 if ((ctxt->value != NULL)
8803 && (ctxt->value->type == XPATH_NODESET)
8804 && (ctxt->value->nodesetval != NULL)
8805 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8806 /*
8807 * limit tree traversing to first node in the result
8808 */
8809 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8810 *first = ctxt->value->nodesetval->nodeTab[0];
8811 }
8812 cur =
8813 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
8814 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00008815 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008816 CHECK_TYPE0(XPATH_NODESET);
8817 arg2 = valuePop(ctxt);
8818
8819 CHECK_TYPE0(XPATH_NODESET);
8820 arg1 = valuePop(ctxt);
8821
8822 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8823 arg2->nodesetval);
8824 valuePush(ctxt, arg1);
8825 xmlXPathFreeObject(arg2);
8826 /* optimizer */
8827 if (total > cur)
8828 xmlXPathCompSwap(op);
8829 return (total + cur);
8830 case XPATH_OP_ROOT:
8831 xmlXPathRoot(ctxt);
8832 return (0);
8833 case XPATH_OP_NODE:
8834 if (op->ch1 != -1)
8835 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008836 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008837 if (op->ch2 != -1)
8838 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008839 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008840 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8841 return (total);
8842 case XPATH_OP_RESET:
8843 if (op->ch1 != -1)
8844 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008845 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008846 if (op->ch2 != -1)
8847 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008848 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008849 ctxt->context->node = NULL;
8850 return (total);
8851 case XPATH_OP_COLLECT:{
8852 if (op->ch1 == -1)
8853 return (total);
8854
8855 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008856 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008857
8858 /*
8859 * Optimization for [n] selection where n is a number
8860 */
8861 if ((op->ch2 != -1) &&
8862 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8863 (comp->steps[op->ch2].ch1 == -1) &&
8864 (comp->steps[op->ch2].ch2 != -1) &&
8865 (comp->steps[comp->steps[op->ch2].ch2].op ==
8866 XPATH_OP_VALUE)) {
8867 xmlXPathObjectPtr val;
8868
8869 val = comp->steps[comp->steps[op->ch2].ch2].value4;
8870 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
8871 int indx = (int) val->floatval;
8872
8873 if (val->floatval == (float) indx) {
8874 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
8875 first, NULL);
8876 return (total);
8877 }
8878 }
8879 }
8880 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
8881 return (total);
8882 }
8883 case XPATH_OP_VALUE:
8884 valuePush(ctxt,
8885 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
8886 return (0);
8887 case XPATH_OP_SORT:
8888 if (op->ch1 != -1)
8889 total +=
8890 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
8891 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00008892 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008893 if ((ctxt->value != NULL)
8894 && (ctxt->value->type == XPATH_NODESET)
8895 && (ctxt->value->nodesetval != NULL))
8896 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8897 return (total);
8898 default:
8899 return (xmlXPathCompOpEval(ctxt, op));
8900 }
8901}
8902
8903/**
8904 * xmlXPathCompOpEvalLast:
8905 * @ctxt: the XPath parser context with the compiled expression
8906 * @op: an XPath compiled operation
8907 * @last: the last elem found so far
8908 *
8909 * Evaluate the Precompiled XPath operation searching only the last
8910 * element in document order
8911 *
8912 * Returns the number of node traversed
8913 */
8914static int
8915xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
8916 xmlNodePtr * last)
8917{
8918 int total = 0, cur;
8919 xmlXPathCompExprPtr comp;
8920 xmlXPathObjectPtr arg1, arg2;
8921
Daniel Veillard556c6682001-10-06 09:59:51 +00008922 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008923 comp = ctxt->comp;
8924 switch (op->op) {
8925 case XPATH_OP_END:
8926 return (0);
8927 case XPATH_OP_UNION:
8928 total =
8929 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00008930 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008931 if ((ctxt->value != NULL)
8932 && (ctxt->value->type == XPATH_NODESET)
8933 && (ctxt->value->nodesetval != NULL)
8934 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8935 /*
8936 * limit tree traversing to first node in the result
8937 */
8938 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8939 *last =
8940 ctxt->value->nodesetval->nodeTab[ctxt->value->
8941 nodesetval->nodeNr -
8942 1];
8943 }
8944 cur =
8945 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00008946 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008947 if ((ctxt->value != NULL)
8948 && (ctxt->value->type == XPATH_NODESET)
8949 && (ctxt->value->nodesetval != NULL)
8950 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8951 }
8952 CHECK_TYPE0(XPATH_NODESET);
8953 arg2 = valuePop(ctxt);
8954
8955 CHECK_TYPE0(XPATH_NODESET);
8956 arg1 = valuePop(ctxt);
8957
8958 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8959 arg2->nodesetval);
8960 valuePush(ctxt, arg1);
8961 xmlXPathFreeObject(arg2);
8962 /* optimizer */
8963 if (total > cur)
8964 xmlXPathCompSwap(op);
8965 return (total + cur);
8966 case XPATH_OP_ROOT:
8967 xmlXPathRoot(ctxt);
8968 return (0);
8969 case XPATH_OP_NODE:
8970 if (op->ch1 != -1)
8971 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008972 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008973 if (op->ch2 != -1)
8974 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008975 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008976 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8977 return (total);
8978 case XPATH_OP_RESET:
8979 if (op->ch1 != -1)
8980 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008981 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008982 if (op->ch2 != -1)
8983 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008984 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008985 ctxt->context->node = NULL;
8986 return (total);
8987 case XPATH_OP_COLLECT:{
8988 if (op->ch1 == -1)
8989 return (0);
8990
8991 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008992 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008993
8994 /*
8995 * Optimization for [n] selection where n is a number
8996 */
8997 if ((op->ch2 != -1) &&
8998 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8999 (comp->steps[op->ch2].ch1 == -1) &&
9000 (comp->steps[op->ch2].ch2 != -1) &&
9001 (comp->steps[comp->steps[op->ch2].ch2].op ==
9002 XPATH_OP_VALUE)) {
9003 xmlXPathObjectPtr val;
9004
9005 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9006 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9007 int indx = (int) val->floatval;
9008
9009 if (val->floatval == (float) indx) {
9010 total +=
9011 xmlXPathNodeCollectAndTestNth(ctxt, op,
9012 indx, NULL,
9013 last);
9014 return (total);
9015 }
9016 }
9017 }
9018 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9019 return (total);
9020 }
9021 case XPATH_OP_VALUE:
9022 valuePush(ctxt,
9023 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9024 return (0);
9025 case XPATH_OP_SORT:
9026 if (op->ch1 != -1)
9027 total +=
9028 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9029 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009030 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009031 if ((ctxt->value != NULL)
9032 && (ctxt->value->type == XPATH_NODESET)
9033 && (ctxt->value->nodesetval != NULL))
9034 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9035 return (total);
9036 default:
9037 return (xmlXPathCompOpEval(ctxt, op));
9038 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009039}
9040
Owen Taylor3473f882001-02-23 17:55:21 +00009041/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009042 * xmlXPathCompOpEval:
9043 * @ctxt: the XPath parser context with the compiled expression
9044 * @op: an XPath compiled operation
9045 *
9046 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009047 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009048 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009049static int
9050xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9051{
9052 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009053 int equal, ret;
9054 xmlXPathCompExprPtr comp;
9055 xmlXPathObjectPtr arg1, arg2;
9056
Daniel Veillard556c6682001-10-06 09:59:51 +00009057 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009058 comp = ctxt->comp;
9059 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009060 case XPATH_OP_END:
9061 return (0);
9062 case XPATH_OP_AND:
9063 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009064 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009065 xmlXPathBooleanFunction(ctxt, 1);
9066 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9067 return (total);
9068 arg2 = valuePop(ctxt);
9069 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009070 if (ctxt->error) {
9071 xmlXPathFreeObject(arg2);
9072 return(0);
9073 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009074 xmlXPathBooleanFunction(ctxt, 1);
9075 arg1 = valuePop(ctxt);
9076 arg1->boolval &= arg2->boolval;
9077 valuePush(ctxt, arg1);
9078 xmlXPathFreeObject(arg2);
9079 return (total);
9080 case XPATH_OP_OR:
9081 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009082 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009083 xmlXPathBooleanFunction(ctxt, 1);
9084 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9085 return (total);
9086 arg2 = valuePop(ctxt);
9087 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009088 if (ctxt->error) {
9089 xmlXPathFreeObject(arg2);
9090 return(0);
9091 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009092 xmlXPathBooleanFunction(ctxt, 1);
9093 arg1 = valuePop(ctxt);
9094 arg1->boolval |= arg2->boolval;
9095 valuePush(ctxt, arg1);
9096 xmlXPathFreeObject(arg2);
9097 return (total);
9098 case XPATH_OP_EQUAL:
9099 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009100 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009101 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009102 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009103 equal = xmlXPathEqualValues(ctxt);
9104 if (op->value)
9105 valuePush(ctxt, xmlXPathNewBoolean(equal));
9106 else
9107 valuePush(ctxt, xmlXPathNewBoolean(!equal));
9108 return (total);
9109 case XPATH_OP_CMP:
9110 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009111 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009112 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009113 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009114 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9115 valuePush(ctxt, xmlXPathNewBoolean(ret));
9116 return (total);
9117 case XPATH_OP_PLUS:
9118 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009119 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009120 if (op->ch2 != -1)
9121 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009122 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009123 if (op->value == 0)
9124 xmlXPathSubValues(ctxt);
9125 else if (op->value == 1)
9126 xmlXPathAddValues(ctxt);
9127 else if (op->value == 2)
9128 xmlXPathValueFlipSign(ctxt);
9129 else if (op->value == 3) {
9130 CAST_TO_NUMBER;
9131 CHECK_TYPE0(XPATH_NUMBER);
9132 }
9133 return (total);
9134 case XPATH_OP_MULT:
9135 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009136 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009137 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009138 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009139 if (op->value == 0)
9140 xmlXPathMultValues(ctxt);
9141 else if (op->value == 1)
9142 xmlXPathDivValues(ctxt);
9143 else if (op->value == 2)
9144 xmlXPathModValues(ctxt);
9145 return (total);
9146 case XPATH_OP_UNION:
9147 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009148 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009149 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009150 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009151 CHECK_TYPE0(XPATH_NODESET);
9152 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009153
Daniel Veillardf06307e2001-07-03 10:35:50 +00009154 CHECK_TYPE0(XPATH_NODESET);
9155 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009156
Daniel Veillardf06307e2001-07-03 10:35:50 +00009157 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9158 arg2->nodesetval);
9159 valuePush(ctxt, arg1);
9160 xmlXPathFreeObject(arg2);
9161 return (total);
9162 case XPATH_OP_ROOT:
9163 xmlXPathRoot(ctxt);
9164 return (total);
9165 case XPATH_OP_NODE:
9166 if (op->ch1 != -1)
9167 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009168 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009169 if (op->ch2 != -1)
9170 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009171 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009172 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9173 return (total);
9174 case XPATH_OP_RESET:
9175 if (op->ch1 != -1)
9176 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009177 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009178 if (op->ch2 != -1)
9179 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009180 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009181 ctxt->context->node = NULL;
9182 return (total);
9183 case XPATH_OP_COLLECT:{
9184 if (op->ch1 == -1)
9185 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009186
Daniel Veillardf06307e2001-07-03 10:35:50 +00009187 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009188 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009189
Daniel Veillardf06307e2001-07-03 10:35:50 +00009190 /*
9191 * Optimization for [n] selection where n is a number
9192 */
9193 if ((op->ch2 != -1) &&
9194 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9195 (comp->steps[op->ch2].ch1 == -1) &&
9196 (comp->steps[op->ch2].ch2 != -1) &&
9197 (comp->steps[comp->steps[op->ch2].ch2].op ==
9198 XPATH_OP_VALUE)) {
9199 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00009200
Daniel Veillardf06307e2001-07-03 10:35:50 +00009201 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9202 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9203 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009204
Daniel Veillardf06307e2001-07-03 10:35:50 +00009205 if (val->floatval == (float) indx) {
9206 total +=
9207 xmlXPathNodeCollectAndTestNth(ctxt, op,
9208 indx, NULL,
9209 NULL);
9210 return (total);
9211 }
9212 }
9213 }
9214 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
9215 return (total);
9216 }
9217 case XPATH_OP_VALUE:
9218 valuePush(ctxt,
9219 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9220 return (total);
9221 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +00009222 xmlXPathObjectPtr val;
9223
Daniel Veillardf06307e2001-07-03 10:35:50 +00009224 if (op->ch1 != -1)
9225 total +=
9226 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009227 if (op->value5 == NULL) {
9228 val = xmlXPathVariableLookup(ctxt->context, op->value4);
9229 if (val == NULL) {
9230 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9231 return(0);
9232 }
9233 valuePush(ctxt, val);
9234 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009235 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009236
Daniel Veillardf06307e2001-07-03 10:35:50 +00009237 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9238 if (URI == NULL) {
9239 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009240 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009241 op->value4, op->value5);
9242 return (total);
9243 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009244 val = xmlXPathVariableLookupNS(ctxt->context,
9245 op->value4, URI);
9246 if (val == NULL) {
9247 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9248 return(0);
9249 }
9250 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009251 }
9252 return (total);
9253 }
9254 case XPATH_OP_FUNCTION:{
9255 xmlXPathFunction func;
9256 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +00009257 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009258
9259 if (op->ch1 != -1)
9260 total +=
9261 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009262 if (ctxt->valueNr < op->value) {
9263 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009264 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +00009265 ctxt->error = XPATH_INVALID_OPERAND;
9266 return (total);
9267 }
9268 for (i = 0; i < op->value; i++)
9269 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
9270 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009271 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +00009272 ctxt->error = XPATH_INVALID_OPERAND;
9273 return (total);
9274 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009275 if (op->cache != NULL)
9276 func = (xmlXPathFunction) op->cache;
9277 else {
9278 const xmlChar *URI = NULL;
9279
9280 if (op->value5 == NULL)
9281 func =
9282 xmlXPathFunctionLookup(ctxt->context,
9283 op->value4);
9284 else {
9285 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9286 if (URI == NULL) {
9287 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009288 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009289 op->value4, op->value5);
9290 return (total);
9291 }
9292 func = xmlXPathFunctionLookupNS(ctxt->context,
9293 op->value4, URI);
9294 }
9295 if (func == NULL) {
9296 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009297 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +00009298 op->value4);
9299 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009300 }
9301 op->cache = (void *) func;
9302 op->cacheURI = (void *) URI;
9303 }
9304 oldFunc = ctxt->context->function;
9305 oldFuncURI = ctxt->context->functionURI;
9306 ctxt->context->function = op->value4;
9307 ctxt->context->functionURI = op->cacheURI;
9308 func(ctxt, op->value);
9309 ctxt->context->function = oldFunc;
9310 ctxt->context->functionURI = oldFuncURI;
9311 return (total);
9312 }
9313 case XPATH_OP_ARG:
9314 if (op->ch1 != -1)
9315 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009316 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009317 if (op->ch2 != -1)
9318 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009319 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009320 return (total);
9321 case XPATH_OP_PREDICATE:
9322 case XPATH_OP_FILTER:{
9323 xmlXPathObjectPtr res;
9324 xmlXPathObjectPtr obj, tmp;
9325 xmlNodeSetPtr newset = NULL;
9326 xmlNodeSetPtr oldset;
9327 xmlNodePtr oldnode;
9328 int i;
9329
9330 /*
9331 * Optimization for ()[1] selection i.e. the first elem
9332 */
9333 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9334 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9335 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
9336 xmlXPathObjectPtr val;
9337
9338 val = comp->steps[op->ch2].value4;
9339 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
9340 (val->floatval == 1.0)) {
9341 xmlNodePtr first = NULL;
9342
9343 total +=
9344 xmlXPathCompOpEvalFirst(ctxt,
9345 &comp->steps[op->ch1],
9346 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009347 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009348 /*
9349 * The nodeset should be in document order,
9350 * Keep only the first value
9351 */
9352 if ((ctxt->value != NULL) &&
9353 (ctxt->value->type == XPATH_NODESET) &&
9354 (ctxt->value->nodesetval != NULL) &&
9355 (ctxt->value->nodesetval->nodeNr > 1))
9356 ctxt->value->nodesetval->nodeNr = 1;
9357 return (total);
9358 }
9359 }
9360 /*
9361 * Optimization for ()[last()] selection i.e. the last elem
9362 */
9363 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9364 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9365 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
9366 int f = comp->steps[op->ch2].ch1;
9367
9368 if ((f != -1) &&
9369 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
9370 (comp->steps[f].value5 == NULL) &&
9371 (comp->steps[f].value == 0) &&
9372 (comp->steps[f].value4 != NULL) &&
9373 (xmlStrEqual
9374 (comp->steps[f].value4, BAD_CAST "last"))) {
9375 xmlNodePtr last = NULL;
9376
9377 total +=
9378 xmlXPathCompOpEvalLast(ctxt,
9379 &comp->steps[op->ch1],
9380 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009381 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009382 /*
9383 * The nodeset should be in document order,
9384 * Keep only the last value
9385 */
9386 if ((ctxt->value != NULL) &&
9387 (ctxt->value->type == XPATH_NODESET) &&
9388 (ctxt->value->nodesetval != NULL) &&
9389 (ctxt->value->nodesetval->nodeTab != NULL) &&
9390 (ctxt->value->nodesetval->nodeNr > 1)) {
9391 ctxt->value->nodesetval->nodeTab[0] =
9392 ctxt->value->nodesetval->nodeTab[ctxt->
9393 value->
9394 nodesetval->
9395 nodeNr -
9396 1];
9397 ctxt->value->nodesetval->nodeNr = 1;
9398 }
9399 return (total);
9400 }
9401 }
9402
9403 if (op->ch1 != -1)
9404 total +=
9405 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009406 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009407 if (op->ch2 == -1)
9408 return (total);
9409 if (ctxt->value == NULL)
9410 return (total);
9411
9412 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009413
9414#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009415 /*
9416 * Hum are we filtering the result of an XPointer expression
9417 */
9418 if (ctxt->value->type == XPATH_LOCATIONSET) {
9419 xmlLocationSetPtr newlocset = NULL;
9420 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009421
Daniel Veillardf06307e2001-07-03 10:35:50 +00009422 /*
9423 * Extract the old locset, and then evaluate the result of the
9424 * expression for all the element in the locset. use it to grow
9425 * up a new locset.
9426 */
9427 CHECK_TYPE0(XPATH_LOCATIONSET);
9428 obj = valuePop(ctxt);
9429 oldlocset = obj->user;
9430 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009431
Daniel Veillardf06307e2001-07-03 10:35:50 +00009432 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
9433 ctxt->context->contextSize = 0;
9434 ctxt->context->proximityPosition = 0;
9435 if (op->ch2 != -1)
9436 total +=
9437 xmlXPathCompOpEval(ctxt,
9438 &comp->steps[op->ch2]);
9439 res = valuePop(ctxt);
9440 if (res != NULL)
9441 xmlXPathFreeObject(res);
9442 valuePush(ctxt, obj);
9443 CHECK_ERROR0;
9444 return (total);
9445 }
9446 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009447
Daniel Veillardf06307e2001-07-03 10:35:50 +00009448 for (i = 0; i < oldlocset->locNr; i++) {
9449 /*
9450 * Run the evaluation with a node list made of a
9451 * single item in the nodelocset.
9452 */
9453 ctxt->context->node = oldlocset->locTab[i]->user;
9454 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9455 valuePush(ctxt, tmp);
9456 ctxt->context->contextSize = oldlocset->locNr;
9457 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009458
Daniel Veillardf06307e2001-07-03 10:35:50 +00009459 if (op->ch2 != -1)
9460 total +=
9461 xmlXPathCompOpEval(ctxt,
9462 &comp->steps[op->ch2]);
9463 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009464
Daniel Veillardf06307e2001-07-03 10:35:50 +00009465 /*
9466 * The result of the evaluation need to be tested to
9467 * decided whether the filter succeeded or not
9468 */
9469 res = valuePop(ctxt);
9470 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9471 xmlXPtrLocationSetAdd(newlocset,
9472 xmlXPathObjectCopy
9473 (oldlocset->locTab[i]));
9474 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009475
Daniel Veillardf06307e2001-07-03 10:35:50 +00009476 /*
9477 * Cleanup
9478 */
9479 if (res != NULL)
9480 xmlXPathFreeObject(res);
9481 if (ctxt->value == tmp) {
9482 res = valuePop(ctxt);
9483 xmlXPathFreeObject(res);
9484 }
9485
9486 ctxt->context->node = NULL;
9487 }
9488
9489 /*
9490 * The result is used as the new evaluation locset.
9491 */
9492 xmlXPathFreeObject(obj);
9493 ctxt->context->node = NULL;
9494 ctxt->context->contextSize = -1;
9495 ctxt->context->proximityPosition = -1;
9496 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
9497 ctxt->context->node = oldnode;
9498 return (total);
9499 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009500#endif /* LIBXML_XPTR_ENABLED */
9501
Daniel Veillardf06307e2001-07-03 10:35:50 +00009502 /*
9503 * Extract the old set, and then evaluate the result of the
9504 * expression for all the element in the set. use it to grow
9505 * up a new set.
9506 */
9507 CHECK_TYPE0(XPATH_NODESET);
9508 obj = valuePop(ctxt);
9509 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00009510
Daniel Veillardf06307e2001-07-03 10:35:50 +00009511 oldnode = ctxt->context->node;
9512 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009513
Daniel Veillardf06307e2001-07-03 10:35:50 +00009514 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
9515 ctxt->context->contextSize = 0;
9516 ctxt->context->proximityPosition = 0;
9517 if (op->ch2 != -1)
9518 total +=
9519 xmlXPathCompOpEval(ctxt,
9520 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009521 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009522 res = valuePop(ctxt);
9523 if (res != NULL)
9524 xmlXPathFreeObject(res);
9525 valuePush(ctxt, obj);
9526 ctxt->context->node = oldnode;
9527 CHECK_ERROR0;
9528 } else {
9529 /*
9530 * Initialize the new set.
9531 */
9532 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009533
Daniel Veillardf06307e2001-07-03 10:35:50 +00009534 for (i = 0; i < oldset->nodeNr; i++) {
9535 /*
9536 * Run the evaluation with a node list made of
9537 * a single item in the nodeset.
9538 */
9539 ctxt->context->node = oldset->nodeTab[i];
9540 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9541 valuePush(ctxt, tmp);
9542 ctxt->context->contextSize = oldset->nodeNr;
9543 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009544
Daniel Veillardf06307e2001-07-03 10:35:50 +00009545 if (op->ch2 != -1)
9546 total +=
9547 xmlXPathCompOpEval(ctxt,
9548 &comp->steps[op->ch2]);
9549 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009550
Daniel Veillardf06307e2001-07-03 10:35:50 +00009551 /*
9552 * The result of the evaluation need to be tested to
9553 * decided whether the filter succeeded or not
9554 */
9555 res = valuePop(ctxt);
9556 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9557 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
9558 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009559
Daniel Veillardf06307e2001-07-03 10:35:50 +00009560 /*
9561 * Cleanup
9562 */
9563 if (res != NULL)
9564 xmlXPathFreeObject(res);
9565 if (ctxt->value == tmp) {
9566 res = valuePop(ctxt);
9567 xmlXPathFreeObject(res);
9568 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009569
Daniel Veillardf06307e2001-07-03 10:35:50 +00009570 ctxt->context->node = NULL;
9571 }
9572
9573 /*
9574 * The result is used as the new evaluation set.
9575 */
9576 xmlXPathFreeObject(obj);
9577 ctxt->context->node = NULL;
9578 ctxt->context->contextSize = -1;
9579 ctxt->context->proximityPosition = -1;
9580 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
9581 }
9582 ctxt->context->node = oldnode;
9583 return (total);
9584 }
9585 case XPATH_OP_SORT:
9586 if (op->ch1 != -1)
9587 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009588 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009589 if ((ctxt->value != NULL) &&
9590 (ctxt->value->type == XPATH_NODESET) &&
9591 (ctxt->value->nodesetval != NULL))
9592 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9593 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009594#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009595 case XPATH_OP_RANGETO:{
9596 xmlXPathObjectPtr range;
9597 xmlXPathObjectPtr res, obj;
9598 xmlXPathObjectPtr tmp;
9599 xmlLocationSetPtr newset = NULL;
9600 xmlNodeSetPtr oldset;
9601 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009602
Daniel Veillardf06307e2001-07-03 10:35:50 +00009603 if (op->ch1 != -1)
9604 total +=
9605 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9606 if (op->ch2 == -1)
9607 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009608
Daniel Veillardf06307e2001-07-03 10:35:50 +00009609 CHECK_TYPE0(XPATH_NODESET);
9610 obj = valuePop(ctxt);
9611 oldset = obj->nodesetval;
9612 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009613
Daniel Veillardf06307e2001-07-03 10:35:50 +00009614 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009615
Daniel Veillardf06307e2001-07-03 10:35:50 +00009616 if (oldset != NULL) {
9617 for (i = 0; i < oldset->nodeNr; i++) {
9618 /*
9619 * Run the evaluation with a node list made of a single item
9620 * in the nodeset.
9621 */
9622 ctxt->context->node = oldset->nodeTab[i];
9623 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9624 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009625
Daniel Veillardf06307e2001-07-03 10:35:50 +00009626 if (op->ch2 != -1)
9627 total +=
9628 xmlXPathCompOpEval(ctxt,
9629 &comp->steps[op->ch2]);
9630 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009631
Daniel Veillardf06307e2001-07-03 10:35:50 +00009632 /*
9633 * The result of the evaluation need to be tested to
9634 * decided whether the filter succeeded or not
9635 */
9636 res = valuePop(ctxt);
9637 range =
9638 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
9639 res);
9640 if (range != NULL) {
9641 xmlXPtrLocationSetAdd(newset, range);
9642 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009643
Daniel Veillardf06307e2001-07-03 10:35:50 +00009644 /*
9645 * Cleanup
9646 */
9647 if (res != NULL)
9648 xmlXPathFreeObject(res);
9649 if (ctxt->value == tmp) {
9650 res = valuePop(ctxt);
9651 xmlXPathFreeObject(res);
9652 }
9653
9654 ctxt->context->node = NULL;
9655 }
9656 }
9657
9658 /*
9659 * The result is used as the new evaluation set.
9660 */
9661 xmlXPathFreeObject(obj);
9662 ctxt->context->node = NULL;
9663 ctxt->context->contextSize = -1;
9664 ctxt->context->proximityPosition = -1;
9665 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
9666 return (total);
9667 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009668#endif /* LIBXML_XPTR_ENABLED */
9669 }
9670 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009671 "XPath: unknown precompiled operation %d\n", op->op);
9672 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009673}
9674
9675/**
9676 * xmlXPathRunEval:
9677 * @ctxt: the XPath parser context with the compiled expression
9678 *
9679 * Evaluate the Precompiled XPath expression in the given context.
9680 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009681static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009682xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
9683 xmlXPathCompExprPtr comp;
9684
9685 if ((ctxt == NULL) || (ctxt->comp == NULL))
9686 return;
9687
9688 if (ctxt->valueTab == NULL) {
9689 /* Allocate the value stack */
9690 ctxt->valueTab = (xmlXPathObjectPtr *)
9691 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
9692 if (ctxt->valueTab == NULL) {
9693 xmlFree(ctxt);
9694 xmlGenericError(xmlGenericErrorContext,
9695 "xmlXPathRunEval: out of memory\n");
9696 return;
9697 }
9698 ctxt->valueNr = 0;
9699 ctxt->valueMax = 10;
9700 ctxt->value = NULL;
9701 }
9702 comp = ctxt->comp;
9703 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
9704}
9705
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009706/************************************************************************
9707 * *
9708 * Public interfaces *
9709 * *
9710 ************************************************************************/
9711
9712/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009713 * xmlXPathEvalPredicate:
9714 * @ctxt: the XPath context
9715 * @res: the Predicate Expression evaluation result
9716 *
9717 * Evaluate a predicate result for the current node.
9718 * A PredicateExpr is evaluated by evaluating the Expr and converting
9719 * the result to a boolean. If the result is a number, the result will
9720 * be converted to true if the number is equal to the position of the
9721 * context node in the context node list (as returned by the position
9722 * function) and will be converted to false otherwise; if the result
9723 * is not a number, then the result will be converted as if by a call
9724 * to the boolean function.
9725 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009726 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009727 */
9728int
9729xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
9730 if (res == NULL) return(0);
9731 switch (res->type) {
9732 case XPATH_BOOLEAN:
9733 return(res->boolval);
9734 case XPATH_NUMBER:
9735 return(res->floatval == ctxt->proximityPosition);
9736 case XPATH_NODESET:
9737 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009738 if (res->nodesetval == NULL)
9739 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009740 return(res->nodesetval->nodeNr != 0);
9741 case XPATH_STRING:
9742 return((res->stringval != NULL) &&
9743 (xmlStrlen(res->stringval) != 0));
9744 default:
9745 STRANGE
9746 }
9747 return(0);
9748}
9749
9750/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009751 * xmlXPathEvaluatePredicateResult:
9752 * @ctxt: the XPath Parser context
9753 * @res: the Predicate Expression evaluation result
9754 *
9755 * Evaluate a predicate result for the current node.
9756 * A PredicateExpr is evaluated by evaluating the Expr and converting
9757 * the result to a boolean. If the result is a number, the result will
9758 * be converted to true if the number is equal to the position of the
9759 * context node in the context node list (as returned by the position
9760 * function) and will be converted to false otherwise; if the result
9761 * is not a number, then the result will be converted as if by a call
9762 * to the boolean function.
9763 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009764 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009765 */
9766int
9767xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
9768 xmlXPathObjectPtr res) {
9769 if (res == NULL) return(0);
9770 switch (res->type) {
9771 case XPATH_BOOLEAN:
9772 return(res->boolval);
9773 case XPATH_NUMBER:
9774 return(res->floatval == ctxt->context->proximityPosition);
9775 case XPATH_NODESET:
9776 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +00009777 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +00009778 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009779 return(res->nodesetval->nodeNr != 0);
9780 case XPATH_STRING:
9781 return((res->stringval != NULL) &&
9782 (xmlStrlen(res->stringval) != 0));
9783 default:
9784 STRANGE
9785 }
9786 return(0);
9787}
9788
9789/**
9790 * xmlXPathCompile:
9791 * @str: the XPath expression
9792 *
9793 * Compile an XPath expression
9794 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009795 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009796 * the caller has to free the object.
9797 */
9798xmlXPathCompExprPtr
9799xmlXPathCompile(const xmlChar *str) {
9800 xmlXPathParserContextPtr ctxt;
9801 xmlXPathCompExprPtr comp;
9802
9803 xmlXPathInit();
9804
9805 ctxt = xmlXPathNewParserContext(str, NULL);
9806 xmlXPathCompileExpr(ctxt);
9807
Daniel Veillard40af6492001-04-22 08:50:55 +00009808 if (*ctxt->cur != 0) {
9809 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9810 comp = NULL;
9811 } else {
9812 comp = ctxt->comp;
9813 ctxt->comp = NULL;
9814 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009815 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009816#ifdef DEBUG_EVAL_COUNTS
9817 if (comp != NULL) {
9818 comp->string = xmlStrdup(str);
9819 comp->nb = 0;
9820 }
9821#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009822 return(comp);
9823}
9824
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009825/**
9826 * xmlXPathCompiledEval:
9827 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +00009828 * @ctx: the XPath context
9829 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009830 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +00009831 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009832 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +00009833 * the caller has to free the object.
9834 */
9835xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009836xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +00009837 xmlXPathParserContextPtr ctxt;
9838 xmlXPathObjectPtr res, tmp, init = NULL;
9839 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +00009840#ifndef LIBXML_THREAD_ENABLED
9841 static int reentance = 0;
9842#endif
Owen Taylor3473f882001-02-23 17:55:21 +00009843
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009844 if ((comp == NULL) || (ctx == NULL))
9845 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00009846 xmlXPathInit();
9847
9848 CHECK_CONTEXT(ctx)
9849
Daniel Veillard81463942001-10-16 12:34:39 +00009850#ifndef LIBXML_THREAD_ENABLED
9851 reentance++;
9852 if (reentance > 1)
9853 xmlXPathDisableOptimizer = 1;
9854#endif
9855
Daniel Veillardf06307e2001-07-03 10:35:50 +00009856#ifdef DEBUG_EVAL_COUNTS
9857 comp->nb++;
9858 if ((comp->string != NULL) && (comp->nb > 100)) {
9859 fprintf(stderr, "100 x %s\n", comp->string);
9860 comp->nb = 0;
9861 }
9862#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009863 ctxt = xmlXPathCompParserContext(comp, ctx);
9864 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009865
9866 if (ctxt->value == NULL) {
9867 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009868 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00009869 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009870 } else {
9871 res = valuePop(ctxt);
9872 }
9873
Daniel Veillardf06307e2001-07-03 10:35:50 +00009874
Owen Taylor3473f882001-02-23 17:55:21 +00009875 do {
9876 tmp = valuePop(ctxt);
9877 if (tmp != NULL) {
9878 if (tmp != init)
9879 stack++;
9880 xmlXPathFreeObject(tmp);
9881 }
9882 } while (tmp != NULL);
9883 if ((stack != 0) && (res != NULL)) {
9884 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009885 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +00009886 stack);
9887 }
9888 if (ctxt->error != XPATH_EXPRESSION_OK) {
9889 xmlXPathFreeObject(res);
9890 res = NULL;
9891 }
9892
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009893
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009894 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009895 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +00009896#ifndef LIBXML_THREAD_ENABLED
9897 reentance--;
9898#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009899 return(res);
9900}
9901
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009902/**
9903 * xmlXPathEvalExpr:
9904 * @ctxt: the XPath Parser context
9905 *
9906 * Parse and evaluate an XPath expression in the given context,
9907 * then push the result on the context stack
9908 */
9909void
9910xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
9911 xmlXPathCompileExpr(ctxt);
9912 xmlXPathRunEval(ctxt);
9913}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009914
9915/**
9916 * xmlXPathEval:
9917 * @str: the XPath expression
9918 * @ctx: the XPath context
9919 *
9920 * Evaluate the XPath Location Path in the given context.
9921 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009922 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009923 * the caller has to free the object.
9924 */
9925xmlXPathObjectPtr
9926xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
9927 xmlXPathParserContextPtr ctxt;
9928 xmlXPathObjectPtr res, tmp, init = NULL;
9929 int stack = 0;
9930
9931 xmlXPathInit();
9932
9933 CHECK_CONTEXT(ctx)
9934
9935 ctxt = xmlXPathNewParserContext(str, ctx);
9936 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009937
9938 if (ctxt->value == NULL) {
9939 xmlGenericError(xmlGenericErrorContext,
9940 "xmlXPathEval: evaluation failed\n");
9941 res = NULL;
9942 } else if (*ctxt->cur != 0) {
9943 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9944 res = NULL;
9945 } else {
9946 res = valuePop(ctxt);
9947 }
9948
9949 do {
9950 tmp = valuePop(ctxt);
9951 if (tmp != NULL) {
9952 if (tmp != init)
9953 stack++;
9954 xmlXPathFreeObject(tmp);
9955 }
9956 } while (tmp != NULL);
9957 if ((stack != 0) && (res != NULL)) {
9958 xmlGenericError(xmlGenericErrorContext,
9959 "xmlXPathEval: %d object left on the stack\n",
9960 stack);
9961 }
9962 if (ctxt->error != XPATH_EXPRESSION_OK) {
9963 xmlXPathFreeObject(res);
9964 res = NULL;
9965 }
9966
Owen Taylor3473f882001-02-23 17:55:21 +00009967 xmlXPathFreeParserContext(ctxt);
9968 return(res);
9969}
9970
9971/**
9972 * xmlXPathEvalExpression:
9973 * @str: the XPath expression
9974 * @ctxt: the XPath context
9975 *
9976 * Evaluate the XPath expression in the given context.
9977 *
9978 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
9979 * the caller has to free the object.
9980 */
9981xmlXPathObjectPtr
9982xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
9983 xmlXPathParserContextPtr pctxt;
9984 xmlXPathObjectPtr res, tmp;
9985 int stack = 0;
9986
9987 xmlXPathInit();
9988
9989 CHECK_CONTEXT(ctxt)
9990
9991 pctxt = xmlXPathNewParserContext(str, ctxt);
9992 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009993
9994 if (*pctxt->cur != 0) {
9995 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9996 res = NULL;
9997 } else {
9998 res = valuePop(pctxt);
9999 }
10000 do {
10001 tmp = valuePop(pctxt);
10002 if (tmp != NULL) {
10003 xmlXPathFreeObject(tmp);
10004 stack++;
10005 }
10006 } while (tmp != NULL);
10007 if ((stack != 0) && (res != NULL)) {
10008 xmlGenericError(xmlGenericErrorContext,
10009 "xmlXPathEvalExpression: %d object left on the stack\n",
10010 stack);
10011 }
10012 xmlXPathFreeParserContext(pctxt);
10013 return(res);
10014}
10015
10016/**
10017 * xmlXPathRegisterAllFunctions:
10018 * @ctxt: the XPath context
10019 *
10020 * Registers all default XPath functions in this context
10021 */
10022void
10023xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
10024{
10025 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
10026 xmlXPathBooleanFunction);
10027 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
10028 xmlXPathCeilingFunction);
10029 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
10030 xmlXPathCountFunction);
10031 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
10032 xmlXPathConcatFunction);
10033 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
10034 xmlXPathContainsFunction);
10035 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
10036 xmlXPathIdFunction);
10037 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
10038 xmlXPathFalseFunction);
10039 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
10040 xmlXPathFloorFunction);
10041 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
10042 xmlXPathLastFunction);
10043 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
10044 xmlXPathLangFunction);
10045 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
10046 xmlXPathLocalNameFunction);
10047 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
10048 xmlXPathNotFunction);
10049 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
10050 xmlXPathNameFunction);
10051 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
10052 xmlXPathNamespaceURIFunction);
10053 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
10054 xmlXPathNormalizeFunction);
10055 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
10056 xmlXPathNumberFunction);
10057 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
10058 xmlXPathPositionFunction);
10059 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
10060 xmlXPathRoundFunction);
10061 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
10062 xmlXPathStringFunction);
10063 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
10064 xmlXPathStringLengthFunction);
10065 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
10066 xmlXPathStartsWithFunction);
10067 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
10068 xmlXPathSubstringFunction);
10069 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
10070 xmlXPathSubstringBeforeFunction);
10071 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
10072 xmlXPathSubstringAfterFunction);
10073 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
10074 xmlXPathSumFunction);
10075 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
10076 xmlXPathTrueFunction);
10077 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
10078 xmlXPathTranslateFunction);
10079}
10080
10081#endif /* LIBXML_XPATH_ENABLED */