blob: 63edcc031fe9af2565111f91184846e0b49d4e3d [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
5 *
6 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
11 * See COPYRIGHT for the status of this software
12 *
Daniel Veillardc5d64342001-06-24 12:13:24 +000013 * Author: daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000014 *
15 * 14 Nov 2000 ht - truncated declaration of xmlXPathEvalRelativeLocationPath
16 * for VMS
17 */
18
Bjorn Reese70a9da52001-04-21 16:57:29 +000019#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000020#ifdef LIBXML_XPATH_ENABLED
21
Owen Taylor3473f882001-02-23 17:55:21 +000022#include <string.h>
23
24#ifdef HAVE_SYS_TYPES_H
25#include <sys/types.h>
26#endif
27#ifdef HAVE_MATH_H
28#include <math.h>
29#endif
30#ifdef HAVE_FLOAT_H
31#include <float.h>
32#endif
Owen Taylor3473f882001-02-23 17:55:21 +000033#ifdef HAVE_CTYPE_H
34#include <ctype.h>
35#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000036#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000037#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000038#endif
Owen Taylor3473f882001-02-23 17:55:21 +000039
40#include <libxml/xmlmemory.h>
41#include <libxml/tree.h>
42#include <libxml/valid.h>
43#include <libxml/xpath.h>
44#include <libxml/xpathInternals.h>
45#include <libxml/parserInternals.h>
46#include <libxml/hash.h>
47#ifdef LIBXML_XPTR_ENABLED
48#include <libxml/xpointer.h>
49#endif
50#ifdef LIBXML_DEBUG_ENABLED
51#include <libxml/debugXML.h>
52#endif
53#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000054#include <libxml/threads.h>
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
914 */
Owen Taylor3473f882001-02-23 17:55:21 +0000915PUSH_AND_POP(xmlXPathObjectPtr, value)
916
Thomas Broyerf06a3d82001-07-16 04:52:57 +0000917/**
918 * xmlXPathPopBoolean:
919 * @ctxt: an XPath parser context
920 *
921 * Pops a boolean from the stack, handling conversion if needed.
922 * Check error with #xmlXPathCheckError.
923 *
924 * Returns the boolean
925 */
926int
927xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
928 xmlXPathObjectPtr obj;
929 int ret;
930
931 obj = valuePop(ctxt);
932 if (obj == NULL) {
933 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
934 return(0);
935 }
936 ret = xmlXPathCastToBoolean(obj);
937 xmlXPathFreeObject(obj);
938 return(ret);
939}
940
941/**
942 * xmlXPathPopNumber:
943 * @ctxt: an XPath parser context
944 *
945 * Pops a number from the stack, handling conversion if needed.
946 * Check error with #xmlXPathCheckError.
947 *
948 * Returns the number
949 */
950double
951xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
952 xmlXPathObjectPtr obj;
953 double ret;
954
955 obj = valuePop(ctxt);
956 if (obj == NULL) {
957 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
958 return(0);
959 }
960 ret = xmlXPathCastToNumber(obj);
961 xmlXPathFreeObject(obj);
962 return(ret);
963}
964
965/**
966 * xmlXPathPopString:
967 * @ctxt: an XPath parser context
968 *
969 * Pops a string from the stack, handling conversion if needed.
970 * Check error with #xmlXPathCheckError.
971 *
972 * Returns the string
973 */
974xmlChar *
975xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
976 xmlXPathObjectPtr obj;
977 xmlChar * ret;
978
979 obj = valuePop(ctxt);
980 if (obj == NULL) {
981 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
982 return(NULL);
983 }
984 ret = xmlXPathCastToString(obj);
985 /* TODO: needs refactoring somewhere else */
986 if (obj->stringval == ret)
987 obj->stringval = NULL;
988 xmlXPathFreeObject(obj);
989 return(ret);
990}
991
992/**
993 * xmlXPathPopNodeSet:
994 * @ctxt: an XPath parser context
995 *
996 * Pops a node-set from the stack, handling conversion if needed.
997 * Check error with #xmlXPathCheckError.
998 *
999 * Returns the node-set
1000 */
1001xmlNodeSetPtr
1002xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1003 xmlXPathObjectPtr obj;
1004 xmlNodeSetPtr ret;
1005
1006 if (ctxt->value == NULL) {
1007 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1008 return(NULL);
1009 }
1010 if (!xmlXPathStackIsNodeSet(ctxt)) {
1011 xmlXPathSetTypeError(ctxt);
1012 return(NULL);
1013 }
1014 obj = valuePop(ctxt);
1015 ret = obj->nodesetval;
1016 xmlXPathFreeNodeSetList(obj);
1017 return(ret);
1018}
1019
1020/**
1021 * xmlXPathPopExternal:
1022 * @ctxt: an XPath parser context
1023 *
1024 * Pops an external oject from the stack, handling conversion if needed.
1025 * Check error with #xmlXPathCheckError.
1026 *
1027 * Returns the object
1028 */
1029void *
1030xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1031 xmlXPathObjectPtr obj;
1032 void * ret;
1033
1034 if (ctxt->value == NULL) {
1035 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1036 return(NULL);
1037 }
1038 if (ctxt->value->type != XPATH_USERS) {
1039 xmlXPathSetTypeError(ctxt);
1040 return(NULL);
1041 }
1042 obj = valuePop(ctxt);
1043 ret = obj->user;
1044 xmlXPathFreeObject(obj);
1045 return(ret);
1046}
1047
Owen Taylor3473f882001-02-23 17:55:21 +00001048/*
1049 * Macros for accessing the content. Those should be used only by the parser,
1050 * and not exported.
1051 *
1052 * Dirty macros, i.e. one need to make assumption on the context to use them
1053 *
1054 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1055 * CUR returns the current xmlChar value, i.e. a 8 bit value
1056 * in ISO-Latin or UTF-8.
1057 * This should be used internally by the parser
1058 * only to compare to ASCII values otherwise it would break when
1059 * running with UTF-8 encoding.
1060 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1061 * to compare on ASCII based substring.
1062 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1063 * strings within the parser.
1064 * CURRENT Returns the current char value, with the full decoding of
1065 * UTF-8 if we are using this mode. It returns an int.
1066 * NEXT Skip to the next character, this does the proper decoding
1067 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1068 * It returns the pointer to the current xmlChar.
1069 */
1070
1071#define CUR (*ctxt->cur)
1072#define SKIP(val) ctxt->cur += (val)
1073#define NXT(val) ctxt->cur[(val)]
1074#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001075#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1076
1077#define COPY_BUF(l,b,i,v) \
1078 if (l == 1) b[i++] = (xmlChar) v; \
1079 else i += xmlCopyChar(l,&b[i],v)
1080
1081#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001082
1083#define SKIP_BLANKS \
1084 while (IS_BLANK(*(ctxt->cur))) NEXT
1085
1086#define CURRENT (*ctxt->cur)
1087#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1088
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001089
1090#ifndef DBL_DIG
1091#define DBL_DIG 16
1092#endif
1093#ifndef DBL_EPSILON
1094#define DBL_EPSILON 1E-9
1095#endif
1096
1097#define UPPER_DOUBLE 1E9
1098#define LOWER_DOUBLE 1E-5
1099
1100#define INTEGER_DIGITS DBL_DIG
1101#define FRACTION_DIGITS (DBL_DIG + 1)
1102#define EXPONENT_DIGITS (3 + 2)
1103
1104/**
1105 * xmlXPathFormatNumber:
1106 * @number: number to format
1107 * @buffer: output buffer
1108 * @buffersize: size of output buffer
1109 *
1110 * Convert the number into a string representation.
1111 */
1112static void
1113xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1114{
Daniel Veillardcda96922001-08-21 10:56:31 +00001115 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001116 case 1:
1117 if (buffersize > (int)sizeof("+Infinity"))
1118 sprintf(buffer, "+Infinity");
1119 break;
1120 case -1:
1121 if (buffersize > (int)sizeof("-Infinity"))
1122 sprintf(buffer, "-Infinity");
1123 break;
1124 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001125 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001126 if (buffersize > (int)sizeof("NaN"))
1127 sprintf(buffer, "NaN");
1128 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001129 /* 3 is sign, decimal point, and terminating zero */
1130 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1131 int integer_place, fraction_place;
1132 char *ptr;
1133 char *after_fraction;
1134 double absolute_value;
1135 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001136
Bjorn Reese70a9da52001-04-21 16:57:29 +00001137 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001138
Bjorn Reese70a9da52001-04-21 16:57:29 +00001139 /*
1140 * First choose format - scientific or regular floating point.
1141 * In either case, result is in work, and after_fraction points
1142 * just past the fractional part.
1143 */
1144 if ( ((absolute_value > UPPER_DOUBLE) ||
1145 (absolute_value < LOWER_DOUBLE)) &&
1146 (absolute_value != 0.0) ) {
1147 /* Use scientific notation */
1148 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1149 fraction_place = DBL_DIG - 1;
1150 snprintf(work, sizeof(work),"%*.*e",
1151 integer_place, fraction_place, number);
1152 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001153 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001154 else {
1155 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001156 if (absolute_value > 0.0)
1157 integer_place = 1 + (int)log10(absolute_value);
1158 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001159 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001160 fraction_place = (integer_place > 0)
1161 ? DBL_DIG - integer_place
1162 : DBL_DIG;
1163 size = snprintf(work, sizeof(work), "%0.*f",
1164 fraction_place, number);
1165 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001166 }
1167
Bjorn Reese70a9da52001-04-21 16:57:29 +00001168 /* Remove fractional trailing zeroes */
1169 ptr = after_fraction;
1170 while (*(--ptr) == '0')
1171 ;
1172 if (*ptr != '.')
1173 ptr++;
1174 strcpy(ptr, after_fraction);
1175
1176 /* Finally copy result back to caller */
1177 size = strlen(work) + 1;
1178 if (size > buffersize) {
1179 work[buffersize - 1] = 0;
1180 size = buffersize;
1181 }
1182 memcpy(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001183 }
1184 break;
1185 }
1186}
1187
Owen Taylor3473f882001-02-23 17:55:21 +00001188/************************************************************************
1189 * *
1190 * Error handling routines *
1191 * *
1192 ************************************************************************/
1193
1194
Daniel Veillardb44025c2001-10-11 22:55:55 +00001195static const char *xmlXPathErrorMessages[] = {
Owen Taylor3473f882001-02-23 17:55:21 +00001196 "Ok",
1197 "Number encoding",
1198 "Unfinished litteral",
1199 "Start of litteral",
1200 "Expected $ for variable reference",
1201 "Undefined variable",
1202 "Invalid predicate",
1203 "Invalid expression",
1204 "Missing closing curly brace",
1205 "Unregistered function",
1206 "Invalid operand",
1207 "Invalid type",
1208 "Invalid number of arguments",
1209 "Invalid context size",
1210 "Invalid context position",
1211 "Memory allocation error",
1212 "Syntax error",
1213 "Resource error",
1214 "Sub resource error",
Daniel Veillard61d80a22001-04-27 17:13:01 +00001215 "Undefined namespace prefix",
1216 "Encoding error",
1217 "Char out of XML range"
Owen Taylor3473f882001-02-23 17:55:21 +00001218};
1219
1220/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001221 * xmlXPatherror:
Owen Taylor3473f882001-02-23 17:55:21 +00001222 * @ctxt: the XPath Parser context
1223 * @file: the file name
1224 * @line: the line number
1225 * @no: the error number
1226 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001227 * Formats an error message.
Owen Taylor3473f882001-02-23 17:55:21 +00001228 */
1229void
1230xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
1231 int line, int no) {
1232 int n;
1233 const xmlChar *cur;
1234 const xmlChar *base;
1235
1236 xmlGenericError(xmlGenericErrorContext,
1237 "Error %s:%d: %s\n", file, line,
1238 xmlXPathErrorMessages[no]);
1239
1240 cur = ctxt->cur;
1241 base = ctxt->base;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001242 if ((cur == NULL) || (base == NULL))
1243 return;
1244
Owen Taylor3473f882001-02-23 17:55:21 +00001245 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
1246 cur--;
1247 }
1248 n = 0;
1249 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
1250 cur--;
1251 if ((*cur == '\n') || (*cur == '\r')) cur++;
1252 base = cur;
1253 n = 0;
1254 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1255 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
1256 n++;
1257 }
1258 xmlGenericError(xmlGenericErrorContext, "\n");
1259 cur = ctxt->cur;
1260 while ((*cur == '\n') || (*cur == '\r'))
1261 cur--;
1262 n = 0;
1263 while ((cur != base) && (n++ < 80)) {
1264 xmlGenericError(xmlGenericErrorContext, " ");
1265 base++;
1266 }
1267 xmlGenericError(xmlGenericErrorContext,"^\n");
1268}
1269
1270
1271/************************************************************************
1272 * *
1273 * Routines to handle NodeSets *
1274 * *
1275 ************************************************************************/
1276
1277/**
1278 * xmlXPathCmpNodes:
1279 * @node1: the first node
1280 * @node2: the second node
1281 *
1282 * Compare two nodes w.r.t document order
1283 *
1284 * Returns -2 in case of error 1 if first point < second point, 0 if
1285 * that's the same node, -1 otherwise
1286 */
1287int
1288xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1289 int depth1, depth2;
1290 xmlNodePtr cur, root;
1291
1292 if ((node1 == NULL) || (node2 == NULL))
1293 return(-2);
1294 /*
1295 * a couple of optimizations which will avoid computations in most cases
1296 */
1297 if (node1 == node2)
1298 return(0);
Daniel Veillardb33c2012001-04-25 12:59:04 +00001299 if ((node1->type == XML_NAMESPACE_DECL) ||
1300 (node2->type == XML_NAMESPACE_DECL))
1301 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001302 if (node1 == node2->prev)
1303 return(1);
1304 if (node1 == node2->next)
1305 return(-1);
1306
1307 /*
1308 * compute depth to root
1309 */
1310 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1311 if (cur == node1)
1312 return(1);
1313 depth2++;
1314 }
1315 root = cur;
1316 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1317 if (cur == node2)
1318 return(-1);
1319 depth1++;
1320 }
1321 /*
1322 * Distinct document (or distinct entities :-( ) case.
1323 */
1324 if (root != cur) {
1325 return(-2);
1326 }
1327 /*
1328 * get the nearest common ancestor.
1329 */
1330 while (depth1 > depth2) {
1331 depth1--;
1332 node1 = node1->parent;
1333 }
1334 while (depth2 > depth1) {
1335 depth2--;
1336 node2 = node2->parent;
1337 }
1338 while (node1->parent != node2->parent) {
1339 node1 = node1->parent;
1340 node2 = node2->parent;
1341 /* should not happen but just in case ... */
1342 if ((node1 == NULL) || (node2 == NULL))
1343 return(-2);
1344 }
1345 /*
1346 * Find who's first.
1347 */
1348 if (node1 == node2->next)
1349 return(-1);
1350 for (cur = node1->next;cur != NULL;cur = cur->next)
1351 if (cur == node2)
1352 return(1);
1353 return(-1); /* assume there is no sibling list corruption */
1354}
1355
1356/**
1357 * xmlXPathNodeSetSort:
1358 * @set: the node set
1359 *
1360 * Sort the node set in document order
1361 */
1362void
1363xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001364 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001365 xmlNodePtr tmp;
1366
1367 if (set == NULL)
1368 return;
1369
1370 /* Use Shell's sort to sort the node-set */
1371 len = set->nodeNr;
1372 for (incr = len / 2; incr > 0; incr /= 2) {
1373 for (i = incr; i < len; i++) {
1374 j = i - incr;
1375 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001376 if (xmlXPathCmpNodes(set->nodeTab[j],
1377 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001378 tmp = set->nodeTab[j];
1379 set->nodeTab[j] = set->nodeTab[j + incr];
1380 set->nodeTab[j + incr] = tmp;
1381 j -= incr;
1382 } else
1383 break;
1384 }
1385 }
1386 }
1387}
1388
1389#define XML_NODESET_DEFAULT 10
1390/**
1391 * xmlXPathNodeSetCreate:
1392 * @val: an initial xmlNodePtr, or NULL
1393 *
1394 * Create a new xmlNodeSetPtr of type double and of value @val
1395 *
1396 * Returns the newly created object.
1397 */
1398xmlNodeSetPtr
1399xmlXPathNodeSetCreate(xmlNodePtr val) {
1400 xmlNodeSetPtr ret;
1401
1402 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1403 if (ret == NULL) {
1404 xmlGenericError(xmlGenericErrorContext,
1405 "xmlXPathNewNodeSet: out of memory\n");
1406 return(NULL);
1407 }
1408 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1409 if (val != NULL) {
1410 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1411 sizeof(xmlNodePtr));
1412 if (ret->nodeTab == NULL) {
1413 xmlGenericError(xmlGenericErrorContext,
1414 "xmlXPathNewNodeSet: out of memory\n");
1415 return(NULL);
1416 }
1417 memset(ret->nodeTab, 0 ,
1418 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1419 ret->nodeMax = XML_NODESET_DEFAULT;
1420 ret->nodeTab[ret->nodeNr++] = val;
1421 }
1422 return(ret);
1423}
1424
1425/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001426 * xmlXPathNodeSetContains:
1427 * @cur: the node-set
1428 * @val: the node
1429 *
1430 * checks whether @cur contains @val
1431 *
1432 * Returns true (1) if @cur contains @val, false (0) otherwise
1433 */
1434int
1435xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1436 int i;
1437
1438 for (i = 0; i < cur->nodeNr; i++) {
1439 if (cur->nodeTab[i] == val)
1440 return(1);
1441 }
1442 return(0);
1443}
1444
1445/**
Owen Taylor3473f882001-02-23 17:55:21 +00001446 * xmlXPathNodeSetAdd:
1447 * @cur: the initial node set
1448 * @val: a new xmlNodePtr
1449 *
1450 * add a new xmlNodePtr ot an existing NodeSet
1451 */
1452void
1453xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1454 int i;
1455
1456 if (val == NULL) return;
1457
1458 /*
1459 * check against doublons
1460 */
1461 for (i = 0;i < cur->nodeNr;i++)
1462 if (cur->nodeTab[i] == val) return;
1463
1464 /*
1465 * grow the nodeTab if needed
1466 */
1467 if (cur->nodeMax == 0) {
1468 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1469 sizeof(xmlNodePtr));
1470 if (cur->nodeTab == NULL) {
1471 xmlGenericError(xmlGenericErrorContext,
1472 "xmlXPathNodeSetAdd: out of memory\n");
1473 return;
1474 }
1475 memset(cur->nodeTab, 0 ,
1476 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1477 cur->nodeMax = XML_NODESET_DEFAULT;
1478 } else if (cur->nodeNr == cur->nodeMax) {
1479 xmlNodePtr *temp;
1480
1481 cur->nodeMax *= 2;
1482 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1483 sizeof(xmlNodePtr));
1484 if (temp == NULL) {
1485 xmlGenericError(xmlGenericErrorContext,
1486 "xmlXPathNodeSetAdd: out of memory\n");
1487 return;
1488 }
1489 cur->nodeTab = temp;
1490 }
1491 cur->nodeTab[cur->nodeNr++] = val;
1492}
1493
1494/**
1495 * xmlXPathNodeSetAddUnique:
1496 * @cur: the initial node set
1497 * @val: a new xmlNodePtr
1498 *
1499 * add a new xmlNodePtr ot an existing NodeSet, optimized version
1500 * when we are sure the node is not already in the set.
1501 */
1502void
1503xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1504 if (val == NULL) return;
1505
1506 /*
1507 * grow the nodeTab if needed
1508 */
1509 if (cur->nodeMax == 0) {
1510 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1511 sizeof(xmlNodePtr));
1512 if (cur->nodeTab == NULL) {
1513 xmlGenericError(xmlGenericErrorContext,
1514 "xmlXPathNodeSetAddUnique: out of memory\n");
1515 return;
1516 }
1517 memset(cur->nodeTab, 0 ,
1518 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1519 cur->nodeMax = XML_NODESET_DEFAULT;
1520 } else if (cur->nodeNr == cur->nodeMax) {
1521 xmlNodePtr *temp;
1522
1523 cur->nodeMax *= 2;
1524 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1525 sizeof(xmlNodePtr));
1526 if (temp == NULL) {
1527 xmlGenericError(xmlGenericErrorContext,
1528 "xmlXPathNodeSetAddUnique: out of memory\n");
1529 return;
1530 }
1531 cur->nodeTab = temp;
1532 }
1533 cur->nodeTab[cur->nodeNr++] = val;
1534}
1535
1536/**
1537 * xmlXPathNodeSetMerge:
1538 * @val1: the first NodeSet or NULL
1539 * @val2: the second NodeSet
1540 *
1541 * Merges two nodesets, all nodes from @val2 are added to @val1
1542 * if @val1 is NULL, a new set is created and copied from @val2
1543 *
1544 * Returns val1 once extended or NULL in case of error.
1545 */
1546xmlNodeSetPtr
1547xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001548 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001549
1550 if (val2 == NULL) return(val1);
1551 if (val1 == NULL) {
1552 val1 = xmlXPathNodeSetCreate(NULL);
1553 }
1554
1555 initNr = val1->nodeNr;
1556
1557 for (i = 0;i < val2->nodeNr;i++) {
1558 /*
1559 * check against doublons
1560 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001561 skip = 0;
1562 for (j = 0; j < initNr; j++) {
1563 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1564 skip = 1;
1565 break;
1566 }
1567 }
1568 if (skip)
1569 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001570
1571 /*
1572 * grow the nodeTab if needed
1573 */
1574 if (val1->nodeMax == 0) {
1575 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1576 sizeof(xmlNodePtr));
1577 if (val1->nodeTab == NULL) {
1578 xmlGenericError(xmlGenericErrorContext,
1579 "xmlXPathNodeSetMerge: out of memory\n");
1580 return(NULL);
1581 }
1582 memset(val1->nodeTab, 0 ,
1583 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1584 val1->nodeMax = XML_NODESET_DEFAULT;
1585 } else if (val1->nodeNr == val1->nodeMax) {
1586 xmlNodePtr *temp;
1587
1588 val1->nodeMax *= 2;
1589 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1590 sizeof(xmlNodePtr));
1591 if (temp == NULL) {
1592 xmlGenericError(xmlGenericErrorContext,
1593 "xmlXPathNodeSetMerge: out of memory\n");
1594 return(NULL);
1595 }
1596 val1->nodeTab = temp;
1597 }
1598 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1599 }
1600
1601 return(val1);
1602}
1603
1604/**
1605 * xmlXPathNodeSetDel:
1606 * @cur: the initial node set
1607 * @val: an xmlNodePtr
1608 *
1609 * Removes an xmlNodePtr from an existing NodeSet
1610 */
1611void
1612xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
1613 int i;
1614
1615 if (cur == NULL) return;
1616 if (val == NULL) return;
1617
1618 /*
1619 * check against doublons
1620 */
1621 for (i = 0;i < cur->nodeNr;i++)
1622 if (cur->nodeTab[i] == val) break;
1623
1624 if (i >= cur->nodeNr) {
1625#ifdef DEBUG
1626 xmlGenericError(xmlGenericErrorContext,
1627 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
1628 val->name);
1629#endif
1630 return;
1631 }
1632 cur->nodeNr--;
1633 for (;i < cur->nodeNr;i++)
1634 cur->nodeTab[i] = cur->nodeTab[i + 1];
1635 cur->nodeTab[cur->nodeNr] = NULL;
1636}
1637
1638/**
1639 * xmlXPathNodeSetRemove:
1640 * @cur: the initial node set
1641 * @val: the index to remove
1642 *
1643 * Removes an entry from an existing NodeSet list.
1644 */
1645void
1646xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
1647 if (cur == NULL) return;
1648 if (val >= cur->nodeNr) return;
1649 cur->nodeNr--;
1650 for (;val < cur->nodeNr;val++)
1651 cur->nodeTab[val] = cur->nodeTab[val + 1];
1652 cur->nodeTab[cur->nodeNr] = NULL;
1653}
1654
1655/**
1656 * xmlXPathFreeNodeSet:
1657 * @obj: the xmlNodeSetPtr to free
1658 *
1659 * Free the NodeSet compound (not the actual nodes !).
1660 */
1661void
1662xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
1663 if (obj == NULL) return;
1664 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001665 xmlFree(obj->nodeTab);
1666 }
Owen Taylor3473f882001-02-23 17:55:21 +00001667 xmlFree(obj);
1668}
1669
1670/**
1671 * xmlXPathFreeValueTree:
1672 * @obj: the xmlNodeSetPtr to free
1673 *
1674 * Free the NodeSet compound and the actual tree, this is different
1675 * from xmlXPathFreeNodeSet()
1676 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001677static void
Owen Taylor3473f882001-02-23 17:55:21 +00001678xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
1679 int i;
1680
1681 if (obj == NULL) return;
1682 for (i = 0;i < obj->nodeNr;i++)
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00001683 if (obj->nodeTab[i] != NULL)
Daniel Veillardbbd51d52001-02-24 03:07:03 +00001684 xmlFreeNodeList(obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001685
1686 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001687 xmlFree(obj->nodeTab);
1688 }
Owen Taylor3473f882001-02-23 17:55:21 +00001689 xmlFree(obj);
1690}
1691
1692#if defined(DEBUG) || defined(DEBUG_STEP)
1693/**
1694 * xmlGenericErrorContextNodeSet:
1695 * @output: a FILE * for the output
1696 * @obj: the xmlNodeSetPtr to free
1697 *
1698 * Quick display of a NodeSet
1699 */
1700void
1701xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
1702 int i;
1703
1704 if (output == NULL) output = xmlGenericErrorContext;
1705 if (obj == NULL) {
1706 fprintf(output, "NodeSet == NULL !\n");
1707 return;
1708 }
1709 if (obj->nodeNr == 0) {
1710 fprintf(output, "NodeSet is empty\n");
1711 return;
1712 }
1713 if (obj->nodeTab == NULL) {
1714 fprintf(output, " nodeTab == NULL !\n");
1715 return;
1716 }
1717 for (i = 0; i < obj->nodeNr; i++) {
1718 if (obj->nodeTab[i] == NULL) {
1719 fprintf(output, " NULL !\n");
1720 return;
1721 }
1722 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
1723 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
1724 fprintf(output, " /");
1725 else if (obj->nodeTab[i]->name == NULL)
1726 fprintf(output, " noname!");
1727 else fprintf(output, " %s", obj->nodeTab[i]->name);
1728 }
1729 fprintf(output, "\n");
1730}
1731#endif
1732
1733/**
1734 * xmlXPathNewNodeSet:
1735 * @val: the NodePtr value
1736 *
1737 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1738 * it with the single Node @val
1739 *
1740 * Returns the newly created object.
1741 */
1742xmlXPathObjectPtr
1743xmlXPathNewNodeSet(xmlNodePtr val) {
1744 xmlXPathObjectPtr ret;
1745
1746 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1747 if (ret == NULL) {
1748 xmlGenericError(xmlGenericErrorContext,
1749 "xmlXPathNewNodeSet: out of memory\n");
1750 return(NULL);
1751 }
1752 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1753 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00001754 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001755 ret->nodesetval = xmlXPathNodeSetCreate(val);
1756 return(ret);
1757}
1758
1759/**
1760 * xmlXPathNewValueTree:
1761 * @val: the NodePtr value
1762 *
1763 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
1764 * it with the tree root @val
1765 *
1766 * Returns the newly created object.
1767 */
1768xmlXPathObjectPtr
1769xmlXPathNewValueTree(xmlNodePtr val) {
1770 xmlXPathObjectPtr ret;
1771
1772 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1773 if (ret == NULL) {
1774 xmlGenericError(xmlGenericErrorContext,
1775 "xmlXPathNewNodeSet: out of memory\n");
1776 return(NULL);
1777 }
1778 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1779 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00001780 ret->boolval = 1;
1781 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00001782 ret->nodesetval = xmlXPathNodeSetCreate(val);
1783 return(ret);
1784}
1785
1786/**
1787 * xmlXPathNewNodeSetList:
1788 * @val: an existing NodeSet
1789 *
1790 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1791 * it with the Nodeset @val
1792 *
1793 * Returns the newly created object.
1794 */
1795xmlXPathObjectPtr
1796xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
1797 xmlXPathObjectPtr ret;
1798 int i;
1799
1800 if (val == NULL)
1801 ret = NULL;
1802 else if (val->nodeTab == NULL)
1803 ret = xmlXPathNewNodeSet(NULL);
1804 else
1805 {
1806 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
1807 for (i = 1; i < val->nodeNr; ++i)
1808 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
1809 }
1810
1811 return(ret);
1812}
1813
1814/**
1815 * xmlXPathWrapNodeSet:
1816 * @val: the NodePtr value
1817 *
1818 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1819 *
1820 * Returns the newly created object.
1821 */
1822xmlXPathObjectPtr
1823xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
1824 xmlXPathObjectPtr ret;
1825
1826 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1827 if (ret == NULL) {
1828 xmlGenericError(xmlGenericErrorContext,
1829 "xmlXPathWrapNodeSet: out of memory\n");
1830 return(NULL);
1831 }
1832 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1833 ret->type = XPATH_NODESET;
1834 ret->nodesetval = val;
1835 return(ret);
1836}
1837
1838/**
1839 * xmlXPathFreeNodeSetList:
1840 * @obj: an existing NodeSetList object
1841 *
1842 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
1843 * the list contrary to xmlXPathFreeObject().
1844 */
1845void
1846xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
1847 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001848 xmlFree(obj);
1849}
1850
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001851/**
1852 * xmlXPathDifference:
1853 * @nodes1: a node-set
1854 * @nodes2: a node-set
1855 *
1856 * Implements the EXSLT - Sets difference() function:
1857 * node-set set:difference (node-set, node-set)
1858 *
1859 * Returns the difference between the two node sets, or nodes1 if
1860 * nodes2 is empty
1861 */
1862xmlNodeSetPtr
1863xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
1864 xmlNodeSetPtr ret;
1865 int i, l1;
1866 xmlNodePtr cur;
1867
1868 if (xmlXPathNodeSetIsEmpty(nodes2))
1869 return(nodes1);
1870
1871 ret = xmlXPathNodeSetCreate(NULL);
1872 if (xmlXPathNodeSetIsEmpty(nodes1))
1873 return(ret);
1874
1875 l1 = xmlXPathNodeSetGetLength(nodes1);
1876
1877 for (i = 0; i < l1; i++) {
1878 cur = xmlXPathNodeSetItem(nodes1, i);
1879 if (!xmlXPathNodeSetContains(nodes2, cur))
1880 xmlXPathNodeSetAddUnique(ret, cur);
1881 }
1882 return(ret);
1883}
1884
1885/**
1886 * xmlXPathIntersection:
1887 * @nodes1: a node-set
1888 * @nodes2: a node-set
1889 *
1890 * Implements the EXSLT - Sets intersection() function:
1891 * node-set set:intersection (node-set, node-set)
1892 *
1893 * Returns a node set comprising the nodes that are within both the
1894 * node sets passed as arguments
1895 */
1896xmlNodeSetPtr
1897xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
1898 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
1899 int i, l1;
1900 xmlNodePtr cur;
1901
1902 if (xmlXPathNodeSetIsEmpty(nodes1))
1903 return(ret);
1904 if (xmlXPathNodeSetIsEmpty(nodes2))
1905 return(ret);
1906
1907 l1 = xmlXPathNodeSetGetLength(nodes1);
1908
1909 for (i = 0; i < l1; i++) {
1910 cur = xmlXPathNodeSetItem(nodes1, i);
1911 if (xmlXPathNodeSetContains(nodes2, cur))
1912 xmlXPathNodeSetAddUnique(ret, cur);
1913 }
1914 return(ret);
1915}
1916
1917/**
1918 * xmlXPathDistinctSorted:
1919 * @nodes: a node-set, sorted by document order
1920 *
1921 * Implements the EXSLT - Sets distinct() function:
1922 * node-set set:distinct (node-set)
1923 *
1924 * Returns a subset of the nodes contained in @nodes, or @nodes if
1925 * it is empty
1926 */
1927xmlNodeSetPtr
1928xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
1929 xmlNodeSetPtr ret;
1930 xmlHashTablePtr hash;
1931 int i, l;
1932 xmlChar * strval;
1933 xmlNodePtr cur;
1934
1935 if (xmlXPathNodeSetIsEmpty(nodes))
1936 return(nodes);
1937
1938 ret = xmlXPathNodeSetCreate(NULL);
1939 l = xmlXPathNodeSetGetLength(nodes);
1940 hash = xmlHashCreate (l);
1941 for (i = 0; i < l; i++) {
1942 cur = xmlXPathNodeSetItem(nodes, i);
1943 strval = xmlXPathCastNodeToString(cur);
1944 if (xmlHashLookup(hash, strval) == NULL) {
1945 xmlHashAddEntry(hash, strval, strval);
1946 xmlXPathNodeSetAddUnique(ret, cur);
1947 } else {
1948 xmlFree(strval);
1949 }
1950 }
1951 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
1952 return(ret);
1953}
1954
1955/**
1956 * xmlXPathDistinct:
1957 * @nodes: a node-set
1958 *
1959 * Implements the EXSLT - Sets distinct() function:
1960 * node-set set:distinct (node-set)
1961 * @nodes is sorted by document order, then #exslSetsDistinctSorted
1962 * is called with the sorted node-set
1963 *
1964 * Returns a subset of the nodes contained in @nodes, or @nodes if
1965 * it is empty
1966 */
1967xmlNodeSetPtr
1968xmlXPathDistinct (xmlNodeSetPtr nodes) {
1969 if (xmlXPathNodeSetIsEmpty(nodes))
1970 return(nodes);
1971
1972 xmlXPathNodeSetSort(nodes);
1973 return(xmlXPathDistinctSorted(nodes));
1974}
1975
1976/**
1977 * xmlXPathHasSameNodes:
1978 * @nodes1: a node-set
1979 * @nodes2: a node-set
1980 *
1981 * Implements the EXSLT - Sets has-same-nodes function:
1982 * boolean set:has-same-node(node-set, node-set)
1983 *
1984 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
1985 * otherwise
1986 */
1987int
1988xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
1989 int i, l;
1990 xmlNodePtr cur;
1991
1992 if (xmlXPathNodeSetIsEmpty(nodes1) ||
1993 xmlXPathNodeSetIsEmpty(nodes2))
1994 return(0);
1995
1996 l = xmlXPathNodeSetGetLength(nodes1);
1997 for (i = 0; i < l; i++) {
1998 cur = xmlXPathNodeSetItem(nodes1, i);
1999 if (xmlXPathNodeSetContains(nodes2, cur))
2000 return(1);
2001 }
2002 return(0);
2003}
2004
2005/**
2006 * xmlXPathNodeLeadingSorted:
2007 * @nodes: a node-set, sorted by document order
2008 * @node: a node
2009 *
2010 * Implements the EXSLT - Sets leading() function:
2011 * node-set set:leading (node-set, node-set)
2012 *
2013 * Returns the nodes in @nodes that precede @node in document order,
2014 * @nodes if @node is NULL or an empty node-set if @nodes
2015 * doesn't contain @node
2016 */
2017xmlNodeSetPtr
2018xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2019 int i, l;
2020 xmlNodePtr cur;
2021 xmlNodeSetPtr ret;
2022
2023 if (node == NULL)
2024 return(nodes);
2025
2026 ret = xmlXPathNodeSetCreate(NULL);
2027 if (xmlXPathNodeSetIsEmpty(nodes) ||
2028 (!xmlXPathNodeSetContains(nodes, node)))
2029 return(ret);
2030
2031 l = xmlXPathNodeSetGetLength(nodes);
2032 for (i = 0; i < l; i++) {
2033 cur = xmlXPathNodeSetItem(nodes, i);
2034 if (cur == node)
2035 break;
2036 xmlXPathNodeSetAddUnique(ret, cur);
2037 }
2038 return(ret);
2039}
2040
2041/**
2042 * xmlXPathNodeLeading:
2043 * @nodes: a node-set
2044 * @node: a node
2045 *
2046 * Implements the EXSLT - Sets leading() function:
2047 * node-set set:leading (node-set, node-set)
2048 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2049 * is called.
2050 *
2051 * Returns the nodes in @nodes that precede @node in document order,
2052 * @nodes if @node is NULL or an empty node-set if @nodes
2053 * doesn't contain @node
2054 */
2055xmlNodeSetPtr
2056xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2057 xmlXPathNodeSetSort(nodes);
2058 return(xmlXPathNodeLeadingSorted(nodes, node));
2059}
2060
2061/**
2062 * xmlXPathLeadingSorted:
2063 * @nodes1: a node-set, sorted by document order
2064 * @nodes2: a node-set, sorted by document order
2065 *
2066 * Implements the EXSLT - Sets leading() function:
2067 * node-set set:leading (node-set, node-set)
2068 *
2069 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2070 * in document order, @nodes1 if @nodes2 is NULL or empty or
2071 * an empty node-set if @nodes1 doesn't contain @nodes2
2072 */
2073xmlNodeSetPtr
2074xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2075 if (xmlXPathNodeSetIsEmpty(nodes2))
2076 return(nodes1);
2077 return(xmlXPathNodeLeadingSorted(nodes1,
2078 xmlXPathNodeSetItem(nodes2, 1)));
2079}
2080
2081/**
2082 * xmlXPathLeading:
2083 * @nodes1: a node-set
2084 * @nodes2: a node-set
2085 *
2086 * Implements the EXSLT - Sets leading() function:
2087 * node-set set:leading (node-set, node-set)
2088 * @nodes1 and @nodes2 are sorted by document order, then
2089 * #exslSetsLeadingSorted is called.
2090 *
2091 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2092 * in document order, @nodes1 if @nodes2 is NULL or empty or
2093 * an empty node-set if @nodes1 doesn't contain @nodes2
2094 */
2095xmlNodeSetPtr
2096xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2097 if (xmlXPathNodeSetIsEmpty(nodes2))
2098 return(nodes1);
2099 if (xmlXPathNodeSetIsEmpty(nodes1))
2100 return(xmlXPathNodeSetCreate(NULL));
2101 xmlXPathNodeSetSort(nodes1);
2102 xmlXPathNodeSetSort(nodes2);
2103 return(xmlXPathNodeLeadingSorted(nodes1,
2104 xmlXPathNodeSetItem(nodes2, 1)));
2105}
2106
2107/**
2108 * xmlXPathNodeTrailingSorted:
2109 * @nodes: a node-set, sorted by document order
2110 * @node: a node
2111 *
2112 * Implements the EXSLT - Sets trailing() function:
2113 * node-set set:trailing (node-set, node-set)
2114 *
2115 * Returns the nodes in @nodes that follow @node in document order,
2116 * @nodes if @node is NULL or an empty node-set if @nodes
2117 * doesn't contain @node
2118 */
2119xmlNodeSetPtr
2120xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2121 int i, l;
2122 xmlNodePtr cur;
2123 xmlNodeSetPtr ret;
2124
2125 if (node == NULL)
2126 return(nodes);
2127
2128 ret = xmlXPathNodeSetCreate(NULL);
2129 if (xmlXPathNodeSetIsEmpty(nodes) ||
2130 (!xmlXPathNodeSetContains(nodes, node)))
2131 return(ret);
2132
2133 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002134 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002135 cur = xmlXPathNodeSetItem(nodes, i);
2136 if (cur == node)
2137 break;
2138 xmlXPathNodeSetAddUnique(ret, cur);
2139 }
2140 return(ret);
2141}
2142
2143/**
2144 * xmlXPathNodeTrailing:
2145 * @nodes: a node-set
2146 * @node: a node
2147 *
2148 * Implements the EXSLT - Sets trailing() function:
2149 * node-set set:trailing (node-set, node-set)
2150 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2151 * is called.
2152 *
2153 * Returns the nodes in @nodes that follow @node in document order,
2154 * @nodes if @node is NULL or an empty node-set if @nodes
2155 * doesn't contain @node
2156 */
2157xmlNodeSetPtr
2158xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2159 xmlXPathNodeSetSort(nodes);
2160 return(xmlXPathNodeTrailingSorted(nodes, node));
2161}
2162
2163/**
2164 * xmlXPathTrailingSorted:
2165 * @nodes1: a node-set, sorted by document order
2166 * @nodes2: a node-set, sorted by document order
2167 *
2168 * Implements the EXSLT - Sets trailing() function:
2169 * node-set set:trailing (node-set, node-set)
2170 *
2171 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2172 * in document order, @nodes1 if @nodes2 is NULL or empty or
2173 * an empty node-set if @nodes1 doesn't contain @nodes2
2174 */
2175xmlNodeSetPtr
2176xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2177 if (xmlXPathNodeSetIsEmpty(nodes2))
2178 return(nodes1);
2179 return(xmlXPathNodeTrailingSorted(nodes1,
2180 xmlXPathNodeSetItem(nodes2, 0)));
2181}
2182
2183/**
2184 * xmlXPathTrailing:
2185 * @nodes1: a node-set
2186 * @nodes2: a node-set
2187 *
2188 * Implements the EXSLT - Sets trailing() function:
2189 * node-set set:trailing (node-set, node-set)
2190 * @nodes1 and @nodes2 are sorted by document order, then
2191 * #xmlXPathTrailingSorted is called.
2192 *
2193 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2194 * in document order, @nodes1 if @nodes2 is NULL or empty or
2195 * an empty node-set if @nodes1 doesn't contain @nodes2
2196 */
2197xmlNodeSetPtr
2198xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2199 if (xmlXPathNodeSetIsEmpty(nodes2))
2200 return(nodes1);
2201 if (xmlXPathNodeSetIsEmpty(nodes1))
2202 return(xmlXPathNodeSetCreate(NULL));
2203 xmlXPathNodeSetSort(nodes1);
2204 xmlXPathNodeSetSort(nodes2);
2205 return(xmlXPathNodeTrailingSorted(nodes1,
2206 xmlXPathNodeSetItem(nodes2, 0)));
2207}
2208
Owen Taylor3473f882001-02-23 17:55:21 +00002209/************************************************************************
2210 * *
2211 * Routines to handle extra functions *
2212 * *
2213 ************************************************************************/
2214
2215/**
2216 * xmlXPathRegisterFunc:
2217 * @ctxt: the XPath context
2218 * @name: the function name
2219 * @f: the function implementation or NULL
2220 *
2221 * Register a new function. If @f is NULL it unregisters the function
2222 *
2223 * Returns 0 in case of success, -1 in case of error
2224 */
2225int
2226xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2227 xmlXPathFunction f) {
2228 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2229}
2230
2231/**
2232 * xmlXPathRegisterFuncNS:
2233 * @ctxt: the XPath context
2234 * @name: the function name
2235 * @ns_uri: the function namespace URI
2236 * @f: the function implementation or NULL
2237 *
2238 * Register a new function. If @f is NULL it unregisters the function
2239 *
2240 * Returns 0 in case of success, -1 in case of error
2241 */
2242int
2243xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2244 const xmlChar *ns_uri, xmlXPathFunction f) {
2245 if (ctxt == NULL)
2246 return(-1);
2247 if (name == NULL)
2248 return(-1);
2249
2250 if (ctxt->funcHash == NULL)
2251 ctxt->funcHash = xmlHashCreate(0);
2252 if (ctxt->funcHash == NULL)
2253 return(-1);
2254 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2255}
2256
2257/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002258 * xmlXPathRegisterFuncLookup:
2259 * @ctxt: the XPath context
2260 * @f: the lookup function
2261 * @data: the lookup data
2262 *
2263 * Registers an external mecanism to do function lookup.
2264 */
2265void
2266xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2267 xmlXPathFuncLookupFunc f,
2268 void *funcCtxt) {
2269 if (ctxt == NULL)
2270 return;
2271 ctxt->funcLookupFunc = (void *) f;
2272 ctxt->funcLookupData = funcCtxt;
2273}
2274
2275/**
Owen Taylor3473f882001-02-23 17:55:21 +00002276 * xmlXPathFunctionLookup:
2277 * @ctxt: the XPath context
2278 * @name: the function name
2279 *
2280 * Search in the Function array of the context for the given
2281 * function.
2282 *
2283 * Returns the xmlXPathFunction or NULL if not found
2284 */
2285xmlXPathFunction
2286xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002287 if (ctxt == NULL)
2288 return (NULL);
2289
2290 if (ctxt->funcLookupFunc != NULL) {
2291 xmlXPathFunction ret;
2292
2293 ret = ((xmlXPathFuncLookupFunc) ctxt->funcLookupFunc)
2294 (ctxt->funcLookupData, name, NULL);
2295 if (ret != NULL)
2296 return(ret);
2297 }
Owen Taylor3473f882001-02-23 17:55:21 +00002298 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2299}
2300
2301/**
2302 * xmlXPathFunctionLookupNS:
2303 * @ctxt: the XPath context
2304 * @name: the function name
2305 * @ns_uri: the function namespace URI
2306 *
2307 * Search in the Function array of the context for the given
2308 * function.
2309 *
2310 * Returns the xmlXPathFunction or NULL if not found
2311 */
2312xmlXPathFunction
2313xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2314 const xmlChar *ns_uri) {
2315 if (ctxt == NULL)
2316 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002317 if (name == NULL)
2318 return(NULL);
2319
Thomas Broyerba4ad322001-07-26 16:55:21 +00002320 if (ctxt->funcLookupFunc != NULL) {
2321 xmlXPathFunction ret;
2322
2323 ret = ((xmlXPathFuncLookupFunc) ctxt->funcLookupFunc)
2324 (ctxt->funcLookupData, name, ns_uri);
2325 if (ret != NULL)
2326 return(ret);
2327 }
2328
2329 if (ctxt->funcHash == NULL)
2330 return(NULL);
2331
Owen Taylor3473f882001-02-23 17:55:21 +00002332 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2333}
2334
2335/**
2336 * xmlXPathRegisteredFuncsCleanup:
2337 * @ctxt: the XPath context
2338 *
2339 * Cleanup the XPath context data associated to registered functions
2340 */
2341void
2342xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2343 if (ctxt == NULL)
2344 return;
2345
2346 xmlHashFree(ctxt->funcHash, NULL);
2347 ctxt->funcHash = NULL;
2348}
2349
2350/************************************************************************
2351 * *
2352 * Routines to handle Variable *
2353 * *
2354 ************************************************************************/
2355
2356/**
2357 * xmlXPathRegisterVariable:
2358 * @ctxt: the XPath context
2359 * @name: the variable name
2360 * @value: the variable value or NULL
2361 *
2362 * Register a new variable value. If @value is NULL it unregisters
2363 * the variable
2364 *
2365 * Returns 0 in case of success, -1 in case of error
2366 */
2367int
2368xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2369 xmlXPathObjectPtr value) {
2370 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2371}
2372
2373/**
2374 * xmlXPathRegisterVariableNS:
2375 * @ctxt: the XPath context
2376 * @name: the variable name
2377 * @ns_uri: the variable namespace URI
2378 * @value: the variable value or NULL
2379 *
2380 * Register a new variable value. If @value is NULL it unregisters
2381 * the variable
2382 *
2383 * Returns 0 in case of success, -1 in case of error
2384 */
2385int
2386xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2387 const xmlChar *ns_uri,
2388 xmlXPathObjectPtr value) {
2389 if (ctxt == NULL)
2390 return(-1);
2391 if (name == NULL)
2392 return(-1);
2393
2394 if (ctxt->varHash == NULL)
2395 ctxt->varHash = xmlHashCreate(0);
2396 if (ctxt->varHash == NULL)
2397 return(-1);
2398 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2399 (void *) value,
2400 (xmlHashDeallocator)xmlXPathFreeObject));
2401}
2402
2403/**
2404 * xmlXPathRegisterVariableLookup:
2405 * @ctxt: the XPath context
2406 * @f: the lookup function
2407 * @data: the lookup data
2408 *
2409 * register an external mechanism to do variable lookup
2410 */
2411void
2412xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2413 xmlXPathVariableLookupFunc f, void *data) {
2414 if (ctxt == NULL)
2415 return;
2416 ctxt->varLookupFunc = (void *) f;
2417 ctxt->varLookupData = data;
2418}
2419
2420/**
2421 * xmlXPathVariableLookup:
2422 * @ctxt: the XPath context
2423 * @name: the variable name
2424 *
2425 * Search in the Variable array of the context for the given
2426 * variable value.
2427 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002428 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002429 */
2430xmlXPathObjectPtr
2431xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2432 if (ctxt == NULL)
2433 return(NULL);
2434
2435 if (ctxt->varLookupFunc != NULL) {
2436 xmlXPathObjectPtr ret;
2437
2438 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2439 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002440 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002441 }
2442 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2443}
2444
2445/**
2446 * xmlXPathVariableLookupNS:
2447 * @ctxt: the XPath context
2448 * @name: the variable name
2449 * @ns_uri: the variable namespace URI
2450 *
2451 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002452 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002453 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002454 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002455 */
2456xmlXPathObjectPtr
2457xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2458 const xmlChar *ns_uri) {
2459 if (ctxt == NULL)
2460 return(NULL);
2461
2462 if (ctxt->varLookupFunc != NULL) {
2463 xmlXPathObjectPtr ret;
2464
2465 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2466 (ctxt->varLookupData, name, ns_uri);
2467 if (ret != NULL) return(ret);
2468 }
2469
2470 if (ctxt->varHash == NULL)
2471 return(NULL);
2472 if (name == NULL)
2473 return(NULL);
2474
Daniel Veillard8c357d52001-07-03 23:43:33 +00002475 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2476 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002477}
2478
2479/**
2480 * xmlXPathRegisteredVariablesCleanup:
2481 * @ctxt: the XPath context
2482 *
2483 * Cleanup the XPath context data associated to registered variables
2484 */
2485void
2486xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2487 if (ctxt == NULL)
2488 return;
2489
Daniel Veillard76d66f42001-05-16 21:05:17 +00002490 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002491 ctxt->varHash = NULL;
2492}
2493
2494/**
2495 * xmlXPathRegisterNs:
2496 * @ctxt: the XPath context
2497 * @prefix: the namespace prefix
2498 * @ns_uri: the namespace name
2499 *
2500 * Register a new namespace. If @ns_uri is NULL it unregisters
2501 * the namespace
2502 *
2503 * Returns 0 in case of success, -1 in case of error
2504 */
2505int
2506xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2507 const xmlChar *ns_uri) {
2508 if (ctxt == NULL)
2509 return(-1);
2510 if (prefix == NULL)
2511 return(-1);
2512
2513 if (ctxt->nsHash == NULL)
2514 ctxt->nsHash = xmlHashCreate(10);
2515 if (ctxt->nsHash == NULL)
2516 return(-1);
2517 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) ns_uri,
2518 (xmlHashDeallocator)xmlFree));
2519}
2520
2521/**
2522 * xmlXPathNsLookup:
2523 * @ctxt: the XPath context
2524 * @prefix: the namespace prefix value
2525 *
2526 * Search in the namespace declaration array of the context for the given
2527 * namespace name associated to the given prefix
2528 *
2529 * Returns the value or NULL if not found
2530 */
2531const xmlChar *
2532xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2533 if (ctxt == NULL)
2534 return(NULL);
2535 if (prefix == NULL)
2536 return(NULL);
2537
2538#ifdef XML_XML_NAMESPACE
2539 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
2540 return(XML_XML_NAMESPACE);
2541#endif
2542
Daniel Veillardc8f620b2001-04-30 20:31:33 +00002543 if (ctxt->namespaces != NULL) {
2544 int i;
2545
2546 for (i = 0;i < ctxt->nsNr;i++) {
2547 if ((ctxt->namespaces[i] != NULL) &&
2548 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
2549 return(ctxt->namespaces[i]->href);
2550 }
2551 }
Owen Taylor3473f882001-02-23 17:55:21 +00002552
2553 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
2554}
2555
2556/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002557 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00002558 * @ctxt: the XPath context
2559 *
2560 * Cleanup the XPath context data associated to registered variables
2561 */
2562void
2563xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2564 if (ctxt == NULL)
2565 return;
2566
2567 xmlHashFree(ctxt->nsHash, NULL);
2568 ctxt->nsHash = NULL;
2569}
2570
2571/************************************************************************
2572 * *
2573 * Routines to handle Values *
2574 * *
2575 ************************************************************************/
2576
2577/* Allocations are terrible, one need to optimize all this !!! */
2578
2579/**
2580 * xmlXPathNewFloat:
2581 * @val: the double value
2582 *
2583 * Create a new xmlXPathObjectPtr of type double and of value @val
2584 *
2585 * Returns the newly created object.
2586 */
2587xmlXPathObjectPtr
2588xmlXPathNewFloat(double val) {
2589 xmlXPathObjectPtr ret;
2590
2591 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2592 if (ret == NULL) {
2593 xmlGenericError(xmlGenericErrorContext,
2594 "xmlXPathNewFloat: out of memory\n");
2595 return(NULL);
2596 }
2597 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2598 ret->type = XPATH_NUMBER;
2599 ret->floatval = val;
2600 return(ret);
2601}
2602
2603/**
2604 * xmlXPathNewBoolean:
2605 * @val: the boolean value
2606 *
2607 * Create a new xmlXPathObjectPtr of type boolean and of value @val
2608 *
2609 * Returns the newly created object.
2610 */
2611xmlXPathObjectPtr
2612xmlXPathNewBoolean(int val) {
2613 xmlXPathObjectPtr ret;
2614
2615 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2616 if (ret == NULL) {
2617 xmlGenericError(xmlGenericErrorContext,
2618 "xmlXPathNewBoolean: out of memory\n");
2619 return(NULL);
2620 }
2621 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2622 ret->type = XPATH_BOOLEAN;
2623 ret->boolval = (val != 0);
2624 return(ret);
2625}
2626
2627/**
2628 * xmlXPathNewString:
2629 * @val: the xmlChar * value
2630 *
2631 * Create a new xmlXPathObjectPtr of type string and of value @val
2632 *
2633 * Returns the newly created object.
2634 */
2635xmlXPathObjectPtr
2636xmlXPathNewString(const xmlChar *val) {
2637 xmlXPathObjectPtr ret;
2638
2639 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2640 if (ret == NULL) {
2641 xmlGenericError(xmlGenericErrorContext,
2642 "xmlXPathNewString: out of memory\n");
2643 return(NULL);
2644 }
2645 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2646 ret->type = XPATH_STRING;
2647 if (val != NULL)
2648 ret->stringval = xmlStrdup(val);
2649 else
2650 ret->stringval = xmlStrdup((const xmlChar *)"");
2651 return(ret);
2652}
2653
2654/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002655 * xmlXPathWrapString:
2656 * @val: the xmlChar * value
2657 *
2658 * Wraps the @val string into an XPath object.
2659 *
2660 * Returns the newly created object.
2661 */
2662xmlXPathObjectPtr
2663xmlXPathWrapString (xmlChar *val) {
2664 xmlXPathObjectPtr ret;
2665
2666 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2667 if (ret == NULL) {
2668 xmlGenericError(xmlGenericErrorContext,
2669 "xmlXPathWrapString: out of memory\n");
2670 return(NULL);
2671 }
2672 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2673 ret->type = XPATH_STRING;
2674 ret->stringval = val;
2675 return(ret);
2676}
2677
2678/**
Owen Taylor3473f882001-02-23 17:55:21 +00002679 * xmlXPathNewCString:
2680 * @val: the char * value
2681 *
2682 * Create a new xmlXPathObjectPtr of type string and of value @val
2683 *
2684 * Returns the newly created object.
2685 */
2686xmlXPathObjectPtr
2687xmlXPathNewCString(const char *val) {
2688 xmlXPathObjectPtr ret;
2689
2690 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2691 if (ret == NULL) {
2692 xmlGenericError(xmlGenericErrorContext,
2693 "xmlXPathNewCString: out of memory\n");
2694 return(NULL);
2695 }
2696 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2697 ret->type = XPATH_STRING;
2698 ret->stringval = xmlStrdup(BAD_CAST val);
2699 return(ret);
2700}
2701
2702/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002703 * xmlXPathWrapCString:
2704 * @val: the char * value
2705 *
2706 * Wraps a string into an XPath object.
2707 *
2708 * Returns the newly created object.
2709 */
2710xmlXPathObjectPtr
2711xmlXPathWrapCString (char * val) {
2712 return(xmlXPathWrapString((xmlChar *)(val)));
2713}
2714
2715/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002716 * xmlXPathWrapExternal:
2717 * @val: the user data
2718 *
2719 * Wraps the @val data into an XPath object.
2720 *
2721 * Returns the newly created object.
2722 */
2723xmlXPathObjectPtr
2724xmlXPathWrapExternal (void *val) {
2725 xmlXPathObjectPtr ret;
2726
2727 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2728 if (ret == NULL) {
2729 xmlGenericError(xmlGenericErrorContext,
2730 "xmlXPathWrapString: out of memory\n");
2731 return(NULL);
2732 }
2733 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2734 ret->type = XPATH_USERS;
2735 ret->user = val;
2736 return(ret);
2737}
2738
2739/**
Owen Taylor3473f882001-02-23 17:55:21 +00002740 * xmlXPathObjectCopy:
2741 * @val: the original object
2742 *
2743 * allocate a new copy of a given object
2744 *
2745 * Returns the newly created object.
2746 */
2747xmlXPathObjectPtr
2748xmlXPathObjectCopy(xmlXPathObjectPtr val) {
2749 xmlXPathObjectPtr ret;
2750
2751 if (val == NULL)
2752 return(NULL);
2753
2754 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2755 if (ret == NULL) {
2756 xmlGenericError(xmlGenericErrorContext,
2757 "xmlXPathObjectCopy: out of memory\n");
2758 return(NULL);
2759 }
2760 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
2761 switch (val->type) {
2762 case XPATH_BOOLEAN:
2763 case XPATH_NUMBER:
2764 case XPATH_POINT:
2765 case XPATH_RANGE:
2766 break;
2767 case XPATH_STRING:
2768 ret->stringval = xmlStrdup(val->stringval);
2769 break;
2770 case XPATH_XSLT_TREE:
2771 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002772 (val->nodesetval->nodeTab != NULL)) {
2773 ret->boolval = 1;
Daniel Veillard6ab38382001-10-06 13:08:27 +00002774 ret->user = xmlDocCopyNode(val->nodesetval->nodeTab[0],
2775 val->nodesetval->nodeTab[0]->doc, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00002776 ret->nodesetval = xmlXPathNodeSetCreate(
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002777 (xmlNodePtr) ret->user);
2778 } else
Owen Taylor3473f882001-02-23 17:55:21 +00002779 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002780 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00002781 break;
2782 case XPATH_NODESET:
2783 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002784 /* Do not deallocate the copied tree value */
2785 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002786 break;
2787 case XPATH_LOCATIONSET:
2788#ifdef LIBXML_XPTR_ENABLED
2789 {
2790 xmlLocationSetPtr loc = val->user;
2791 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
2792 break;
2793 }
2794#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00002795 case XPATH_USERS:
2796 ret->user = val->user;
2797 break;
2798 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00002799 xmlGenericError(xmlGenericErrorContext,
2800 "xmlXPathObjectCopy: unsupported type %d\n",
2801 val->type);
2802 break;
2803 }
2804 return(ret);
2805}
2806
2807/**
2808 * xmlXPathFreeObject:
2809 * @obj: the object to free
2810 *
2811 * Free up an xmlXPathObjectPtr object.
2812 */
2813void
2814xmlXPathFreeObject(xmlXPathObjectPtr obj) {
2815 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002816 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00002817 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002818 if (obj->user != NULL) {
2819 xmlFreeNodeList((xmlNodePtr) obj->user);
2820 xmlXPathFreeNodeSet(obj->nodesetval);
2821 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00002822 xmlXPathFreeValueTree(obj->nodesetval);
2823 } else {
2824 if (obj->nodesetval != NULL)
2825 xmlXPathFreeNodeSet(obj->nodesetval);
2826 }
Owen Taylor3473f882001-02-23 17:55:21 +00002827#ifdef LIBXML_XPTR_ENABLED
2828 } else if (obj->type == XPATH_LOCATIONSET) {
2829 if (obj->user != NULL)
2830 xmlXPtrFreeLocationSet(obj->user);
2831#endif
2832 } else if (obj->type == XPATH_STRING) {
2833 if (obj->stringval != NULL)
2834 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00002835 }
2836
Owen Taylor3473f882001-02-23 17:55:21 +00002837 xmlFree(obj);
2838}
2839
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002840
2841/************************************************************************
2842 * *
2843 * Type Casting Routines *
2844 * *
2845 ************************************************************************/
2846
2847/**
2848 * xmlXPathCastBooleanToString:
2849 * @val: a boolean
2850 *
2851 * Converts a boolean to its string value.
2852 *
2853 * Returns a newly allocated string.
2854 */
2855xmlChar *
2856xmlXPathCastBooleanToString (int val) {
2857 xmlChar *ret;
2858 if (val)
2859 ret = xmlStrdup((const xmlChar *) "true");
2860 else
2861 ret = xmlStrdup((const xmlChar *) "false");
2862 return(ret);
2863}
2864
2865/**
2866 * xmlXPathCastNumberToString:
2867 * @val: a number
2868 *
2869 * Converts a number to its string value.
2870 *
2871 * Returns a newly allocated string.
2872 */
2873xmlChar *
2874xmlXPathCastNumberToString (double val) {
2875 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00002876 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002877 case 1:
2878 ret = xmlStrdup((const xmlChar *) "+Infinity");
2879 break;
2880 case -1:
2881 ret = xmlStrdup((const xmlChar *) "-Infinity");
2882 break;
2883 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00002884 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002885 ret = xmlStrdup((const xmlChar *) "NaN");
2886 } else {
2887 /* could be improved */
2888 char buf[100];
2889 xmlXPathFormatNumber(val, buf, 100);
2890 ret = xmlStrdup((const xmlChar *) buf);
2891 }
2892 }
2893 return(ret);
2894}
2895
2896/**
2897 * xmlXPathCastNodeToString:
2898 * @node: a node
2899 *
2900 * Converts a node to its string value.
2901 *
2902 * Returns a newly allocated string.
2903 */
2904xmlChar *
2905xmlXPathCastNodeToString (xmlNodePtr node) {
2906 return(xmlNodeGetContent(node));
2907}
2908
2909/**
2910 * xmlXPathCastNodeSetToString:
2911 * @ns: a node-set
2912 *
2913 * Converts a node-set to its string value.
2914 *
2915 * Returns a newly allocated string.
2916 */
2917xmlChar *
2918xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
2919 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
2920 return(xmlStrdup((const xmlChar *) ""));
2921
2922 xmlXPathNodeSetSort(ns);
2923 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
2924}
2925
2926/**
2927 * xmlXPathCastToString:
2928 * @val: an XPath object
2929 *
2930 * Converts an existing object to its string() equivalent
2931 *
2932 * Returns the string value of the object, NULL in case of error.
2933 * A new string is allocated only if needed (val isn't a
2934 * string object).
2935 */
2936xmlChar *
2937xmlXPathCastToString(xmlXPathObjectPtr val) {
2938 xmlChar *ret = NULL;
2939
2940 if (val == NULL)
2941 return(xmlStrdup((const xmlChar *) ""));
2942 switch (val->type) {
2943 case XPATH_UNDEFINED:
2944#ifdef DEBUG_EXPR
2945 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
2946#endif
2947 ret = xmlStrdup((const xmlChar *) "");
2948 break;
2949 case XPATH_XSLT_TREE:
2950 case XPATH_NODESET:
2951 ret = xmlXPathCastNodeSetToString(val->nodesetval);
2952 break;
2953 case XPATH_STRING:
2954 return(val->stringval);
2955 case XPATH_BOOLEAN:
2956 ret = xmlXPathCastBooleanToString(val->boolval);
2957 break;
2958 case XPATH_NUMBER: {
2959 ret = xmlXPathCastNumberToString(val->floatval);
2960 break;
2961 }
2962 case XPATH_USERS:
2963 case XPATH_POINT:
2964 case XPATH_RANGE:
2965 case XPATH_LOCATIONSET:
2966 TODO
2967 ret = xmlStrdup((const xmlChar *) "");
2968 break;
2969 }
2970 return(ret);
2971}
2972
2973/**
2974 * xmlXPathConvertString:
2975 * @val: an XPath object
2976 *
2977 * Converts an existing object to its string() equivalent
2978 *
2979 * Returns the new object, the old one is freed (or the operation
2980 * is done directly on @val)
2981 */
2982xmlXPathObjectPtr
2983xmlXPathConvertString(xmlXPathObjectPtr val) {
2984 xmlChar *res = NULL;
2985
2986 if (val == NULL)
2987 return(xmlXPathNewCString(""));
2988
2989 switch (val->type) {
2990 case XPATH_UNDEFINED:
2991#ifdef DEBUG_EXPR
2992 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2993#endif
2994 break;
2995 case XPATH_XSLT_TREE:
2996 case XPATH_NODESET:
2997 res = xmlXPathCastNodeSetToString(val->nodesetval);
2998 break;
2999 case XPATH_STRING:
3000 return(val);
3001 case XPATH_BOOLEAN:
3002 res = xmlXPathCastBooleanToString(val->boolval);
3003 break;
3004 case XPATH_NUMBER:
3005 res = xmlXPathCastNumberToString(val->floatval);
3006 break;
3007 case XPATH_USERS:
3008 case XPATH_POINT:
3009 case XPATH_RANGE:
3010 case XPATH_LOCATIONSET:
3011 TODO;
3012 break;
3013 }
3014 xmlXPathFreeObject(val);
3015 if (res == NULL)
3016 return(xmlXPathNewCString(""));
3017 return(xmlXPathWrapString(res));
3018}
3019
3020/**
3021 * xmlXPathCastBooleanToNumber:
3022 * @val: a boolean
3023 *
3024 * Converts a boolean to its number value
3025 *
3026 * Returns the number value
3027 */
3028double
3029xmlXPathCastBooleanToNumber(int val) {
3030 if (val)
3031 return(1.0);
3032 return(0.0);
3033}
3034
3035/**
3036 * xmlXPathCastStringToNumber:
3037 * @val: a string
3038 *
3039 * Converts a string to its number value
3040 *
3041 * Returns the number value
3042 */
3043double
3044xmlXPathCastStringToNumber(const xmlChar * val) {
3045 return(xmlXPathStringEvalNumber(val));
3046}
3047
3048/**
3049 * xmlXPathCastNodeToNumber:
3050 * @node: a node
3051 *
3052 * Converts a node to its number value
3053 *
3054 * Returns the number value
3055 */
3056double
3057xmlXPathCastNodeToNumber (xmlNodePtr node) {
3058 xmlChar *strval;
3059 double ret;
3060
3061 if (node == NULL)
3062 return(xmlXPathNAN);
3063 strval = xmlXPathCastNodeToString(node);
3064 if (strval == NULL)
3065 return(xmlXPathNAN);
3066 ret = xmlXPathCastStringToNumber(strval);
3067 xmlFree(strval);
3068
3069 return(ret);
3070}
3071
3072/**
3073 * xmlXPathCastNodeSetToNumber:
3074 * @ns: a node-set
3075 *
3076 * Converts a node-set to its number value
3077 *
3078 * Returns the number value
3079 */
3080double
3081xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3082 xmlChar *str;
3083 double ret;
3084
3085 if (ns == NULL)
3086 return(xmlXPathNAN);
3087 str = xmlXPathCastNodeSetToString(ns);
3088 ret = xmlXPathCastStringToNumber(str);
3089 xmlFree(str);
3090 return(ret);
3091}
3092
3093/**
3094 * xmlXPathCastToNumber:
3095 * @val: an XPath object
3096 *
3097 * Converts an XPath object to its number value
3098 *
3099 * Returns the number value
3100 */
3101double
3102xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3103 double ret = 0.0;
3104
3105 if (val == NULL)
3106 return(xmlXPathNAN);
3107 switch (val->type) {
3108 case XPATH_UNDEFINED:
3109#ifdef DEGUB_EXPR
3110 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3111#endif
3112 ret = xmlXPathNAN;
3113 break;
3114 case XPATH_XSLT_TREE:
3115 case XPATH_NODESET:
3116 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3117 break;
3118 case XPATH_STRING:
3119 ret = xmlXPathCastStringToNumber(val->stringval);
3120 break;
3121 case XPATH_NUMBER:
3122 ret = val->floatval;
3123 break;
3124 case XPATH_BOOLEAN:
3125 ret = xmlXPathCastBooleanToNumber(val->boolval);
3126 break;
3127 case XPATH_USERS:
3128 case XPATH_POINT:
3129 case XPATH_RANGE:
3130 case XPATH_LOCATIONSET:
3131 TODO;
3132 ret = xmlXPathNAN;
3133 break;
3134 }
3135 return(ret);
3136}
3137
3138/**
3139 * xmlXPathConvertNumber:
3140 * @val: an XPath object
3141 *
3142 * Converts an existing object to its number() equivalent
3143 *
3144 * Returns the new object, the old one is freed (or the operation
3145 * is done directly on @val)
3146 */
3147xmlXPathObjectPtr
3148xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3149 xmlXPathObjectPtr ret;
3150
3151 if (val == NULL)
3152 return(xmlXPathNewFloat(0.0));
3153 if (val->type == XPATH_NUMBER)
3154 return(val);
3155 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3156 xmlXPathFreeObject(val);
3157 return(ret);
3158}
3159
3160/**
3161 * xmlXPathCastNumberToBoolean:
3162 * @val: a number
3163 *
3164 * Converts a number to its boolean value
3165 *
3166 * Returns the boolean value
3167 */
3168int
3169xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003170 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003171 return(0);
3172 return(1);
3173}
3174
3175/**
3176 * xmlXPathCastStringToBoolean:
3177 * @val: a string
3178 *
3179 * Converts a string to its boolean value
3180 *
3181 * Returns the boolean value
3182 */
3183int
3184xmlXPathCastStringToBoolean (const xmlChar *val) {
3185 if ((val == NULL) || (xmlStrlen(val) == 0))
3186 return(0);
3187 return(1);
3188}
3189
3190/**
3191 * xmlXPathCastNodeSetToBoolean:
3192 * @ns: a node-set
3193 *
3194 * Converts a node-set to its boolean value
3195 *
3196 * Returns the boolean value
3197 */
3198int
3199xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3200 if ((ns == NULL) || (ns->nodeNr == 0))
3201 return(0);
3202 return(1);
3203}
3204
3205/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003206 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003207 * @val: an XPath object
3208 *
3209 * Converts an XPath object to its boolean value
3210 *
3211 * Returns the boolean value
3212 */
3213int
3214xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3215 int ret = 0;
3216
3217 if (val == NULL)
3218 return(0);
3219 switch (val->type) {
3220 case XPATH_UNDEFINED:
3221#ifdef DEBUG_EXPR
3222 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3223#endif
3224 ret = 0;
3225 break;
3226 case XPATH_XSLT_TREE:
3227 case XPATH_NODESET:
3228 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3229 break;
3230 case XPATH_STRING:
3231 ret = xmlXPathCastStringToBoolean(val->stringval);
3232 break;
3233 case XPATH_NUMBER:
3234 ret = xmlXPathCastNumberToBoolean(val->floatval);
3235 break;
3236 case XPATH_BOOLEAN:
3237 ret = val->boolval;
3238 break;
3239 case XPATH_USERS:
3240 case XPATH_POINT:
3241 case XPATH_RANGE:
3242 case XPATH_LOCATIONSET:
3243 TODO;
3244 ret = 0;
3245 break;
3246 }
3247 return(ret);
3248}
3249
3250
3251/**
3252 * xmlXPathConvertBoolean:
3253 * @val: an XPath object
3254 *
3255 * Converts an existing object to its boolean() equivalent
3256 *
3257 * Returns the new object, the old one is freed (or the operation
3258 * is done directly on @val)
3259 */
3260xmlXPathObjectPtr
3261xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3262 xmlXPathObjectPtr ret;
3263
3264 if (val == NULL)
3265 return(xmlXPathNewBoolean(0));
3266 if (val->type == XPATH_BOOLEAN)
3267 return(val);
3268 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3269 xmlXPathFreeObject(val);
3270 return(ret);
3271}
3272
Owen Taylor3473f882001-02-23 17:55:21 +00003273/************************************************************************
3274 * *
3275 * Routines to handle XPath contexts *
3276 * *
3277 ************************************************************************/
3278
3279/**
3280 * xmlXPathNewContext:
3281 * @doc: the XML document
3282 *
3283 * Create a new xmlXPathContext
3284 *
3285 * Returns the xmlXPathContext just allocated.
3286 */
3287xmlXPathContextPtr
3288xmlXPathNewContext(xmlDocPtr doc) {
3289 xmlXPathContextPtr ret;
3290
3291 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3292 if (ret == NULL) {
3293 xmlGenericError(xmlGenericErrorContext,
3294 "xmlXPathNewContext: out of memory\n");
3295 return(NULL);
3296 }
3297 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3298 ret->doc = doc;
3299 ret->node = NULL;
3300
3301 ret->varHash = NULL;
3302
3303 ret->nb_types = 0;
3304 ret->max_types = 0;
3305 ret->types = NULL;
3306
3307 ret->funcHash = xmlHashCreate(0);
3308
3309 ret->nb_axis = 0;
3310 ret->max_axis = 0;
3311 ret->axis = NULL;
3312
3313 ret->nsHash = NULL;
3314 ret->user = NULL;
3315
3316 ret->contextSize = -1;
3317 ret->proximityPosition = -1;
3318
3319 xmlXPathRegisterAllFunctions(ret);
3320
3321 return(ret);
3322}
3323
3324/**
3325 * xmlXPathFreeContext:
3326 * @ctxt: the context to free
3327 *
3328 * Free up an xmlXPathContext
3329 */
3330void
3331xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3332 xmlXPathRegisteredNsCleanup(ctxt);
3333 xmlXPathRegisteredFuncsCleanup(ctxt);
3334 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003335 xmlFree(ctxt);
3336}
3337
3338/************************************************************************
3339 * *
3340 * Routines to handle XPath parser contexts *
3341 * *
3342 ************************************************************************/
3343
3344#define CHECK_CTXT(ctxt) \
3345 if (ctxt == NULL) { \
3346 xmlGenericError(xmlGenericErrorContext, \
3347 "%s:%d Internal error: ctxt == NULL\n", \
3348 __FILE__, __LINE__); \
3349 } \
3350
3351
3352#define CHECK_CONTEXT(ctxt) \
3353 if (ctxt == NULL) { \
3354 xmlGenericError(xmlGenericErrorContext, \
3355 "%s:%d Internal error: no context\n", \
3356 __FILE__, __LINE__); \
3357 } \
3358 else if (ctxt->doc == NULL) { \
3359 xmlGenericError(xmlGenericErrorContext, \
3360 "%s:%d Internal error: no document\n", \
3361 __FILE__, __LINE__); \
3362 } \
3363 else if (ctxt->doc->children == NULL) { \
3364 xmlGenericError(xmlGenericErrorContext, \
3365 "%s:%d Internal error: document without root\n", \
3366 __FILE__, __LINE__); \
3367 } \
3368
3369
3370/**
3371 * xmlXPathNewParserContext:
3372 * @str: the XPath expression
3373 * @ctxt: the XPath context
3374 *
3375 * Create a new xmlXPathParserContext
3376 *
3377 * Returns the xmlXPathParserContext just allocated.
3378 */
3379xmlXPathParserContextPtr
3380xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3381 xmlXPathParserContextPtr ret;
3382
3383 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3384 if (ret == NULL) {
3385 xmlGenericError(xmlGenericErrorContext,
3386 "xmlXPathNewParserContext: out of memory\n");
3387 return(NULL);
3388 }
3389 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3390 ret->cur = ret->base = str;
3391 ret->context = ctxt;
3392
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003393 ret->comp = xmlXPathNewCompExpr();
3394 if (ret->comp == NULL) {
3395 xmlFree(ret->valueTab);
3396 xmlFree(ret);
3397 return(NULL);
3398 }
3399
3400 return(ret);
3401}
3402
3403/**
3404 * xmlXPathCompParserContext:
3405 * @comp: the XPath compiled expression
3406 * @ctxt: the XPath context
3407 *
3408 * Create a new xmlXPathParserContext when processing a compiled expression
3409 *
3410 * Returns the xmlXPathParserContext just allocated.
3411 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003412static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003413xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3414 xmlXPathParserContextPtr ret;
3415
3416 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3417 if (ret == NULL) {
3418 xmlGenericError(xmlGenericErrorContext,
3419 "xmlXPathNewParserContext: out of memory\n");
3420 return(NULL);
3421 }
3422 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3423
Owen Taylor3473f882001-02-23 17:55:21 +00003424 /* Allocate the value stack */
3425 ret->valueTab = (xmlXPathObjectPtr *)
3426 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003427 if (ret->valueTab == NULL) {
3428 xmlFree(ret);
3429 xmlGenericError(xmlGenericErrorContext,
3430 "xmlXPathNewParserContext: out of memory\n");
3431 return(NULL);
3432 }
Owen Taylor3473f882001-02-23 17:55:21 +00003433 ret->valueNr = 0;
3434 ret->valueMax = 10;
3435 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003436
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003437 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003438 ret->comp = comp;
3439
Owen Taylor3473f882001-02-23 17:55:21 +00003440 return(ret);
3441}
3442
3443/**
3444 * xmlXPathFreeParserContext:
3445 * @ctxt: the context to free
3446 *
3447 * Free up an xmlXPathParserContext
3448 */
3449void
3450xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3451 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003452 xmlFree(ctxt->valueTab);
3453 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003454 if (ctxt->comp)
3455 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003456 xmlFree(ctxt);
3457}
3458
3459/************************************************************************
3460 * *
3461 * The implicit core function library *
3462 * *
3463 ************************************************************************/
3464
Owen Taylor3473f882001-02-23 17:55:21 +00003465/**
Daniel Veillardf06307e2001-07-03 10:35:50 +00003466 * xmlXPathNodeStringHash:
3467 * @node: a node pointer
3468 *
3469 * Function computing the beginning of the string value of the node,
3470 * used to speed up comparisons
3471 *
3472 * Returns an int usable as a hash
3473 */
3474static unsigned int
3475xmlXPathNodeValHash(xmlNodePtr node) {
3476 int len = 2;
3477 const xmlChar * string = NULL;
3478 xmlNodePtr tmp = NULL;
3479 unsigned int ret = 0;
3480
3481 if (node == NULL)
3482 return(0);
3483
3484
3485 switch (node->type) {
3486 case XML_COMMENT_NODE:
3487 case XML_PI_NODE:
3488 case XML_CDATA_SECTION_NODE:
3489 case XML_TEXT_NODE:
3490 string = node->content;
3491 if (string == NULL)
3492 return(0);
3493 if (string[0] == 0)
3494 return(0);
3495 return(((unsigned int) string[0]) +
3496 (((unsigned int) string[1]) << 8));
3497 case XML_NAMESPACE_DECL:
3498 string = ((xmlNsPtr)node)->href;
3499 if (string == NULL)
3500 return(0);
3501 if (string[0] == 0)
3502 return(0);
3503 return(((unsigned int) string[0]) +
3504 (((unsigned int) string[1]) << 8));
3505 case XML_ATTRIBUTE_NODE:
3506 tmp = ((xmlAttrPtr) node)->children;
3507 break;
3508 case XML_ELEMENT_NODE:
3509 tmp = node->children;
3510 break;
3511 default:
3512 return(0);
3513 }
3514 while (tmp != NULL) {
3515 switch (tmp->type) {
3516 case XML_COMMENT_NODE:
3517 case XML_PI_NODE:
3518 case XML_CDATA_SECTION_NODE:
3519 case XML_TEXT_NODE:
3520 string = tmp->content;
3521 break;
3522 case XML_NAMESPACE_DECL:
3523 string = ((xmlNsPtr)tmp)->href;
3524 break;
3525 default:
3526 break;
3527 }
3528 if ((string != NULL) && (string[0] != 0)) {
3529 if (string[0] == 0)
3530 return(0);
3531 if (len == 1) {
3532 return(ret + (((unsigned int) string[0]) << 8));
3533 }
3534 if (string[1] == 0) {
3535 len = 1;
3536 ret = (unsigned int) string[0];
3537 } else {
3538 return(((unsigned int) string[0]) +
3539 (((unsigned int) string[1]) << 8));
3540 }
3541 }
3542 /*
3543 * Skip to next node
3544 */
3545 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
3546 if (tmp->children->type != XML_ENTITY_DECL) {
3547 tmp = tmp->children;
3548 continue;
3549 }
3550 }
3551 if (tmp == node)
3552 break;
3553
3554 if (tmp->next != NULL) {
3555 tmp = tmp->next;
3556 continue;
3557 }
3558
3559 do {
3560 tmp = tmp->parent;
3561 if (tmp == NULL)
3562 break;
3563 if (tmp == node) {
3564 tmp = NULL;
3565 break;
3566 }
3567 if (tmp->next != NULL) {
3568 tmp = tmp->next;
3569 break;
3570 }
3571 } while (tmp != NULL);
3572 }
3573 return(ret);
3574}
3575
3576/**
3577 * xmlXPathStringHash:
3578 * @string: a string
3579 *
3580 * Function computing the beginning of the string value of the node,
3581 * used to speed up comparisons
3582 *
3583 * Returns an int usable as a hash
3584 */
3585static unsigned int
3586xmlXPathStringHash(const xmlChar * string) {
3587 if (string == NULL)
3588 return((unsigned int) 0);
3589 if (string[0] == 0)
3590 return(0);
3591 return(((unsigned int) string[0]) +
3592 (((unsigned int) string[1]) << 8));
3593}
3594
3595/**
Owen Taylor3473f882001-02-23 17:55:21 +00003596 * xmlXPathCompareNodeSetFloat:
3597 * @ctxt: the XPath Parser context
3598 * @inf: less than (1) or greater than (0)
3599 * @strict: is the comparison strict
3600 * @arg: the node set
3601 * @f: the value
3602 *
3603 * Implement the compare operation between a nodeset and a number
3604 * @ns < @val (1, 1, ...
3605 * @ns <= @val (1, 0, ...
3606 * @ns > @val (0, 1, ...
3607 * @ns >= @val (0, 0, ...
3608 *
3609 * If one object to be compared is a node-set and the other is a number,
3610 * then the comparison will be true if and only if there is a node in the
3611 * node-set such that the result of performing the comparison on the number
3612 * to be compared and on the result of converting the string-value of that
3613 * node to a number using the number function is true.
3614 *
3615 * Returns 0 or 1 depending on the results of the test.
3616 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003617static int
Owen Taylor3473f882001-02-23 17:55:21 +00003618xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
3619 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
3620 int i, ret = 0;
3621 xmlNodeSetPtr ns;
3622 xmlChar *str2;
3623
3624 if ((f == NULL) || (arg == NULL) ||
3625 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3626 xmlXPathFreeObject(arg);
3627 xmlXPathFreeObject(f);
3628 return(0);
3629 }
3630 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003631 if (ns != NULL) {
3632 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003633 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003634 if (str2 != NULL) {
3635 valuePush(ctxt,
3636 xmlXPathNewString(str2));
3637 xmlFree(str2);
3638 xmlXPathNumberFunction(ctxt, 1);
3639 valuePush(ctxt, xmlXPathObjectCopy(f));
3640 ret = xmlXPathCompareValues(ctxt, inf, strict);
3641 if (ret)
3642 break;
3643 }
3644 }
Owen Taylor3473f882001-02-23 17:55:21 +00003645 }
3646 xmlXPathFreeObject(arg);
3647 xmlXPathFreeObject(f);
3648 return(ret);
3649}
3650
3651/**
3652 * xmlXPathCompareNodeSetString:
3653 * @ctxt: the XPath Parser context
3654 * @inf: less than (1) or greater than (0)
3655 * @strict: is the comparison strict
3656 * @arg: the node set
3657 * @s: the value
3658 *
3659 * Implement the compare operation between a nodeset and a string
3660 * @ns < @val (1, 1, ...
3661 * @ns <= @val (1, 0, ...
3662 * @ns > @val (0, 1, ...
3663 * @ns >= @val (0, 0, ...
3664 *
3665 * If one object to be compared is a node-set and the other is a string,
3666 * then the comparison will be true if and only if there is a node in
3667 * the node-set such that the result of performing the comparison on the
3668 * string-value of the node and the other string is true.
3669 *
3670 * Returns 0 or 1 depending on the results of the test.
3671 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003672static int
Owen Taylor3473f882001-02-23 17:55:21 +00003673xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
3674 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
3675 int i, ret = 0;
3676 xmlNodeSetPtr ns;
3677 xmlChar *str2;
3678
3679 if ((s == NULL) || (arg == NULL) ||
3680 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3681 xmlXPathFreeObject(arg);
3682 xmlXPathFreeObject(s);
3683 return(0);
3684 }
3685 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003686 if (ns != NULL) {
3687 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003688 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003689 if (str2 != NULL) {
3690 valuePush(ctxt,
3691 xmlXPathNewString(str2));
3692 xmlFree(str2);
3693 valuePush(ctxt, xmlXPathObjectCopy(s));
3694 ret = xmlXPathCompareValues(ctxt, inf, strict);
3695 if (ret)
3696 break;
3697 }
3698 }
Owen Taylor3473f882001-02-23 17:55:21 +00003699 }
3700 xmlXPathFreeObject(arg);
3701 xmlXPathFreeObject(s);
3702 return(ret);
3703}
3704
3705/**
3706 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003707 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00003708 * @strict: is the comparison strict
3709 * @arg1: the fist node set object
3710 * @arg2: the second node set object
3711 *
3712 * Implement the compare operation on nodesets:
3713 *
3714 * If both objects to be compared are node-sets, then the comparison
3715 * will be true if and only if there is a node in the first node-set
3716 * and a node in the second node-set such that the result of performing
3717 * the comparison on the string-values of the two nodes is true.
3718 * ....
3719 * When neither object to be compared is a node-set and the operator
3720 * is <=, <, >= or >, then the objects are compared by converting both
3721 * objects to numbers and comparing the numbers according to IEEE 754.
3722 * ....
3723 * The number function converts its argument to a number as follows:
3724 * - a string that consists of optional whitespace followed by an
3725 * optional minus sign followed by a Number followed by whitespace
3726 * is converted to the IEEE 754 number that is nearest (according
3727 * to the IEEE 754 round-to-nearest rule) to the mathematical value
3728 * represented by the string; any other string is converted to NaN
3729 *
3730 * Conclusion all nodes need to be converted first to their string value
3731 * and then the comparison must be done when possible
3732 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003733static int
3734xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00003735 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3736 int i, j, init = 0;
3737 double val1;
3738 double *values2;
3739 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003740 xmlNodeSetPtr ns1;
3741 xmlNodeSetPtr ns2;
3742
3743 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003744 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
3745 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003746 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003747 }
Owen Taylor3473f882001-02-23 17:55:21 +00003748 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003749 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
3750 xmlXPathFreeObject(arg1);
3751 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003752 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003753 }
Owen Taylor3473f882001-02-23 17:55:21 +00003754
3755 ns1 = arg1->nodesetval;
3756 ns2 = arg2->nodesetval;
3757
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003758 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003759 xmlXPathFreeObject(arg1);
3760 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003761 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003762 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003763 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003764 xmlXPathFreeObject(arg1);
3765 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003766 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003767 }
Owen Taylor3473f882001-02-23 17:55:21 +00003768
3769 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
3770 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003771 xmlXPathFreeObject(arg1);
3772 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003773 return(0);
3774 }
3775 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003776 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00003777 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00003778 continue;
3779 for (j = 0;j < ns2->nodeNr;j++) {
3780 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003781 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00003782 }
Daniel Veillardcda96922001-08-21 10:56:31 +00003783 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00003784 continue;
3785 if (inf && strict)
3786 ret = (val1 < values2[j]);
3787 else 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 if (ret)
3794 break;
3795 }
3796 if (ret)
3797 break;
3798 init = 1;
3799 }
3800 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003801 xmlXPathFreeObject(arg1);
3802 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003803 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003804}
3805
3806/**
3807 * xmlXPathCompareNodeSetValue:
3808 * @ctxt: the XPath Parser context
3809 * @inf: less than (1) or greater than (0)
3810 * @strict: is the comparison strict
3811 * @arg: the node set
3812 * @val: the value
3813 *
3814 * Implement the compare operation between a nodeset and a value
3815 * @ns < @val (1, 1, ...
3816 * @ns <= @val (1, 0, ...
3817 * @ns > @val (0, 1, ...
3818 * @ns >= @val (0, 0, ...
3819 *
3820 * If one object to be compared is a node-set and the other is a boolean,
3821 * then the comparison will be true if and only if the result of performing
3822 * the comparison on the boolean and on the result of converting
3823 * the node-set to a boolean using the boolean function is true.
3824 *
3825 * Returns 0 or 1 depending on the results of the test.
3826 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003827static int
Owen Taylor3473f882001-02-23 17:55:21 +00003828xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
3829 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
3830 if ((val == NULL) || (arg == NULL) ||
3831 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3832 return(0);
3833
3834 switch(val->type) {
3835 case XPATH_NUMBER:
3836 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
3837 case XPATH_NODESET:
3838 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003839 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00003840 case XPATH_STRING:
3841 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
3842 case XPATH_BOOLEAN:
3843 valuePush(ctxt, arg);
3844 xmlXPathBooleanFunction(ctxt, 1);
3845 valuePush(ctxt, val);
3846 return(xmlXPathCompareValues(ctxt, inf, strict));
3847 default:
3848 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00003849 }
3850 return(0);
3851}
3852
3853/**
3854 * xmlXPathEqualNodeSetString
3855 * @arg: the nodeset object argument
3856 * @str: the string to compare to.
3857 *
3858 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3859 * If one object to be compared is a node-set and the other is a string,
3860 * then the comparison will be true if and only if there is a node in
3861 * the node-set such that the result of performing the comparison on the
3862 * string-value of the node and the other string is true.
3863 *
3864 * Returns 0 or 1 depending on the results of the test.
3865 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003866static int
Daniel Veillardf06307e2001-07-03 10:35:50 +00003867xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str)
3868{
Owen Taylor3473f882001-02-23 17:55:21 +00003869 int i;
3870 xmlNodeSetPtr ns;
3871 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003872 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00003873
3874 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00003875 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3876 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00003877 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003878 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003879 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00003880 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00003881 if (ns->nodeNr <= 0) {
3882 if (hash == 0)
3883 return(1);
3884 return(0);
3885 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003886 for (i = 0; i < ns->nodeNr; i++) {
3887 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
3888 str2 = xmlNodeGetContent(ns->nodeTab[i]);
3889 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
3890 xmlFree(str2);
3891 return (1);
3892 }
3893 if (str2 != NULL)
3894 xmlFree(str2);
3895 }
Owen Taylor3473f882001-02-23 17:55:21 +00003896 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003897 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00003898}
3899
3900/**
3901 * xmlXPathEqualNodeSetFloat
3902 * @arg: the nodeset object argument
3903 * @f: the float to compare to
3904 *
3905 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3906 * If one object to be compared is a node-set and the other is a number,
3907 * then the comparison will be true if and only if there is a node in
3908 * the node-set such that the result of performing the comparison on the
3909 * number to be compared and on the result of converting the string-value
3910 * of that node to a number using the number function is true.
3911 *
3912 * Returns 0 or 1 depending on the results of the test.
3913 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003914static int
Owen Taylor3473f882001-02-23 17:55:21 +00003915xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) {
3916 char buf[100] = "";
3917
3918 if ((arg == NULL) ||
3919 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3920 return(0);
3921
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003922 xmlXPathFormatNumber(f, buf, sizeof(buf));
Owen Taylor3473f882001-02-23 17:55:21 +00003923 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
3924}
3925
3926
3927/**
3928 * xmlXPathEqualNodeSets
3929 * @arg1: first nodeset object argument
3930 * @arg2: second nodeset object argument
3931 *
3932 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
3933 * If both objects to be compared are node-sets, then the comparison
3934 * will be true if and only if there is a node in the first node-set and
3935 * a node in the second node-set such that the result of performing the
3936 * comparison on the string-values of the two nodes is true.
3937 *
3938 * (needless to say, this is a costly operation)
3939 *
3940 * Returns 0 or 1 depending on the results of the test.
3941 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003942static int
Owen Taylor3473f882001-02-23 17:55:21 +00003943xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3944 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003945 unsigned int *hashs1;
3946 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00003947 xmlChar **values1;
3948 xmlChar **values2;
3949 int ret = 0;
3950 xmlNodeSetPtr ns1;
3951 xmlNodeSetPtr ns2;
3952
3953 if ((arg1 == NULL) ||
3954 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
3955 return(0);
3956 if ((arg2 == NULL) ||
3957 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
3958 return(0);
3959
3960 ns1 = arg1->nodesetval;
3961 ns2 = arg2->nodesetval;
3962
Daniel Veillard911f49a2001-04-07 15:39:35 +00003963 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00003964 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003965 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00003966 return(0);
3967
3968 /*
3969 * check if there is a node pertaining to both sets
3970 */
3971 for (i = 0;i < ns1->nodeNr;i++)
3972 for (j = 0;j < ns2->nodeNr;j++)
3973 if (ns1->nodeTab[i] == ns2->nodeTab[j])
3974 return(1);
3975
3976 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
3977 if (values1 == NULL)
3978 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00003979 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
3980 if (hashs1 == NULL) {
3981 xmlFree(values1);
3982 return(0);
3983 }
Owen Taylor3473f882001-02-23 17:55:21 +00003984 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
3985 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
3986 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00003987 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00003988 xmlFree(values1);
3989 return(0);
3990 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003991 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
3992 if (hashs2 == NULL) {
3993 xmlFree(hashs1);
3994 xmlFree(values1);
3995 xmlFree(values2);
3996 return(0);
3997 }
Owen Taylor3473f882001-02-23 17:55:21 +00003998 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
3999 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004000 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004001 for (j = 0;j < ns2->nodeNr;j++) {
4002 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004003 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
4004 if (hashs1[i] == hashs2[j]) {
4005 if (values1[i] == NULL)
4006 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4007 if (values2[j] == NULL)
4008 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
4009 ret = xmlStrEqual(values1[i], values2[j]);
4010 if (ret)
4011 break;
4012 }
Owen Taylor3473f882001-02-23 17:55:21 +00004013 }
4014 if (ret)
4015 break;
4016 }
4017 for (i = 0;i < ns1->nodeNr;i++)
4018 if (values1[i] != NULL)
4019 xmlFree(values1[i]);
4020 for (j = 0;j < ns2->nodeNr;j++)
4021 if (values2[j] != NULL)
4022 xmlFree(values2[j]);
4023 xmlFree(values1);
4024 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004025 xmlFree(hashs1);
4026 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004027 return(ret);
4028}
4029
4030/**
4031 * xmlXPathEqualValues:
4032 * @ctxt: the XPath Parser context
4033 *
4034 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4035 *
4036 * Returns 0 or 1 depending on the results of the test.
4037 */
4038int
4039xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4040 xmlXPathObjectPtr arg1, arg2;
4041 int ret = 0;
4042
4043 arg1 = valuePop(ctxt);
4044 if (arg1 == NULL)
4045 XP_ERROR0(XPATH_INVALID_OPERAND);
4046
4047 arg2 = valuePop(ctxt);
4048 if (arg2 == NULL) {
4049 xmlXPathFreeObject(arg1);
4050 XP_ERROR0(XPATH_INVALID_OPERAND);
4051 }
4052
4053 if (arg1 == arg2) {
4054#ifdef DEBUG_EXPR
4055 xmlGenericError(xmlGenericErrorContext,
4056 "Equal: by pointer\n");
4057#endif
4058 return(1);
4059 }
4060
4061 switch (arg1->type) {
4062 case XPATH_UNDEFINED:
4063#ifdef DEBUG_EXPR
4064 xmlGenericError(xmlGenericErrorContext,
4065 "Equal: undefined\n");
4066#endif
4067 break;
4068 case XPATH_XSLT_TREE:
4069 case XPATH_NODESET:
4070 switch (arg2->type) {
4071 case XPATH_UNDEFINED:
4072#ifdef DEBUG_EXPR
4073 xmlGenericError(xmlGenericErrorContext,
4074 "Equal: undefined\n");
4075#endif
4076 break;
4077 case XPATH_XSLT_TREE:
4078 case XPATH_NODESET:
4079 ret = xmlXPathEqualNodeSets(arg1, arg2);
4080 break;
4081 case XPATH_BOOLEAN:
4082 if ((arg1->nodesetval == NULL) ||
4083 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4084 else
4085 ret = 1;
4086 ret = (ret == arg2->boolval);
4087 break;
4088 case XPATH_NUMBER:
4089 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
4090 break;
4091 case XPATH_STRING:
4092 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
4093 break;
4094 case XPATH_USERS:
4095 case XPATH_POINT:
4096 case XPATH_RANGE:
4097 case XPATH_LOCATIONSET:
4098 TODO
4099 break;
4100 }
4101 break;
4102 case XPATH_BOOLEAN:
4103 switch (arg2->type) {
4104 case XPATH_UNDEFINED:
4105#ifdef DEBUG_EXPR
4106 xmlGenericError(xmlGenericErrorContext,
4107 "Equal: undefined\n");
4108#endif
4109 break;
4110 case XPATH_NODESET:
4111 case XPATH_XSLT_TREE:
4112 if ((arg2->nodesetval == NULL) ||
4113 (arg2->nodesetval->nodeNr == 0)) ret = 0;
4114 else
4115 ret = 1;
4116 break;
4117 case XPATH_BOOLEAN:
4118#ifdef DEBUG_EXPR
4119 xmlGenericError(xmlGenericErrorContext,
4120 "Equal: %d boolean %d \n",
4121 arg1->boolval, arg2->boolval);
4122#endif
4123 ret = (arg1->boolval == arg2->boolval);
4124 break;
4125 case XPATH_NUMBER:
4126 if (arg2->floatval) ret = 1;
4127 else ret = 0;
4128 ret = (arg1->boolval == ret);
4129 break;
4130 case XPATH_STRING:
4131 if ((arg2->stringval == NULL) ||
4132 (arg2->stringval[0] == 0)) ret = 0;
4133 else
4134 ret = 1;
4135 ret = (arg1->boolval == ret);
4136 break;
4137 case XPATH_USERS:
4138 case XPATH_POINT:
4139 case XPATH_RANGE:
4140 case XPATH_LOCATIONSET:
4141 TODO
4142 break;
4143 }
4144 break;
4145 case XPATH_NUMBER:
4146 switch (arg2->type) {
4147 case XPATH_UNDEFINED:
4148#ifdef DEBUG_EXPR
4149 xmlGenericError(xmlGenericErrorContext,
4150 "Equal: undefined\n");
4151#endif
4152 break;
4153 case XPATH_NODESET:
4154 case XPATH_XSLT_TREE:
4155 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
4156 break;
4157 case XPATH_BOOLEAN:
4158 if (arg1->floatval) ret = 1;
4159 else ret = 0;
4160 ret = (arg2->boolval == ret);
4161 break;
4162 case XPATH_STRING:
4163 valuePush(ctxt, arg2);
4164 xmlXPathNumberFunction(ctxt, 1);
4165 arg2 = valuePop(ctxt);
4166 /* no break on purpose */
4167 case XPATH_NUMBER:
4168 ret = (arg1->floatval == arg2->floatval);
4169 break;
4170 case XPATH_USERS:
4171 case XPATH_POINT:
4172 case XPATH_RANGE:
4173 case XPATH_LOCATIONSET:
4174 TODO
4175 break;
4176 }
4177 break;
4178 case XPATH_STRING:
4179 switch (arg2->type) {
4180 case XPATH_UNDEFINED:
4181#ifdef DEBUG_EXPR
4182 xmlGenericError(xmlGenericErrorContext,
4183 "Equal: undefined\n");
4184#endif
4185 break;
4186 case XPATH_NODESET:
4187 case XPATH_XSLT_TREE:
4188 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
4189 break;
4190 case XPATH_BOOLEAN:
4191 if ((arg1->stringval == NULL) ||
4192 (arg1->stringval[0] == 0)) ret = 0;
4193 else
4194 ret = 1;
4195 ret = (arg2->boolval == ret);
4196 break;
4197 case XPATH_STRING:
4198 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4199 break;
4200 case XPATH_NUMBER:
4201 valuePush(ctxt, arg1);
4202 xmlXPathNumberFunction(ctxt, 1);
4203 arg1 = valuePop(ctxt);
4204 ret = (arg1->floatval == arg2->floatval);
4205 break;
4206 case XPATH_USERS:
4207 case XPATH_POINT:
4208 case XPATH_RANGE:
4209 case XPATH_LOCATIONSET:
4210 TODO
4211 break;
4212 }
4213 break;
4214 case XPATH_USERS:
4215 case XPATH_POINT:
4216 case XPATH_RANGE:
4217 case XPATH_LOCATIONSET:
4218 TODO
4219 break;
4220 }
4221 xmlXPathFreeObject(arg1);
4222 xmlXPathFreeObject(arg2);
4223 return(ret);
4224}
4225
4226
4227/**
4228 * xmlXPathCompareValues:
4229 * @ctxt: the XPath Parser context
4230 * @inf: less than (1) or greater than (0)
4231 * @strict: is the comparison strict
4232 *
4233 * Implement the compare operation on XPath objects:
4234 * @arg1 < @arg2 (1, 1, ...
4235 * @arg1 <= @arg2 (1, 0, ...
4236 * @arg1 > @arg2 (0, 1, ...
4237 * @arg1 >= @arg2 (0, 0, ...
4238 *
4239 * When neither object to be compared is a node-set and the operator is
4240 * <=, <, >=, >, then the objects are compared by converted both objects
4241 * to numbers and comparing the numbers according to IEEE 754. The <
4242 * comparison will be true if and only if the first number is less than the
4243 * second number. The <= comparison will be true if and only if the first
4244 * number is less than or equal to the second number. The > comparison
4245 * will be true if and only if the first number is greater than the second
4246 * number. The >= comparison will be true if and only if the first number
4247 * is greater than or equal to the second number.
4248 *
4249 * Returns 1 if the comparaison succeeded, 0 if it failed
4250 */
4251int
4252xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
4253 int ret = 0;
4254 xmlXPathObjectPtr arg1, arg2;
4255
4256 arg2 = valuePop(ctxt);
4257 if (arg2 == NULL) {
4258 XP_ERROR0(XPATH_INVALID_OPERAND);
4259 }
4260
4261 arg1 = valuePop(ctxt);
4262 if (arg1 == NULL) {
4263 xmlXPathFreeObject(arg2);
4264 XP_ERROR0(XPATH_INVALID_OPERAND);
4265 }
4266
4267 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
4268 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004269 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004270 } else {
4271 if (arg1->type == XPATH_NODESET) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004272 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4273 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004274 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004275 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4276 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004277 }
4278 }
4279 return(ret);
4280 }
4281
4282 if (arg1->type != XPATH_NUMBER) {
4283 valuePush(ctxt, arg1);
4284 xmlXPathNumberFunction(ctxt, 1);
4285 arg1 = valuePop(ctxt);
4286 }
4287 if (arg1->type != XPATH_NUMBER) {
4288 xmlXPathFreeObject(arg1);
4289 xmlXPathFreeObject(arg2);
4290 XP_ERROR0(XPATH_INVALID_OPERAND);
4291 }
4292 if (arg2->type != XPATH_NUMBER) {
4293 valuePush(ctxt, arg2);
4294 xmlXPathNumberFunction(ctxt, 1);
4295 arg2 = valuePop(ctxt);
4296 }
4297 if (arg2->type != XPATH_NUMBER) {
4298 xmlXPathFreeObject(arg1);
4299 xmlXPathFreeObject(arg2);
4300 XP_ERROR0(XPATH_INVALID_OPERAND);
4301 }
4302 /*
4303 * Add tests for infinity and nan
4304 * => feedback on 3.4 for Inf and NaN
4305 */
4306 if (inf && strict)
4307 ret = (arg1->floatval < arg2->floatval);
4308 else 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 xmlXPathFreeObject(arg1);
4315 xmlXPathFreeObject(arg2);
4316 return(ret);
4317}
4318
4319/**
4320 * xmlXPathValueFlipSign:
4321 * @ctxt: the XPath Parser context
4322 *
4323 * Implement the unary - operation on an XPath object
4324 * The numeric operators convert their operands to numbers as if
4325 * by calling the number function.
4326 */
4327void
4328xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004329 CAST_TO_NUMBER;
4330 CHECK_TYPE(XPATH_NUMBER);
4331 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00004332}
4333
4334/**
4335 * xmlXPathAddValues:
4336 * @ctxt: the XPath Parser context
4337 *
4338 * Implement the add operation on XPath objects:
4339 * The numeric operators convert their operands to numbers as if
4340 * by calling the number function.
4341 */
4342void
4343xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
4344 xmlXPathObjectPtr arg;
4345 double val;
4346
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004347 arg = valuePop(ctxt);
4348 if (arg == NULL)
4349 XP_ERROR(XPATH_INVALID_OPERAND);
4350 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004351 xmlXPathFreeObject(arg);
4352
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004353 CAST_TO_NUMBER;
4354 CHECK_TYPE(XPATH_NUMBER);
4355 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00004356}
4357
4358/**
4359 * xmlXPathSubValues:
4360 * @ctxt: the XPath Parser context
4361 *
4362 * Implement the substraction operation on XPath objects:
4363 * The numeric operators convert their operands to numbers as if
4364 * by calling the number function.
4365 */
4366void
4367xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
4368 xmlXPathObjectPtr arg;
4369 double val;
4370
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004371 arg = valuePop(ctxt);
4372 if (arg == NULL)
4373 XP_ERROR(XPATH_INVALID_OPERAND);
4374 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004375 xmlXPathFreeObject(arg);
4376
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004377 CAST_TO_NUMBER;
4378 CHECK_TYPE(XPATH_NUMBER);
4379 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004380}
4381
4382/**
4383 * xmlXPathMultValues:
4384 * @ctxt: the XPath Parser context
4385 *
4386 * Implement the multiply operation on XPath objects:
4387 * The numeric operators convert their operands to numbers as if
4388 * by calling the number function.
4389 */
4390void
4391xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
4392 xmlXPathObjectPtr arg;
4393 double val;
4394
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004395 arg = valuePop(ctxt);
4396 if (arg == NULL)
4397 XP_ERROR(XPATH_INVALID_OPERAND);
4398 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004399 xmlXPathFreeObject(arg);
4400
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004401 CAST_TO_NUMBER;
4402 CHECK_TYPE(XPATH_NUMBER);
4403 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004404}
4405
4406/**
4407 * xmlXPathDivValues:
4408 * @ctxt: the XPath Parser context
4409 *
4410 * Implement the div operation on XPath objects @arg1 / @arg2:
4411 * The numeric operators convert their operands to numbers as if
4412 * by calling the number function.
4413 */
4414void
4415xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
4416 xmlXPathObjectPtr arg;
4417 double val;
4418
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004419 arg = valuePop(ctxt);
4420 if (arg == NULL)
4421 XP_ERROR(XPATH_INVALID_OPERAND);
4422 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004423 xmlXPathFreeObject(arg);
4424
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004425 CAST_TO_NUMBER;
4426 CHECK_TYPE(XPATH_NUMBER);
4427 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004428}
4429
4430/**
4431 * xmlXPathModValues:
4432 * @ctxt: the XPath Parser context
4433 *
4434 * Implement the mod operation on XPath objects: @arg1 / @arg2
4435 * The numeric operators convert their operands to numbers as if
4436 * by calling the number function.
4437 */
4438void
4439xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
4440 xmlXPathObjectPtr arg;
4441 int arg1, arg2;
4442
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004443 arg = valuePop(ctxt);
4444 if (arg == NULL)
4445 XP_ERROR(XPATH_INVALID_OPERAND);
4446 arg2 = (int) xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004447 xmlXPathFreeObject(arg);
4448
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004449 CAST_TO_NUMBER;
4450 CHECK_TYPE(XPATH_NUMBER);
4451 arg1 = (int) ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00004452 if (arg2 == 0)
4453 ctxt->value->floatval = xmlXPathNAN;
4454 else
4455 ctxt->value->floatval = arg1 % arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00004456}
4457
4458/************************************************************************
4459 * *
4460 * The traversal functions *
4461 * *
4462 ************************************************************************/
4463
Owen Taylor3473f882001-02-23 17:55:21 +00004464/*
4465 * A traversal function enumerates nodes along an axis.
4466 * Initially it must be called with NULL, and it indicates
4467 * termination on the axis by returning NULL.
4468 */
4469typedef xmlNodePtr (*xmlXPathTraversalFunction)
4470 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
4471
4472/**
4473 * xmlXPathNextSelf:
4474 * @ctxt: the XPath Parser context
4475 * @cur: the current node in the traversal
4476 *
4477 * Traversal function for the "self" direction
4478 * The self axis contains just the context node itself
4479 *
4480 * Returns the next element following that axis
4481 */
4482xmlNodePtr
4483xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4484 if (cur == NULL)
4485 return(ctxt->context->node);
4486 return(NULL);
4487}
4488
4489/**
4490 * xmlXPathNextChild:
4491 * @ctxt: the XPath Parser context
4492 * @cur: the current node in the traversal
4493 *
4494 * Traversal function for the "child" direction
4495 * The child axis contains the children of the context node in document order.
4496 *
4497 * Returns the next element following that axis
4498 */
4499xmlNodePtr
4500xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4501 if (cur == NULL) {
4502 if (ctxt->context->node == NULL) return(NULL);
4503 switch (ctxt->context->node->type) {
4504 case XML_ELEMENT_NODE:
4505 case XML_TEXT_NODE:
4506 case XML_CDATA_SECTION_NODE:
4507 case XML_ENTITY_REF_NODE:
4508 case XML_ENTITY_NODE:
4509 case XML_PI_NODE:
4510 case XML_COMMENT_NODE:
4511 case XML_NOTATION_NODE:
4512 case XML_DTD_NODE:
4513 return(ctxt->context->node->children);
4514 case XML_DOCUMENT_NODE:
4515 case XML_DOCUMENT_TYPE_NODE:
4516 case XML_DOCUMENT_FRAG_NODE:
4517 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004518#ifdef LIBXML_DOCB_ENABLED
4519 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004520#endif
4521 return(((xmlDocPtr) ctxt->context->node)->children);
4522 case XML_ELEMENT_DECL:
4523 case XML_ATTRIBUTE_DECL:
4524 case XML_ENTITY_DECL:
4525 case XML_ATTRIBUTE_NODE:
4526 case XML_NAMESPACE_DECL:
4527 case XML_XINCLUDE_START:
4528 case XML_XINCLUDE_END:
4529 return(NULL);
4530 }
4531 return(NULL);
4532 }
4533 if ((cur->type == XML_DOCUMENT_NODE) ||
4534 (cur->type == XML_HTML_DOCUMENT_NODE))
4535 return(NULL);
4536 return(cur->next);
4537}
4538
4539/**
4540 * xmlXPathNextDescendant:
4541 * @ctxt: the XPath Parser context
4542 * @cur: the current node in the traversal
4543 *
4544 * Traversal function for the "descendant" direction
4545 * the descendant axis contains the descendants of the context node in document
4546 * order; a descendant is a child or a child of a child and so on.
4547 *
4548 * Returns the next element following that axis
4549 */
4550xmlNodePtr
4551xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4552 if (cur == NULL) {
4553 if (ctxt->context->node == NULL)
4554 return(NULL);
4555 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4556 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4557 return(NULL);
4558
4559 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
4560 return(ctxt->context->doc->children);
4561 return(ctxt->context->node->children);
4562 }
4563
Daniel Veillard567e1b42001-08-01 15:53:47 +00004564 if (cur->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004565 if (cur->children->type != XML_ENTITY_DECL)
Daniel Veillard567e1b42001-08-01 15:53:47 +00004566 return(cur->children);
4567 }
4568
4569 if (cur == ctxt->context->node) return(NULL);
4570
Owen Taylor3473f882001-02-23 17:55:21 +00004571 if (cur->next != NULL) return(cur->next);
4572
4573 do {
4574 cur = cur->parent;
4575 if (cur == NULL) return(NULL);
4576 if (cur == ctxt->context->node) return(NULL);
4577 if (cur->next != NULL) {
4578 cur = cur->next;
4579 return(cur);
4580 }
4581 } while (cur != NULL);
4582 return(cur);
4583}
4584
4585/**
4586 * xmlXPathNextDescendantOrSelf:
4587 * @ctxt: the XPath Parser context
4588 * @cur: the current node in the traversal
4589 *
4590 * Traversal function for the "descendant-or-self" direction
4591 * the descendant-or-self axis contains the context node and the descendants
4592 * of the context node in document order; thus the context node is the first
4593 * node on the axis, and the first child of the context node is the second node
4594 * on the axis
4595 *
4596 * Returns the next element following that axis
4597 */
4598xmlNodePtr
4599xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4600 if (cur == NULL) {
4601 if (ctxt->context->node == NULL)
4602 return(NULL);
4603 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4604 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4605 return(NULL);
4606 return(ctxt->context->node);
4607 }
4608
4609 return(xmlXPathNextDescendant(ctxt, cur));
4610}
4611
4612/**
4613 * xmlXPathNextParent:
4614 * @ctxt: the XPath Parser context
4615 * @cur: the current node in the traversal
4616 *
4617 * Traversal function for the "parent" direction
4618 * The parent axis contains the parent of the context node, if there is one.
4619 *
4620 * Returns the next element following that axis
4621 */
4622xmlNodePtr
4623xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4624 /*
4625 * the parent of an attribute or namespace node is the element
4626 * to which the attribute or namespace node is attached
4627 * Namespace handling !!!
4628 */
4629 if (cur == NULL) {
4630 if (ctxt->context->node == NULL) return(NULL);
4631 switch (ctxt->context->node->type) {
4632 case XML_ELEMENT_NODE:
4633 case XML_TEXT_NODE:
4634 case XML_CDATA_SECTION_NODE:
4635 case XML_ENTITY_REF_NODE:
4636 case XML_ENTITY_NODE:
4637 case XML_PI_NODE:
4638 case XML_COMMENT_NODE:
4639 case XML_NOTATION_NODE:
4640 case XML_DTD_NODE:
4641 case XML_ELEMENT_DECL:
4642 case XML_ATTRIBUTE_DECL:
4643 case XML_XINCLUDE_START:
4644 case XML_XINCLUDE_END:
4645 case XML_ENTITY_DECL:
4646 if (ctxt->context->node->parent == NULL)
4647 return((xmlNodePtr) ctxt->context->doc);
4648 return(ctxt->context->node->parent);
4649 case XML_ATTRIBUTE_NODE: {
4650 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4651
4652 return(att->parent);
4653 }
4654 case XML_DOCUMENT_NODE:
4655 case XML_DOCUMENT_TYPE_NODE:
4656 case XML_DOCUMENT_FRAG_NODE:
4657 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004658#ifdef LIBXML_DOCB_ENABLED
4659 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004660#endif
4661 return(NULL);
4662 case XML_NAMESPACE_DECL:
4663 /*
4664 * TODO !!! may require extending struct _xmlNs with
4665 * parent field
4666 * C.f. Infoset case...
4667 */
4668 return(NULL);
4669 }
4670 }
4671 return(NULL);
4672}
4673
4674/**
4675 * xmlXPathNextAncestor:
4676 * @ctxt: the XPath Parser context
4677 * @cur: the current node in the traversal
4678 *
4679 * Traversal function for the "ancestor" direction
4680 * the ancestor axis contains the ancestors of the context node; the ancestors
4681 * of the context node consist of the parent of context node and the parent's
4682 * parent and so on; the nodes are ordered in reverse document order; thus the
4683 * parent is the first node on the axis, and the parent's parent is the second
4684 * node on the axis
4685 *
4686 * Returns the next element following that axis
4687 */
4688xmlNodePtr
4689xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4690 /*
4691 * the parent of an attribute or namespace node is the element
4692 * to which the attribute or namespace node is attached
4693 * !!!!!!!!!!!!!
4694 */
4695 if (cur == NULL) {
4696 if (ctxt->context->node == NULL) return(NULL);
4697 switch (ctxt->context->node->type) {
4698 case XML_ELEMENT_NODE:
4699 case XML_TEXT_NODE:
4700 case XML_CDATA_SECTION_NODE:
4701 case XML_ENTITY_REF_NODE:
4702 case XML_ENTITY_NODE:
4703 case XML_PI_NODE:
4704 case XML_COMMENT_NODE:
4705 case XML_DTD_NODE:
4706 case XML_ELEMENT_DECL:
4707 case XML_ATTRIBUTE_DECL:
4708 case XML_ENTITY_DECL:
4709 case XML_NOTATION_NODE:
4710 case XML_XINCLUDE_START:
4711 case XML_XINCLUDE_END:
4712 if (ctxt->context->node->parent == NULL)
4713 return((xmlNodePtr) ctxt->context->doc);
4714 return(ctxt->context->node->parent);
4715 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004716 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00004717
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004718 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00004719 }
4720 case XML_DOCUMENT_NODE:
4721 case XML_DOCUMENT_TYPE_NODE:
4722 case XML_DOCUMENT_FRAG_NODE:
4723 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004724#ifdef LIBXML_DOCB_ENABLED
4725 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004726#endif
4727 return(NULL);
4728 case XML_NAMESPACE_DECL:
4729 /*
4730 * TODO !!! may require extending struct _xmlNs with
4731 * parent field
4732 * C.f. Infoset case...
4733 */
4734 return(NULL);
4735 }
4736 return(NULL);
4737 }
4738 if (cur == ctxt->context->doc->children)
4739 return((xmlNodePtr) ctxt->context->doc);
4740 if (cur == (xmlNodePtr) ctxt->context->doc)
4741 return(NULL);
4742 switch (cur->type) {
4743 case XML_ELEMENT_NODE:
4744 case XML_TEXT_NODE:
4745 case XML_CDATA_SECTION_NODE:
4746 case XML_ENTITY_REF_NODE:
4747 case XML_ENTITY_NODE:
4748 case XML_PI_NODE:
4749 case XML_COMMENT_NODE:
4750 case XML_NOTATION_NODE:
4751 case XML_DTD_NODE:
4752 case XML_ELEMENT_DECL:
4753 case XML_ATTRIBUTE_DECL:
4754 case XML_ENTITY_DECL:
4755 case XML_XINCLUDE_START:
4756 case XML_XINCLUDE_END:
4757 return(cur->parent);
4758 case XML_ATTRIBUTE_NODE: {
4759 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4760
4761 return(att->parent);
4762 }
4763 case XML_DOCUMENT_NODE:
4764 case XML_DOCUMENT_TYPE_NODE:
4765 case XML_DOCUMENT_FRAG_NODE:
4766 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004767#ifdef LIBXML_DOCB_ENABLED
4768 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004769#endif
4770 return(NULL);
4771 case XML_NAMESPACE_DECL:
4772 /*
4773 * TODO !!! may require extending struct _xmlNs with
4774 * parent field
4775 * C.f. Infoset case...
4776 */
4777 return(NULL);
4778 }
4779 return(NULL);
4780}
4781
4782/**
4783 * xmlXPathNextAncestorOrSelf:
4784 * @ctxt: the XPath Parser context
4785 * @cur: the current node in the traversal
4786 *
4787 * Traversal function for the "ancestor-or-self" direction
4788 * he ancestor-or-self axis contains the context node and ancestors of
4789 * the context node in reverse document order; thus the context node is
4790 * the first node on the axis, and the context node's parent the second;
4791 * parent here is defined the same as with the parent axis.
4792 *
4793 * Returns the next element following that axis
4794 */
4795xmlNodePtr
4796xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4797 if (cur == NULL)
4798 return(ctxt->context->node);
4799 return(xmlXPathNextAncestor(ctxt, cur));
4800}
4801
4802/**
4803 * xmlXPathNextFollowingSibling:
4804 * @ctxt: the XPath Parser context
4805 * @cur: the current node in the traversal
4806 *
4807 * Traversal function for the "following-sibling" direction
4808 * The following-sibling axis contains the following siblings of the context
4809 * node in document order.
4810 *
4811 * Returns the next element following that axis
4812 */
4813xmlNodePtr
4814xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4815 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4816 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4817 return(NULL);
4818 if (cur == (xmlNodePtr) ctxt->context->doc)
4819 return(NULL);
4820 if (cur == NULL)
4821 return(ctxt->context->node->next);
4822 return(cur->next);
4823}
4824
4825/**
4826 * xmlXPathNextPrecedingSibling:
4827 * @ctxt: the XPath Parser context
4828 * @cur: the current node in the traversal
4829 *
4830 * Traversal function for the "preceding-sibling" direction
4831 * The preceding-sibling axis contains the preceding siblings of the context
4832 * node in reverse document order; the first preceding sibling is first on the
4833 * axis; the sibling preceding that node is the second on the axis and so on.
4834 *
4835 * Returns the next element following that axis
4836 */
4837xmlNodePtr
4838xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4839 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4840 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4841 return(NULL);
4842 if (cur == (xmlNodePtr) ctxt->context->doc)
4843 return(NULL);
4844 if (cur == NULL)
4845 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004846 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
4847 cur = cur->prev;
4848 if (cur == NULL)
4849 return(ctxt->context->node->prev);
4850 }
Owen Taylor3473f882001-02-23 17:55:21 +00004851 return(cur->prev);
4852}
4853
4854/**
4855 * xmlXPathNextFollowing:
4856 * @ctxt: the XPath Parser context
4857 * @cur: the current node in the traversal
4858 *
4859 * Traversal function for the "following" direction
4860 * The following axis contains all nodes in the same document as the context
4861 * node that are after the context node in document order, excluding any
4862 * descendants and excluding attribute nodes and namespace nodes; the nodes
4863 * are ordered in document order
4864 *
4865 * Returns the next element following that axis
4866 */
4867xmlNodePtr
4868xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4869 if (cur != NULL && cur->children != NULL)
4870 return cur->children ;
4871 if (cur == NULL) cur = ctxt->context->node;
4872 if (cur == NULL) return(NULL) ; /* ERROR */
4873 if (cur->next != NULL) return(cur->next) ;
4874 do {
4875 cur = cur->parent;
4876 if (cur == NULL) return(NULL);
4877 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
4878 if (cur->next != NULL) return(cur->next);
4879 } while (cur != NULL);
4880 return(cur);
4881}
4882
4883/*
4884 * xmlXPathIsAncestor:
4885 * @ancestor: the ancestor node
4886 * @node: the current node
4887 *
4888 * Check that @ancestor is a @node's ancestor
4889 *
4890 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
4891 */
4892static int
4893xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
4894 if ((ancestor == NULL) || (node == NULL)) return(0);
4895 /* nodes need to be in the same document */
4896 if (ancestor->doc != node->doc) return(0);
4897 /* avoid searching if ancestor or node is the root node */
4898 if (ancestor == (xmlNodePtr) node->doc) return(1);
4899 if (node == (xmlNodePtr) ancestor->doc) return(0);
4900 while (node->parent != NULL) {
4901 if (node->parent == ancestor)
4902 return(1);
4903 node = node->parent;
4904 }
4905 return(0);
4906}
4907
4908/**
4909 * xmlXPathNextPreceding:
4910 * @ctxt: the XPath Parser context
4911 * @cur: the current node in the traversal
4912 *
4913 * Traversal function for the "preceding" direction
4914 * the preceding axis contains all nodes in the same document as the context
4915 * node that are before the context node in document order, excluding any
4916 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4917 * ordered in reverse document order
4918 *
4919 * Returns the next element following that axis
4920 */
4921xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00004922xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
4923{
Owen Taylor3473f882001-02-23 17:55:21 +00004924 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004925 cur = ctxt->context->node;
4926 if (cur == NULL)
4927 return (NULL);
4928 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
4929 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00004930 do {
4931 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004932 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
4933 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004934 }
4935
4936 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004937 if (cur == NULL)
4938 return (NULL);
4939 if (cur == ctxt->context->doc->children)
4940 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004941 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00004942 return (cur);
4943}
4944
4945/**
4946 * xmlXPathNextPrecedingInternal:
4947 * @ctxt: the XPath Parser context
4948 * @cur: the current node in the traversal
4949 *
4950 * Traversal function for the "preceding" direction
4951 * the preceding axis contains all nodes in the same document as the context
4952 * node that are before the context node in document order, excluding any
4953 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4954 * ordered in reverse document order
4955 * This is a faster implementation but internal only since it requires a
4956 * state kept in the parser context: ctxt->ancestor.
4957 *
4958 * Returns the next element following that axis
4959 */
4960static xmlNodePtr
4961xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
4962 xmlNodePtr cur)
4963{
4964 if (cur == NULL) {
4965 cur = ctxt->context->node;
4966 if (cur == NULL)
4967 return (NULL);
4968 ctxt->ancestor = cur->parent;
4969 }
4970 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
4971 cur = cur->prev;
4972 while (cur->prev == NULL) {
4973 cur = cur->parent;
4974 if (cur == NULL)
4975 return (NULL);
4976 if (cur == ctxt->context->doc->children)
4977 return (NULL);
4978 if (cur != ctxt->ancestor)
4979 return (cur);
4980 ctxt->ancestor = cur->parent;
4981 }
4982 cur = cur->prev;
4983 while (cur->last != NULL)
4984 cur = cur->last;
4985 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004986}
4987
4988/**
4989 * xmlXPathNextNamespace:
4990 * @ctxt: the XPath Parser context
4991 * @cur: the current attribute in the traversal
4992 *
4993 * Traversal function for the "namespace" direction
4994 * the namespace axis contains the namespace nodes of the context node;
4995 * the order of nodes on this axis is implementation-defined; the axis will
4996 * be empty unless the context node is an element
4997 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00004998 * We keep the XML namespace node at the end of the list.
4999 *
Owen Taylor3473f882001-02-23 17:55:21 +00005000 * Returns the next element following that axis
5001 */
5002xmlNodePtr
5003xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005004 xmlNodePtr ret;
5005
Owen Taylor3473f882001-02-23 17:55:21 +00005006 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005007 if (cur == (xmlNodePtr) xmlXPathXMLNamespace)
5008 return(NULL);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005009 if ((cur == NULL) || (ctxt->context->tmpNsList == NULL)) {
5010 if (ctxt->context->tmpNsList != NULL)
5011 xmlFree(ctxt->context->tmpNsList);
5012 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005013 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005014 if (ctxt->context->tmpNsList == NULL) return(NULL);
5015 ctxt->context->tmpNsNr = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005016 }
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005017 ret = (xmlNodePtr)ctxt->context->tmpNsList[ctxt->context->tmpNsNr++];
5018 if (ret == NULL) {
5019 xmlFree(ctxt->context->tmpNsList);
5020 ctxt->context->tmpNsList = NULL;
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005021 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005022 }
5023 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005024}
5025
5026/**
5027 * xmlXPathNextAttribute:
5028 * @ctxt: the XPath Parser context
5029 * @cur: the current attribute in the traversal
5030 *
5031 * Traversal function for the "attribute" direction
5032 * TODO: support DTD inherited default attributes
5033 *
5034 * Returns the next element following that axis
5035 */
5036xmlNodePtr
5037xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005038 if (ctxt->context->node == NULL)
5039 return(NULL);
5040 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5041 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005042 if (cur == NULL) {
5043 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5044 return(NULL);
5045 return((xmlNodePtr)ctxt->context->node->properties);
5046 }
5047 return((xmlNodePtr)cur->next);
5048}
5049
5050/************************************************************************
5051 * *
5052 * NodeTest Functions *
5053 * *
5054 ************************************************************************/
5055
Owen Taylor3473f882001-02-23 17:55:21 +00005056#define IS_FUNCTION 200
5057
Owen Taylor3473f882001-02-23 17:55:21 +00005058
5059/************************************************************************
5060 * *
5061 * Implicit tree core function library *
5062 * *
5063 ************************************************************************/
5064
5065/**
5066 * xmlXPathRoot:
5067 * @ctxt: the XPath Parser context
5068 *
5069 * Initialize the context to the root of the document
5070 */
5071void
5072xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5073 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5074 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5075}
5076
5077/************************************************************************
5078 * *
5079 * The explicit core function library *
5080 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5081 * *
5082 ************************************************************************/
5083
5084
5085/**
5086 * xmlXPathLastFunction:
5087 * @ctxt: the XPath Parser context
5088 * @nargs: the number of arguments
5089 *
5090 * Implement the last() XPath function
5091 * number last()
5092 * The last function returns the number of nodes in the context node list.
5093 */
5094void
5095xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5096 CHECK_ARITY(0);
5097 if (ctxt->context->contextSize >= 0) {
5098 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5099#ifdef DEBUG_EXPR
5100 xmlGenericError(xmlGenericErrorContext,
5101 "last() : %d\n", ctxt->context->contextSize);
5102#endif
5103 } else {
5104 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5105 }
5106}
5107
5108/**
5109 * xmlXPathPositionFunction:
5110 * @ctxt: the XPath Parser context
5111 * @nargs: the number of arguments
5112 *
5113 * Implement the position() XPath function
5114 * number position()
5115 * The position function returns the position of the context node in the
5116 * context node list. The first position is 1, and so the last positionr
5117 * will be equal to last().
5118 */
5119void
5120xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5121 CHECK_ARITY(0);
5122 if (ctxt->context->proximityPosition >= 0) {
5123 valuePush(ctxt,
5124 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5125#ifdef DEBUG_EXPR
5126 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5127 ctxt->context->proximityPosition);
5128#endif
5129 } else {
5130 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5131 }
5132}
5133
5134/**
5135 * xmlXPathCountFunction:
5136 * @ctxt: the XPath Parser context
5137 * @nargs: the number of arguments
5138 *
5139 * Implement the count() XPath function
5140 * number count(node-set)
5141 */
5142void
5143xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5144 xmlXPathObjectPtr cur;
5145
5146 CHECK_ARITY(1);
5147 if ((ctxt->value == NULL) ||
5148 ((ctxt->value->type != XPATH_NODESET) &&
5149 (ctxt->value->type != XPATH_XSLT_TREE)))
5150 XP_ERROR(XPATH_INVALID_TYPE);
5151 cur = valuePop(ctxt);
5152
Daniel Veillard911f49a2001-04-07 15:39:35 +00005153 if ((cur == NULL) || (cur->nodesetval == NULL))
5154 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00005155 else if (cur->type == XPATH_NODESET) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005156 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005157 } else {
5158 if ((cur->nodesetval->nodeNr != 1) ||
5159 (cur->nodesetval->nodeTab == NULL)) {
5160 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5161 } else {
5162 xmlNodePtr tmp;
5163 int i = 0;
5164
5165 tmp = cur->nodesetval->nodeTab[0];
5166 if (tmp != NULL) {
5167 tmp = tmp->children;
5168 while (tmp != NULL) {
5169 tmp = tmp->next;
5170 i++;
5171 }
5172 }
5173 valuePush(ctxt, xmlXPathNewFloat((double) i));
5174 }
5175 }
Owen Taylor3473f882001-02-23 17:55:21 +00005176 xmlXPathFreeObject(cur);
5177}
5178
5179/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005180 * xmlXPathGetElementsByIds:
5181 * @doc: the document
5182 * @ids: a whitespace separated list of IDs
5183 *
5184 * Selects elements by their unique ID.
5185 *
5186 * Returns a node-set of selected elements.
5187 */
5188static xmlNodeSetPtr
5189xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5190 xmlNodeSetPtr ret;
5191 const xmlChar *cur = ids;
5192 xmlChar *ID;
5193 xmlAttrPtr attr;
5194 xmlNodePtr elem = NULL;
5195
5196 ret = xmlXPathNodeSetCreate(NULL);
5197
5198 while (IS_BLANK(*cur)) cur++;
5199 while (*cur != 0) {
5200 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
5201 (*cur == '.') || (*cur == '-') ||
5202 (*cur == '_') || (*cur == ':') ||
5203 (IS_COMBINING(*cur)) ||
5204 (IS_EXTENDER(*cur)))
5205 cur++;
5206
5207 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
5208
5209 ID = xmlStrndup(ids, cur - ids);
5210 attr = xmlGetID(doc, ID);
5211 if (attr != NULL) {
5212 elem = attr->parent;
5213 xmlXPathNodeSetAdd(ret, elem);
5214 }
5215 if (ID != NULL)
5216 xmlFree(ID);
5217
5218 while (IS_BLANK(*cur)) cur++;
5219 ids = cur;
5220 }
5221 return(ret);
5222}
5223
5224/**
Owen Taylor3473f882001-02-23 17:55:21 +00005225 * xmlXPathIdFunction:
5226 * @ctxt: the XPath Parser context
5227 * @nargs: the number of arguments
5228 *
5229 * Implement the id() XPath function
5230 * node-set id(object)
5231 * The id function selects elements by their unique ID
5232 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5233 * then the result is the union of the result of applying id to the
5234 * string value of each of the nodes in the argument node-set. When the
5235 * argument to id is of any other type, the argument is converted to a
5236 * string as if by a call to the string function; the string is split
5237 * into a whitespace-separated list of tokens (whitespace is any sequence
5238 * of characters matching the production S); the result is a node-set
5239 * containing the elements in the same document as the context node that
5240 * have a unique ID equal to any of the tokens in the list.
5241 */
5242void
5243xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005244 xmlChar *tokens;
5245 xmlNodeSetPtr ret;
5246 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00005247
5248 CHECK_ARITY(1);
5249 obj = valuePop(ctxt);
5250 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
5251 if (obj->type == XPATH_NODESET) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005252 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00005253 int i;
5254
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005255 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005256
Daniel Veillard911f49a2001-04-07 15:39:35 +00005257 if (obj->nodesetval != NULL) {
5258 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005259 tokens =
5260 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
5261 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
5262 ret = xmlXPathNodeSetMerge(ret, ns);
5263 xmlXPathFreeNodeSet(ns);
5264 if (tokens != NULL)
5265 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00005266 }
Owen Taylor3473f882001-02-23 17:55:21 +00005267 }
5268
5269 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005270 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005271 return;
5272 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005273 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00005274
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005275 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
5276 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005277
Owen Taylor3473f882001-02-23 17:55:21 +00005278 xmlXPathFreeObject(obj);
5279 return;
5280}
5281
5282/**
5283 * xmlXPathLocalNameFunction:
5284 * @ctxt: the XPath Parser context
5285 * @nargs: the number of arguments
5286 *
5287 * Implement the local-name() XPath function
5288 * string local-name(node-set?)
5289 * The local-name function returns a string containing the local part
5290 * of the name of the node in the argument node-set that is first in
5291 * document order. If the node-set is empty or the first node has no
5292 * name, an empty string is returned. If the argument is omitted it
5293 * defaults to the context node.
5294 */
5295void
5296xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5297 xmlXPathObjectPtr cur;
5298
5299 if (nargs == 0) {
5300 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5301 nargs = 1;
5302 }
5303
5304 CHECK_ARITY(1);
5305 if ((ctxt->value == NULL) ||
5306 ((ctxt->value->type != XPATH_NODESET) &&
5307 (ctxt->value->type != XPATH_XSLT_TREE)))
5308 XP_ERROR(XPATH_INVALID_TYPE);
5309 cur = valuePop(ctxt);
5310
Daniel Veillard911f49a2001-04-07 15:39:35 +00005311 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005312 valuePush(ctxt, xmlXPathNewCString(""));
5313 } else {
5314 int i = 0; /* Should be first in document order !!!!! */
5315 switch (cur->nodesetval->nodeTab[i]->type) {
5316 case XML_ELEMENT_NODE:
5317 case XML_ATTRIBUTE_NODE:
5318 case XML_PI_NODE:
5319 valuePush(ctxt,
5320 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
5321 break;
5322 case XML_NAMESPACE_DECL:
5323 valuePush(ctxt, xmlXPathNewString(
5324 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
5325 break;
5326 default:
5327 valuePush(ctxt, xmlXPathNewCString(""));
5328 }
5329 }
5330 xmlXPathFreeObject(cur);
5331}
5332
5333/**
5334 * xmlXPathNamespaceURIFunction:
5335 * @ctxt: the XPath Parser context
5336 * @nargs: the number of arguments
5337 *
5338 * Implement the namespace-uri() XPath function
5339 * string namespace-uri(node-set?)
5340 * The namespace-uri function returns a string containing the
5341 * namespace URI of the expanded name of the node in the argument
5342 * node-set that is first in document order. If the node-set is empty,
5343 * the first node has no name, or the expanded name has no namespace
5344 * URI, an empty string is returned. If the argument is omitted it
5345 * defaults to the context node.
5346 */
5347void
5348xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5349 xmlXPathObjectPtr cur;
5350
5351 if (nargs == 0) {
5352 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5353 nargs = 1;
5354 }
5355 CHECK_ARITY(1);
5356 if ((ctxt->value == NULL) ||
5357 ((ctxt->value->type != XPATH_NODESET) &&
5358 (ctxt->value->type != XPATH_XSLT_TREE)))
5359 XP_ERROR(XPATH_INVALID_TYPE);
5360 cur = valuePop(ctxt);
5361
Daniel Veillard911f49a2001-04-07 15:39:35 +00005362 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005363 valuePush(ctxt, xmlXPathNewCString(""));
5364 } else {
5365 int i = 0; /* Should be first in document order !!!!! */
5366 switch (cur->nodesetval->nodeTab[i]->type) {
5367 case XML_ELEMENT_NODE:
5368 case XML_ATTRIBUTE_NODE:
5369 if (cur->nodesetval->nodeTab[i]->ns == NULL)
5370 valuePush(ctxt, xmlXPathNewCString(""));
5371 else
5372 valuePush(ctxt, xmlXPathNewString(
5373 cur->nodesetval->nodeTab[i]->ns->href));
5374 break;
5375 default:
5376 valuePush(ctxt, xmlXPathNewCString(""));
5377 }
5378 }
5379 xmlXPathFreeObject(cur);
5380}
5381
5382/**
5383 * xmlXPathNameFunction:
5384 * @ctxt: the XPath Parser context
5385 * @nargs: the number of arguments
5386 *
5387 * Implement the name() XPath function
5388 * string name(node-set?)
5389 * The name function returns a string containing a QName representing
5390 * the name of the node in the argument node-set that is first in documenti
5391 * order. The QName must represent the name with respect to the namespace
5392 * declarations in effect on the node whose name is being represented.
5393 * Typically, this will be the form in which the name occurred in the XML
5394 * source. This need not be the case if there are namespace declarations
5395 * in effect on the node that associate multiple prefixes with the same
5396 * namespace. However, an implementation may include information about
5397 * the original prefix in its representation of nodes; in this case, an
5398 * implementation can ensure that the returned string is always the same
5399 * as the QName used in the XML source. If the argument it omitted it
5400 * defaults to the context node.
5401 * Libxml keep the original prefix so the "real qualified name" used is
5402 * returned.
5403 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005404static void
Daniel Veillard04383752001-07-08 14:27:15 +00005405xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
5406{
Owen Taylor3473f882001-02-23 17:55:21 +00005407 xmlXPathObjectPtr cur;
5408
5409 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00005410 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5411 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00005412 }
5413
5414 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00005415 if ((ctxt->value == NULL) ||
5416 ((ctxt->value->type != XPATH_NODESET) &&
5417 (ctxt->value->type != XPATH_XSLT_TREE)))
5418 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00005419 cur = valuePop(ctxt);
5420
Daniel Veillard911f49a2001-04-07 15:39:35 +00005421 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00005422 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00005423 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00005424 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005425
Daniel Veillard04383752001-07-08 14:27:15 +00005426 switch (cur->nodesetval->nodeTab[i]->type) {
5427 case XML_ELEMENT_NODE:
5428 case XML_ATTRIBUTE_NODE:
5429 if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
5430 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL))
5431 valuePush(ctxt,
5432 xmlXPathNewString(cur->nodesetval->
5433 nodeTab[i]->name));
5434
5435 else {
5436 char name[2000];
5437
5438 snprintf(name, sizeof(name), "%s:%s",
5439 (char *) cur->nodesetval->nodeTab[i]->ns->
5440 prefix,
5441 (char *) cur->nodesetval->nodeTab[i]->name);
5442 name[sizeof(name) - 1] = 0;
5443 valuePush(ctxt, xmlXPathNewCString(name));
5444 }
5445 break;
5446 default:
5447 valuePush(ctxt,
5448 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
5449 xmlXPathLocalNameFunction(ctxt, 1);
5450 }
Owen Taylor3473f882001-02-23 17:55:21 +00005451 }
5452 xmlXPathFreeObject(cur);
5453}
5454
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005455
5456/**
Owen Taylor3473f882001-02-23 17:55:21 +00005457 * xmlXPathStringFunction:
5458 * @ctxt: the XPath Parser context
5459 * @nargs: the number of arguments
5460 *
5461 * Implement the string() XPath function
5462 * string string(object?)
5463 * he string function converts an object to a string as follows:
5464 * - A node-set is converted to a string by returning the value of
5465 * the node in the node-set that is first in document order.
5466 * If the node-set is empty, an empty string is returned.
5467 * - A number is converted to a string as follows
5468 * + NaN is converted to the string NaN
5469 * + positive zero is converted to the string 0
5470 * + negative zero is converted to the string 0
5471 * + positive infinity is converted to the string Infinity
5472 * + negative infinity is converted to the string -Infinity
5473 * + if the number is an integer, the number is represented in
5474 * decimal form as a Number with no decimal point and no leading
5475 * zeros, preceded by a minus sign (-) if the number is negative
5476 * + otherwise, the number is represented in decimal form as a
5477 * Number including a decimal point with at least one digit
5478 * before the decimal point and at least one digit after the
5479 * decimal point, preceded by a minus sign (-) if the number
5480 * is negative; there must be no leading zeros before the decimal
5481 * point apart possibly from the one required digit immediatelyi
5482 * before the decimal point; beyond the one required digit
5483 * after the decimal point there must be as many, but only as
5484 * many, more digits as are needed to uniquely distinguish the
5485 * number from all other IEEE 754 numeric values.
5486 * - The boolean false value is converted to the string false.
5487 * The boolean true value is converted to the string true.
5488 *
5489 * If the argument is omitted, it defaults to a node-set with the
5490 * context node as its only member.
5491 */
5492void
5493xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5494 xmlXPathObjectPtr cur;
5495
5496 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005497 valuePush(ctxt,
5498 xmlXPathWrapString(
5499 xmlXPathCastNodeToString(ctxt->context->node)));
5500 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005501 }
5502
5503 CHECK_ARITY(1);
5504 cur = valuePop(ctxt);
5505 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005506 cur = xmlXPathConvertString(cur);
5507 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005508}
5509
5510/**
5511 * xmlXPathStringLengthFunction:
5512 * @ctxt: the XPath Parser context
5513 * @nargs: the number of arguments
5514 *
5515 * Implement the string-length() XPath function
5516 * number string-length(string?)
5517 * The string-length returns the number of characters in the string
5518 * (see [3.6 Strings]). If the argument is omitted, it defaults to
5519 * the context node converted to a string, in other words the value
5520 * of the context node.
5521 */
5522void
5523xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5524 xmlXPathObjectPtr cur;
5525
5526 if (nargs == 0) {
5527 if (ctxt->context->node == NULL) {
5528 valuePush(ctxt, xmlXPathNewFloat(0));
5529 } else {
5530 xmlChar *content;
5531
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005532 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005533 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00005534 xmlFree(content);
5535 }
5536 return;
5537 }
5538 CHECK_ARITY(1);
5539 CAST_TO_STRING;
5540 CHECK_TYPE(XPATH_STRING);
5541 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005542 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00005543 xmlXPathFreeObject(cur);
5544}
5545
5546/**
5547 * xmlXPathConcatFunction:
5548 * @ctxt: the XPath Parser context
5549 * @nargs: the number of arguments
5550 *
5551 * Implement the concat() XPath function
5552 * string concat(string, string, string*)
5553 * The concat function returns the concatenation of its arguments.
5554 */
5555void
5556xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5557 xmlXPathObjectPtr cur, newobj;
5558 xmlChar *tmp;
5559
5560 if (nargs < 2) {
5561 CHECK_ARITY(2);
5562 }
5563
5564 CAST_TO_STRING;
5565 cur = valuePop(ctxt);
5566 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
5567 xmlXPathFreeObject(cur);
5568 return;
5569 }
5570 nargs--;
5571
5572 while (nargs > 0) {
5573 CAST_TO_STRING;
5574 newobj = valuePop(ctxt);
5575 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
5576 xmlXPathFreeObject(newobj);
5577 xmlXPathFreeObject(cur);
5578 XP_ERROR(XPATH_INVALID_TYPE);
5579 }
5580 tmp = xmlStrcat(newobj->stringval, cur->stringval);
5581 newobj->stringval = cur->stringval;
5582 cur->stringval = tmp;
5583
5584 xmlXPathFreeObject(newobj);
5585 nargs--;
5586 }
5587 valuePush(ctxt, cur);
5588}
5589
5590/**
5591 * xmlXPathContainsFunction:
5592 * @ctxt: the XPath Parser context
5593 * @nargs: the number of arguments
5594 *
5595 * Implement the contains() XPath function
5596 * boolean contains(string, string)
5597 * The contains function returns true if the first argument string
5598 * contains the second argument string, and otherwise returns false.
5599 */
5600void
5601xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5602 xmlXPathObjectPtr hay, needle;
5603
5604 CHECK_ARITY(2);
5605 CAST_TO_STRING;
5606 CHECK_TYPE(XPATH_STRING);
5607 needle = valuePop(ctxt);
5608 CAST_TO_STRING;
5609 hay = valuePop(ctxt);
5610 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5611 xmlXPathFreeObject(hay);
5612 xmlXPathFreeObject(needle);
5613 XP_ERROR(XPATH_INVALID_TYPE);
5614 }
5615 if (xmlStrstr(hay->stringval, needle->stringval))
5616 valuePush(ctxt, xmlXPathNewBoolean(1));
5617 else
5618 valuePush(ctxt, xmlXPathNewBoolean(0));
5619 xmlXPathFreeObject(hay);
5620 xmlXPathFreeObject(needle);
5621}
5622
5623/**
5624 * xmlXPathStartsWithFunction:
5625 * @ctxt: the XPath Parser context
5626 * @nargs: the number of arguments
5627 *
5628 * Implement the starts-with() XPath function
5629 * boolean starts-with(string, string)
5630 * The starts-with function returns true if the first argument string
5631 * starts with the second argument string, and otherwise returns false.
5632 */
5633void
5634xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5635 xmlXPathObjectPtr hay, needle;
5636 int n;
5637
5638 CHECK_ARITY(2);
5639 CAST_TO_STRING;
5640 CHECK_TYPE(XPATH_STRING);
5641 needle = valuePop(ctxt);
5642 CAST_TO_STRING;
5643 hay = valuePop(ctxt);
5644 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5645 xmlXPathFreeObject(hay);
5646 xmlXPathFreeObject(needle);
5647 XP_ERROR(XPATH_INVALID_TYPE);
5648 }
5649 n = xmlStrlen(needle->stringval);
5650 if (xmlStrncmp(hay->stringval, needle->stringval, n))
5651 valuePush(ctxt, xmlXPathNewBoolean(0));
5652 else
5653 valuePush(ctxt, xmlXPathNewBoolean(1));
5654 xmlXPathFreeObject(hay);
5655 xmlXPathFreeObject(needle);
5656}
5657
5658/**
5659 * xmlXPathSubstringFunction:
5660 * @ctxt: the XPath Parser context
5661 * @nargs: the number of arguments
5662 *
5663 * Implement the substring() XPath function
5664 * string substring(string, number, number?)
5665 * The substring function returns the substring of the first argument
5666 * starting at the position specified in the second argument with
5667 * length specified in the third argument. For example,
5668 * substring("12345",2,3) returns "234". If the third argument is not
5669 * specified, it returns the substring starting at the position specified
5670 * in the second argument and continuing to the end of the string. For
5671 * example, substring("12345",2) returns "2345". More precisely, each
5672 * character in the string (see [3.6 Strings]) is considered to have a
5673 * numeric position: the position of the first character is 1, the position
5674 * of the second character is 2 and so on. The returned substring contains
5675 * those characters for which the position of the character is greater than
5676 * or equal to the second argument and, if the third argument is specified,
5677 * less than the sum of the second and third arguments; the comparisons
5678 * and addition used for the above follow the standard IEEE 754 rules. Thus:
5679 * - substring("12345", 1.5, 2.6) returns "234"
5680 * - substring("12345", 0, 3) returns "12"
5681 * - substring("12345", 0 div 0, 3) returns ""
5682 * - substring("12345", 1, 0 div 0) returns ""
5683 * - substring("12345", -42, 1 div 0) returns "12345"
5684 * - substring("12345", -1 div 0, 1 div 0) returns ""
5685 */
5686void
5687xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5688 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005689 double le=0, in;
5690 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00005691 xmlChar *ret;
5692
Owen Taylor3473f882001-02-23 17:55:21 +00005693 if (nargs < 2) {
5694 CHECK_ARITY(2);
5695 }
5696 if (nargs > 3) {
5697 CHECK_ARITY(3);
5698 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005699 /*
5700 * take care of possible last (position) argument
5701 */
Owen Taylor3473f882001-02-23 17:55:21 +00005702 if (nargs == 3) {
5703 CAST_TO_NUMBER;
5704 CHECK_TYPE(XPATH_NUMBER);
5705 len = valuePop(ctxt);
5706 le = len->floatval;
5707 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00005708 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005709
Owen Taylor3473f882001-02-23 17:55:21 +00005710 CAST_TO_NUMBER;
5711 CHECK_TYPE(XPATH_NUMBER);
5712 start = valuePop(ctxt);
5713 in = start->floatval;
5714 xmlXPathFreeObject(start);
5715 CAST_TO_STRING;
5716 CHECK_TYPE(XPATH_STRING);
5717 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00005718 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005719
Daniel Veillard97ac1312001-05-30 19:14:17 +00005720 /*
5721 * If last pos not present, calculate last position
5722 */
5723 if (nargs != 3)
5724 le = m;
5725
5726 /*
5727 * To meet our requirements, initial index calculations
5728 * must be done before we convert to integer format
5729 *
5730 * First we normalize indices
5731 */
5732 in -= 1.0;
5733 le += in;
5734 if (in < 0.0)
5735 in = 0.0;
5736 if (le > (double)m)
5737 le = (double)m;
5738
5739 /*
5740 * Now we go to integer form, rounding up
5741 */
Owen Taylor3473f882001-02-23 17:55:21 +00005742 i = (int) in;
5743 if (((double)i) != in) i++;
5744
Owen Taylor3473f882001-02-23 17:55:21 +00005745 l = (int) le;
5746 if (((double)l) != le) l++;
5747
Daniel Veillard97ac1312001-05-30 19:14:17 +00005748 if (l > m) l=m;
Owen Taylor3473f882001-02-23 17:55:21 +00005749
5750 /* number of chars to copy */
5751 l -= i;
5752
Daniel Veillard97ac1312001-05-30 19:14:17 +00005753 ret = xmlUTF8Strsub(str->stringval, i, l);
Owen Taylor3473f882001-02-23 17:55:21 +00005754 if (ret == NULL)
5755 valuePush(ctxt, xmlXPathNewCString(""));
5756 else {
5757 valuePush(ctxt, xmlXPathNewString(ret));
5758 xmlFree(ret);
5759 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005760
Owen Taylor3473f882001-02-23 17:55:21 +00005761 xmlXPathFreeObject(str);
5762}
5763
5764/**
5765 * xmlXPathSubstringBeforeFunction:
5766 * @ctxt: the XPath Parser context
5767 * @nargs: the number of arguments
5768 *
5769 * Implement the substring-before() XPath function
5770 * string substring-before(string, string)
5771 * The substring-before function returns the substring of the first
5772 * argument string that precedes the first occurrence of the second
5773 * argument string in the first argument string, or the empty string
5774 * if the first argument string does not contain the second argument
5775 * string. For example, substring-before("1999/04/01","/") returns 1999.
5776 */
5777void
5778xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5779 xmlXPathObjectPtr str;
5780 xmlXPathObjectPtr find;
5781 xmlBufferPtr target;
5782 const xmlChar *point;
5783 int offset;
5784
5785 CHECK_ARITY(2);
5786 CAST_TO_STRING;
5787 find = valuePop(ctxt);
5788 CAST_TO_STRING;
5789 str = valuePop(ctxt);
5790
5791 target = xmlBufferCreate();
5792 if (target) {
5793 point = xmlStrstr(str->stringval, find->stringval);
5794 if (point) {
5795 offset = (int)(point - str->stringval);
5796 xmlBufferAdd(target, str->stringval, offset);
5797 }
5798 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5799 xmlBufferFree(target);
5800 }
5801
5802 xmlXPathFreeObject(str);
5803 xmlXPathFreeObject(find);
5804}
5805
5806/**
5807 * xmlXPathSubstringAfterFunction:
5808 * @ctxt: the XPath Parser context
5809 * @nargs: the number of arguments
5810 *
5811 * Implement the substring-after() XPath function
5812 * string substring-after(string, string)
5813 * The substring-after function returns the substring of the first
5814 * argument string that follows the first occurrence of the second
5815 * argument string in the first argument string, or the empty stringi
5816 * if the first argument string does not contain the second argument
5817 * string. For example, substring-after("1999/04/01","/") returns 04/01,
5818 * and substring-after("1999/04/01","19") returns 99/04/01.
5819 */
5820void
5821xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5822 xmlXPathObjectPtr str;
5823 xmlXPathObjectPtr find;
5824 xmlBufferPtr target;
5825 const xmlChar *point;
5826 int offset;
5827
5828 CHECK_ARITY(2);
5829 CAST_TO_STRING;
5830 find = valuePop(ctxt);
5831 CAST_TO_STRING;
5832 str = valuePop(ctxt);
5833
5834 target = xmlBufferCreate();
5835 if (target) {
5836 point = xmlStrstr(str->stringval, find->stringval);
5837 if (point) {
5838 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
5839 xmlBufferAdd(target, &str->stringval[offset],
5840 xmlStrlen(str->stringval) - offset);
5841 }
5842 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5843 xmlBufferFree(target);
5844 }
5845
5846 xmlXPathFreeObject(str);
5847 xmlXPathFreeObject(find);
5848}
5849
5850/**
5851 * xmlXPathNormalizeFunction:
5852 * @ctxt: the XPath Parser context
5853 * @nargs: the number of arguments
5854 *
5855 * Implement the normalize-space() XPath function
5856 * string normalize-space(string?)
5857 * The normalize-space function returns the argument string with white
5858 * space normalized by stripping leading and trailing whitespace
5859 * and replacing sequences of whitespace characters by a single
5860 * space. Whitespace characters are the same allowed by the S production
5861 * in XML. If the argument is omitted, it defaults to the context
5862 * node converted to a string, in other words the value of the context node.
5863 */
5864void
5865xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5866 xmlXPathObjectPtr obj = NULL;
5867 xmlChar *source = NULL;
5868 xmlBufferPtr target;
5869 xmlChar blank;
5870
5871 if (nargs == 0) {
5872 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005873 valuePush(ctxt,
5874 xmlXPathWrapString(
5875 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00005876 nargs = 1;
5877 }
5878
5879 CHECK_ARITY(1);
5880 CAST_TO_STRING;
5881 CHECK_TYPE(XPATH_STRING);
5882 obj = valuePop(ctxt);
5883 source = obj->stringval;
5884
5885 target = xmlBufferCreate();
5886 if (target && source) {
5887
5888 /* Skip leading whitespaces */
5889 while (IS_BLANK(*source))
5890 source++;
5891
5892 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
5893 blank = 0;
5894 while (*source) {
5895 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005896 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00005897 } else {
5898 if (blank) {
5899 xmlBufferAdd(target, &blank, 1);
5900 blank = 0;
5901 }
5902 xmlBufferAdd(target, source, 1);
5903 }
5904 source++;
5905 }
5906
5907 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5908 xmlBufferFree(target);
5909 }
5910 xmlXPathFreeObject(obj);
5911}
5912
5913/**
5914 * xmlXPathTranslateFunction:
5915 * @ctxt: the XPath Parser context
5916 * @nargs: the number of arguments
5917 *
5918 * Implement the translate() XPath function
5919 * string translate(string, string, string)
5920 * The translate function returns the first argument string with
5921 * occurrences of characters in the second argument string replaced
5922 * by the character at the corresponding position in the third argument
5923 * string. For example, translate("bar","abc","ABC") returns the string
5924 * BAr. If there is a character in the second argument string with no
5925 * character at a corresponding position in the third argument string
5926 * (because the second argument string is longer than the third argument
5927 * string), then occurrences of that character in the first argument
5928 * string are removed. For example, translate("--aaa--","abc-","ABC")
5929 * returns "AAA". If a character occurs more than once in second
5930 * argument string, then the first occurrence determines the replacement
5931 * character. If the third argument string is longer than the second
5932 * argument string, then excess characters are ignored.
5933 */
5934void
5935xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00005936 xmlXPathObjectPtr str;
5937 xmlXPathObjectPtr from;
5938 xmlXPathObjectPtr to;
5939 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005940 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00005941 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005942 xmlChar *point;
5943 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00005944
Daniel Veillarde043ee12001-04-16 14:08:07 +00005945 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00005946
Daniel Veillarde043ee12001-04-16 14:08:07 +00005947 CAST_TO_STRING;
5948 to = valuePop(ctxt);
5949 CAST_TO_STRING;
5950 from = valuePop(ctxt);
5951 CAST_TO_STRING;
5952 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005953
Daniel Veillarde043ee12001-04-16 14:08:07 +00005954 target = xmlBufferCreate();
5955 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005956 max = xmlUTF8Strlen(to->stringval);
5957 for (cptr = str->stringval; (ch=*cptr); ) {
5958 offset = xmlUTF8Strloc(from->stringval, cptr);
5959 if (offset >= 0) {
5960 if (offset < max) {
5961 point = xmlUTF8Strpos(to->stringval, offset);
5962 if (point)
5963 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
5964 }
5965 } else
5966 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
5967
5968 /* Step to next character in input */
5969 cptr++;
5970 if ( ch & 0x80 ) {
5971 /* if not simple ascii, verify proper format */
5972 if ( (ch & 0xc0) != 0xc0 ) {
5973 xmlGenericError(xmlGenericErrorContext,
5974 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5975 break;
5976 }
5977 /* then skip over remaining bytes for this char */
5978 while ( (ch <<= 1) & 0x80 )
5979 if ( (*cptr++ & 0xc0) != 0x80 ) {
5980 xmlGenericError(xmlGenericErrorContext,
5981 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5982 break;
5983 }
5984 if (ch & 0x80) /* must have had error encountered */
5985 break;
5986 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005987 }
Owen Taylor3473f882001-02-23 17:55:21 +00005988 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005989 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5990 xmlBufferFree(target);
5991 xmlXPathFreeObject(str);
5992 xmlXPathFreeObject(from);
5993 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00005994}
5995
5996/**
5997 * xmlXPathBooleanFunction:
5998 * @ctxt: the XPath Parser context
5999 * @nargs: the number of arguments
6000 *
6001 * Implement the boolean() XPath function
6002 * boolean boolean(object)
6003 * he boolean function converts its argument to a boolean as follows:
6004 * - a number is true if and only if it is neither positive or
6005 * negative zero nor NaN
6006 * - a node-set is true if and only if it is non-empty
6007 * - a string is true if and only if its length is non-zero
6008 */
6009void
6010xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6011 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006012
6013 CHECK_ARITY(1);
6014 cur = valuePop(ctxt);
6015 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006016 cur = xmlXPathConvertBoolean(cur);
6017 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006018}
6019
6020/**
6021 * xmlXPathNotFunction:
6022 * @ctxt: the XPath Parser context
6023 * @nargs: the number of arguments
6024 *
6025 * Implement the not() XPath function
6026 * boolean not(boolean)
6027 * The not function returns true if its argument is false,
6028 * and false otherwise.
6029 */
6030void
6031xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6032 CHECK_ARITY(1);
6033 CAST_TO_BOOLEAN;
6034 CHECK_TYPE(XPATH_BOOLEAN);
6035 ctxt->value->boolval = ! ctxt->value->boolval;
6036}
6037
6038/**
6039 * xmlXPathTrueFunction:
6040 * @ctxt: the XPath Parser context
6041 * @nargs: the number of arguments
6042 *
6043 * Implement the true() XPath function
6044 * boolean true()
6045 */
6046void
6047xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6048 CHECK_ARITY(0);
6049 valuePush(ctxt, xmlXPathNewBoolean(1));
6050}
6051
6052/**
6053 * xmlXPathFalseFunction:
6054 * @ctxt: the XPath Parser context
6055 * @nargs: the number of arguments
6056 *
6057 * Implement the false() XPath function
6058 * boolean false()
6059 */
6060void
6061xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6062 CHECK_ARITY(0);
6063 valuePush(ctxt, xmlXPathNewBoolean(0));
6064}
6065
6066/**
6067 * xmlXPathLangFunction:
6068 * @ctxt: the XPath Parser context
6069 * @nargs: the number of arguments
6070 *
6071 * Implement the lang() XPath function
6072 * boolean lang(string)
6073 * The lang function returns true or false depending on whether the
6074 * language of the context node as specified by xml:lang attributes
6075 * is the same as or is a sublanguage of the language specified by
6076 * the argument string. The language of the context node is determined
6077 * by the value of the xml:lang attribute on the context node, or, if
6078 * the context node has no xml:lang attribute, by the value of the
6079 * xml:lang attribute on the nearest ancestor of the context node that
6080 * has an xml:lang attribute. If there is no such attribute, then lang
6081 * returns false. If there is such an attribute, then lang returns
6082 * true if the attribute value is equal to the argument ignoring case,
6083 * or if there is some suffix starting with - such that the attribute
6084 * value is equal to the argument ignoring that suffix of the attribute
6085 * value and ignoring case.
6086 */
6087void
6088xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6089 xmlXPathObjectPtr val;
6090 const xmlChar *theLang;
6091 const xmlChar *lang;
6092 int ret = 0;
6093 int i;
6094
6095 CHECK_ARITY(1);
6096 CAST_TO_STRING;
6097 CHECK_TYPE(XPATH_STRING);
6098 val = valuePop(ctxt);
6099 lang = val->stringval;
6100 theLang = xmlNodeGetLang(ctxt->context->node);
6101 if ((theLang != NULL) && (lang != NULL)) {
6102 for (i = 0;lang[i] != 0;i++)
6103 if (toupper(lang[i]) != toupper(theLang[i]))
6104 goto not_equal;
6105 ret = 1;
6106 }
6107not_equal:
6108 xmlXPathFreeObject(val);
6109 valuePush(ctxt, xmlXPathNewBoolean(ret));
6110}
6111
6112/**
6113 * xmlXPathNumberFunction:
6114 * @ctxt: the XPath Parser context
6115 * @nargs: the number of arguments
6116 *
6117 * Implement the number() XPath function
6118 * number number(object?)
6119 */
6120void
6121xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6122 xmlXPathObjectPtr cur;
6123 double res;
6124
6125 if (nargs == 0) {
6126 if (ctxt->context->node == NULL) {
6127 valuePush(ctxt, xmlXPathNewFloat(0.0));
6128 } else {
6129 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6130
6131 res = xmlXPathStringEvalNumber(content);
6132 valuePush(ctxt, xmlXPathNewFloat(res));
6133 xmlFree(content);
6134 }
6135 return;
6136 }
6137
6138 CHECK_ARITY(1);
6139 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006140 cur = xmlXPathConvertNumber(cur);
6141 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006142}
6143
6144/**
6145 * xmlXPathSumFunction:
6146 * @ctxt: the XPath Parser context
6147 * @nargs: the number of arguments
6148 *
6149 * Implement the sum() XPath function
6150 * number sum(node-set)
6151 * The sum function returns the sum of the values of the nodes in
6152 * the argument node-set.
6153 */
6154void
6155xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6156 xmlXPathObjectPtr cur;
6157 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006158 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006159
6160 CHECK_ARITY(1);
6161 if ((ctxt->value == NULL) ||
6162 ((ctxt->value->type != XPATH_NODESET) &&
6163 (ctxt->value->type != XPATH_XSLT_TREE)))
6164 XP_ERROR(XPATH_INVALID_TYPE);
6165 cur = valuePop(ctxt);
6166
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006167 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006168 valuePush(ctxt, xmlXPathNewFloat(0.0));
6169 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006170 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6171 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006172 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006173 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006174 }
6175 xmlXPathFreeObject(cur);
6176}
6177
6178/**
6179 * xmlXPathFloorFunction:
6180 * @ctxt: the XPath Parser context
6181 * @nargs: the number of arguments
6182 *
6183 * Implement the floor() XPath function
6184 * number floor(number)
6185 * The floor function returns the largest (closest to positive infinity)
6186 * number that is not greater than the argument and that is an integer.
6187 */
6188void
6189xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6190 CHECK_ARITY(1);
6191 CAST_TO_NUMBER;
6192 CHECK_TYPE(XPATH_NUMBER);
6193#if 0
6194 ctxt->value->floatval = floor(ctxt->value->floatval);
6195#else
6196 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
6197 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
6198#endif
6199}
6200
6201/**
6202 * xmlXPathCeilingFunction:
6203 * @ctxt: the XPath Parser context
6204 * @nargs: the number of arguments
6205 *
6206 * Implement the ceiling() XPath function
6207 * number ceiling(number)
6208 * The ceiling function returns the smallest (closest to negative infinity)
6209 * number that is not less than the argument and that is an integer.
6210 */
6211void
6212xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6213 double f;
6214
6215 CHECK_ARITY(1);
6216 CAST_TO_NUMBER;
6217 CHECK_TYPE(XPATH_NUMBER);
6218
6219#if 0
6220 ctxt->value->floatval = ceil(ctxt->value->floatval);
6221#else
6222 f = (double)((int) ctxt->value->floatval);
6223 if (f != ctxt->value->floatval)
6224 ctxt->value->floatval = f + 1;
6225#endif
6226}
6227
6228/**
6229 * xmlXPathRoundFunction:
6230 * @ctxt: the XPath Parser context
6231 * @nargs: the number of arguments
6232 *
6233 * Implement the round() XPath function
6234 * number round(number)
6235 * The round function returns the number that is closest to the
6236 * argument and that is an integer. If there are two such numbers,
6237 * then the one that is even is returned.
6238 */
6239void
6240xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6241 double f;
6242
6243 CHECK_ARITY(1);
6244 CAST_TO_NUMBER;
6245 CHECK_TYPE(XPATH_NUMBER);
6246
Daniel Veillardcda96922001-08-21 10:56:31 +00006247 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
6248 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
6249 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00006250 (ctxt->value->floatval == 0.0))
6251 return;
6252
6253#if 0
6254 f = floor(ctxt->value->floatval);
6255#else
6256 f = (double)((int) ctxt->value->floatval);
6257#endif
6258 if (ctxt->value->floatval < f + 0.5)
6259 ctxt->value->floatval = f;
6260 else
6261 ctxt->value->floatval = f + 1;
6262}
6263
6264/************************************************************************
6265 * *
6266 * The Parser *
6267 * *
6268 ************************************************************************/
6269
6270/*
6271 * a couple of forward declarations since we use a recursive call based
6272 * implementation.
6273 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006274static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006275static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006276static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006277#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006278static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
6279#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006280#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006281static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006282#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00006283static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
6284 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00006285
6286/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00006287 * xmlXPathCurrentChar:
6288 * @ctxt: the XPath parser context
6289 * @cur: pointer to the beginning of the char
6290 * @len: pointer to the length of the char read
6291 *
6292 * The current char value, if using UTF-8 this may actaully span multiple
6293 * bytes in the input buffer.
6294 *
Daniel Veillard60087f32001-10-10 09:45:09 +00006295 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00006296 */
6297
6298static int
6299xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
6300 unsigned char c;
6301 unsigned int val;
6302 const xmlChar *cur;
6303
6304 if (ctxt == NULL)
6305 return(0);
6306 cur = ctxt->cur;
6307
6308 /*
6309 * We are supposed to handle UTF8, check it's valid
6310 * From rfc2044: encoding of the Unicode values on UTF-8:
6311 *
6312 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
6313 * 0000 0000-0000 007F 0xxxxxxx
6314 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
6315 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
6316 *
6317 * Check for the 0x110000 limit too
6318 */
6319 c = *cur;
6320 if (c & 0x80) {
6321 if ((cur[1] & 0xc0) != 0x80)
6322 goto encoding_error;
6323 if ((c & 0xe0) == 0xe0) {
6324
6325 if ((cur[2] & 0xc0) != 0x80)
6326 goto encoding_error;
6327 if ((c & 0xf0) == 0xf0) {
6328 if (((c & 0xf8) != 0xf0) ||
6329 ((cur[3] & 0xc0) != 0x80))
6330 goto encoding_error;
6331 /* 4-byte code */
6332 *len = 4;
6333 val = (cur[0] & 0x7) << 18;
6334 val |= (cur[1] & 0x3f) << 12;
6335 val |= (cur[2] & 0x3f) << 6;
6336 val |= cur[3] & 0x3f;
6337 } else {
6338 /* 3-byte code */
6339 *len = 3;
6340 val = (cur[0] & 0xf) << 12;
6341 val |= (cur[1] & 0x3f) << 6;
6342 val |= cur[2] & 0x3f;
6343 }
6344 } else {
6345 /* 2-byte code */
6346 *len = 2;
6347 val = (cur[0] & 0x1f) << 6;
6348 val |= cur[1] & 0x3f;
6349 }
6350 if (!IS_CHAR(val)) {
6351 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
6352 }
6353 return(val);
6354 } else {
6355 /* 1-byte code */
6356 *len = 1;
6357 return((int) *cur);
6358 }
6359encoding_error:
6360 /*
6361 * If we detect an UTF8 error that probably mean that the
6362 * input encoding didn't get properly advertized in the
6363 * declaration header. Report the error and switch the encoding
6364 * to ISO-Latin-1 (if you don't like this policy, just declare the
6365 * encoding !)
6366 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00006367 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00006368 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006369}
6370
6371/**
Owen Taylor3473f882001-02-23 17:55:21 +00006372 * xmlXPathParseNCName:
6373 * @ctxt: the XPath Parser context
6374 *
6375 * parse an XML namespace non qualified name.
6376 *
6377 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
6378 *
6379 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
6380 * CombiningChar | Extender
6381 *
6382 * Returns the namespace name or NULL
6383 */
6384
6385xmlChar *
6386xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00006387 const xmlChar *in;
6388 xmlChar *ret;
6389 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006390
Daniel Veillard2156a562001-04-28 12:24:34 +00006391 /*
6392 * Accelerator for simple ASCII names
6393 */
6394 in = ctxt->cur;
6395 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6396 ((*in >= 0x41) && (*in <= 0x5A)) ||
6397 (*in == '_')) {
6398 in++;
6399 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6400 ((*in >= 0x41) && (*in <= 0x5A)) ||
6401 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00006402 (*in == '_') || (*in == '.') ||
6403 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00006404 in++;
6405 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
6406 (*in == '[') || (*in == ']') || (*in == ':') ||
6407 (*in == '@') || (*in == '*')) {
6408 count = in - ctxt->cur;
6409 if (count == 0)
6410 return(NULL);
6411 ret = xmlStrndup(ctxt->cur, count);
6412 ctxt->cur = in;
6413 return(ret);
6414 }
6415 }
6416 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00006417}
6418
Daniel Veillard2156a562001-04-28 12:24:34 +00006419
Owen Taylor3473f882001-02-23 17:55:21 +00006420/**
6421 * xmlXPathParseQName:
6422 * @ctxt: the XPath Parser context
6423 * @prefix: a xmlChar **
6424 *
6425 * parse an XML qualified name
6426 *
6427 * [NS 5] QName ::= (Prefix ':')? LocalPart
6428 *
6429 * [NS 6] Prefix ::= NCName
6430 *
6431 * [NS 7] LocalPart ::= NCName
6432 *
6433 * Returns the function returns the local part, and prefix is updated
6434 * to get the Prefix if any.
6435 */
6436
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006437static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006438xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
6439 xmlChar *ret = NULL;
6440
6441 *prefix = NULL;
6442 ret = xmlXPathParseNCName(ctxt);
6443 if (CUR == ':') {
6444 *prefix = ret;
6445 NEXT;
6446 ret = xmlXPathParseNCName(ctxt);
6447 }
6448 return(ret);
6449}
6450
6451/**
6452 * xmlXPathParseName:
6453 * @ctxt: the XPath Parser context
6454 *
6455 * parse an XML name
6456 *
6457 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6458 * CombiningChar | Extender
6459 *
6460 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6461 *
6462 * Returns the namespace name or NULL
6463 */
6464
6465xmlChar *
6466xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006467 const xmlChar *in;
6468 xmlChar *ret;
6469 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006470
Daniel Veillard61d80a22001-04-27 17:13:01 +00006471 /*
6472 * Accelerator for simple ASCII names
6473 */
6474 in = ctxt->cur;
6475 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6476 ((*in >= 0x41) && (*in <= 0x5A)) ||
6477 (*in == '_') || (*in == ':')) {
6478 in++;
6479 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6480 ((*in >= 0x41) && (*in <= 0x5A)) ||
6481 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00006482 (*in == '_') || (*in == '-') ||
6483 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00006484 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00006485 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006486 count = in - ctxt->cur;
6487 ret = xmlStrndup(ctxt->cur, count);
6488 ctxt->cur = in;
6489 return(ret);
6490 }
6491 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006492 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00006493}
6494
Daniel Veillard61d80a22001-04-27 17:13:01 +00006495static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00006496xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006497 xmlChar buf[XML_MAX_NAMELEN + 5];
6498 int len = 0, l;
6499 int c;
6500
6501 /*
6502 * Handler for more complex cases
6503 */
6504 c = CUR_CHAR(l);
6505 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00006506 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
6507 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00006508 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00006509 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006510 return(NULL);
6511 }
6512
6513 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
6514 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
6515 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006516 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006517 (IS_COMBINING(c)) ||
6518 (IS_EXTENDER(c)))) {
6519 COPY_BUF(l,buf,len,c);
6520 NEXTL(l);
6521 c = CUR_CHAR(l);
6522 if (len >= XML_MAX_NAMELEN) {
6523 /*
6524 * Okay someone managed to make a huge name, so he's ready to pay
6525 * for the processing speed.
6526 */
6527 xmlChar *buffer;
6528 int max = len * 2;
6529
6530 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
6531 if (buffer == NULL) {
6532 XP_ERROR0(XPATH_MEMORY_ERROR);
6533 }
6534 memcpy(buffer, buf, len);
6535 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
6536 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006537 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006538 (IS_COMBINING(c)) ||
6539 (IS_EXTENDER(c))) {
6540 if (len + 10 > max) {
6541 max *= 2;
6542 buffer = (xmlChar *) xmlRealloc(buffer,
6543 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00006544 if (buffer == NULL) {
6545 XP_ERROR0(XPATH_MEMORY_ERROR);
6546 }
6547 }
6548 COPY_BUF(l,buffer,len,c);
6549 NEXTL(l);
6550 c = CUR_CHAR(l);
6551 }
6552 buffer[len] = 0;
6553 return(buffer);
6554 }
6555 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006556 if (len == 0)
6557 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006558 return(xmlStrndup(buf, len));
6559}
Owen Taylor3473f882001-02-23 17:55:21 +00006560/**
6561 * xmlXPathStringEvalNumber:
6562 * @str: A string to scan
6563 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00006564 * [30a] Float ::= Number ('e' Digits?)?
6565 *
Owen Taylor3473f882001-02-23 17:55:21 +00006566 * [30] Number ::= Digits ('.' Digits?)?
6567 * | '.' Digits
6568 * [31] Digits ::= [0-9]+
6569 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006570 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00006571 * In complement of the Number expression, this function also handles
6572 * negative values : '-' Number.
6573 *
6574 * Returns the double value.
6575 */
6576double
6577xmlXPathStringEvalNumber(const xmlChar *str) {
6578 const xmlChar *cur = str;
6579 double ret = 0.0;
6580 double mult = 1;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006581 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006582 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006583 int exponent = 0;
6584 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006585#ifdef __GNUC__
6586 unsigned long tmp = 0;
6587#endif
Bjorn Reese70a9da52001-04-21 16:57:29 +00006588
Owen Taylor3473f882001-02-23 17:55:21 +00006589 while (IS_BLANK(*cur)) cur++;
6590 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
6591 return(xmlXPathNAN);
6592 }
6593 if (*cur == '-') {
6594 isneg = 1;
6595 cur++;
6596 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00006597
6598#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006599 /*
Daniel Veillardb06c6142001-08-27 14:26:30 +00006600 * tmp is a workaround against a gcc compiler bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006601 */
Owen Taylor3473f882001-02-23 17:55:21 +00006602 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006603 tmp = tmp * 10 + (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00006604 ok = 1;
6605 cur++;
6606 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006607 ret = (double) tmp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00006608#else
6609 while ((*cur >= '0') && (*cur <= '9')) {
6610 ret = ret * 10 + (*cur - '0');
6611 ok = 1;
6612 cur++;
6613 }
6614#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006615
Owen Taylor3473f882001-02-23 17:55:21 +00006616 if (*cur == '.') {
6617 cur++;
6618 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
6619 return(xmlXPathNAN);
6620 }
6621 while ((*cur >= '0') && (*cur <= '9')) {
6622 mult /= 10;
6623 ret = ret + (*cur - '0') * mult;
6624 cur++;
6625 }
6626 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006627 if ((*cur == 'e') || (*cur == 'E')) {
6628 cur++;
6629 if (*cur == '-') {
6630 is_exponent_negative = 1;
6631 cur++;
6632 }
6633 while ((*cur >= '0') && (*cur <= '9')) {
6634 exponent = exponent * 10 + (*cur - '0');
6635 cur++;
6636 }
6637 }
Owen Taylor3473f882001-02-23 17:55:21 +00006638 while (IS_BLANK(*cur)) cur++;
6639 if (*cur != 0) return(xmlXPathNAN);
6640 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006641 if (is_exponent_negative) exponent = -exponent;
6642 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00006643 return(ret);
6644}
6645
6646/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006647 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00006648 * @ctxt: the XPath Parser context
6649 *
6650 * [30] Number ::= Digits ('.' Digits?)?
6651 * | '.' Digits
6652 * [31] Digits ::= [0-9]+
6653 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006654 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00006655 *
6656 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006657static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006658xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
6659{
Owen Taylor3473f882001-02-23 17:55:21 +00006660 double ret = 0.0;
6661 double mult = 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006662 int ok = 0, tmp = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006663 int exponent = 0;
6664 int is_exponent_negative = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006665
6666 CHECK_ERROR;
6667 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
6668 XP_ERROR(XPATH_NUMBER_ERROR);
6669 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006670 /*
6671 * Try to work around a gcc optimizer bug
6672 */
Owen Taylor3473f882001-02-23 17:55:21 +00006673 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006674 tmp = tmp * 10 + (CUR - '0');
6675 ok = 1;
6676 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +00006677 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006678 ret = (double) tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00006679 if (CUR == '.') {
6680 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006681 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
6682 XP_ERROR(XPATH_NUMBER_ERROR);
6683 }
6684 while ((CUR >= '0') && (CUR <= '9')) {
6685 mult /= 10;
6686 ret = ret + (CUR - '0') * mult;
6687 NEXT;
6688 }
Owen Taylor3473f882001-02-23 17:55:21 +00006689 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006690 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006691 NEXT;
6692 if (CUR == '-') {
6693 is_exponent_negative = 1;
6694 NEXT;
6695 }
6696 while ((CUR >= '0') && (CUR <= '9')) {
6697 exponent = exponent * 10 + (CUR - '0');
6698 NEXT;
6699 }
6700 if (is_exponent_negative)
6701 exponent = -exponent;
6702 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006703 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006704 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006705 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006706}
6707
6708/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006709 * xmlXPathParseLiteral:
6710 * @ctxt: the XPath Parser context
6711 *
6712 * Parse a Literal
6713 *
6714 * [29] Literal ::= '"' [^"]* '"'
6715 * | "'" [^']* "'"
6716 *
6717 * Returns the value found or NULL in case of error
6718 */
6719static xmlChar *
6720xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
6721 const xmlChar *q;
6722 xmlChar *ret = NULL;
6723
6724 if (CUR == '"') {
6725 NEXT;
6726 q = CUR_PTR;
6727 while ((IS_CHAR(CUR)) && (CUR != '"'))
6728 NEXT;
6729 if (!IS_CHAR(CUR)) {
6730 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6731 } else {
6732 ret = xmlStrndup(q, CUR_PTR - q);
6733 NEXT;
6734 }
6735 } else if (CUR == '\'') {
6736 NEXT;
6737 q = CUR_PTR;
6738 while ((IS_CHAR(CUR)) && (CUR != '\''))
6739 NEXT;
6740 if (!IS_CHAR(CUR)) {
6741 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6742 } else {
6743 ret = xmlStrndup(q, CUR_PTR - q);
6744 NEXT;
6745 }
6746 } else {
6747 XP_ERROR0(XPATH_START_LITERAL_ERROR);
6748 }
6749 return(ret);
6750}
6751
6752/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006753 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00006754 * @ctxt: the XPath Parser context
6755 *
6756 * Parse a Literal and push it on the stack.
6757 *
6758 * [29] Literal ::= '"' [^"]* '"'
6759 * | "'" [^']* "'"
6760 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006761 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00006762 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006763static void
6764xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006765 const xmlChar *q;
6766 xmlChar *ret = NULL;
6767
6768 if (CUR == '"') {
6769 NEXT;
6770 q = CUR_PTR;
6771 while ((IS_CHAR(CUR)) && (CUR != '"'))
6772 NEXT;
6773 if (!IS_CHAR(CUR)) {
6774 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
6775 } else {
6776 ret = xmlStrndup(q, CUR_PTR - q);
6777 NEXT;
6778 }
6779 } else if (CUR == '\'') {
6780 NEXT;
6781 q = CUR_PTR;
6782 while ((IS_CHAR(CUR)) && (CUR != '\''))
6783 NEXT;
6784 if (!IS_CHAR(CUR)) {
6785 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
6786 } else {
6787 ret = xmlStrndup(q, CUR_PTR - q);
6788 NEXT;
6789 }
6790 } else {
6791 XP_ERROR(XPATH_START_LITERAL_ERROR);
6792 }
6793 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006794 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
6795 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006796 xmlFree(ret);
6797}
6798
6799/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006800 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00006801 * @ctxt: the XPath Parser context
6802 *
6803 * Parse a VariableReference, evaluate it and push it on the stack.
6804 *
6805 * The variable bindings consist of a mapping from variable names
6806 * to variable values. The value of a variable is an object, which
6807 * of any of the types that are possible for the value of an expression,
6808 * and may also be of additional types not specified here.
6809 *
6810 * Early evaluation is possible since:
6811 * The variable bindings [...] used to evaluate a subexpression are
6812 * always the same as those used to evaluate the containing expression.
6813 *
6814 * [36] VariableReference ::= '$' QName
6815 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006816static void
6817xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006818 xmlChar *name;
6819 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006820
6821 SKIP_BLANKS;
6822 if (CUR != '$') {
6823 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
6824 }
6825 NEXT;
6826 name = xmlXPathParseQName(ctxt, &prefix);
6827 if (name == NULL) {
6828 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
6829 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006830 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006831 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
6832 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006833 SKIP_BLANKS;
6834}
6835
6836/**
6837 * xmlXPathIsNodeType:
6838 * @ctxt: the XPath Parser context
6839 * @name: a name string
6840 *
6841 * Is the name given a NodeType one.
6842 *
6843 * [38] NodeType ::= 'comment'
6844 * | 'text'
6845 * | 'processing-instruction'
6846 * | 'node'
6847 *
6848 * Returns 1 if true 0 otherwise
6849 */
6850int
6851xmlXPathIsNodeType(const xmlChar *name) {
6852 if (name == NULL)
6853 return(0);
6854
6855 if (xmlStrEqual(name, BAD_CAST "comment"))
6856 return(1);
6857 if (xmlStrEqual(name, BAD_CAST "text"))
6858 return(1);
6859 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
6860 return(1);
6861 if (xmlStrEqual(name, BAD_CAST "node"))
6862 return(1);
6863 return(0);
6864}
6865
6866/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006867 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00006868 * @ctxt: the XPath Parser context
6869 *
6870 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
6871 * [17] Argument ::= Expr
6872 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006873 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00006874 * pushed on the stack
6875 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006876static void
6877xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006878 xmlChar *name;
6879 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006880 int nbargs = 0;
6881
6882 name = xmlXPathParseQName(ctxt, &prefix);
6883 if (name == NULL) {
6884 XP_ERROR(XPATH_EXPR_ERROR);
6885 }
6886 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006887#ifdef DEBUG_EXPR
6888 if (prefix == NULL)
6889 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
6890 name);
6891 else
6892 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
6893 prefix, name);
6894#endif
6895
Owen Taylor3473f882001-02-23 17:55:21 +00006896 if (CUR != '(') {
6897 XP_ERROR(XPATH_EXPR_ERROR);
6898 }
6899 NEXT;
6900 SKIP_BLANKS;
6901
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006902 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006903 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006904 int op1 = ctxt->comp->last;
6905 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006906 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006907 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006908 nbargs++;
6909 if (CUR == ')') break;
6910 if (CUR != ',') {
6911 XP_ERROR(XPATH_EXPR_ERROR);
6912 }
6913 NEXT;
6914 SKIP_BLANKS;
6915 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006916 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
6917 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006918 NEXT;
6919 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006920}
6921
6922/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006923 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006924 * @ctxt: the XPath Parser context
6925 *
6926 * [15] PrimaryExpr ::= VariableReference
6927 * | '(' Expr ')'
6928 * | Literal
6929 * | Number
6930 * | FunctionCall
6931 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006932 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006933 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006934static void
6935xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006936 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006937 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006938 else if (CUR == '(') {
6939 NEXT;
6940 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006941 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006942 if (CUR != ')') {
6943 XP_ERROR(XPATH_EXPR_ERROR);
6944 }
6945 NEXT;
6946 SKIP_BLANKS;
6947 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006948 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006949 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006950 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006951 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006952 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006953 }
6954 SKIP_BLANKS;
6955}
6956
6957/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006958 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006959 * @ctxt: the XPath Parser context
6960 *
6961 * [20] FilterExpr ::= PrimaryExpr
6962 * | FilterExpr Predicate
6963 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006964 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006965 * Square brackets are used to filter expressions in the same way that
6966 * they are used in location paths. It is an error if the expression to
6967 * be filtered does not evaluate to a node-set. The context node list
6968 * used for evaluating the expression in square brackets is the node-set
6969 * to be filtered listed in document order.
6970 */
6971
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006972static void
6973xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
6974 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006975 CHECK_ERROR;
6976 SKIP_BLANKS;
6977
6978 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006979 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00006980 SKIP_BLANKS;
6981 }
6982
6983
6984}
6985
6986/**
6987 * xmlXPathScanName:
6988 * @ctxt: the XPath Parser context
6989 *
6990 * Trickery: parse an XML name but without consuming the input flow
6991 * Needed to avoid insanity in the parser state.
6992 *
6993 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6994 * CombiningChar | Extender
6995 *
6996 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6997 *
6998 * [6] Names ::= Name (S Name)*
6999 *
7000 * Returns the Name parsed or NULL
7001 */
7002
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007003static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007004xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7005 xmlChar buf[XML_MAX_NAMELEN];
7006 int len = 0;
7007
7008 SKIP_BLANKS;
7009 if (!IS_LETTER(CUR) && (CUR != '_') &&
7010 (CUR != ':')) {
7011 return(NULL);
7012 }
7013
7014 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7015 (NXT(len) == '.') || (NXT(len) == '-') ||
7016 (NXT(len) == '_') || (NXT(len) == ':') ||
7017 (IS_COMBINING(NXT(len))) ||
7018 (IS_EXTENDER(NXT(len)))) {
7019 buf[len] = NXT(len);
7020 len++;
7021 if (len >= XML_MAX_NAMELEN) {
7022 xmlGenericError(xmlGenericErrorContext,
7023 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7024 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7025 (NXT(len) == '.') || (NXT(len) == '-') ||
7026 (NXT(len) == '_') || (NXT(len) == ':') ||
7027 (IS_COMBINING(NXT(len))) ||
7028 (IS_EXTENDER(NXT(len))))
7029 len++;
7030 break;
7031 }
7032 }
7033 return(xmlStrndup(buf, len));
7034}
7035
7036/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007037 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007038 * @ctxt: the XPath Parser context
7039 *
7040 * [19] PathExpr ::= LocationPath
7041 * | FilterExpr
7042 * | FilterExpr '/' RelativeLocationPath
7043 * | FilterExpr '//' RelativeLocationPath
7044 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007045 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007046 * The / operator and // operators combine an arbitrary expression
7047 * and a relative location path. It is an error if the expression
7048 * does not evaluate to a node-set.
7049 * The / operator does composition in the same way as when / is
7050 * used in a location path. As in location paths, // is short for
7051 * /descendant-or-self::node()/.
7052 */
7053
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007054static void
7055xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007056 int lc = 1; /* Should we branch to LocationPath ? */
7057 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7058
7059 SKIP_BLANKS;
7060 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
7061 (CUR == '\'') || (CUR == '"')) {
7062 lc = 0;
7063 } else if (CUR == '*') {
7064 /* relative or absolute location path */
7065 lc = 1;
7066 } else if (CUR == '/') {
7067 /* relative or absolute location path */
7068 lc = 1;
7069 } else if (CUR == '@') {
7070 /* relative abbreviated attribute location path */
7071 lc = 1;
7072 } else if (CUR == '.') {
7073 /* relative abbreviated attribute location path */
7074 lc = 1;
7075 } else {
7076 /*
7077 * Problem is finding if we have a name here whether it's:
7078 * - a nodetype
7079 * - a function call in which case it's followed by '('
7080 * - an axis in which case it's followed by ':'
7081 * - a element name
7082 * We do an a priori analysis here rather than having to
7083 * maintain parsed token content through the recursive function
7084 * calls. This looks uglier but makes the code quite easier to
7085 * read/write/debug.
7086 */
7087 SKIP_BLANKS;
7088 name = xmlXPathScanName(ctxt);
7089 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7090#ifdef DEBUG_STEP
7091 xmlGenericError(xmlGenericErrorContext,
7092 "PathExpr: Axis\n");
7093#endif
7094 lc = 1;
7095 xmlFree(name);
7096 } else if (name != NULL) {
7097 int len =xmlStrlen(name);
7098 int blank = 0;
7099
7100
7101 while (NXT(len) != 0) {
7102 if (NXT(len) == '/') {
7103 /* element name */
7104#ifdef DEBUG_STEP
7105 xmlGenericError(xmlGenericErrorContext,
7106 "PathExpr: AbbrRelLocation\n");
7107#endif
7108 lc = 1;
7109 break;
7110 } else if (IS_BLANK(NXT(len))) {
7111 /* skip to next */
7112 blank = 1;
7113 } else if (NXT(len) == ':') {
7114#ifdef DEBUG_STEP
7115 xmlGenericError(xmlGenericErrorContext,
7116 "PathExpr: AbbrRelLocation\n");
7117#endif
7118 lc = 1;
7119 break;
7120 } else if ((NXT(len) == '(')) {
7121 /* Note Type or Function */
7122 if (xmlXPathIsNodeType(name)) {
7123#ifdef DEBUG_STEP
7124 xmlGenericError(xmlGenericErrorContext,
7125 "PathExpr: Type search\n");
7126#endif
7127 lc = 1;
7128 } else {
7129#ifdef DEBUG_STEP
7130 xmlGenericError(xmlGenericErrorContext,
7131 "PathExpr: function call\n");
7132#endif
7133 lc = 0;
7134 }
7135 break;
7136 } else if ((NXT(len) == '[')) {
7137 /* element name */
7138#ifdef DEBUG_STEP
7139 xmlGenericError(xmlGenericErrorContext,
7140 "PathExpr: AbbrRelLocation\n");
7141#endif
7142 lc = 1;
7143 break;
7144 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7145 (NXT(len) == '=')) {
7146 lc = 1;
7147 break;
7148 } else {
7149 lc = 1;
7150 break;
7151 }
7152 len++;
7153 }
7154 if (NXT(len) == 0) {
7155#ifdef DEBUG_STEP
7156 xmlGenericError(xmlGenericErrorContext,
7157 "PathExpr: AbbrRelLocation\n");
7158#endif
7159 /* element name */
7160 lc = 1;
7161 }
7162 xmlFree(name);
7163 } else {
7164 /* make sure all cases are covered explicitely */
7165 XP_ERROR(XPATH_EXPR_ERROR);
7166 }
7167 }
7168
7169 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007170 if (CUR == '/') {
7171 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7172 } else {
7173 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007174 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007175 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007176 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007177 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007178 CHECK_ERROR;
7179 if ((CUR == '/') && (NXT(1) == '/')) {
7180 SKIP(2);
7181 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007182
7183 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7184 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7185 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7186
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007187 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007188 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007189 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007190 }
7191 }
7192 SKIP_BLANKS;
7193}
7194
7195/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007196 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007197 * @ctxt: the XPath Parser context
7198 *
7199 * [18] UnionExpr ::= PathExpr
7200 * | UnionExpr '|' PathExpr
7201 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007202 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007203 */
7204
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007205static void
7206xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7207 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007208 CHECK_ERROR;
7209 SKIP_BLANKS;
7210 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007211 int op1 = ctxt->comp->last;
7212 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007213
7214 NEXT;
7215 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007216 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007217
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007218 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
7219
Owen Taylor3473f882001-02-23 17:55:21 +00007220 SKIP_BLANKS;
7221 }
Owen Taylor3473f882001-02-23 17:55:21 +00007222}
7223
7224/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007225 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007226 * @ctxt: the XPath Parser context
7227 *
7228 * [27] UnaryExpr ::= UnionExpr
7229 * | '-' UnaryExpr
7230 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007231 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007232 */
7233
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007234static void
7235xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007236 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007237 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007238
7239 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00007240 while (CUR == '-') {
7241 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007242 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007243 NEXT;
7244 SKIP_BLANKS;
7245 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007246
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007247 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007248 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007249 if (found) {
7250 if (minus)
7251 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
7252 else
7253 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007254 }
7255}
7256
7257/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007258 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007259 * @ctxt: the XPath Parser context
7260 *
7261 * [26] MultiplicativeExpr ::= UnaryExpr
7262 * | MultiplicativeExpr MultiplyOperator UnaryExpr
7263 * | MultiplicativeExpr 'div' UnaryExpr
7264 * | MultiplicativeExpr 'mod' UnaryExpr
7265 * [34] MultiplyOperator ::= '*'
7266 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007267 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007268 */
7269
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007270static void
7271xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
7272 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007273 CHECK_ERROR;
7274 SKIP_BLANKS;
7275 while ((CUR == '*') ||
7276 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
7277 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
7278 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007279 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007280
7281 if (CUR == '*') {
7282 op = 0;
7283 NEXT;
7284 } else if (CUR == 'd') {
7285 op = 1;
7286 SKIP(3);
7287 } else if (CUR == 'm') {
7288 op = 2;
7289 SKIP(3);
7290 }
7291 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007292 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007293 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007294 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007295 SKIP_BLANKS;
7296 }
7297}
7298
7299/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007300 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007301 * @ctxt: the XPath Parser context
7302 *
7303 * [25] AdditiveExpr ::= MultiplicativeExpr
7304 * | AdditiveExpr '+' MultiplicativeExpr
7305 * | AdditiveExpr '-' MultiplicativeExpr
7306 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007307 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007308 */
7309
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007310static void
7311xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007312
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007313 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007314 CHECK_ERROR;
7315 SKIP_BLANKS;
7316 while ((CUR == '+') || (CUR == '-')) {
7317 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007318 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007319
7320 if (CUR == '+') plus = 1;
7321 else plus = 0;
7322 NEXT;
7323 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007324 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007325 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007326 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007327 SKIP_BLANKS;
7328 }
7329}
7330
7331/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007332 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007333 * @ctxt: the XPath Parser context
7334 *
7335 * [24] RelationalExpr ::= AdditiveExpr
7336 * | RelationalExpr '<' AdditiveExpr
7337 * | RelationalExpr '>' AdditiveExpr
7338 * | RelationalExpr '<=' AdditiveExpr
7339 * | RelationalExpr '>=' AdditiveExpr
7340 *
7341 * A <= B > C is allowed ? Answer from James, yes with
7342 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
7343 * which is basically what got implemented.
7344 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007345 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00007346 * on the stack
7347 */
7348
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007349static void
7350xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
7351 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007352 CHECK_ERROR;
7353 SKIP_BLANKS;
7354 while ((CUR == '<') ||
7355 (CUR == '>') ||
7356 ((CUR == '<') && (NXT(1) == '=')) ||
7357 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007358 int inf, strict;
7359 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007360
7361 if (CUR == '<') inf = 1;
7362 else inf = 0;
7363 if (NXT(1) == '=') strict = 0;
7364 else strict = 1;
7365 NEXT;
7366 if (!strict) NEXT;
7367 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007368 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007369 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007370 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00007371 SKIP_BLANKS;
7372 }
7373}
7374
7375/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007376 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007377 * @ctxt: the XPath Parser context
7378 *
7379 * [23] EqualityExpr ::= RelationalExpr
7380 * | EqualityExpr '=' RelationalExpr
7381 * | EqualityExpr '!=' RelationalExpr
7382 *
7383 * A != B != C is allowed ? Answer from James, yes with
7384 * (RelationalExpr = RelationalExpr) = RelationalExpr
7385 * (RelationalExpr != RelationalExpr) != RelationalExpr
7386 * which is basically what got implemented.
7387 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007388 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007389 *
7390 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007391static void
7392xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
7393 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007394 CHECK_ERROR;
7395 SKIP_BLANKS;
7396 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007397 int eq;
7398 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007399
7400 if (CUR == '=') eq = 1;
7401 else eq = 0;
7402 NEXT;
7403 if (!eq) NEXT;
7404 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007405 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007406 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007407 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007408 SKIP_BLANKS;
7409 }
7410}
7411
7412/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007413 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007414 * @ctxt: the XPath Parser context
7415 *
7416 * [22] AndExpr ::= EqualityExpr
7417 * | AndExpr 'and' EqualityExpr
7418 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007419 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007420 *
7421 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007422static void
7423xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
7424 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007425 CHECK_ERROR;
7426 SKIP_BLANKS;
7427 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007428 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007429 SKIP(3);
7430 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007431 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007432 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007433 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007434 SKIP_BLANKS;
7435 }
7436}
7437
7438/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007439 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007440 * @ctxt: the XPath Parser context
7441 *
7442 * [14] Expr ::= OrExpr
7443 * [21] OrExpr ::= AndExpr
7444 * | OrExpr 'or' AndExpr
7445 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007446 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00007447 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007448static void
7449xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
7450 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007451 CHECK_ERROR;
7452 SKIP_BLANKS;
7453 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007454 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007455 SKIP(2);
7456 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007457 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007458 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007459 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
7460 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00007461 SKIP_BLANKS;
7462 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007463 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
7464 /* more ops could be optimized too */
7465 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
7466 }
Owen Taylor3473f882001-02-23 17:55:21 +00007467}
7468
7469/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007470 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00007471 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007472 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00007473 *
7474 * [8] Predicate ::= '[' PredicateExpr ']'
7475 * [9] PredicateExpr ::= Expr
7476 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007477 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00007478 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007479static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007480xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007481 int op1 = ctxt->comp->last;
7482
7483 SKIP_BLANKS;
7484 if (CUR != '[') {
7485 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7486 }
7487 NEXT;
7488 SKIP_BLANKS;
7489
7490 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007491 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007492 CHECK_ERROR;
7493
7494 if (CUR != ']') {
7495 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7496 }
7497
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007498 if (filter)
7499 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
7500 else
7501 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007502
7503 NEXT;
7504 SKIP_BLANKS;
7505}
7506
7507/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007508 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00007509 * @ctxt: the XPath Parser context
7510 * @test: pointer to a xmlXPathTestVal
7511 * @type: pointer to a xmlXPathTypeVal
7512 * @prefix: placeholder for a possible name prefix
7513 *
7514 * [7] NodeTest ::= NameTest
7515 * | NodeType '(' ')'
7516 * | 'processing-instruction' '(' Literal ')'
7517 *
7518 * [37] NameTest ::= '*'
7519 * | NCName ':' '*'
7520 * | QName
7521 * [38] NodeType ::= 'comment'
7522 * | 'text'
7523 * | 'processing-instruction'
7524 * | 'node'
7525 *
7526 * Returns the name found and update @test, @type and @prefix appropriately
7527 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007528static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007529xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
7530 xmlXPathTypeVal *type, const xmlChar **prefix,
7531 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00007532 int blanks;
7533
7534 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
7535 STRANGE;
7536 return(NULL);
7537 }
7538 *type = 0;
7539 *test = 0;
7540 *prefix = NULL;
7541 SKIP_BLANKS;
7542
7543 if ((name == NULL) && (CUR == '*')) {
7544 /*
7545 * All elements
7546 */
7547 NEXT;
7548 *test = NODE_TEST_ALL;
7549 return(NULL);
7550 }
7551
7552 if (name == NULL)
7553 name = xmlXPathParseNCName(ctxt);
7554 if (name == NULL) {
7555 XP_ERROR0(XPATH_EXPR_ERROR);
7556 }
7557
7558 blanks = IS_BLANK(CUR);
7559 SKIP_BLANKS;
7560 if (CUR == '(') {
7561 NEXT;
7562 /*
7563 * NodeType or PI search
7564 */
7565 if (xmlStrEqual(name, BAD_CAST "comment"))
7566 *type = NODE_TYPE_COMMENT;
7567 else if (xmlStrEqual(name, BAD_CAST "node"))
7568 *type = NODE_TYPE_NODE;
7569 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
7570 *type = NODE_TYPE_PI;
7571 else if (xmlStrEqual(name, BAD_CAST "text"))
7572 *type = NODE_TYPE_TEXT;
7573 else {
7574 if (name != NULL)
7575 xmlFree(name);
7576 XP_ERROR0(XPATH_EXPR_ERROR);
7577 }
7578
7579 *test = NODE_TEST_TYPE;
7580
7581 SKIP_BLANKS;
7582 if (*type == NODE_TYPE_PI) {
7583 /*
7584 * Specific case: search a PI by name.
7585 */
Owen Taylor3473f882001-02-23 17:55:21 +00007586 if (name != NULL)
7587 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00007588 name = NULL;
7589 if (CUR != ')') {
7590 name = xmlXPathParseLiteral(ctxt);
7591 CHECK_ERROR 0;
7592 SKIP_BLANKS;
7593 }
Owen Taylor3473f882001-02-23 17:55:21 +00007594 }
7595 if (CUR != ')') {
7596 if (name != NULL)
7597 xmlFree(name);
7598 XP_ERROR0(XPATH_UNCLOSED_ERROR);
7599 }
7600 NEXT;
7601 return(name);
7602 }
7603 *test = NODE_TEST_NAME;
7604 if ((!blanks) && (CUR == ':')) {
7605 NEXT;
7606
7607 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007608 * Since currently the parser context don't have a
7609 * namespace list associated:
7610 * The namespace name for this prefix can be computed
7611 * only at evaluation time. The compilation is done
7612 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00007613 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007614#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00007615 *prefix = xmlXPathNsLookup(ctxt->context, name);
7616 if (name != NULL)
7617 xmlFree(name);
7618 if (*prefix == NULL) {
7619 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
7620 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007621#else
7622 *prefix = name;
7623#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007624
7625 if (CUR == '*') {
7626 /*
7627 * All elements
7628 */
7629 NEXT;
7630 *test = NODE_TEST_ALL;
7631 return(NULL);
7632 }
7633
7634 name = xmlXPathParseNCName(ctxt);
7635 if (name == NULL) {
7636 XP_ERROR0(XPATH_EXPR_ERROR);
7637 }
7638 }
7639 return(name);
7640}
7641
7642/**
7643 * xmlXPathIsAxisName:
7644 * @name: a preparsed name token
7645 *
7646 * [6] AxisName ::= 'ancestor'
7647 * | 'ancestor-or-self'
7648 * | 'attribute'
7649 * | 'child'
7650 * | 'descendant'
7651 * | 'descendant-or-self'
7652 * | 'following'
7653 * | 'following-sibling'
7654 * | 'namespace'
7655 * | 'parent'
7656 * | 'preceding'
7657 * | 'preceding-sibling'
7658 * | 'self'
7659 *
7660 * Returns the axis or 0
7661 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007662static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00007663xmlXPathIsAxisName(const xmlChar *name) {
7664 xmlXPathAxisVal ret = 0;
7665 switch (name[0]) {
7666 case 'a':
7667 if (xmlStrEqual(name, BAD_CAST "ancestor"))
7668 ret = AXIS_ANCESTOR;
7669 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
7670 ret = AXIS_ANCESTOR_OR_SELF;
7671 if (xmlStrEqual(name, BAD_CAST "attribute"))
7672 ret = AXIS_ATTRIBUTE;
7673 break;
7674 case 'c':
7675 if (xmlStrEqual(name, BAD_CAST "child"))
7676 ret = AXIS_CHILD;
7677 break;
7678 case 'd':
7679 if (xmlStrEqual(name, BAD_CAST "descendant"))
7680 ret = AXIS_DESCENDANT;
7681 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
7682 ret = AXIS_DESCENDANT_OR_SELF;
7683 break;
7684 case 'f':
7685 if (xmlStrEqual(name, BAD_CAST "following"))
7686 ret = AXIS_FOLLOWING;
7687 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
7688 ret = AXIS_FOLLOWING_SIBLING;
7689 break;
7690 case 'n':
7691 if (xmlStrEqual(name, BAD_CAST "namespace"))
7692 ret = AXIS_NAMESPACE;
7693 break;
7694 case 'p':
7695 if (xmlStrEqual(name, BAD_CAST "parent"))
7696 ret = AXIS_PARENT;
7697 if (xmlStrEqual(name, BAD_CAST "preceding"))
7698 ret = AXIS_PRECEDING;
7699 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
7700 ret = AXIS_PRECEDING_SIBLING;
7701 break;
7702 case 's':
7703 if (xmlStrEqual(name, BAD_CAST "self"))
7704 ret = AXIS_SELF;
7705 break;
7706 }
7707 return(ret);
7708}
7709
7710/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007711 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00007712 * @ctxt: the XPath Parser context
7713 *
7714 * [4] Step ::= AxisSpecifier NodeTest Predicate*
7715 * | AbbreviatedStep
7716 *
7717 * [12] AbbreviatedStep ::= '.' | '..'
7718 *
7719 * [5] AxisSpecifier ::= AxisName '::'
7720 * | AbbreviatedAxisSpecifier
7721 *
7722 * [13] AbbreviatedAxisSpecifier ::= '@'?
7723 *
7724 * Modified for XPtr range support as:
7725 *
7726 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
7727 * | AbbreviatedStep
7728 * | 'range-to' '(' Expr ')' Predicate*
7729 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007730 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00007731 * A location step of . is short for self::node(). This is
7732 * particularly useful in conjunction with //. For example, the
7733 * location path .//para is short for
7734 * self::node()/descendant-or-self::node()/child::para
7735 * and so will select all para descendant elements of the context
7736 * node.
7737 * Similarly, a location step of .. is short for parent::node().
7738 * For example, ../title is short for parent::node()/child::title
7739 * and so will select the title children of the parent of the context
7740 * node.
7741 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007742static void
7743xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007744#ifdef LIBXML_XPTR_ENABLED
7745 int rangeto = 0;
7746 int op2 = -1;
7747#endif
7748
Owen Taylor3473f882001-02-23 17:55:21 +00007749 SKIP_BLANKS;
7750 if ((CUR == '.') && (NXT(1) == '.')) {
7751 SKIP(2);
7752 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007753 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
7754 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007755 } else if (CUR == '.') {
7756 NEXT;
7757 SKIP_BLANKS;
7758 } else {
7759 xmlChar *name = NULL;
7760 const xmlChar *prefix = NULL;
7761 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007762 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007763 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007764 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00007765
7766 /*
7767 * The modification needed for XPointer change to the production
7768 */
7769#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007770 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00007771 name = xmlXPathParseNCName(ctxt);
7772 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007773 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007774 xmlFree(name);
7775 SKIP_BLANKS;
7776 if (CUR != '(') {
7777 XP_ERROR(XPATH_EXPR_ERROR);
7778 }
7779 NEXT;
7780 SKIP_BLANKS;
7781
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007782 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007783 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00007784 CHECK_ERROR;
7785
7786 SKIP_BLANKS;
7787 if (CUR != ')') {
7788 XP_ERROR(XPATH_EXPR_ERROR);
7789 }
7790 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007791 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007792 goto eval_predicates;
7793 }
7794 }
7795#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00007796 if (CUR == '*') {
7797 axis = AXIS_CHILD;
7798 } else {
7799 if (name == NULL)
7800 name = xmlXPathParseNCName(ctxt);
7801 if (name != NULL) {
7802 axis = xmlXPathIsAxisName(name);
7803 if (axis != 0) {
7804 SKIP_BLANKS;
7805 if ((CUR == ':') && (NXT(1) == ':')) {
7806 SKIP(2);
7807 xmlFree(name);
7808 name = NULL;
7809 } else {
7810 /* an element name can conflict with an axis one :-\ */
7811 axis = AXIS_CHILD;
7812 }
Owen Taylor3473f882001-02-23 17:55:21 +00007813 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00007814 axis = AXIS_CHILD;
7815 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007816 } else if (CUR == '@') {
7817 NEXT;
7818 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00007819 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00007820 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00007821 }
Owen Taylor3473f882001-02-23 17:55:21 +00007822 }
7823
7824 CHECK_ERROR;
7825
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007826 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00007827 if (test == 0)
7828 return;
7829
7830#ifdef DEBUG_STEP
7831 xmlGenericError(xmlGenericErrorContext,
7832 "Basis : computing new set\n");
7833#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007834
Owen Taylor3473f882001-02-23 17:55:21 +00007835#ifdef DEBUG_STEP
7836 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007837 if (ctxt->value == NULL)
7838 xmlGenericError(xmlGenericErrorContext, "no value\n");
7839 else if (ctxt->value->nodesetval == NULL)
7840 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7841 else
7842 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007843#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007844
7845eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007846 op1 = ctxt->comp->last;
7847 ctxt->comp->last = -1;
7848
Owen Taylor3473f882001-02-23 17:55:21 +00007849 SKIP_BLANKS;
7850 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007851 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007852 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007853
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007854#ifdef LIBXML_XPTR_ENABLED
7855 if (rangeto) {
7856 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
7857 } else
7858#endif
7859 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
7860 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007861
Owen Taylor3473f882001-02-23 17:55:21 +00007862 }
7863#ifdef DEBUG_STEP
7864 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007865 if (ctxt->value == NULL)
7866 xmlGenericError(xmlGenericErrorContext, "no value\n");
7867 else if (ctxt->value->nodesetval == NULL)
7868 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7869 else
7870 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
7871 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007872#endif
7873}
7874
7875/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007876 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007877 * @ctxt: the XPath Parser context
7878 *
7879 * [3] RelativeLocationPath ::= Step
7880 * | RelativeLocationPath '/' Step
7881 * | AbbreviatedRelativeLocationPath
7882 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
7883 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007884 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00007885 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007886static void
Owen Taylor3473f882001-02-23 17:55:21 +00007887#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007888xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007889#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007890xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007891#endif
7892(xmlXPathParserContextPtr ctxt) {
7893 SKIP_BLANKS;
7894 if ((CUR == '/') && (NXT(1) == '/')) {
7895 SKIP(2);
7896 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007897 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7898 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007899 } else if (CUR == '/') {
7900 NEXT;
7901 SKIP_BLANKS;
7902 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007903 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007904 SKIP_BLANKS;
7905 while (CUR == '/') {
7906 if ((CUR == '/') && (NXT(1) == '/')) {
7907 SKIP(2);
7908 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007909 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00007910 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007911 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007912 } else if (CUR == '/') {
7913 NEXT;
7914 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007915 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007916 }
7917 SKIP_BLANKS;
7918 }
7919}
7920
7921/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007922 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007923 * @ctxt: the XPath Parser context
7924 *
7925 * [1] LocationPath ::= RelativeLocationPath
7926 * | AbsoluteLocationPath
7927 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
7928 * | AbbreviatedAbsoluteLocationPath
7929 * [10] AbbreviatedAbsoluteLocationPath ::=
7930 * '//' RelativeLocationPath
7931 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007932 * Compile a location path
7933 *
Owen Taylor3473f882001-02-23 17:55:21 +00007934 * // is short for /descendant-or-self::node()/. For example,
7935 * //para is short for /descendant-or-self::node()/child::para and
7936 * so will select any para element in the document (even a para element
7937 * that is a document element will be selected by //para since the
7938 * document element node is a child of the root node); div//para is
7939 * short for div/descendant-or-self::node()/child::para and so will
7940 * select all para descendants of div children.
7941 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007942static void
7943xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007944 SKIP_BLANKS;
7945 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007946 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007947 } else {
7948 while (CUR == '/') {
7949 if ((CUR == '/') && (NXT(1) == '/')) {
7950 SKIP(2);
7951 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007952 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7953 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007954 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007955 } else if (CUR == '/') {
7956 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00007957 SKIP_BLANKS;
7958 if ((CUR != 0 ) &&
7959 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
7960 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007961 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007962 }
7963 }
7964 }
7965}
7966
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007967/************************************************************************
7968 * *
7969 * XPath precompiled expression evaluation *
7970 * *
7971 ************************************************************************/
7972
Daniel Veillardf06307e2001-07-03 10:35:50 +00007973static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007974xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
7975
7976/**
7977 * xmlXPathNodeCollectAndTest:
7978 * @ctxt: the XPath Parser context
7979 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00007980 * @first: pointer to the first element in document order
7981 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007982 *
7983 * This is the function implementing a step: based on the current list
7984 * of nodes, it builds up a new list, looking at all nodes under that
7985 * axis and selecting them it also do the predicate filtering
7986 *
7987 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00007988 *
7989 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007990 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00007991static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007992xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00007993 xmlXPathStepOpPtr op,
7994 xmlNodePtr * first, xmlNodePtr * last)
7995{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007996 xmlXPathAxisVal axis = op->value;
7997 xmlXPathTestVal test = op->value2;
7998 xmlXPathTypeVal type = op->value3;
7999 const xmlChar *prefix = op->value4;
8000 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008001 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008002
8003#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008004 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008005#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008006 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008007 xmlNodeSetPtr ret, list;
8008 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008009 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008010 xmlNodePtr cur = NULL;
8011 xmlXPathObjectPtr obj;
8012 xmlNodeSetPtr nodelist;
8013 xmlNodePtr tmp;
8014
Daniel Veillardf06307e2001-07-03 10:35:50 +00008015 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008016 obj = valuePop(ctxt);
8017 addNode = xmlXPathNodeSetAdd;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008018 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008019 URI = xmlXPathNsLookup(ctxt->context, prefix);
8020 if (URI == NULL)
8021 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008022 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008023#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008024 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008025#endif
8026 switch (axis) {
8027 case AXIS_ANCESTOR:
8028#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008029 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008030#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008031 first = NULL;
8032 next = xmlXPathNextAncestor;
8033 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008034 case AXIS_ANCESTOR_OR_SELF:
8035#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008036 xmlGenericError(xmlGenericErrorContext,
8037 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008038#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008039 first = NULL;
8040 next = xmlXPathNextAncestorOrSelf;
8041 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008042 case AXIS_ATTRIBUTE:
8043#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008044 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008045#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008046 first = NULL;
8047 last = NULL;
8048 next = xmlXPathNextAttribute;
8049 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008050 case AXIS_CHILD:
8051#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008052 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008053#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008054 last = NULL;
8055 next = xmlXPathNextChild;
8056 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008057 case AXIS_DESCENDANT:
8058#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008059 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008060#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008061 last = NULL;
8062 next = xmlXPathNextDescendant;
8063 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008064 case AXIS_DESCENDANT_OR_SELF:
8065#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008066 xmlGenericError(xmlGenericErrorContext,
8067 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008068#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008069 last = NULL;
8070 next = xmlXPathNextDescendantOrSelf;
8071 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008072 case AXIS_FOLLOWING:
8073#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008074 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008075#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008076 last = NULL;
8077 next = xmlXPathNextFollowing;
8078 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008079 case AXIS_FOLLOWING_SIBLING:
8080#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008081 xmlGenericError(xmlGenericErrorContext,
8082 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008083#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008084 last = NULL;
8085 next = xmlXPathNextFollowingSibling;
8086 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008087 case AXIS_NAMESPACE:
8088#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008089 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008090#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008091 first = NULL;
8092 last = NULL;
8093 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8094 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008095 case AXIS_PARENT:
8096#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008097 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008098#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008099 first = NULL;
8100 next = xmlXPathNextParent;
8101 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008102 case AXIS_PRECEDING:
8103#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008104 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008105#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008106 first = NULL;
8107 next = xmlXPathNextPrecedingInternal;
8108 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008109 case AXIS_PRECEDING_SIBLING:
8110#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008111 xmlGenericError(xmlGenericErrorContext,
8112 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008113#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008114 first = NULL;
8115 next = xmlXPathNextPrecedingSibling;
8116 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008117 case AXIS_SELF:
8118#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008119 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008120#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008121 first = NULL;
8122 last = NULL;
8123 next = xmlXPathNextSelf;
8124 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008125 }
8126 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008127 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008128
8129 nodelist = obj->nodesetval;
8130 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008131 xmlXPathFreeObject(obj);
8132 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8133 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008134 }
8135 addNode = xmlXPathNodeSetAddUnique;
8136 ret = NULL;
8137#ifdef DEBUG_STEP
8138 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008139 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008140 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008141 case NODE_TEST_NONE:
8142 xmlGenericError(xmlGenericErrorContext,
8143 " searching for none !!!\n");
8144 break;
8145 case NODE_TEST_TYPE:
8146 xmlGenericError(xmlGenericErrorContext,
8147 " searching for type %d\n", type);
8148 break;
8149 case NODE_TEST_PI:
8150 xmlGenericError(xmlGenericErrorContext,
8151 " searching for PI !!!\n");
8152 break;
8153 case NODE_TEST_ALL:
8154 xmlGenericError(xmlGenericErrorContext,
8155 " searching for *\n");
8156 break;
8157 case NODE_TEST_NS:
8158 xmlGenericError(xmlGenericErrorContext,
8159 " searching for namespace %s\n",
8160 prefix);
8161 break;
8162 case NODE_TEST_NAME:
8163 xmlGenericError(xmlGenericErrorContext,
8164 " searching for name %s\n", name);
8165 if (prefix != NULL)
8166 xmlGenericError(xmlGenericErrorContext,
8167 " with namespace %s\n", prefix);
8168 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008169 }
8170 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8171#endif
8172 /*
8173 * 2.3 Node Tests
8174 * - For the attribute axis, the principal node type is attribute.
8175 * - For the namespace axis, the principal node type is namespace.
8176 * - For other axes, the principal node type is element.
8177 *
8178 * A node test * is true for any node of the
8179 * principal node type. For example, child::* willi
8180 * select all element children of the context node
8181 */
8182 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008183 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008184 ctxt->context->node = nodelist->nodeTab[i];
8185
Daniel Veillardf06307e2001-07-03 10:35:50 +00008186 cur = NULL;
8187 list = xmlXPathNodeSetCreate(NULL);
8188 do {
8189 cur = next(ctxt, cur);
8190 if (cur == NULL)
8191 break;
8192 if ((first != NULL) && (*first == cur))
8193 break;
8194 if (((t % 256) == 0) &&
8195 (first != NULL) && (*first != NULL) &&
8196 (xmlXPathCmpNodes(*first, cur) >= 0))
8197 break;
8198 if ((last != NULL) && (*last == cur))
8199 break;
8200 if (((t % 256) == 0) &&
8201 (last != NULL) && (*last != NULL) &&
8202 (xmlXPathCmpNodes(cur, *last) >= 0))
8203 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008204 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008205#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008206 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8207#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008208 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008209 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008210 ctxt->context->node = tmp;
8211 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008212 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008213 if ((cur->type == type) ||
8214 ((type == NODE_TYPE_NODE) &&
8215 ((cur->type == XML_DOCUMENT_NODE) ||
8216 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8217 (cur->type == XML_ELEMENT_NODE) ||
8218 (cur->type == XML_PI_NODE) ||
8219 (cur->type == XML_COMMENT_NODE) ||
8220 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00008221 (cur->type == XML_TEXT_NODE))) ||
8222 ((type == NODE_TYPE_TEXT) &&
8223 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008224#ifdef DEBUG_STEP
8225 n++;
8226#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008227 addNode(list, cur);
8228 }
8229 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008230 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008231 if (cur->type == XML_PI_NODE) {
8232 if ((name != NULL) &&
8233 (!xmlStrEqual(name, cur->name)))
8234 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008235#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008236 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008237#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008238 addNode(list, cur);
8239 }
8240 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008241 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008242 if (axis == AXIS_ATTRIBUTE) {
8243 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008244#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008245 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008246#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008247 addNode(list, cur);
8248 }
8249 } else if (axis == AXIS_NAMESPACE) {
8250 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008251#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008252 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008253#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008254 addNode(list, cur);
8255 }
8256 } else {
8257 if (cur->type == XML_ELEMENT_NODE) {
8258 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008259#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008260 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008261#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008262 addNode(list, cur);
8263 } else if ((cur->ns != NULL) &&
8264 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008265#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008266 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008267#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008268 addNode(list, cur);
8269 }
8270 }
8271 }
8272 break;
8273 case NODE_TEST_NS:{
8274 TODO;
8275 break;
8276 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008277 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008278 switch (cur->type) {
8279 case XML_ELEMENT_NODE:
8280 if (xmlStrEqual(name, cur->name)) {
8281 if (prefix == NULL) {
8282 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008283#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008284 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008285#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008286 addNode(list, cur);
8287 }
8288 } else {
8289 if ((cur->ns != NULL) &&
8290 (xmlStrEqual(URI,
8291 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008292#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008293 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008294#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008295 addNode(list, cur);
8296 }
8297 }
8298 }
8299 break;
8300 case XML_ATTRIBUTE_NODE:{
8301 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008302
Daniel Veillardf06307e2001-07-03 10:35:50 +00008303 if (xmlStrEqual(name, attr->name)) {
8304 if (prefix == NULL) {
8305 if ((attr->ns == NULL) ||
8306 (attr->ns->prefix == NULL)) {
8307#ifdef DEBUG_STEP
8308 n++;
8309#endif
8310 addNode(list,
8311 (xmlNodePtr) attr);
8312 }
8313 } else {
8314 if ((attr->ns != NULL) &&
8315 (xmlStrEqual(URI,
8316 attr->ns->
8317 href))) {
8318#ifdef DEBUG_STEP
8319 n++;
8320#endif
8321 addNode(list,
8322 (xmlNodePtr) attr);
8323 }
8324 }
8325 }
8326 break;
8327 }
8328 case XML_NAMESPACE_DECL:
8329 if (cur->type == XML_NAMESPACE_DECL) {
8330 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008331
Daniel Veillardf06307e2001-07-03 10:35:50 +00008332 if ((ns->prefix != NULL) && (name != NULL)
8333 && (xmlStrEqual(ns->prefix, name))) {
8334#ifdef DEBUG_STEP
8335 n++;
8336#endif
8337 addNode(list, cur);
8338 }
8339 }
8340 break;
8341 default:
8342 break;
8343 }
8344 break;
8345 break;
8346 }
8347 } while (cur != NULL);
8348
8349 /*
8350 * If there is some predicate filtering do it now
8351 */
8352 if (op->ch2 != -1) {
8353 xmlXPathObjectPtr obj2;
8354
8355 valuePush(ctxt, xmlXPathWrapNodeSet(list));
8356 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
8357 CHECK_TYPE0(XPATH_NODESET);
8358 obj2 = valuePop(ctxt);
8359 list = obj2->nodesetval;
8360 obj2->nodesetval = NULL;
8361 xmlXPathFreeObject(obj2);
8362 }
8363 if (ret == NULL) {
8364 ret = list;
8365 } else {
8366 ret = xmlXPathNodeSetMerge(ret, list);
8367 xmlXPathFreeNodeSet(list);
8368 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008369 }
8370 ctxt->context->node = tmp;
8371#ifdef DEBUG_STEP
8372 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008373 "\nExamined %d nodes, found %d nodes at that step\n",
8374 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008375#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008376 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00008377 if ((obj->boolval) && (obj->user != NULL)) {
8378 ctxt->value->boolval = 1;
8379 ctxt->value->user = obj->user;
8380 obj->user = NULL;
8381 obj->boolval = 0;
8382 }
8383 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008384 return(t);
8385}
8386
8387/**
8388 * xmlXPathNodeCollectAndTestNth:
8389 * @ctxt: the XPath Parser context
8390 * @op: the XPath precompiled step operation
8391 * @indx: the index to collect
8392 * @first: pointer to the first element in document order
8393 * @last: pointer to the last element in document order
8394 *
8395 * This is the function implementing a step: based on the current list
8396 * of nodes, it builds up a new list, looking at all nodes under that
8397 * axis and selecting them it also do the predicate filtering
8398 *
8399 * Pushes the new NodeSet resulting from the search.
8400 * Returns the number of node traversed
8401 */
8402static int
8403xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
8404 xmlXPathStepOpPtr op, int indx,
8405 xmlNodePtr * first, xmlNodePtr * last)
8406{
8407 xmlXPathAxisVal axis = op->value;
8408 xmlXPathTestVal test = op->value2;
8409 xmlXPathTypeVal type = op->value3;
8410 const xmlChar *prefix = op->value4;
8411 const xmlChar *name = op->value5;
8412 const xmlChar *URI = NULL;
8413 int n = 0, t = 0;
8414
8415 int i;
8416 xmlNodeSetPtr list;
8417 xmlXPathTraversalFunction next = NULL;
8418 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
8419 xmlNodePtr cur = NULL;
8420 xmlXPathObjectPtr obj;
8421 xmlNodeSetPtr nodelist;
8422 xmlNodePtr tmp;
8423
8424 CHECK_TYPE0(XPATH_NODESET);
8425 obj = valuePop(ctxt);
8426 addNode = xmlXPathNodeSetAdd;
8427 if (prefix != NULL) {
8428 URI = xmlXPathNsLookup(ctxt->context, prefix);
8429 if (URI == NULL)
8430 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8431 }
8432#ifdef DEBUG_STEP_NTH
8433 xmlGenericError(xmlGenericErrorContext, "new step : ");
8434 if (first != NULL) {
8435 if (*first != NULL)
8436 xmlGenericError(xmlGenericErrorContext, "first = %s ",
8437 (*first)->name);
8438 else
8439 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
8440 }
8441 if (last != NULL) {
8442 if (*last != NULL)
8443 xmlGenericError(xmlGenericErrorContext, "last = %s ",
8444 (*last)->name);
8445 else
8446 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
8447 }
8448#endif
8449 switch (axis) {
8450 case AXIS_ANCESTOR:
8451#ifdef DEBUG_STEP_NTH
8452 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
8453#endif
8454 first = NULL;
8455 next = xmlXPathNextAncestor;
8456 break;
8457 case AXIS_ANCESTOR_OR_SELF:
8458#ifdef DEBUG_STEP_NTH
8459 xmlGenericError(xmlGenericErrorContext,
8460 "axis 'ancestors-or-self' ");
8461#endif
8462 first = NULL;
8463 next = xmlXPathNextAncestorOrSelf;
8464 break;
8465 case AXIS_ATTRIBUTE:
8466#ifdef DEBUG_STEP_NTH
8467 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
8468#endif
8469 first = NULL;
8470 last = NULL;
8471 next = xmlXPathNextAttribute;
8472 break;
8473 case AXIS_CHILD:
8474#ifdef DEBUG_STEP_NTH
8475 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
8476#endif
8477 last = NULL;
8478 next = xmlXPathNextChild;
8479 break;
8480 case AXIS_DESCENDANT:
8481#ifdef DEBUG_STEP_NTH
8482 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
8483#endif
8484 last = NULL;
8485 next = xmlXPathNextDescendant;
8486 break;
8487 case AXIS_DESCENDANT_OR_SELF:
8488#ifdef DEBUG_STEP_NTH
8489 xmlGenericError(xmlGenericErrorContext,
8490 "axis 'descendant-or-self' ");
8491#endif
8492 last = NULL;
8493 next = xmlXPathNextDescendantOrSelf;
8494 break;
8495 case AXIS_FOLLOWING:
8496#ifdef DEBUG_STEP_NTH
8497 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
8498#endif
8499 last = NULL;
8500 next = xmlXPathNextFollowing;
8501 break;
8502 case AXIS_FOLLOWING_SIBLING:
8503#ifdef DEBUG_STEP_NTH
8504 xmlGenericError(xmlGenericErrorContext,
8505 "axis 'following-siblings' ");
8506#endif
8507 last = NULL;
8508 next = xmlXPathNextFollowingSibling;
8509 break;
8510 case AXIS_NAMESPACE:
8511#ifdef DEBUG_STEP_NTH
8512 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
8513#endif
8514 last = NULL;
8515 first = NULL;
8516 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8517 break;
8518 case AXIS_PARENT:
8519#ifdef DEBUG_STEP_NTH
8520 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
8521#endif
8522 first = NULL;
8523 next = xmlXPathNextParent;
8524 break;
8525 case AXIS_PRECEDING:
8526#ifdef DEBUG_STEP_NTH
8527 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
8528#endif
8529 first = NULL;
8530 next = xmlXPathNextPrecedingInternal;
8531 break;
8532 case AXIS_PRECEDING_SIBLING:
8533#ifdef DEBUG_STEP_NTH
8534 xmlGenericError(xmlGenericErrorContext,
8535 "axis 'preceding-sibling' ");
8536#endif
8537 first = NULL;
8538 next = xmlXPathNextPrecedingSibling;
8539 break;
8540 case AXIS_SELF:
8541#ifdef DEBUG_STEP_NTH
8542 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
8543#endif
8544 first = NULL;
8545 last = NULL;
8546 next = xmlXPathNextSelf;
8547 break;
8548 }
8549 if (next == NULL)
8550 return(0);
8551
8552 nodelist = obj->nodesetval;
8553 if (nodelist == NULL) {
8554 xmlXPathFreeObject(obj);
8555 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8556 return(0);
8557 }
8558 addNode = xmlXPathNodeSetAddUnique;
8559#ifdef DEBUG_STEP_NTH
8560 xmlGenericError(xmlGenericErrorContext,
8561 " context contains %d nodes\n", nodelist->nodeNr);
8562 switch (test) {
8563 case NODE_TEST_NONE:
8564 xmlGenericError(xmlGenericErrorContext,
8565 " searching for none !!!\n");
8566 break;
8567 case NODE_TEST_TYPE:
8568 xmlGenericError(xmlGenericErrorContext,
8569 " searching for type %d\n", type);
8570 break;
8571 case NODE_TEST_PI:
8572 xmlGenericError(xmlGenericErrorContext,
8573 " searching for PI !!!\n");
8574 break;
8575 case NODE_TEST_ALL:
8576 xmlGenericError(xmlGenericErrorContext,
8577 " searching for *\n");
8578 break;
8579 case NODE_TEST_NS:
8580 xmlGenericError(xmlGenericErrorContext,
8581 " searching for namespace %s\n",
8582 prefix);
8583 break;
8584 case NODE_TEST_NAME:
8585 xmlGenericError(xmlGenericErrorContext,
8586 " searching for name %s\n", name);
8587 if (prefix != NULL)
8588 xmlGenericError(xmlGenericErrorContext,
8589 " with namespace %s\n", prefix);
8590 break;
8591 }
8592 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8593#endif
8594 /*
8595 * 2.3 Node Tests
8596 * - For the attribute axis, the principal node type is attribute.
8597 * - For the namespace axis, the principal node type is namespace.
8598 * - For other axes, the principal node type is element.
8599 *
8600 * A node test * is true for any node of the
8601 * principal node type. For example, child::* willi
8602 * select all element children of the context node
8603 */
8604 tmp = ctxt->context->node;
8605 list = xmlXPathNodeSetCreate(NULL);
8606 for (i = 0; i < nodelist->nodeNr; i++) {
8607 ctxt->context->node = nodelist->nodeTab[i];
8608
8609 cur = NULL;
8610 n = 0;
8611 do {
8612 cur = next(ctxt, cur);
8613 if (cur == NULL)
8614 break;
8615 if ((first != NULL) && (*first == cur))
8616 break;
8617 if (((t % 256) == 0) &&
8618 (first != NULL) && (*first != NULL) &&
8619 (xmlXPathCmpNodes(*first, cur) >= 0))
8620 break;
8621 if ((last != NULL) && (*last == cur))
8622 break;
8623 if (((t % 256) == 0) &&
8624 (last != NULL) && (*last != NULL) &&
8625 (xmlXPathCmpNodes(cur, *last) >= 0))
8626 break;
8627 t++;
8628 switch (test) {
8629 case NODE_TEST_NONE:
8630 ctxt->context->node = tmp;
8631 STRANGE return(0);
8632 case NODE_TEST_TYPE:
8633 if ((cur->type == type) ||
8634 ((type == NODE_TYPE_NODE) &&
8635 ((cur->type == XML_DOCUMENT_NODE) ||
8636 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8637 (cur->type == XML_ELEMENT_NODE) ||
8638 (cur->type == XML_PI_NODE) ||
8639 (cur->type == XML_COMMENT_NODE) ||
8640 (cur->type == XML_CDATA_SECTION_NODE) ||
8641 (cur->type == XML_TEXT_NODE)))) {
8642 n++;
8643 if (n == indx)
8644 addNode(list, cur);
8645 }
8646 break;
8647 case NODE_TEST_PI:
8648 if (cur->type == XML_PI_NODE) {
8649 if ((name != NULL) &&
8650 (!xmlStrEqual(name, cur->name)))
8651 break;
8652 n++;
8653 if (n == indx)
8654 addNode(list, cur);
8655 }
8656 break;
8657 case NODE_TEST_ALL:
8658 if (axis == AXIS_ATTRIBUTE) {
8659 if (cur->type == XML_ATTRIBUTE_NODE) {
8660 n++;
8661 if (n == indx)
8662 addNode(list, cur);
8663 }
8664 } else if (axis == AXIS_NAMESPACE) {
8665 if (cur->type == XML_NAMESPACE_DECL) {
8666 n++;
8667 if (n == indx)
8668 addNode(list, cur);
8669 }
8670 } else {
8671 if (cur->type == XML_ELEMENT_NODE) {
8672 if (prefix == NULL) {
8673 n++;
8674 if (n == indx)
8675 addNode(list, cur);
8676 } else if ((cur->ns != NULL) &&
8677 (xmlStrEqual(URI, cur->ns->href))) {
8678 n++;
8679 if (n == indx)
8680 addNode(list, cur);
8681 }
8682 }
8683 }
8684 break;
8685 case NODE_TEST_NS:{
8686 TODO;
8687 break;
8688 }
8689 case NODE_TEST_NAME:
8690 switch (cur->type) {
8691 case XML_ELEMENT_NODE:
8692 if (xmlStrEqual(name, cur->name)) {
8693 if (prefix == NULL) {
8694 if (cur->ns == NULL) {
8695 n++;
8696 if (n == indx)
8697 addNode(list, cur);
8698 }
8699 } else {
8700 if ((cur->ns != NULL) &&
8701 (xmlStrEqual(URI,
8702 cur->ns->href))) {
8703 n++;
8704 if (n == indx)
8705 addNode(list, cur);
8706 }
8707 }
8708 }
8709 break;
8710 case XML_ATTRIBUTE_NODE:{
8711 xmlAttrPtr attr = (xmlAttrPtr) cur;
8712
8713 if (xmlStrEqual(name, attr->name)) {
8714 if (prefix == NULL) {
8715 if ((attr->ns == NULL) ||
8716 (attr->ns->prefix == NULL)) {
8717 n++;
8718 if (n == indx)
8719 addNode(list, cur);
8720 }
8721 } else {
8722 if ((attr->ns != NULL) &&
8723 (xmlStrEqual(URI,
8724 attr->ns->
8725 href))) {
8726 n++;
8727 if (n == indx)
8728 addNode(list, cur);
8729 }
8730 }
8731 }
8732 break;
8733 }
8734 case XML_NAMESPACE_DECL:
8735 if (cur->type == XML_NAMESPACE_DECL) {
8736 xmlNsPtr ns = (xmlNsPtr) cur;
8737
8738 if ((ns->prefix != NULL) && (name != NULL)
8739 && (xmlStrEqual(ns->prefix, name))) {
8740 n++;
8741 if (n == indx)
8742 addNode(list, cur);
8743 }
8744 }
8745 break;
8746 default:
8747 break;
8748 }
8749 break;
8750 break;
8751 }
8752 } while (n < indx);
8753 }
8754 ctxt->context->node = tmp;
8755#ifdef DEBUG_STEP_NTH
8756 xmlGenericError(xmlGenericErrorContext,
8757 "\nExamined %d nodes, found %d nodes at that step\n",
8758 t, list->nodeNr);
8759#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008760 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00008761 if ((obj->boolval) && (obj->user != NULL)) {
8762 ctxt->value->boolval = 1;
8763 ctxt->value->user = obj->user;
8764 obj->user = NULL;
8765 obj->boolval = 0;
8766 }
8767 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008768 return(t);
8769}
8770
8771/**
8772 * xmlXPathCompOpEvalFirst:
8773 * @ctxt: the XPath parser context with the compiled expression
8774 * @op: an XPath compiled operation
8775 * @first: the first elem found so far
8776 *
8777 * Evaluate the Precompiled XPath operation searching only the first
8778 * element in document order
8779 *
8780 * Returns the number of examined objects.
8781 */
8782static int
8783xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
8784 xmlXPathStepOpPtr op, xmlNodePtr * first)
8785{
8786 int total = 0, cur;
8787 xmlXPathCompExprPtr comp;
8788 xmlXPathObjectPtr arg1, arg2;
8789
Daniel Veillard556c6682001-10-06 09:59:51 +00008790 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008791 comp = ctxt->comp;
8792 switch (op->op) {
8793 case XPATH_OP_END:
8794 return (0);
8795 case XPATH_OP_UNION:
8796 total =
8797 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
8798 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00008799 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008800 if ((ctxt->value != NULL)
8801 && (ctxt->value->type == XPATH_NODESET)
8802 && (ctxt->value->nodesetval != NULL)
8803 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8804 /*
8805 * limit tree traversing to first node in the result
8806 */
8807 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8808 *first = ctxt->value->nodesetval->nodeTab[0];
8809 }
8810 cur =
8811 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
8812 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00008813 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008814 CHECK_TYPE0(XPATH_NODESET);
8815 arg2 = valuePop(ctxt);
8816
8817 CHECK_TYPE0(XPATH_NODESET);
8818 arg1 = valuePop(ctxt);
8819
8820 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8821 arg2->nodesetval);
8822 valuePush(ctxt, arg1);
8823 xmlXPathFreeObject(arg2);
8824 /* optimizer */
8825 if (total > cur)
8826 xmlXPathCompSwap(op);
8827 return (total + cur);
8828 case XPATH_OP_ROOT:
8829 xmlXPathRoot(ctxt);
8830 return (0);
8831 case XPATH_OP_NODE:
8832 if (op->ch1 != -1)
8833 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008834 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008835 if (op->ch2 != -1)
8836 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008837 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008838 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8839 return (total);
8840 case XPATH_OP_RESET:
8841 if (op->ch1 != -1)
8842 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008843 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008844 if (op->ch2 != -1)
8845 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008846 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008847 ctxt->context->node = NULL;
8848 return (total);
8849 case XPATH_OP_COLLECT:{
8850 if (op->ch1 == -1)
8851 return (total);
8852
8853 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008854 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008855
8856 /*
8857 * Optimization for [n] selection where n is a number
8858 */
8859 if ((op->ch2 != -1) &&
8860 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8861 (comp->steps[op->ch2].ch1 == -1) &&
8862 (comp->steps[op->ch2].ch2 != -1) &&
8863 (comp->steps[comp->steps[op->ch2].ch2].op ==
8864 XPATH_OP_VALUE)) {
8865 xmlXPathObjectPtr val;
8866
8867 val = comp->steps[comp->steps[op->ch2].ch2].value4;
8868 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
8869 int indx = (int) val->floatval;
8870
8871 if (val->floatval == (float) indx) {
8872 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
8873 first, NULL);
8874 return (total);
8875 }
8876 }
8877 }
8878 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
8879 return (total);
8880 }
8881 case XPATH_OP_VALUE:
8882 valuePush(ctxt,
8883 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
8884 return (0);
8885 case XPATH_OP_SORT:
8886 if (op->ch1 != -1)
8887 total +=
8888 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
8889 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00008890 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008891 if ((ctxt->value != NULL)
8892 && (ctxt->value->type == XPATH_NODESET)
8893 && (ctxt->value->nodesetval != NULL))
8894 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8895 return (total);
8896 default:
8897 return (xmlXPathCompOpEval(ctxt, op));
8898 }
8899}
8900
8901/**
8902 * xmlXPathCompOpEvalLast:
8903 * @ctxt: the XPath parser context with the compiled expression
8904 * @op: an XPath compiled operation
8905 * @last: the last elem found so far
8906 *
8907 * Evaluate the Precompiled XPath operation searching only the last
8908 * element in document order
8909 *
8910 * Returns the number of node traversed
8911 */
8912static int
8913xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
8914 xmlNodePtr * last)
8915{
8916 int total = 0, cur;
8917 xmlXPathCompExprPtr comp;
8918 xmlXPathObjectPtr arg1, arg2;
8919
Daniel Veillard556c6682001-10-06 09:59:51 +00008920 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008921 comp = ctxt->comp;
8922 switch (op->op) {
8923 case XPATH_OP_END:
8924 return (0);
8925 case XPATH_OP_UNION:
8926 total =
8927 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00008928 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008929 if ((ctxt->value != NULL)
8930 && (ctxt->value->type == XPATH_NODESET)
8931 && (ctxt->value->nodesetval != NULL)
8932 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8933 /*
8934 * limit tree traversing to first node in the result
8935 */
8936 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8937 *last =
8938 ctxt->value->nodesetval->nodeTab[ctxt->value->
8939 nodesetval->nodeNr -
8940 1];
8941 }
8942 cur =
8943 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00008944 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008945 if ((ctxt->value != NULL)
8946 && (ctxt->value->type == XPATH_NODESET)
8947 && (ctxt->value->nodesetval != NULL)
8948 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8949 }
8950 CHECK_TYPE0(XPATH_NODESET);
8951 arg2 = valuePop(ctxt);
8952
8953 CHECK_TYPE0(XPATH_NODESET);
8954 arg1 = valuePop(ctxt);
8955
8956 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8957 arg2->nodesetval);
8958 valuePush(ctxt, arg1);
8959 xmlXPathFreeObject(arg2);
8960 /* optimizer */
8961 if (total > cur)
8962 xmlXPathCompSwap(op);
8963 return (total + cur);
8964 case XPATH_OP_ROOT:
8965 xmlXPathRoot(ctxt);
8966 return (0);
8967 case XPATH_OP_NODE:
8968 if (op->ch1 != -1)
8969 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008970 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008971 if (op->ch2 != -1)
8972 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008973 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008974 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8975 return (total);
8976 case XPATH_OP_RESET:
8977 if (op->ch1 != -1)
8978 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008979 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008980 if (op->ch2 != -1)
8981 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008982 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008983 ctxt->context->node = NULL;
8984 return (total);
8985 case XPATH_OP_COLLECT:{
8986 if (op->ch1 == -1)
8987 return (0);
8988
8989 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00008990 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008991
8992 /*
8993 * Optimization for [n] selection where n is a number
8994 */
8995 if ((op->ch2 != -1) &&
8996 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8997 (comp->steps[op->ch2].ch1 == -1) &&
8998 (comp->steps[op->ch2].ch2 != -1) &&
8999 (comp->steps[comp->steps[op->ch2].ch2].op ==
9000 XPATH_OP_VALUE)) {
9001 xmlXPathObjectPtr val;
9002
9003 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9004 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9005 int indx = (int) val->floatval;
9006
9007 if (val->floatval == (float) indx) {
9008 total +=
9009 xmlXPathNodeCollectAndTestNth(ctxt, op,
9010 indx, NULL,
9011 last);
9012 return (total);
9013 }
9014 }
9015 }
9016 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9017 return (total);
9018 }
9019 case XPATH_OP_VALUE:
9020 valuePush(ctxt,
9021 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9022 return (0);
9023 case XPATH_OP_SORT:
9024 if (op->ch1 != -1)
9025 total +=
9026 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9027 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009028 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009029 if ((ctxt->value != NULL)
9030 && (ctxt->value->type == XPATH_NODESET)
9031 && (ctxt->value->nodesetval != NULL))
9032 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9033 return (total);
9034 default:
9035 return (xmlXPathCompOpEval(ctxt, op));
9036 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009037}
9038
Owen Taylor3473f882001-02-23 17:55:21 +00009039/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009040 * xmlXPathCompOpEval:
9041 * @ctxt: the XPath parser context with the compiled expression
9042 * @op: an XPath compiled operation
9043 *
9044 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009045 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009046 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009047static int
9048xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9049{
9050 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009051 int equal, ret;
9052 xmlXPathCompExprPtr comp;
9053 xmlXPathObjectPtr arg1, arg2;
9054
Daniel Veillard556c6682001-10-06 09:59:51 +00009055 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009056 comp = ctxt->comp;
9057 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009058 case XPATH_OP_END:
9059 return (0);
9060 case XPATH_OP_AND:
9061 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009062 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009063 xmlXPathBooleanFunction(ctxt, 1);
9064 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9065 return (total);
9066 arg2 = valuePop(ctxt);
9067 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009068 if (ctxt->error) {
9069 xmlXPathFreeObject(arg2);
9070 return(0);
9071 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009072 xmlXPathBooleanFunction(ctxt, 1);
9073 arg1 = valuePop(ctxt);
9074 arg1->boolval &= arg2->boolval;
9075 valuePush(ctxt, arg1);
9076 xmlXPathFreeObject(arg2);
9077 return (total);
9078 case XPATH_OP_OR:
9079 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009080 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009081 xmlXPathBooleanFunction(ctxt, 1);
9082 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9083 return (total);
9084 arg2 = valuePop(ctxt);
9085 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009086 if (ctxt->error) {
9087 xmlXPathFreeObject(arg2);
9088 return(0);
9089 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009090 xmlXPathBooleanFunction(ctxt, 1);
9091 arg1 = valuePop(ctxt);
9092 arg1->boolval |= arg2->boolval;
9093 valuePush(ctxt, arg1);
9094 xmlXPathFreeObject(arg2);
9095 return (total);
9096 case XPATH_OP_EQUAL:
9097 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009098 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009099 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009100 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009101 equal = xmlXPathEqualValues(ctxt);
9102 if (op->value)
9103 valuePush(ctxt, xmlXPathNewBoolean(equal));
9104 else
9105 valuePush(ctxt, xmlXPathNewBoolean(!equal));
9106 return (total);
9107 case XPATH_OP_CMP:
9108 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009109 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009110 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009111 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009112 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9113 valuePush(ctxt, xmlXPathNewBoolean(ret));
9114 return (total);
9115 case XPATH_OP_PLUS:
9116 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009117 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009118 if (op->ch2 != -1)
9119 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009120 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009121 if (op->value == 0)
9122 xmlXPathSubValues(ctxt);
9123 else if (op->value == 1)
9124 xmlXPathAddValues(ctxt);
9125 else if (op->value == 2)
9126 xmlXPathValueFlipSign(ctxt);
9127 else if (op->value == 3) {
9128 CAST_TO_NUMBER;
9129 CHECK_TYPE0(XPATH_NUMBER);
9130 }
9131 return (total);
9132 case XPATH_OP_MULT:
9133 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009134 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009135 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009136 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009137 if (op->value == 0)
9138 xmlXPathMultValues(ctxt);
9139 else if (op->value == 1)
9140 xmlXPathDivValues(ctxt);
9141 else if (op->value == 2)
9142 xmlXPathModValues(ctxt);
9143 return (total);
9144 case XPATH_OP_UNION:
9145 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009146 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009147 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009148 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009149 CHECK_TYPE0(XPATH_NODESET);
9150 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009151
Daniel Veillardf06307e2001-07-03 10:35:50 +00009152 CHECK_TYPE0(XPATH_NODESET);
9153 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009154
Daniel Veillardf06307e2001-07-03 10:35:50 +00009155 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9156 arg2->nodesetval);
9157 valuePush(ctxt, arg1);
9158 xmlXPathFreeObject(arg2);
9159 return (total);
9160 case XPATH_OP_ROOT:
9161 xmlXPathRoot(ctxt);
9162 return (total);
9163 case XPATH_OP_NODE:
9164 if (op->ch1 != -1)
9165 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009166 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009167 if (op->ch2 != -1)
9168 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009169 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009170 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9171 return (total);
9172 case XPATH_OP_RESET:
9173 if (op->ch1 != -1)
9174 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009175 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009176 if (op->ch2 != -1)
9177 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009178 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009179 ctxt->context->node = NULL;
9180 return (total);
9181 case XPATH_OP_COLLECT:{
9182 if (op->ch1 == -1)
9183 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009184
Daniel Veillardf06307e2001-07-03 10:35:50 +00009185 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009186 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009187
Daniel Veillardf06307e2001-07-03 10:35:50 +00009188 /*
9189 * Optimization for [n] selection where n is a number
9190 */
9191 if ((op->ch2 != -1) &&
9192 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9193 (comp->steps[op->ch2].ch1 == -1) &&
9194 (comp->steps[op->ch2].ch2 != -1) &&
9195 (comp->steps[comp->steps[op->ch2].ch2].op ==
9196 XPATH_OP_VALUE)) {
9197 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00009198
Daniel Veillardf06307e2001-07-03 10:35:50 +00009199 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9200 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9201 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009202
Daniel Veillardf06307e2001-07-03 10:35:50 +00009203 if (val->floatval == (float) indx) {
9204 total +=
9205 xmlXPathNodeCollectAndTestNth(ctxt, op,
9206 indx, NULL,
9207 NULL);
9208 return (total);
9209 }
9210 }
9211 }
9212 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
9213 return (total);
9214 }
9215 case XPATH_OP_VALUE:
9216 valuePush(ctxt,
9217 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9218 return (total);
9219 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +00009220 xmlXPathObjectPtr val;
9221
Daniel Veillardf06307e2001-07-03 10:35:50 +00009222 if (op->ch1 != -1)
9223 total +=
9224 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009225 if (op->value5 == NULL) {
9226 val = xmlXPathVariableLookup(ctxt->context, op->value4);
9227 if (val == NULL) {
9228 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9229 return(0);
9230 }
9231 valuePush(ctxt, val);
9232 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009233 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009234
Daniel Veillardf06307e2001-07-03 10:35:50 +00009235 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9236 if (URI == NULL) {
9237 xmlGenericError(xmlGenericErrorContext,
9238 "xmlXPathRunEval: variable %s bound to undefined prefix %s\n",
9239 op->value4, op->value5);
9240 return (total);
9241 }
Daniel Veillard556c6682001-10-06 09:59:51 +00009242 val = xmlXPathVariableLookupNS(ctxt->context,
9243 op->value4, URI);
9244 if (val == NULL) {
9245 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
9246 return(0);
9247 }
9248 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009249 }
9250 return (total);
9251 }
9252 case XPATH_OP_FUNCTION:{
9253 xmlXPathFunction func;
9254 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +00009255 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009256
9257 if (op->ch1 != -1)
9258 total +=
9259 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009260 if (ctxt->valueNr < op->value) {
9261 xmlGenericError(xmlGenericErrorContext,
9262 "xmlXPathRunEval: parameter error\n");
9263 ctxt->error = XPATH_INVALID_OPERAND;
9264 return (total);
9265 }
9266 for (i = 0; i < op->value; i++)
9267 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
9268 xmlGenericError(xmlGenericErrorContext,
9269 "xmlXPathRunEval: parameter error\n");
9270 ctxt->error = XPATH_INVALID_OPERAND;
9271 return (total);
9272 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009273 if (op->cache != NULL)
9274 func = (xmlXPathFunction) op->cache;
9275 else {
9276 const xmlChar *URI = NULL;
9277
9278 if (op->value5 == NULL)
9279 func =
9280 xmlXPathFunctionLookup(ctxt->context,
9281 op->value4);
9282 else {
9283 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9284 if (URI == NULL) {
9285 xmlGenericError(xmlGenericErrorContext,
9286 "xmlXPathRunEval: function %s bound to undefined prefix %s\n",
9287 op->value4, op->value5);
9288 return (total);
9289 }
9290 func = xmlXPathFunctionLookupNS(ctxt->context,
9291 op->value4, URI);
9292 }
9293 if (func == NULL) {
9294 xmlGenericError(xmlGenericErrorContext,
9295 "xmlXPathRunEval: function %s not found\n",
9296 op->value4);
9297 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009298 }
9299 op->cache = (void *) func;
9300 op->cacheURI = (void *) URI;
9301 }
9302 oldFunc = ctxt->context->function;
9303 oldFuncURI = ctxt->context->functionURI;
9304 ctxt->context->function = op->value4;
9305 ctxt->context->functionURI = op->cacheURI;
9306 func(ctxt, op->value);
9307 ctxt->context->function = oldFunc;
9308 ctxt->context->functionURI = oldFuncURI;
9309 return (total);
9310 }
9311 case XPATH_OP_ARG:
9312 if (op->ch1 != -1)
9313 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009314 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009315 if (op->ch2 != -1)
9316 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009317 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009318 return (total);
9319 case XPATH_OP_PREDICATE:
9320 case XPATH_OP_FILTER:{
9321 xmlXPathObjectPtr res;
9322 xmlXPathObjectPtr obj, tmp;
9323 xmlNodeSetPtr newset = NULL;
9324 xmlNodeSetPtr oldset;
9325 xmlNodePtr oldnode;
9326 int i;
9327
9328 /*
9329 * Optimization for ()[1] selection i.e. the first elem
9330 */
9331 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9332 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9333 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
9334 xmlXPathObjectPtr val;
9335
9336 val = comp->steps[op->ch2].value4;
9337 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
9338 (val->floatval == 1.0)) {
9339 xmlNodePtr first = NULL;
9340
9341 total +=
9342 xmlXPathCompOpEvalFirst(ctxt,
9343 &comp->steps[op->ch1],
9344 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009345 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009346 /*
9347 * The nodeset should be in document order,
9348 * Keep only the first value
9349 */
9350 if ((ctxt->value != NULL) &&
9351 (ctxt->value->type == XPATH_NODESET) &&
9352 (ctxt->value->nodesetval != NULL) &&
9353 (ctxt->value->nodesetval->nodeNr > 1))
9354 ctxt->value->nodesetval->nodeNr = 1;
9355 return (total);
9356 }
9357 }
9358 /*
9359 * Optimization for ()[last()] selection i.e. the last elem
9360 */
9361 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9362 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9363 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
9364 int f = comp->steps[op->ch2].ch1;
9365
9366 if ((f != -1) &&
9367 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
9368 (comp->steps[f].value5 == NULL) &&
9369 (comp->steps[f].value == 0) &&
9370 (comp->steps[f].value4 != NULL) &&
9371 (xmlStrEqual
9372 (comp->steps[f].value4, BAD_CAST "last"))) {
9373 xmlNodePtr last = NULL;
9374
9375 total +=
9376 xmlXPathCompOpEvalLast(ctxt,
9377 &comp->steps[op->ch1],
9378 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009379 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009380 /*
9381 * The nodeset should be in document order,
9382 * Keep only the last value
9383 */
9384 if ((ctxt->value != NULL) &&
9385 (ctxt->value->type == XPATH_NODESET) &&
9386 (ctxt->value->nodesetval != NULL) &&
9387 (ctxt->value->nodesetval->nodeTab != NULL) &&
9388 (ctxt->value->nodesetval->nodeNr > 1)) {
9389 ctxt->value->nodesetval->nodeTab[0] =
9390 ctxt->value->nodesetval->nodeTab[ctxt->
9391 value->
9392 nodesetval->
9393 nodeNr -
9394 1];
9395 ctxt->value->nodesetval->nodeNr = 1;
9396 }
9397 return (total);
9398 }
9399 }
9400
9401 if (op->ch1 != -1)
9402 total +=
9403 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009404 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009405 if (op->ch2 == -1)
9406 return (total);
9407 if (ctxt->value == NULL)
9408 return (total);
9409
9410 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009411
9412#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009413 /*
9414 * Hum are we filtering the result of an XPointer expression
9415 */
9416 if (ctxt->value->type == XPATH_LOCATIONSET) {
9417 xmlLocationSetPtr newlocset = NULL;
9418 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009419
Daniel Veillardf06307e2001-07-03 10:35:50 +00009420 /*
9421 * Extract the old locset, and then evaluate the result of the
9422 * expression for all the element in the locset. use it to grow
9423 * up a new locset.
9424 */
9425 CHECK_TYPE0(XPATH_LOCATIONSET);
9426 obj = valuePop(ctxt);
9427 oldlocset = obj->user;
9428 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009429
Daniel Veillardf06307e2001-07-03 10:35:50 +00009430 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
9431 ctxt->context->contextSize = 0;
9432 ctxt->context->proximityPosition = 0;
9433 if (op->ch2 != -1)
9434 total +=
9435 xmlXPathCompOpEval(ctxt,
9436 &comp->steps[op->ch2]);
9437 res = valuePop(ctxt);
9438 if (res != NULL)
9439 xmlXPathFreeObject(res);
9440 valuePush(ctxt, obj);
9441 CHECK_ERROR0;
9442 return (total);
9443 }
9444 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009445
Daniel Veillardf06307e2001-07-03 10:35:50 +00009446 for (i = 0; i < oldlocset->locNr; i++) {
9447 /*
9448 * Run the evaluation with a node list made of a
9449 * single item in the nodelocset.
9450 */
9451 ctxt->context->node = oldlocset->locTab[i]->user;
9452 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9453 valuePush(ctxt, tmp);
9454 ctxt->context->contextSize = oldlocset->locNr;
9455 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009456
Daniel Veillardf06307e2001-07-03 10:35:50 +00009457 if (op->ch2 != -1)
9458 total +=
9459 xmlXPathCompOpEval(ctxt,
9460 &comp->steps[op->ch2]);
9461 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009462
Daniel Veillardf06307e2001-07-03 10:35:50 +00009463 /*
9464 * The result of the evaluation need to be tested to
9465 * decided whether the filter succeeded or not
9466 */
9467 res = valuePop(ctxt);
9468 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9469 xmlXPtrLocationSetAdd(newlocset,
9470 xmlXPathObjectCopy
9471 (oldlocset->locTab[i]));
9472 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009473
Daniel Veillardf06307e2001-07-03 10:35:50 +00009474 /*
9475 * Cleanup
9476 */
9477 if (res != NULL)
9478 xmlXPathFreeObject(res);
9479 if (ctxt->value == tmp) {
9480 res = valuePop(ctxt);
9481 xmlXPathFreeObject(res);
9482 }
9483
9484 ctxt->context->node = NULL;
9485 }
9486
9487 /*
9488 * The result is used as the new evaluation locset.
9489 */
9490 xmlXPathFreeObject(obj);
9491 ctxt->context->node = NULL;
9492 ctxt->context->contextSize = -1;
9493 ctxt->context->proximityPosition = -1;
9494 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
9495 ctxt->context->node = oldnode;
9496 return (total);
9497 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009498#endif /* LIBXML_XPTR_ENABLED */
9499
Daniel Veillardf06307e2001-07-03 10:35:50 +00009500 /*
9501 * Extract the old set, and then evaluate the result of the
9502 * expression for all the element in the set. use it to grow
9503 * up a new set.
9504 */
9505 CHECK_TYPE0(XPATH_NODESET);
9506 obj = valuePop(ctxt);
9507 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00009508
Daniel Veillardf06307e2001-07-03 10:35:50 +00009509 oldnode = ctxt->context->node;
9510 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009511
Daniel Veillardf06307e2001-07-03 10:35:50 +00009512 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
9513 ctxt->context->contextSize = 0;
9514 ctxt->context->proximityPosition = 0;
9515 if (op->ch2 != -1)
9516 total +=
9517 xmlXPathCompOpEval(ctxt,
9518 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009519 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009520 res = valuePop(ctxt);
9521 if (res != NULL)
9522 xmlXPathFreeObject(res);
9523 valuePush(ctxt, obj);
9524 ctxt->context->node = oldnode;
9525 CHECK_ERROR0;
9526 } else {
9527 /*
9528 * Initialize the new set.
9529 */
9530 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009531
Daniel Veillardf06307e2001-07-03 10:35:50 +00009532 for (i = 0; i < oldset->nodeNr; i++) {
9533 /*
9534 * Run the evaluation with a node list made of
9535 * a single item in the nodeset.
9536 */
9537 ctxt->context->node = oldset->nodeTab[i];
9538 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9539 valuePush(ctxt, tmp);
9540 ctxt->context->contextSize = oldset->nodeNr;
9541 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009542
Daniel Veillardf06307e2001-07-03 10:35:50 +00009543 if (op->ch2 != -1)
9544 total +=
9545 xmlXPathCompOpEval(ctxt,
9546 &comp->steps[op->ch2]);
9547 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009548
Daniel Veillardf06307e2001-07-03 10:35:50 +00009549 /*
9550 * The result of the evaluation need to be tested to
9551 * decided whether the filter succeeded or not
9552 */
9553 res = valuePop(ctxt);
9554 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9555 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
9556 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009557
Daniel Veillardf06307e2001-07-03 10:35:50 +00009558 /*
9559 * Cleanup
9560 */
9561 if (res != NULL)
9562 xmlXPathFreeObject(res);
9563 if (ctxt->value == tmp) {
9564 res = valuePop(ctxt);
9565 xmlXPathFreeObject(res);
9566 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009567
Daniel Veillardf06307e2001-07-03 10:35:50 +00009568 ctxt->context->node = NULL;
9569 }
9570
9571 /*
9572 * The result is used as the new evaluation set.
9573 */
9574 xmlXPathFreeObject(obj);
9575 ctxt->context->node = NULL;
9576 ctxt->context->contextSize = -1;
9577 ctxt->context->proximityPosition = -1;
9578 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
9579 }
9580 ctxt->context->node = oldnode;
9581 return (total);
9582 }
9583 case XPATH_OP_SORT:
9584 if (op->ch1 != -1)
9585 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009586 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009587 if ((ctxt->value != NULL) &&
9588 (ctxt->value->type == XPATH_NODESET) &&
9589 (ctxt->value->nodesetval != NULL))
9590 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9591 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009592#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009593 case XPATH_OP_RANGETO:{
9594 xmlXPathObjectPtr range;
9595 xmlXPathObjectPtr res, obj;
9596 xmlXPathObjectPtr tmp;
9597 xmlLocationSetPtr newset = NULL;
9598 xmlNodeSetPtr oldset;
9599 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009600
Daniel Veillardf06307e2001-07-03 10:35:50 +00009601 if (op->ch1 != -1)
9602 total +=
9603 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9604 if (op->ch2 == -1)
9605 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009606
Daniel Veillardf06307e2001-07-03 10:35:50 +00009607 CHECK_TYPE0(XPATH_NODESET);
9608 obj = valuePop(ctxt);
9609 oldset = obj->nodesetval;
9610 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009611
Daniel Veillardf06307e2001-07-03 10:35:50 +00009612 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009613
Daniel Veillardf06307e2001-07-03 10:35:50 +00009614 if (oldset != NULL) {
9615 for (i = 0; i < oldset->nodeNr; i++) {
9616 /*
9617 * Run the evaluation with a node list made of a single item
9618 * in the nodeset.
9619 */
9620 ctxt->context->node = oldset->nodeTab[i];
9621 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9622 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009623
Daniel Veillardf06307e2001-07-03 10:35:50 +00009624 if (op->ch2 != -1)
9625 total +=
9626 xmlXPathCompOpEval(ctxt,
9627 &comp->steps[op->ch2]);
9628 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009629
Daniel Veillardf06307e2001-07-03 10:35:50 +00009630 /*
9631 * The result of the evaluation need to be tested to
9632 * decided whether the filter succeeded or not
9633 */
9634 res = valuePop(ctxt);
9635 range =
9636 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
9637 res);
9638 if (range != NULL) {
9639 xmlXPtrLocationSetAdd(newset, range);
9640 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009641
Daniel Veillardf06307e2001-07-03 10:35:50 +00009642 /*
9643 * Cleanup
9644 */
9645 if (res != NULL)
9646 xmlXPathFreeObject(res);
9647 if (ctxt->value == tmp) {
9648 res = valuePop(ctxt);
9649 xmlXPathFreeObject(res);
9650 }
9651
9652 ctxt->context->node = NULL;
9653 }
9654 }
9655
9656 /*
9657 * The result is used as the new evaluation set.
9658 */
9659 xmlXPathFreeObject(obj);
9660 ctxt->context->node = NULL;
9661 ctxt->context->contextSize = -1;
9662 ctxt->context->proximityPosition = -1;
9663 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
9664 return (total);
9665 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009666#endif /* LIBXML_XPTR_ENABLED */
9667 }
9668 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009669 "XPath: unknown precompiled operation %d\n", op->op);
9670 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009671}
9672
9673/**
9674 * xmlXPathRunEval:
9675 * @ctxt: the XPath parser context with the compiled expression
9676 *
9677 * Evaluate the Precompiled XPath expression in the given context.
9678 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009679static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009680xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
9681 xmlXPathCompExprPtr comp;
9682
9683 if ((ctxt == NULL) || (ctxt->comp == NULL))
9684 return;
9685
9686 if (ctxt->valueTab == NULL) {
9687 /* Allocate the value stack */
9688 ctxt->valueTab = (xmlXPathObjectPtr *)
9689 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
9690 if (ctxt->valueTab == NULL) {
9691 xmlFree(ctxt);
9692 xmlGenericError(xmlGenericErrorContext,
9693 "xmlXPathRunEval: out of memory\n");
9694 return;
9695 }
9696 ctxt->valueNr = 0;
9697 ctxt->valueMax = 10;
9698 ctxt->value = NULL;
9699 }
9700 comp = ctxt->comp;
9701 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
9702}
9703
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009704/************************************************************************
9705 * *
9706 * Public interfaces *
9707 * *
9708 ************************************************************************/
9709
9710/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009711 * xmlXPathEvalPredicate:
9712 * @ctxt: the XPath context
9713 * @res: the Predicate Expression evaluation result
9714 *
9715 * Evaluate a predicate result for the current node.
9716 * A PredicateExpr is evaluated by evaluating the Expr and converting
9717 * the result to a boolean. If the result is a number, the result will
9718 * be converted to true if the number is equal to the position of the
9719 * context node in the context node list (as returned by the position
9720 * function) and will be converted to false otherwise; if the result
9721 * is not a number, then the result will be converted as if by a call
9722 * to the boolean function.
9723 *
9724 * Return 1 if predicate is true, 0 otherwise
9725 */
9726int
9727xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
9728 if (res == NULL) return(0);
9729 switch (res->type) {
9730 case XPATH_BOOLEAN:
9731 return(res->boolval);
9732 case XPATH_NUMBER:
9733 return(res->floatval == ctxt->proximityPosition);
9734 case XPATH_NODESET:
9735 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009736 if (res->nodesetval == NULL)
9737 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009738 return(res->nodesetval->nodeNr != 0);
9739 case XPATH_STRING:
9740 return((res->stringval != NULL) &&
9741 (xmlStrlen(res->stringval) != 0));
9742 default:
9743 STRANGE
9744 }
9745 return(0);
9746}
9747
9748/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009749 * xmlXPathEvaluatePredicateResult:
9750 * @ctxt: the XPath Parser context
9751 * @res: the Predicate Expression evaluation result
9752 *
9753 * Evaluate a predicate result for the current node.
9754 * A PredicateExpr is evaluated by evaluating the Expr and converting
9755 * the result to a boolean. If the result is a number, the result will
9756 * be converted to true if the number is equal to the position of the
9757 * context node in the context node list (as returned by the position
9758 * function) and will be converted to false otherwise; if the result
9759 * is not a number, then the result will be converted as if by a call
9760 * to the boolean function.
9761 *
9762 * Return 1 if predicate is true, 0 otherwise
9763 */
9764int
9765xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
9766 xmlXPathObjectPtr res) {
9767 if (res == NULL) return(0);
9768 switch (res->type) {
9769 case XPATH_BOOLEAN:
9770 return(res->boolval);
9771 case XPATH_NUMBER:
9772 return(res->floatval == ctxt->context->proximityPosition);
9773 case XPATH_NODESET:
9774 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +00009775 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +00009776 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009777 return(res->nodesetval->nodeNr != 0);
9778 case XPATH_STRING:
9779 return((res->stringval != NULL) &&
9780 (xmlStrlen(res->stringval) != 0));
9781 default:
9782 STRANGE
9783 }
9784 return(0);
9785}
9786
9787/**
9788 * xmlXPathCompile:
9789 * @str: the XPath expression
9790 *
9791 * Compile an XPath expression
9792 *
9793 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9794 * the caller has to free the object.
9795 */
9796xmlXPathCompExprPtr
9797xmlXPathCompile(const xmlChar *str) {
9798 xmlXPathParserContextPtr ctxt;
9799 xmlXPathCompExprPtr comp;
9800
9801 xmlXPathInit();
9802
9803 ctxt = xmlXPathNewParserContext(str, NULL);
9804 xmlXPathCompileExpr(ctxt);
9805
Daniel Veillard40af6492001-04-22 08:50:55 +00009806 if (*ctxt->cur != 0) {
9807 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9808 comp = NULL;
9809 } else {
9810 comp = ctxt->comp;
9811 ctxt->comp = NULL;
9812 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009813 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009814#ifdef DEBUG_EVAL_COUNTS
9815 if (comp != NULL) {
9816 comp->string = xmlStrdup(str);
9817 comp->nb = 0;
9818 }
9819#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009820 return(comp);
9821}
9822
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009823/**
9824 * xmlXPathCompiledEval:
9825 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +00009826 * @ctx: the XPath context
9827 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009828 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +00009829 *
9830 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9831 * the caller has to free the object.
9832 */
9833xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009834xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +00009835 xmlXPathParserContextPtr ctxt;
9836 xmlXPathObjectPtr res, tmp, init = NULL;
9837 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +00009838#ifndef LIBXML_THREAD_ENABLED
9839 static int reentance = 0;
9840#endif
Owen Taylor3473f882001-02-23 17:55:21 +00009841
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009842 if ((comp == NULL) || (ctx == NULL))
9843 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00009844 xmlXPathInit();
9845
9846 CHECK_CONTEXT(ctx)
9847
Daniel Veillard81463942001-10-16 12:34:39 +00009848#ifndef LIBXML_THREAD_ENABLED
9849 reentance++;
9850 if (reentance > 1)
9851 xmlXPathDisableOptimizer = 1;
9852#endif
9853
Daniel Veillardf06307e2001-07-03 10:35:50 +00009854#ifdef DEBUG_EVAL_COUNTS
9855 comp->nb++;
9856 if ((comp->string != NULL) && (comp->nb > 100)) {
9857 fprintf(stderr, "100 x %s\n", comp->string);
9858 comp->nb = 0;
9859 }
9860#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009861 ctxt = xmlXPathCompParserContext(comp, ctx);
9862 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009863
9864 if (ctxt->value == NULL) {
9865 xmlGenericError(xmlGenericErrorContext,
9866 "xmlXPathEval: evaluation failed\n");
9867 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009868 } else {
9869 res = valuePop(ctxt);
9870 }
9871
Daniel Veillardf06307e2001-07-03 10:35:50 +00009872
Owen Taylor3473f882001-02-23 17:55:21 +00009873 do {
9874 tmp = valuePop(ctxt);
9875 if (tmp != NULL) {
9876 if (tmp != init)
9877 stack++;
9878 xmlXPathFreeObject(tmp);
9879 }
9880 } while (tmp != NULL);
9881 if ((stack != 0) && (res != NULL)) {
9882 xmlGenericError(xmlGenericErrorContext,
9883 "xmlXPathEval: %d object left on the stack\n",
9884 stack);
9885 }
9886 if (ctxt->error != XPATH_EXPRESSION_OK) {
9887 xmlXPathFreeObject(res);
9888 res = NULL;
9889 }
9890
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009891
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009892 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009893 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +00009894#ifndef LIBXML_THREAD_ENABLED
9895 reentance--;
9896#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009897 return(res);
9898}
9899
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009900/**
9901 * xmlXPathEvalExpr:
9902 * @ctxt: the XPath Parser context
9903 *
9904 * Parse and evaluate an XPath expression in the given context,
9905 * then push the result on the context stack
9906 */
9907void
9908xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
9909 xmlXPathCompileExpr(ctxt);
9910 xmlXPathRunEval(ctxt);
9911}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009912
9913/**
9914 * xmlXPathEval:
9915 * @str: the XPath expression
9916 * @ctx: the XPath context
9917 *
9918 * Evaluate the XPath Location Path in the given context.
9919 *
9920 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9921 * the caller has to free the object.
9922 */
9923xmlXPathObjectPtr
9924xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
9925 xmlXPathParserContextPtr ctxt;
9926 xmlXPathObjectPtr res, tmp, init = NULL;
9927 int stack = 0;
9928
9929 xmlXPathInit();
9930
9931 CHECK_CONTEXT(ctx)
9932
9933 ctxt = xmlXPathNewParserContext(str, ctx);
9934 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009935
9936 if (ctxt->value == NULL) {
9937 xmlGenericError(xmlGenericErrorContext,
9938 "xmlXPathEval: evaluation failed\n");
9939 res = NULL;
9940 } else if (*ctxt->cur != 0) {
9941 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9942 res = NULL;
9943 } else {
9944 res = valuePop(ctxt);
9945 }
9946
9947 do {
9948 tmp = valuePop(ctxt);
9949 if (tmp != NULL) {
9950 if (tmp != init)
9951 stack++;
9952 xmlXPathFreeObject(tmp);
9953 }
9954 } while (tmp != NULL);
9955 if ((stack != 0) && (res != NULL)) {
9956 xmlGenericError(xmlGenericErrorContext,
9957 "xmlXPathEval: %d object left on the stack\n",
9958 stack);
9959 }
9960 if (ctxt->error != XPATH_EXPRESSION_OK) {
9961 xmlXPathFreeObject(res);
9962 res = NULL;
9963 }
9964
Owen Taylor3473f882001-02-23 17:55:21 +00009965 xmlXPathFreeParserContext(ctxt);
9966 return(res);
9967}
9968
9969/**
9970 * xmlXPathEvalExpression:
9971 * @str: the XPath expression
9972 * @ctxt: the XPath context
9973 *
9974 * Evaluate the XPath expression in the given context.
9975 *
9976 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
9977 * the caller has to free the object.
9978 */
9979xmlXPathObjectPtr
9980xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
9981 xmlXPathParserContextPtr pctxt;
9982 xmlXPathObjectPtr res, tmp;
9983 int stack = 0;
9984
9985 xmlXPathInit();
9986
9987 CHECK_CONTEXT(ctxt)
9988
9989 pctxt = xmlXPathNewParserContext(str, ctxt);
9990 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009991
9992 if (*pctxt->cur != 0) {
9993 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9994 res = NULL;
9995 } else {
9996 res = valuePop(pctxt);
9997 }
9998 do {
9999 tmp = valuePop(pctxt);
10000 if (tmp != NULL) {
10001 xmlXPathFreeObject(tmp);
10002 stack++;
10003 }
10004 } while (tmp != NULL);
10005 if ((stack != 0) && (res != NULL)) {
10006 xmlGenericError(xmlGenericErrorContext,
10007 "xmlXPathEvalExpression: %d object left on the stack\n",
10008 stack);
10009 }
10010 xmlXPathFreeParserContext(pctxt);
10011 return(res);
10012}
10013
10014/**
10015 * xmlXPathRegisterAllFunctions:
10016 * @ctxt: the XPath context
10017 *
10018 * Registers all default XPath functions in this context
10019 */
10020void
10021xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
10022{
10023 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
10024 xmlXPathBooleanFunction);
10025 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
10026 xmlXPathCeilingFunction);
10027 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
10028 xmlXPathCountFunction);
10029 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
10030 xmlXPathConcatFunction);
10031 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
10032 xmlXPathContainsFunction);
10033 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
10034 xmlXPathIdFunction);
10035 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
10036 xmlXPathFalseFunction);
10037 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
10038 xmlXPathFloorFunction);
10039 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
10040 xmlXPathLastFunction);
10041 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
10042 xmlXPathLangFunction);
10043 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
10044 xmlXPathLocalNameFunction);
10045 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
10046 xmlXPathNotFunction);
10047 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
10048 xmlXPathNameFunction);
10049 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
10050 xmlXPathNamespaceURIFunction);
10051 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
10052 xmlXPathNormalizeFunction);
10053 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
10054 xmlXPathNumberFunction);
10055 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
10056 xmlXPathPositionFunction);
10057 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
10058 xmlXPathRoundFunction);
10059 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
10060 xmlXPathStringFunction);
10061 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
10062 xmlXPathStringLengthFunction);
10063 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
10064 xmlXPathStartsWithFunction);
10065 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
10066 xmlXPathSubstringFunction);
10067 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
10068 xmlXPathSubstringBeforeFunction);
10069 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
10070 xmlXPathSubstringAfterFunction);
10071 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
10072 xmlXPathSumFunction);
10073 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
10074 xmlXPathTrueFunction);
10075 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
10076 xmlXPathTranslateFunction);
10077}
10078
10079#endif /* LIBXML_XPATH_ENABLED */