blob: 984752ace6a79f80b4d151f14a2e5c10fbf46380 [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>
Bjorn Reese45029602001-08-21 09:23:53 +000054#include <libxml/trionan.h>
Owen Taylor3473f882001-02-23 17:55:21 +000055
56/* #define DEBUG */
57/* #define DEBUG_STEP */
Daniel Veillardf06307e2001-07-03 10:35:50 +000058/* #define DEBUG_STEP_NTH */
Owen Taylor3473f882001-02-23 17:55:21 +000059/* #define DEBUG_EXPR */
Daniel Veillardf06307e2001-07-03 10:35:50 +000060/* #define DEBUG_EVAL_COUNTS */
Owen Taylor3473f882001-02-23 17:55:21 +000061
62void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
63double xmlXPathStringEvalNumber(const xmlChar *str);
Daniel Veillard5792e162001-04-30 17:44:45 +000064double xmlXPathDivideBy(double f, double fzero);
Owen Taylor3473f882001-02-23 17:55:21 +000065
Daniel Veillard9e7160d2001-03-18 23:17:47 +000066/************************************************************************
67 * *
68 * Floating point stuff *
69 * *
70 ************************************************************************/
71
Owen Taylor3473f882001-02-23 17:55:21 +000072/*
Owen Taylor3473f882001-02-23 17:55:21 +000073 * The lack of portability of this section of the libc is annoying !
74 */
75double xmlXPathNAN = 0;
76double xmlXPathPINF = 1;
77double xmlXPathNINF = -1;
78
Owen Taylor3473f882001-02-23 17:55:21 +000079/**
80 * xmlXPathInit:
81 *
82 * Initialize the XPath environment
83 */
84void
85xmlXPathInit(void) {
86 static int initialized = 0;
87
88 if (initialized) return;
89
Bjorn Reese45029602001-08-21 09:23:53 +000090 xmlXPathPINF = trio_pinf();
91 xmlXPathNINF = trio_ninf();
92 xmlXPathNAN = trio_nan();
Owen Taylor3473f882001-02-23 17:55:21 +000093
94 initialized = 1;
95}
96
97/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +000098 * *
99 * Parser Types *
100 * *
101 ************************************************************************/
102
103/*
104 * Types are private:
105 */
106
107typedef enum {
108 XPATH_OP_END=0,
109 XPATH_OP_AND,
110 XPATH_OP_OR,
111 XPATH_OP_EQUAL,
112 XPATH_OP_CMP,
113 XPATH_OP_PLUS,
114 XPATH_OP_MULT,
115 XPATH_OP_UNION,
116 XPATH_OP_ROOT,
117 XPATH_OP_NODE,
118 XPATH_OP_RESET,
119 XPATH_OP_COLLECT,
120 XPATH_OP_VALUE,
121 XPATH_OP_VARIABLE,
122 XPATH_OP_FUNCTION,
123 XPATH_OP_ARG,
124 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000125 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000126 XPATH_OP_SORT
127#ifdef LIBXML_XPTR_ENABLED
128 ,XPATH_OP_RANGETO
129#endif
130} xmlXPathOp;
131
132typedef enum {
133 AXIS_ANCESTOR = 1,
134 AXIS_ANCESTOR_OR_SELF,
135 AXIS_ATTRIBUTE,
136 AXIS_CHILD,
137 AXIS_DESCENDANT,
138 AXIS_DESCENDANT_OR_SELF,
139 AXIS_FOLLOWING,
140 AXIS_FOLLOWING_SIBLING,
141 AXIS_NAMESPACE,
142 AXIS_PARENT,
143 AXIS_PRECEDING,
144 AXIS_PRECEDING_SIBLING,
145 AXIS_SELF
146} xmlXPathAxisVal;
147
148typedef enum {
149 NODE_TEST_NONE = 0,
150 NODE_TEST_TYPE = 1,
151 NODE_TEST_PI = 2,
152 NODE_TEST_ALL = 3,
153 NODE_TEST_NS = 4,
154 NODE_TEST_NAME = 5
155} xmlXPathTestVal;
156
157typedef enum {
158 NODE_TYPE_NODE = 0,
159 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
160 NODE_TYPE_TEXT = XML_TEXT_NODE,
161 NODE_TYPE_PI = XML_PI_NODE
162} xmlXPathTypeVal;
163
164
165typedef struct _xmlXPathStepOp xmlXPathStepOp;
166typedef xmlXPathStepOp *xmlXPathStepOpPtr;
167struct _xmlXPathStepOp {
168 xmlXPathOp op;
169 int ch1;
170 int ch2;
171 int value;
172 int value2;
173 int value3;
174 void *value4;
175 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000176 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000177 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000178};
179
180struct _xmlXPathCompExpr {
181 int nbStep;
182 int maxStep;
183 xmlXPathStepOp *steps; /* ops for computation */
184 int last;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000185#ifdef DEBUG_EVAL_COUNTS
186 int nb;
187 xmlChar *string;
188#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000189};
190
191/************************************************************************
192 * *
193 * Parser Type functions *
194 * *
195 ************************************************************************/
196
197/**
198 * xmlXPathNewCompExpr:
199 *
200 * Create a new Xpath component
201 *
202 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
203 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000204static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000205xmlXPathNewCompExpr(void) {
206 xmlXPathCompExprPtr cur;
207
208 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
209 if (cur == NULL) {
210 xmlGenericError(xmlGenericErrorContext,
211 "xmlXPathNewCompExpr : malloc failed\n");
212 return(NULL);
213 }
214 memset(cur, 0, sizeof(xmlXPathCompExpr));
215 cur->maxStep = 10;
216 cur->nbStep = 0;
217 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
218 sizeof(xmlXPathStepOp));
219 if (cur->steps == NULL) {
220 xmlGenericError(xmlGenericErrorContext,
221 "xmlXPathNewCompExpr : malloc failed\n");
222 xmlFree(cur);
223 return(NULL);
224 }
225 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
226 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000227#ifdef DEBUG_EVAL_COUNTS
228 cur->nb = 0;
229#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000230 return(cur);
231}
232
233/**
234 * xmlXPathFreeCompExpr:
235 * @comp: an XPATH comp
236 *
237 * Free up the memory allocated by @comp
238 */
239void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000240xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
241{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000242 xmlXPathStepOpPtr op;
243 int i;
244
245 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000246 return;
247 for (i = 0; i < comp->nbStep; i++) {
248 op = &comp->steps[i];
249 if (op->value4 != NULL) {
250 if (op->op == XPATH_OP_VALUE)
251 xmlXPathFreeObject(op->value4);
252 else
253 xmlFree(op->value4);
254 }
255 if (op->value5 != NULL)
256 xmlFree(op->value5);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000257 }
258 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000259 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000260 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000261#ifdef DEBUG_EVAL_COUNTS
262 if (comp->string != NULL) {
263 xmlFree(comp->string);
264 }
265#endif
266
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000267 xmlFree(comp);
268}
269
270/**
271 * xmlXPathCompExprAdd:
272 * @comp: the compiled expression
273 * @ch1: first child index
274 * @ch2: second child index
275 * @op: an op
276 * @value: the first int value
277 * @value2: the second int value
278 * @value3: the third int value
279 * @value4: the first string value
280 * @value5: the second string value
281 *
282 * Add an step to an XPath Compiled Expression
283 *
284 * Returns -1 in case of failure, the index otherwise
285 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000286static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000287xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
288 xmlXPathOp op, int value,
289 int value2, int value3, void *value4, void *value5) {
290 if (comp->nbStep >= comp->maxStep) {
291 xmlXPathStepOp *real;
292
293 comp->maxStep *= 2;
294 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
295 comp->maxStep * sizeof(xmlXPathStepOp));
296 if (real == NULL) {
297 comp->maxStep /= 2;
298 xmlGenericError(xmlGenericErrorContext,
299 "xmlXPathCompExprAdd : realloc failed\n");
300 return(-1);
301 }
302 comp->steps = real;
303 }
304 comp->last = comp->nbStep;
305 comp->steps[comp->nbStep].ch1 = ch1;
306 comp->steps[comp->nbStep].ch2 = ch2;
307 comp->steps[comp->nbStep].op = op;
308 comp->steps[comp->nbStep].value = value;
309 comp->steps[comp->nbStep].value2 = value2;
310 comp->steps[comp->nbStep].value3 = value3;
311 comp->steps[comp->nbStep].value4 = value4;
312 comp->steps[comp->nbStep].value5 = value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000313 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000314 return(comp->nbStep++);
315}
316
Daniel Veillardf06307e2001-07-03 10:35:50 +0000317/**
318 * xmlXPathCompSwap:
319 * @comp: the compiled expression
320 * @op: operation index
321 *
322 * Swaps 2 operations in the compiled expression
323 * TODO: not thread safe, disable for multi-thread operations
324 *
325 * Returns -1 in case of failure, the index otherwise
326 */
327static void
328xmlXPathCompSwap(xmlXPathStepOpPtr op) {
329 int tmp;
330
331 tmp = op->ch1;
332 op->ch1 = op->ch2;
333 op->ch2 = tmp;
334}
335
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000336#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
337 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
338 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000339#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
340 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
341 (op), (val), (val2), (val3), (val4), (val5))
342
343#define PUSH_LEAVE_EXPR(op, val, val2) \
344xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
345
346#define PUSH_UNARY_EXPR(op, ch, val, val2) \
347xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
348
349#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
350xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
351
352/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000353 * *
354 * Debugging related functions *
355 * *
356 ************************************************************************/
357
358#define TODO \
359 xmlGenericError(xmlGenericErrorContext, \
360 "Unimplemented block at %s:%d\n", \
361 __FILE__, __LINE__);
362
363#define STRANGE \
364 xmlGenericError(xmlGenericErrorContext, \
365 "Internal error at %s:%d\n", \
366 __FILE__, __LINE__);
367
368#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000369static void
370xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000371 int i;
372 char shift[100];
373
374 for (i = 0;((i < depth) && (i < 25));i++)
375 shift[2 * i] = shift[2 * i + 1] = ' ';
376 shift[2 * i] = shift[2 * i + 1] = 0;
377 if (cur == NULL) {
378 fprintf(output, shift);
379 fprintf(output, "Node is NULL !\n");
380 return;
381
382 }
383
384 if ((cur->type == XML_DOCUMENT_NODE) ||
385 (cur->type == XML_HTML_DOCUMENT_NODE)) {
386 fprintf(output, shift);
387 fprintf(output, " /\n");
388 } else if (cur->type == XML_ATTRIBUTE_NODE)
389 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
390 else
391 xmlDebugDumpOneNode(output, cur, depth);
392}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000393static void
394xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000395 xmlNodePtr tmp;
396 int i;
397 char shift[100];
398
399 for (i = 0;((i < depth) && (i < 25));i++)
400 shift[2 * i] = shift[2 * i + 1] = ' ';
401 shift[2 * i] = shift[2 * i + 1] = 0;
402 if (cur == NULL) {
403 fprintf(output, shift);
404 fprintf(output, "Node is NULL !\n");
405 return;
406
407 }
408
409 while (cur != NULL) {
410 tmp = cur;
411 cur = cur->next;
412 xmlDebugDumpOneNode(output, tmp, depth);
413 }
414}
Owen Taylor3473f882001-02-23 17:55:21 +0000415
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000416static void
417xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000418 int i;
419 char shift[100];
420
421 for (i = 0;((i < depth) && (i < 25));i++)
422 shift[2 * i] = shift[2 * i + 1] = ' ';
423 shift[2 * i] = shift[2 * i + 1] = 0;
424
425 if (cur == NULL) {
426 fprintf(output, shift);
427 fprintf(output, "NodeSet is NULL !\n");
428 return;
429
430 }
431
Daniel Veillard911f49a2001-04-07 15:39:35 +0000432 if (cur != NULL) {
433 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
434 for (i = 0;i < cur->nodeNr;i++) {
435 fprintf(output, shift);
436 fprintf(output, "%d", i + 1);
437 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
438 }
Owen Taylor3473f882001-02-23 17:55:21 +0000439 }
440}
441
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000442static void
443xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000444 int i;
445 char shift[100];
446
447 for (i = 0;((i < depth) && (i < 25));i++)
448 shift[2 * i] = shift[2 * i + 1] = ' ';
449 shift[2 * i] = shift[2 * i + 1] = 0;
450
451 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
452 fprintf(output, shift);
453 fprintf(output, "Value Tree is NULL !\n");
454 return;
455
456 }
457
458 fprintf(output, shift);
459 fprintf(output, "%d", i + 1);
460 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
461}
Owen Taylor3473f882001-02-23 17:55:21 +0000462#if defined(LIBXML_XPTR_ENABLED)
463void xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth);
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000464static void
465xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000466 int i;
467 char shift[100];
468
469 for (i = 0;((i < depth) && (i < 25));i++)
470 shift[2 * i] = shift[2 * i + 1] = ' ';
471 shift[2 * i] = shift[2 * i + 1] = 0;
472
473 if (cur == NULL) {
474 fprintf(output, shift);
475 fprintf(output, "LocationSet is NULL !\n");
476 return;
477
478 }
479
480 for (i = 0;i < cur->locNr;i++) {
481 fprintf(output, shift);
482 fprintf(output, "%d : ", i + 1);
483 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
484 }
485}
Daniel Veillard017b1082001-06-21 11:20:21 +0000486#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000487
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000488/**
489 * xmlXPathDebugDumpObject:
490 * @output: the FILE * to dump the output
491 * @cur: the object to inspect
492 * @depth: indentation level
493 *
494 * Dump the content of the object for debugging purposes
495 */
496void
497xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000498 int i;
499 char shift[100];
500
501 for (i = 0;((i < depth) && (i < 25));i++)
502 shift[2 * i] = shift[2 * i + 1] = ' ';
503 shift[2 * i] = shift[2 * i + 1] = 0;
504
505 fprintf(output, shift);
506
507 if (cur == NULL) {
508 fprintf(output, "Object is empty (NULL)\n");
509 return;
510 }
511 switch(cur->type) {
512 case XPATH_UNDEFINED:
513 fprintf(output, "Object is uninitialized\n");
514 break;
515 case XPATH_NODESET:
516 fprintf(output, "Object is a Node Set :\n");
517 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
518 break;
519 case XPATH_XSLT_TREE:
520 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000521 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000522 break;
523 case XPATH_BOOLEAN:
524 fprintf(output, "Object is a Boolean : ");
525 if (cur->boolval) fprintf(output, "true\n");
526 else fprintf(output, "false\n");
527 break;
528 case XPATH_NUMBER:
Bjorn Reese45029602001-08-21 09:23:53 +0000529 switch (trio_isinf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000530 case 1:
531 fprintf(output, "Object is a number : +Infinity\n");
532 break;
533 case -1:
534 fprintf(output, "Object is a number : -Infinity\n");
535 break;
536 default:
Bjorn Reese45029602001-08-21 09:23:53 +0000537 if (trio_isnan(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000538 fprintf(output, "Object is a number : NaN\n");
539 } else {
540 fprintf(output, "Object is a number : %0g\n", cur->floatval);
541 }
542 }
Owen Taylor3473f882001-02-23 17:55:21 +0000543 break;
544 case XPATH_STRING:
545 fprintf(output, "Object is a string : ");
546 xmlDebugDumpString(output, cur->stringval);
547 fprintf(output, "\n");
548 break;
549 case XPATH_POINT:
550 fprintf(output, "Object is a point : index %d in node", cur->index);
551 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
552 fprintf(output, "\n");
553 break;
554 case XPATH_RANGE:
555 if ((cur->user2 == NULL) ||
556 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
557 fprintf(output, "Object is a collapsed range :\n");
558 fprintf(output, shift);
559 if (cur->index >= 0)
560 fprintf(output, "index %d in ", cur->index);
561 fprintf(output, "node\n");
562 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
563 depth + 1);
564 } else {
565 fprintf(output, "Object is a range :\n");
566 fprintf(output, shift);
567 fprintf(output, "From ");
568 if (cur->index >= 0)
569 fprintf(output, "index %d in ", cur->index);
570 fprintf(output, "node\n");
571 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
572 depth + 1);
573 fprintf(output, shift);
574 fprintf(output, "To ");
575 if (cur->index2 >= 0)
576 fprintf(output, "index %d in ", cur->index2);
577 fprintf(output, "node\n");
578 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
579 depth + 1);
580 fprintf(output, "\n");
581 }
582 break;
583 case XPATH_LOCATIONSET:
584#if defined(LIBXML_XPTR_ENABLED)
585 fprintf(output, "Object is a Location Set:\n");
586 xmlXPathDebugDumpLocationSet(output,
587 (xmlLocationSetPtr) cur->user, depth);
588#endif
589 break;
590 case XPATH_USERS:
591 fprintf(output, "Object is user defined\n");
592 break;
593 }
594}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000595
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000596static void
597xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000598 xmlXPathStepOpPtr op, int depth) {
599 int i;
600 char shift[100];
601
602 for (i = 0;((i < depth) && (i < 25));i++)
603 shift[2 * i] = shift[2 * i + 1] = ' ';
604 shift[2 * i] = shift[2 * i + 1] = 0;
605
606 fprintf(output, shift);
607 if (op == NULL) {
608 fprintf(output, "Step is NULL\n");
609 return;
610 }
611 switch (op->op) {
612 case XPATH_OP_END:
613 fprintf(output, "END"); break;
614 case XPATH_OP_AND:
615 fprintf(output, "AND"); break;
616 case XPATH_OP_OR:
617 fprintf(output, "OR"); break;
618 case XPATH_OP_EQUAL:
619 if (op->value)
620 fprintf(output, "EQUAL =");
621 else
622 fprintf(output, "EQUAL !=");
623 break;
624 case XPATH_OP_CMP:
625 if (op->value)
626 fprintf(output, "CMP <");
627 else
628 fprintf(output, "CMP >");
629 if (!op->value2)
630 fprintf(output, "=");
631 break;
632 case XPATH_OP_PLUS:
633 if (op->value == 0)
634 fprintf(output, "PLUS -");
635 else if (op->value == 1)
636 fprintf(output, "PLUS +");
637 else if (op->value == 2)
638 fprintf(output, "PLUS unary -");
639 else if (op->value == 3)
640 fprintf(output, "PLUS unary - -");
641 break;
642 case XPATH_OP_MULT:
643 if (op->value == 0)
644 fprintf(output, "MULT *");
645 else if (op->value == 1)
646 fprintf(output, "MULT div");
647 else
648 fprintf(output, "MULT mod");
649 break;
650 case XPATH_OP_UNION:
651 fprintf(output, "UNION"); break;
652 case XPATH_OP_ROOT:
653 fprintf(output, "ROOT"); break;
654 case XPATH_OP_NODE:
655 fprintf(output, "NODE"); break;
656 case XPATH_OP_RESET:
657 fprintf(output, "RESET"); break;
658 case XPATH_OP_SORT:
659 fprintf(output, "SORT"); break;
660 case XPATH_OP_COLLECT: {
661 xmlXPathAxisVal axis = op->value;
662 xmlXPathTestVal test = op->value2;
663 xmlXPathTypeVal type = op->value3;
664 const xmlChar *prefix = op->value4;
665 const xmlChar *name = op->value5;
666
667 fprintf(output, "COLLECT ");
668 switch (axis) {
669 case AXIS_ANCESTOR:
670 fprintf(output, " 'ancestors' "); break;
671 case AXIS_ANCESTOR_OR_SELF:
672 fprintf(output, " 'ancestors-or-self' "); break;
673 case AXIS_ATTRIBUTE:
674 fprintf(output, " 'attributes' "); break;
675 case AXIS_CHILD:
676 fprintf(output, " 'child' "); break;
677 case AXIS_DESCENDANT:
678 fprintf(output, " 'descendant' "); break;
679 case AXIS_DESCENDANT_OR_SELF:
680 fprintf(output, " 'descendant-or-self' "); break;
681 case AXIS_FOLLOWING:
682 fprintf(output, " 'following' "); break;
683 case AXIS_FOLLOWING_SIBLING:
684 fprintf(output, " 'following-siblings' "); break;
685 case AXIS_NAMESPACE:
686 fprintf(output, " 'namespace' "); break;
687 case AXIS_PARENT:
688 fprintf(output, " 'parent' "); break;
689 case AXIS_PRECEDING:
690 fprintf(output, " 'preceding' "); break;
691 case AXIS_PRECEDING_SIBLING:
692 fprintf(output, " 'preceding-sibling' "); break;
693 case AXIS_SELF:
694 fprintf(output, " 'self' "); break;
695 }
696 switch (test) {
697 case NODE_TEST_NONE:
698 fprintf(output, "'none' "); break;
699 case NODE_TEST_TYPE:
700 fprintf(output, "'type' "); break;
701 case NODE_TEST_PI:
702 fprintf(output, "'PI' "); break;
703 case NODE_TEST_ALL:
704 fprintf(output, "'all' "); break;
705 case NODE_TEST_NS:
706 fprintf(output, "'namespace' "); break;
707 case NODE_TEST_NAME:
708 fprintf(output, "'name' "); break;
709 }
710 switch (type) {
711 case NODE_TYPE_NODE:
712 fprintf(output, "'node' "); break;
713 case NODE_TYPE_COMMENT:
714 fprintf(output, "'comment' "); break;
715 case NODE_TYPE_TEXT:
716 fprintf(output, "'text' "); break;
717 case NODE_TYPE_PI:
718 fprintf(output, "'PI' "); break;
719 }
720 if (prefix != NULL)
721 fprintf(output, "%s:", prefix);
722 if (name != NULL)
723 fprintf(output, "%s", name);
724 break;
725
726 }
727 case XPATH_OP_VALUE: {
728 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
729
730 fprintf(output, "ELEM ");
731 xmlXPathDebugDumpObject(output, object, 0);
732 goto finish;
733 }
734 case XPATH_OP_VARIABLE: {
735 const xmlChar *prefix = op->value5;
736 const xmlChar *name = op->value4;
737
738 if (prefix != NULL)
739 fprintf(output, "VARIABLE %s:%s", prefix, name);
740 else
741 fprintf(output, "VARIABLE %s", name);
742 break;
743 }
744 case XPATH_OP_FUNCTION: {
745 int nbargs = op->value;
746 const xmlChar *prefix = op->value5;
747 const xmlChar *name = op->value4;
748
749 if (prefix != NULL)
750 fprintf(output, "FUNCTION %s:%s(%d args)",
751 prefix, name, nbargs);
752 else
753 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
754 break;
755 }
756 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
757 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000758 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +0000759#ifdef LIBXML_XPTR_ENABLED
760 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
761#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000762 default:
763 fprintf(output, "UNKNOWN %d\n", op->op); return;
764 }
765 fprintf(output, "\n");
766finish:
767 if (op->ch1 >= 0)
768 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
769 if (op->ch2 >= 0)
770 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
771}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000772
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000773/**
774 * xmlXPathDebugDumpCompExpr:
775 * @output: the FILE * for the output
776 * @comp: the precompiled XPath expression
777 * @depth: the indentation level.
778 *
779 * Dumps the tree of the compiled XPath expression.
780 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000781void
782xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
783 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000784 int i;
785 char shift[100];
786
787 for (i = 0;((i < depth) && (i < 25));i++)
788 shift[2 * i] = shift[2 * i + 1] = ' ';
789 shift[2 * i] = shift[2 * i + 1] = 0;
790
791 fprintf(output, shift);
792
793 if (comp == NULL) {
794 fprintf(output, "Compiled Expression is NULL\n");
795 return;
796 }
797 fprintf(output, "Compiled Expression : %d elements\n",
798 comp->nbStep);
799 i = comp->last;
800 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
801}
Daniel Veillard017b1082001-06-21 11:20:21 +0000802#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000803
804/************************************************************************
805 * *
806 * Parser stacks related functions and macros *
807 * *
808 ************************************************************************/
809
810/*
811 * Generic function for accessing stacks in the Parser Context
812 */
813
814#define PUSH_AND_POP(type, name) \
815extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
816 if (ctxt->name##Nr >= ctxt->name##Max) { \
817 ctxt->name##Max *= 2; \
818 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
819 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
820 if (ctxt->name##Tab == NULL) { \
821 xmlGenericError(xmlGenericErrorContext, \
822 "realloc failed !\n"); \
823 return(0); \
824 } \
825 } \
826 ctxt->name##Tab[ctxt->name##Nr] = value; \
827 ctxt->name = value; \
828 return(ctxt->name##Nr++); \
829} \
830extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
831 type ret; \
832 if (ctxt->name##Nr <= 0) return(0); \
833 ctxt->name##Nr--; \
834 if (ctxt->name##Nr > 0) \
835 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
836 else \
837 ctxt->name = NULL; \
838 ret = ctxt->name##Tab[ctxt->name##Nr]; \
839 ctxt->name##Tab[ctxt->name##Nr] = 0; \
840 return(ret); \
841} \
842
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000843/**
844 * valuePop:
845 * @ctxt: an XPath evaluation context
846 *
847 * Pops the top XPath object from the value stack
848 *
849 * Returns the XPath object just removed
850 */
851/**
852 * valuePush:
853 * @ctxt: an XPath evaluation context
854 * @value: the XPath object
855 *
856 * Pushes a new XPath object on top of the value stack
857 */
Owen Taylor3473f882001-02-23 17:55:21 +0000858PUSH_AND_POP(xmlXPathObjectPtr, value)
859
Thomas Broyerf06a3d82001-07-16 04:52:57 +0000860/**
861 * xmlXPathPopBoolean:
862 * @ctxt: an XPath parser context
863 *
864 * Pops a boolean from the stack, handling conversion if needed.
865 * Check error with #xmlXPathCheckError.
866 *
867 * Returns the boolean
868 */
869int
870xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
871 xmlXPathObjectPtr obj;
872 int ret;
873
874 obj = valuePop(ctxt);
875 if (obj == NULL) {
876 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
877 return(0);
878 }
879 ret = xmlXPathCastToBoolean(obj);
880 xmlXPathFreeObject(obj);
881 return(ret);
882}
883
884/**
885 * xmlXPathPopNumber:
886 * @ctxt: an XPath parser context
887 *
888 * Pops a number from the stack, handling conversion if needed.
889 * Check error with #xmlXPathCheckError.
890 *
891 * Returns the number
892 */
893double
894xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
895 xmlXPathObjectPtr obj;
896 double ret;
897
898 obj = valuePop(ctxt);
899 if (obj == NULL) {
900 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
901 return(0);
902 }
903 ret = xmlXPathCastToNumber(obj);
904 xmlXPathFreeObject(obj);
905 return(ret);
906}
907
908/**
909 * xmlXPathPopString:
910 * @ctxt: an XPath parser context
911 *
912 * Pops a string from the stack, handling conversion if needed.
913 * Check error with #xmlXPathCheckError.
914 *
915 * Returns the string
916 */
917xmlChar *
918xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
919 xmlXPathObjectPtr obj;
920 xmlChar * ret;
921
922 obj = valuePop(ctxt);
923 if (obj == NULL) {
924 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
925 return(NULL);
926 }
927 ret = xmlXPathCastToString(obj);
928 /* TODO: needs refactoring somewhere else */
929 if (obj->stringval == ret)
930 obj->stringval = NULL;
931 xmlXPathFreeObject(obj);
932 return(ret);
933}
934
935/**
936 * xmlXPathPopNodeSet:
937 * @ctxt: an XPath parser context
938 *
939 * Pops a node-set from the stack, handling conversion if needed.
940 * Check error with #xmlXPathCheckError.
941 *
942 * Returns the node-set
943 */
944xmlNodeSetPtr
945xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
946 xmlXPathObjectPtr obj;
947 xmlNodeSetPtr ret;
948
949 if (ctxt->value == NULL) {
950 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
951 return(NULL);
952 }
953 if (!xmlXPathStackIsNodeSet(ctxt)) {
954 xmlXPathSetTypeError(ctxt);
955 return(NULL);
956 }
957 obj = valuePop(ctxt);
958 ret = obj->nodesetval;
959 xmlXPathFreeNodeSetList(obj);
960 return(ret);
961}
962
963/**
964 * xmlXPathPopExternal:
965 * @ctxt: an XPath parser context
966 *
967 * Pops an external oject from the stack, handling conversion if needed.
968 * Check error with #xmlXPathCheckError.
969 *
970 * Returns the object
971 */
972void *
973xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
974 xmlXPathObjectPtr obj;
975 void * ret;
976
977 if (ctxt->value == NULL) {
978 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
979 return(NULL);
980 }
981 if (ctxt->value->type != XPATH_USERS) {
982 xmlXPathSetTypeError(ctxt);
983 return(NULL);
984 }
985 obj = valuePop(ctxt);
986 ret = obj->user;
987 xmlXPathFreeObject(obj);
988 return(ret);
989}
990
Owen Taylor3473f882001-02-23 17:55:21 +0000991/*
992 * Macros for accessing the content. Those should be used only by the parser,
993 * and not exported.
994 *
995 * Dirty macros, i.e. one need to make assumption on the context to use them
996 *
997 * CUR_PTR return the current pointer to the xmlChar to be parsed.
998 * CUR returns the current xmlChar value, i.e. a 8 bit value
999 * in ISO-Latin or UTF-8.
1000 * This should be used internally by the parser
1001 * only to compare to ASCII values otherwise it would break when
1002 * running with UTF-8 encoding.
1003 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1004 * to compare on ASCII based substring.
1005 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1006 * strings within the parser.
1007 * CURRENT Returns the current char value, with the full decoding of
1008 * UTF-8 if we are using this mode. It returns an int.
1009 * NEXT Skip to the next character, this does the proper decoding
1010 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1011 * It returns the pointer to the current xmlChar.
1012 */
1013
1014#define CUR (*ctxt->cur)
1015#define SKIP(val) ctxt->cur += (val)
1016#define NXT(val) ctxt->cur[(val)]
1017#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001018#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1019
1020#define COPY_BUF(l,b,i,v) \
1021 if (l == 1) b[i++] = (xmlChar) v; \
1022 else i += xmlCopyChar(l,&b[i],v)
1023
1024#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001025
1026#define SKIP_BLANKS \
1027 while (IS_BLANK(*(ctxt->cur))) NEXT
1028
1029#define CURRENT (*ctxt->cur)
1030#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1031
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001032
1033#ifndef DBL_DIG
1034#define DBL_DIG 16
1035#endif
1036#ifndef DBL_EPSILON
1037#define DBL_EPSILON 1E-9
1038#endif
1039
1040#define UPPER_DOUBLE 1E9
1041#define LOWER_DOUBLE 1E-5
1042
1043#define INTEGER_DIGITS DBL_DIG
1044#define FRACTION_DIGITS (DBL_DIG + 1)
1045#define EXPONENT_DIGITS (3 + 2)
1046
1047/**
1048 * xmlXPathFormatNumber:
1049 * @number: number to format
1050 * @buffer: output buffer
1051 * @buffersize: size of output buffer
1052 *
1053 * Convert the number into a string representation.
1054 */
1055static void
1056xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1057{
Bjorn Reese45029602001-08-21 09:23:53 +00001058 switch (trio_isinf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001059 case 1:
1060 if (buffersize > (int)sizeof("+Infinity"))
1061 sprintf(buffer, "+Infinity");
1062 break;
1063 case -1:
1064 if (buffersize > (int)sizeof("-Infinity"))
1065 sprintf(buffer, "-Infinity");
1066 break;
1067 default:
Bjorn Reese45029602001-08-21 09:23:53 +00001068 if (trio_isnan(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001069 if (buffersize > (int)sizeof("NaN"))
1070 sprintf(buffer, "NaN");
1071 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001072 /* 3 is sign, decimal point, and terminating zero */
1073 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1074 int integer_place, fraction_place;
1075 char *ptr;
1076 char *after_fraction;
1077 double absolute_value;
1078 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001079
Bjorn Reese70a9da52001-04-21 16:57:29 +00001080 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001081
Bjorn Reese70a9da52001-04-21 16:57:29 +00001082 /*
1083 * First choose format - scientific or regular floating point.
1084 * In either case, result is in work, and after_fraction points
1085 * just past the fractional part.
1086 */
1087 if ( ((absolute_value > UPPER_DOUBLE) ||
1088 (absolute_value < LOWER_DOUBLE)) &&
1089 (absolute_value != 0.0) ) {
1090 /* Use scientific notation */
1091 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1092 fraction_place = DBL_DIG - 1;
1093 snprintf(work, sizeof(work),"%*.*e",
1094 integer_place, fraction_place, number);
1095 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001096 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001097 else {
1098 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001099 if (absolute_value > 0.0)
1100 integer_place = 1 + (int)log10(absolute_value);
1101 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001102 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001103 fraction_place = (integer_place > 0)
1104 ? DBL_DIG - integer_place
1105 : DBL_DIG;
1106 size = snprintf(work, sizeof(work), "%0.*f",
1107 fraction_place, number);
1108 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001109 }
1110
Bjorn Reese70a9da52001-04-21 16:57:29 +00001111 /* Remove fractional trailing zeroes */
1112 ptr = after_fraction;
1113 while (*(--ptr) == '0')
1114 ;
1115 if (*ptr != '.')
1116 ptr++;
1117 strcpy(ptr, after_fraction);
1118
1119 /* Finally copy result back to caller */
1120 size = strlen(work) + 1;
1121 if (size > buffersize) {
1122 work[buffersize - 1] = 0;
1123 size = buffersize;
1124 }
1125 memcpy(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001126 }
1127 break;
1128 }
1129}
1130
Owen Taylor3473f882001-02-23 17:55:21 +00001131/************************************************************************
1132 * *
1133 * Error handling routines *
1134 * *
1135 ************************************************************************/
1136
1137
1138const char *xmlXPathErrorMessages[] = {
1139 "Ok",
1140 "Number encoding",
1141 "Unfinished litteral",
1142 "Start of litteral",
1143 "Expected $ for variable reference",
1144 "Undefined variable",
1145 "Invalid predicate",
1146 "Invalid expression",
1147 "Missing closing curly brace",
1148 "Unregistered function",
1149 "Invalid operand",
1150 "Invalid type",
1151 "Invalid number of arguments",
1152 "Invalid context size",
1153 "Invalid context position",
1154 "Memory allocation error",
1155 "Syntax error",
1156 "Resource error",
1157 "Sub resource error",
Daniel Veillard61d80a22001-04-27 17:13:01 +00001158 "Undefined namespace prefix",
1159 "Encoding error",
1160 "Char out of XML range"
Owen Taylor3473f882001-02-23 17:55:21 +00001161};
1162
1163/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001164 * xmlXPatherror:
Owen Taylor3473f882001-02-23 17:55:21 +00001165 * @ctxt: the XPath Parser context
1166 * @file: the file name
1167 * @line: the line number
1168 * @no: the error number
1169 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001170 * Formats an error message.
Owen Taylor3473f882001-02-23 17:55:21 +00001171 */
1172void
1173xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
1174 int line, int no) {
1175 int n;
1176 const xmlChar *cur;
1177 const xmlChar *base;
1178
1179 xmlGenericError(xmlGenericErrorContext,
1180 "Error %s:%d: %s\n", file, line,
1181 xmlXPathErrorMessages[no]);
1182
1183 cur = ctxt->cur;
1184 base = ctxt->base;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001185 if ((cur == NULL) || (base == NULL))
1186 return;
1187
Owen Taylor3473f882001-02-23 17:55:21 +00001188 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
1189 cur--;
1190 }
1191 n = 0;
1192 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
1193 cur--;
1194 if ((*cur == '\n') || (*cur == '\r')) cur++;
1195 base = cur;
1196 n = 0;
1197 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1198 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
1199 n++;
1200 }
1201 xmlGenericError(xmlGenericErrorContext, "\n");
1202 cur = ctxt->cur;
1203 while ((*cur == '\n') || (*cur == '\r'))
1204 cur--;
1205 n = 0;
1206 while ((cur != base) && (n++ < 80)) {
1207 xmlGenericError(xmlGenericErrorContext, " ");
1208 base++;
1209 }
1210 xmlGenericError(xmlGenericErrorContext,"^\n");
1211}
1212
1213
1214/************************************************************************
1215 * *
1216 * Routines to handle NodeSets *
1217 * *
1218 ************************************************************************/
1219
1220/**
1221 * xmlXPathCmpNodes:
1222 * @node1: the first node
1223 * @node2: the second node
1224 *
1225 * Compare two nodes w.r.t document order
1226 *
1227 * Returns -2 in case of error 1 if first point < second point, 0 if
1228 * that's the same node, -1 otherwise
1229 */
1230int
1231xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1232 int depth1, depth2;
1233 xmlNodePtr cur, root;
1234
1235 if ((node1 == NULL) || (node2 == NULL))
1236 return(-2);
1237 /*
1238 * a couple of optimizations which will avoid computations in most cases
1239 */
1240 if (node1 == node2)
1241 return(0);
Daniel Veillardb33c2012001-04-25 12:59:04 +00001242 if ((node1->type == XML_NAMESPACE_DECL) ||
1243 (node2->type == XML_NAMESPACE_DECL))
1244 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001245 if (node1 == node2->prev)
1246 return(1);
1247 if (node1 == node2->next)
1248 return(-1);
1249
1250 /*
1251 * compute depth to root
1252 */
1253 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1254 if (cur == node1)
1255 return(1);
1256 depth2++;
1257 }
1258 root = cur;
1259 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1260 if (cur == node2)
1261 return(-1);
1262 depth1++;
1263 }
1264 /*
1265 * Distinct document (or distinct entities :-( ) case.
1266 */
1267 if (root != cur) {
1268 return(-2);
1269 }
1270 /*
1271 * get the nearest common ancestor.
1272 */
1273 while (depth1 > depth2) {
1274 depth1--;
1275 node1 = node1->parent;
1276 }
1277 while (depth2 > depth1) {
1278 depth2--;
1279 node2 = node2->parent;
1280 }
1281 while (node1->parent != node2->parent) {
1282 node1 = node1->parent;
1283 node2 = node2->parent;
1284 /* should not happen but just in case ... */
1285 if ((node1 == NULL) || (node2 == NULL))
1286 return(-2);
1287 }
1288 /*
1289 * Find who's first.
1290 */
1291 if (node1 == node2->next)
1292 return(-1);
1293 for (cur = node1->next;cur != NULL;cur = cur->next)
1294 if (cur == node2)
1295 return(1);
1296 return(-1); /* assume there is no sibling list corruption */
1297}
1298
1299/**
1300 * xmlXPathNodeSetSort:
1301 * @set: the node set
1302 *
1303 * Sort the node set in document order
1304 */
1305void
1306xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001307 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001308 xmlNodePtr tmp;
1309
1310 if (set == NULL)
1311 return;
1312
1313 /* Use Shell's sort to sort the node-set */
1314 len = set->nodeNr;
1315 for (incr = len / 2; incr > 0; incr /= 2) {
1316 for (i = incr; i < len; i++) {
1317 j = i - incr;
1318 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001319 if (xmlXPathCmpNodes(set->nodeTab[j],
1320 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001321 tmp = set->nodeTab[j];
1322 set->nodeTab[j] = set->nodeTab[j + incr];
1323 set->nodeTab[j + incr] = tmp;
1324 j -= incr;
1325 } else
1326 break;
1327 }
1328 }
1329 }
1330}
1331
1332#define XML_NODESET_DEFAULT 10
1333/**
1334 * xmlXPathNodeSetCreate:
1335 * @val: an initial xmlNodePtr, or NULL
1336 *
1337 * Create a new xmlNodeSetPtr of type double and of value @val
1338 *
1339 * Returns the newly created object.
1340 */
1341xmlNodeSetPtr
1342xmlXPathNodeSetCreate(xmlNodePtr val) {
1343 xmlNodeSetPtr ret;
1344
1345 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1346 if (ret == NULL) {
1347 xmlGenericError(xmlGenericErrorContext,
1348 "xmlXPathNewNodeSet: out of memory\n");
1349 return(NULL);
1350 }
1351 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1352 if (val != NULL) {
1353 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1354 sizeof(xmlNodePtr));
1355 if (ret->nodeTab == NULL) {
1356 xmlGenericError(xmlGenericErrorContext,
1357 "xmlXPathNewNodeSet: out of memory\n");
1358 return(NULL);
1359 }
1360 memset(ret->nodeTab, 0 ,
1361 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1362 ret->nodeMax = XML_NODESET_DEFAULT;
1363 ret->nodeTab[ret->nodeNr++] = val;
1364 }
1365 return(ret);
1366}
1367
1368/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001369 * xmlXPathNodeSetContains:
1370 * @cur: the node-set
1371 * @val: the node
1372 *
1373 * checks whether @cur contains @val
1374 *
1375 * Returns true (1) if @cur contains @val, false (0) otherwise
1376 */
1377int
1378xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1379 int i;
1380
1381 for (i = 0; i < cur->nodeNr; i++) {
1382 if (cur->nodeTab[i] == val)
1383 return(1);
1384 }
1385 return(0);
1386}
1387
1388/**
Owen Taylor3473f882001-02-23 17:55:21 +00001389 * xmlXPathNodeSetAdd:
1390 * @cur: the initial node set
1391 * @val: a new xmlNodePtr
1392 *
1393 * add a new xmlNodePtr ot an existing NodeSet
1394 */
1395void
1396xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1397 int i;
1398
1399 if (val == NULL) return;
1400
1401 /*
1402 * check against doublons
1403 */
1404 for (i = 0;i < cur->nodeNr;i++)
1405 if (cur->nodeTab[i] == val) return;
1406
1407 /*
1408 * grow the nodeTab if needed
1409 */
1410 if (cur->nodeMax == 0) {
1411 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1412 sizeof(xmlNodePtr));
1413 if (cur->nodeTab == NULL) {
1414 xmlGenericError(xmlGenericErrorContext,
1415 "xmlXPathNodeSetAdd: out of memory\n");
1416 return;
1417 }
1418 memset(cur->nodeTab, 0 ,
1419 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1420 cur->nodeMax = XML_NODESET_DEFAULT;
1421 } else if (cur->nodeNr == cur->nodeMax) {
1422 xmlNodePtr *temp;
1423
1424 cur->nodeMax *= 2;
1425 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1426 sizeof(xmlNodePtr));
1427 if (temp == NULL) {
1428 xmlGenericError(xmlGenericErrorContext,
1429 "xmlXPathNodeSetAdd: out of memory\n");
1430 return;
1431 }
1432 cur->nodeTab = temp;
1433 }
1434 cur->nodeTab[cur->nodeNr++] = val;
1435}
1436
1437/**
1438 * xmlXPathNodeSetAddUnique:
1439 * @cur: the initial node set
1440 * @val: a new xmlNodePtr
1441 *
1442 * add a new xmlNodePtr ot an existing NodeSet, optimized version
1443 * when we are sure the node is not already in the set.
1444 */
1445void
1446xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1447 if (val == NULL) return;
1448
1449 /*
1450 * grow the nodeTab if needed
1451 */
1452 if (cur->nodeMax == 0) {
1453 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1454 sizeof(xmlNodePtr));
1455 if (cur->nodeTab == NULL) {
1456 xmlGenericError(xmlGenericErrorContext,
1457 "xmlXPathNodeSetAddUnique: out of memory\n");
1458 return;
1459 }
1460 memset(cur->nodeTab, 0 ,
1461 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1462 cur->nodeMax = XML_NODESET_DEFAULT;
1463 } else if (cur->nodeNr == cur->nodeMax) {
1464 xmlNodePtr *temp;
1465
1466 cur->nodeMax *= 2;
1467 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1468 sizeof(xmlNodePtr));
1469 if (temp == NULL) {
1470 xmlGenericError(xmlGenericErrorContext,
1471 "xmlXPathNodeSetAddUnique: out of memory\n");
1472 return;
1473 }
1474 cur->nodeTab = temp;
1475 }
1476 cur->nodeTab[cur->nodeNr++] = val;
1477}
1478
1479/**
1480 * xmlXPathNodeSetMerge:
1481 * @val1: the first NodeSet or NULL
1482 * @val2: the second NodeSet
1483 *
1484 * Merges two nodesets, all nodes from @val2 are added to @val1
1485 * if @val1 is NULL, a new set is created and copied from @val2
1486 *
1487 * Returns val1 once extended or NULL in case of error.
1488 */
1489xmlNodeSetPtr
1490xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001491 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001492
1493 if (val2 == NULL) return(val1);
1494 if (val1 == NULL) {
1495 val1 = xmlXPathNodeSetCreate(NULL);
1496 }
1497
1498 initNr = val1->nodeNr;
1499
1500 for (i = 0;i < val2->nodeNr;i++) {
1501 /*
1502 * check against doublons
1503 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001504 skip = 0;
1505 for (j = 0; j < initNr; j++) {
1506 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1507 skip = 1;
1508 break;
1509 }
1510 }
1511 if (skip)
1512 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001513
1514 /*
1515 * grow the nodeTab if needed
1516 */
1517 if (val1->nodeMax == 0) {
1518 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1519 sizeof(xmlNodePtr));
1520 if (val1->nodeTab == NULL) {
1521 xmlGenericError(xmlGenericErrorContext,
1522 "xmlXPathNodeSetMerge: out of memory\n");
1523 return(NULL);
1524 }
1525 memset(val1->nodeTab, 0 ,
1526 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1527 val1->nodeMax = XML_NODESET_DEFAULT;
1528 } else if (val1->nodeNr == val1->nodeMax) {
1529 xmlNodePtr *temp;
1530
1531 val1->nodeMax *= 2;
1532 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1533 sizeof(xmlNodePtr));
1534 if (temp == NULL) {
1535 xmlGenericError(xmlGenericErrorContext,
1536 "xmlXPathNodeSetMerge: out of memory\n");
1537 return(NULL);
1538 }
1539 val1->nodeTab = temp;
1540 }
1541 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1542 }
1543
1544 return(val1);
1545}
1546
1547/**
1548 * xmlXPathNodeSetDel:
1549 * @cur: the initial node set
1550 * @val: an xmlNodePtr
1551 *
1552 * Removes an xmlNodePtr from an existing NodeSet
1553 */
1554void
1555xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
1556 int i;
1557
1558 if (cur == NULL) return;
1559 if (val == NULL) return;
1560
1561 /*
1562 * check against doublons
1563 */
1564 for (i = 0;i < cur->nodeNr;i++)
1565 if (cur->nodeTab[i] == val) break;
1566
1567 if (i >= cur->nodeNr) {
1568#ifdef DEBUG
1569 xmlGenericError(xmlGenericErrorContext,
1570 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
1571 val->name);
1572#endif
1573 return;
1574 }
1575 cur->nodeNr--;
1576 for (;i < cur->nodeNr;i++)
1577 cur->nodeTab[i] = cur->nodeTab[i + 1];
1578 cur->nodeTab[cur->nodeNr] = NULL;
1579}
1580
1581/**
1582 * xmlXPathNodeSetRemove:
1583 * @cur: the initial node set
1584 * @val: the index to remove
1585 *
1586 * Removes an entry from an existing NodeSet list.
1587 */
1588void
1589xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
1590 if (cur == NULL) return;
1591 if (val >= cur->nodeNr) return;
1592 cur->nodeNr--;
1593 for (;val < cur->nodeNr;val++)
1594 cur->nodeTab[val] = cur->nodeTab[val + 1];
1595 cur->nodeTab[cur->nodeNr] = NULL;
1596}
1597
1598/**
1599 * xmlXPathFreeNodeSet:
1600 * @obj: the xmlNodeSetPtr to free
1601 *
1602 * Free the NodeSet compound (not the actual nodes !).
1603 */
1604void
1605xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
1606 if (obj == NULL) return;
1607 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001608 xmlFree(obj->nodeTab);
1609 }
Owen Taylor3473f882001-02-23 17:55:21 +00001610 xmlFree(obj);
1611}
1612
1613/**
1614 * xmlXPathFreeValueTree:
1615 * @obj: the xmlNodeSetPtr to free
1616 *
1617 * Free the NodeSet compound and the actual tree, this is different
1618 * from xmlXPathFreeNodeSet()
1619 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001620static void
Owen Taylor3473f882001-02-23 17:55:21 +00001621xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
1622 int i;
1623
1624 if (obj == NULL) return;
1625 for (i = 0;i < obj->nodeNr;i++)
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00001626 if (obj->nodeTab[i] != NULL)
Daniel Veillardbbd51d52001-02-24 03:07:03 +00001627 xmlFreeNodeList(obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001628
1629 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001630 xmlFree(obj->nodeTab);
1631 }
Owen Taylor3473f882001-02-23 17:55:21 +00001632 xmlFree(obj);
1633}
1634
1635#if defined(DEBUG) || defined(DEBUG_STEP)
1636/**
1637 * xmlGenericErrorContextNodeSet:
1638 * @output: a FILE * for the output
1639 * @obj: the xmlNodeSetPtr to free
1640 *
1641 * Quick display of a NodeSet
1642 */
1643void
1644xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
1645 int i;
1646
1647 if (output == NULL) output = xmlGenericErrorContext;
1648 if (obj == NULL) {
1649 fprintf(output, "NodeSet == NULL !\n");
1650 return;
1651 }
1652 if (obj->nodeNr == 0) {
1653 fprintf(output, "NodeSet is empty\n");
1654 return;
1655 }
1656 if (obj->nodeTab == NULL) {
1657 fprintf(output, " nodeTab == NULL !\n");
1658 return;
1659 }
1660 for (i = 0; i < obj->nodeNr; i++) {
1661 if (obj->nodeTab[i] == NULL) {
1662 fprintf(output, " NULL !\n");
1663 return;
1664 }
1665 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
1666 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
1667 fprintf(output, " /");
1668 else if (obj->nodeTab[i]->name == NULL)
1669 fprintf(output, " noname!");
1670 else fprintf(output, " %s", obj->nodeTab[i]->name);
1671 }
1672 fprintf(output, "\n");
1673}
1674#endif
1675
1676/**
1677 * xmlXPathNewNodeSet:
1678 * @val: the NodePtr value
1679 *
1680 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1681 * it with the single Node @val
1682 *
1683 * Returns the newly created object.
1684 */
1685xmlXPathObjectPtr
1686xmlXPathNewNodeSet(xmlNodePtr val) {
1687 xmlXPathObjectPtr ret;
1688
1689 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1690 if (ret == NULL) {
1691 xmlGenericError(xmlGenericErrorContext,
1692 "xmlXPathNewNodeSet: out of memory\n");
1693 return(NULL);
1694 }
1695 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1696 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00001697 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001698 ret->nodesetval = xmlXPathNodeSetCreate(val);
1699 return(ret);
1700}
1701
1702/**
1703 * xmlXPathNewValueTree:
1704 * @val: the NodePtr value
1705 *
1706 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
1707 * it with the tree root @val
1708 *
1709 * Returns the newly created object.
1710 */
1711xmlXPathObjectPtr
1712xmlXPathNewValueTree(xmlNodePtr val) {
1713 xmlXPathObjectPtr ret;
1714
1715 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1716 if (ret == NULL) {
1717 xmlGenericError(xmlGenericErrorContext,
1718 "xmlXPathNewNodeSet: out of memory\n");
1719 return(NULL);
1720 }
1721 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1722 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00001723 ret->boolval = 1;
1724 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00001725 ret->nodesetval = xmlXPathNodeSetCreate(val);
1726 return(ret);
1727}
1728
1729/**
1730 * xmlXPathNewNodeSetList:
1731 * @val: an existing NodeSet
1732 *
1733 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1734 * it with the Nodeset @val
1735 *
1736 * Returns the newly created object.
1737 */
1738xmlXPathObjectPtr
1739xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
1740 xmlXPathObjectPtr ret;
1741 int i;
1742
1743 if (val == NULL)
1744 ret = NULL;
1745 else if (val->nodeTab == NULL)
1746 ret = xmlXPathNewNodeSet(NULL);
1747 else
1748 {
1749 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
1750 for (i = 1; i < val->nodeNr; ++i)
1751 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
1752 }
1753
1754 return(ret);
1755}
1756
1757/**
1758 * xmlXPathWrapNodeSet:
1759 * @val: the NodePtr value
1760 *
1761 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1762 *
1763 * Returns the newly created object.
1764 */
1765xmlXPathObjectPtr
1766xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
1767 xmlXPathObjectPtr ret;
1768
1769 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1770 if (ret == NULL) {
1771 xmlGenericError(xmlGenericErrorContext,
1772 "xmlXPathWrapNodeSet: out of memory\n");
1773 return(NULL);
1774 }
1775 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1776 ret->type = XPATH_NODESET;
1777 ret->nodesetval = val;
1778 return(ret);
1779}
1780
1781/**
1782 * xmlXPathFreeNodeSetList:
1783 * @obj: an existing NodeSetList object
1784 *
1785 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
1786 * the list contrary to xmlXPathFreeObject().
1787 */
1788void
1789xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
1790 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001791 xmlFree(obj);
1792}
1793
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001794/**
1795 * xmlXPathDifference:
1796 * @nodes1: a node-set
1797 * @nodes2: a node-set
1798 *
1799 * Implements the EXSLT - Sets difference() function:
1800 * node-set set:difference (node-set, node-set)
1801 *
1802 * Returns the difference between the two node sets, or nodes1 if
1803 * nodes2 is empty
1804 */
1805xmlNodeSetPtr
1806xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
1807 xmlNodeSetPtr ret;
1808 int i, l1;
1809 xmlNodePtr cur;
1810
1811 if (xmlXPathNodeSetIsEmpty(nodes2))
1812 return(nodes1);
1813
1814 ret = xmlXPathNodeSetCreate(NULL);
1815 if (xmlXPathNodeSetIsEmpty(nodes1))
1816 return(ret);
1817
1818 l1 = xmlXPathNodeSetGetLength(nodes1);
1819
1820 for (i = 0; i < l1; i++) {
1821 cur = xmlXPathNodeSetItem(nodes1, i);
1822 if (!xmlXPathNodeSetContains(nodes2, cur))
1823 xmlXPathNodeSetAddUnique(ret, cur);
1824 }
1825 return(ret);
1826}
1827
1828/**
1829 * xmlXPathIntersection:
1830 * @nodes1: a node-set
1831 * @nodes2: a node-set
1832 *
1833 * Implements the EXSLT - Sets intersection() function:
1834 * node-set set:intersection (node-set, node-set)
1835 *
1836 * Returns a node set comprising the nodes that are within both the
1837 * node sets passed as arguments
1838 */
1839xmlNodeSetPtr
1840xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
1841 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
1842 int i, l1;
1843 xmlNodePtr cur;
1844
1845 if (xmlXPathNodeSetIsEmpty(nodes1))
1846 return(ret);
1847 if (xmlXPathNodeSetIsEmpty(nodes2))
1848 return(ret);
1849
1850 l1 = xmlXPathNodeSetGetLength(nodes1);
1851
1852 for (i = 0; i < l1; i++) {
1853 cur = xmlXPathNodeSetItem(nodes1, i);
1854 if (xmlXPathNodeSetContains(nodes2, cur))
1855 xmlXPathNodeSetAddUnique(ret, cur);
1856 }
1857 return(ret);
1858}
1859
1860/**
1861 * xmlXPathDistinctSorted:
1862 * @nodes: a node-set, sorted by document order
1863 *
1864 * Implements the EXSLT - Sets distinct() function:
1865 * node-set set:distinct (node-set)
1866 *
1867 * Returns a subset of the nodes contained in @nodes, or @nodes if
1868 * it is empty
1869 */
1870xmlNodeSetPtr
1871xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
1872 xmlNodeSetPtr ret;
1873 xmlHashTablePtr hash;
1874 int i, l;
1875 xmlChar * strval;
1876 xmlNodePtr cur;
1877
1878 if (xmlXPathNodeSetIsEmpty(nodes))
1879 return(nodes);
1880
1881 ret = xmlXPathNodeSetCreate(NULL);
1882 l = xmlXPathNodeSetGetLength(nodes);
1883 hash = xmlHashCreate (l);
1884 for (i = 0; i < l; i++) {
1885 cur = xmlXPathNodeSetItem(nodes, i);
1886 strval = xmlXPathCastNodeToString(cur);
1887 if (xmlHashLookup(hash, strval) == NULL) {
1888 xmlHashAddEntry(hash, strval, strval);
1889 xmlXPathNodeSetAddUnique(ret, cur);
1890 } else {
1891 xmlFree(strval);
1892 }
1893 }
1894 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
1895 return(ret);
1896}
1897
1898/**
1899 * xmlXPathDistinct:
1900 * @nodes: a node-set
1901 *
1902 * Implements the EXSLT - Sets distinct() function:
1903 * node-set set:distinct (node-set)
1904 * @nodes is sorted by document order, then #exslSetsDistinctSorted
1905 * is called with the sorted node-set
1906 *
1907 * Returns a subset of the nodes contained in @nodes, or @nodes if
1908 * it is empty
1909 */
1910xmlNodeSetPtr
1911xmlXPathDistinct (xmlNodeSetPtr nodes) {
1912 if (xmlXPathNodeSetIsEmpty(nodes))
1913 return(nodes);
1914
1915 xmlXPathNodeSetSort(nodes);
1916 return(xmlXPathDistinctSorted(nodes));
1917}
1918
1919/**
1920 * xmlXPathHasSameNodes:
1921 * @nodes1: a node-set
1922 * @nodes2: a node-set
1923 *
1924 * Implements the EXSLT - Sets has-same-nodes function:
1925 * boolean set:has-same-node(node-set, node-set)
1926 *
1927 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
1928 * otherwise
1929 */
1930int
1931xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
1932 int i, l;
1933 xmlNodePtr cur;
1934
1935 if (xmlXPathNodeSetIsEmpty(nodes1) ||
1936 xmlXPathNodeSetIsEmpty(nodes2))
1937 return(0);
1938
1939 l = xmlXPathNodeSetGetLength(nodes1);
1940 for (i = 0; i < l; i++) {
1941 cur = xmlXPathNodeSetItem(nodes1, i);
1942 if (xmlXPathNodeSetContains(nodes2, cur))
1943 return(1);
1944 }
1945 return(0);
1946}
1947
1948/**
1949 * xmlXPathNodeLeadingSorted:
1950 * @nodes: a node-set, sorted by document order
1951 * @node: a node
1952 *
1953 * Implements the EXSLT - Sets leading() function:
1954 * node-set set:leading (node-set, node-set)
1955 *
1956 * Returns the nodes in @nodes that precede @node in document order,
1957 * @nodes if @node is NULL or an empty node-set if @nodes
1958 * doesn't contain @node
1959 */
1960xmlNodeSetPtr
1961xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
1962 int i, l;
1963 xmlNodePtr cur;
1964 xmlNodeSetPtr ret;
1965
1966 if (node == NULL)
1967 return(nodes);
1968
1969 ret = xmlXPathNodeSetCreate(NULL);
1970 if (xmlXPathNodeSetIsEmpty(nodes) ||
1971 (!xmlXPathNodeSetContains(nodes, node)))
1972 return(ret);
1973
1974 l = xmlXPathNodeSetGetLength(nodes);
1975 for (i = 0; i < l; i++) {
1976 cur = xmlXPathNodeSetItem(nodes, i);
1977 if (cur == node)
1978 break;
1979 xmlXPathNodeSetAddUnique(ret, cur);
1980 }
1981 return(ret);
1982}
1983
1984/**
1985 * xmlXPathNodeLeading:
1986 * @nodes: a node-set
1987 * @node: a node
1988 *
1989 * Implements the EXSLT - Sets leading() function:
1990 * node-set set:leading (node-set, node-set)
1991 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
1992 * is called.
1993 *
1994 * Returns the nodes in @nodes that precede @node in document order,
1995 * @nodes if @node is NULL or an empty node-set if @nodes
1996 * doesn't contain @node
1997 */
1998xmlNodeSetPtr
1999xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2000 xmlXPathNodeSetSort(nodes);
2001 return(xmlXPathNodeLeadingSorted(nodes, node));
2002}
2003
2004/**
2005 * xmlXPathLeadingSorted:
2006 * @nodes1: a node-set, sorted by document order
2007 * @nodes2: a node-set, sorted by document order
2008 *
2009 * Implements the EXSLT - Sets leading() function:
2010 * node-set set:leading (node-set, node-set)
2011 *
2012 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2013 * in document order, @nodes1 if @nodes2 is NULL or empty or
2014 * an empty node-set if @nodes1 doesn't contain @nodes2
2015 */
2016xmlNodeSetPtr
2017xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2018 if (xmlXPathNodeSetIsEmpty(nodes2))
2019 return(nodes1);
2020 return(xmlXPathNodeLeadingSorted(nodes1,
2021 xmlXPathNodeSetItem(nodes2, 1)));
2022}
2023
2024/**
2025 * xmlXPathLeading:
2026 * @nodes1: a node-set
2027 * @nodes2: a node-set
2028 *
2029 * Implements the EXSLT - Sets leading() function:
2030 * node-set set:leading (node-set, node-set)
2031 * @nodes1 and @nodes2 are sorted by document order, then
2032 * #exslSetsLeadingSorted is called.
2033 *
2034 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2035 * in document order, @nodes1 if @nodes2 is NULL or empty or
2036 * an empty node-set if @nodes1 doesn't contain @nodes2
2037 */
2038xmlNodeSetPtr
2039xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2040 if (xmlXPathNodeSetIsEmpty(nodes2))
2041 return(nodes1);
2042 if (xmlXPathNodeSetIsEmpty(nodes1))
2043 return(xmlXPathNodeSetCreate(NULL));
2044 xmlXPathNodeSetSort(nodes1);
2045 xmlXPathNodeSetSort(nodes2);
2046 return(xmlXPathNodeLeadingSorted(nodes1,
2047 xmlXPathNodeSetItem(nodes2, 1)));
2048}
2049
2050/**
2051 * xmlXPathNodeTrailingSorted:
2052 * @nodes: a node-set, sorted by document order
2053 * @node: a node
2054 *
2055 * Implements the EXSLT - Sets trailing() function:
2056 * node-set set:trailing (node-set, node-set)
2057 *
2058 * Returns the nodes in @nodes that follow @node in document order,
2059 * @nodes if @node is NULL or an empty node-set if @nodes
2060 * doesn't contain @node
2061 */
2062xmlNodeSetPtr
2063xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2064 int i, l;
2065 xmlNodePtr cur;
2066 xmlNodeSetPtr ret;
2067
2068 if (node == NULL)
2069 return(nodes);
2070
2071 ret = xmlXPathNodeSetCreate(NULL);
2072 if (xmlXPathNodeSetIsEmpty(nodes) ||
2073 (!xmlXPathNodeSetContains(nodes, node)))
2074 return(ret);
2075
2076 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002077 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002078 cur = xmlXPathNodeSetItem(nodes, i);
2079 if (cur == node)
2080 break;
2081 xmlXPathNodeSetAddUnique(ret, cur);
2082 }
2083 return(ret);
2084}
2085
2086/**
2087 * xmlXPathNodeTrailing:
2088 * @nodes: a node-set
2089 * @node: a node
2090 *
2091 * Implements the EXSLT - Sets trailing() function:
2092 * node-set set:trailing (node-set, node-set)
2093 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2094 * is called.
2095 *
2096 * Returns the nodes in @nodes that follow @node in document order,
2097 * @nodes if @node is NULL or an empty node-set if @nodes
2098 * doesn't contain @node
2099 */
2100xmlNodeSetPtr
2101xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2102 xmlXPathNodeSetSort(nodes);
2103 return(xmlXPathNodeTrailingSorted(nodes, node));
2104}
2105
2106/**
2107 * xmlXPathTrailingSorted:
2108 * @nodes1: a node-set, sorted by document order
2109 * @nodes2: a node-set, sorted by document order
2110 *
2111 * Implements the EXSLT - Sets trailing() function:
2112 * node-set set:trailing (node-set, node-set)
2113 *
2114 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2115 * in document order, @nodes1 if @nodes2 is NULL or empty or
2116 * an empty node-set if @nodes1 doesn't contain @nodes2
2117 */
2118xmlNodeSetPtr
2119xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2120 if (xmlXPathNodeSetIsEmpty(nodes2))
2121 return(nodes1);
2122 return(xmlXPathNodeTrailingSorted(nodes1,
2123 xmlXPathNodeSetItem(nodes2, 0)));
2124}
2125
2126/**
2127 * xmlXPathTrailing:
2128 * @nodes1: a node-set
2129 * @nodes2: a node-set
2130 *
2131 * Implements the EXSLT - Sets trailing() function:
2132 * node-set set:trailing (node-set, node-set)
2133 * @nodes1 and @nodes2 are sorted by document order, then
2134 * #xmlXPathTrailingSorted is called.
2135 *
2136 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2137 * in document order, @nodes1 if @nodes2 is NULL or empty or
2138 * an empty node-set if @nodes1 doesn't contain @nodes2
2139 */
2140xmlNodeSetPtr
2141xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2142 if (xmlXPathNodeSetIsEmpty(nodes2))
2143 return(nodes1);
2144 if (xmlXPathNodeSetIsEmpty(nodes1))
2145 return(xmlXPathNodeSetCreate(NULL));
2146 xmlXPathNodeSetSort(nodes1);
2147 xmlXPathNodeSetSort(nodes2);
2148 return(xmlXPathNodeTrailingSorted(nodes1,
2149 xmlXPathNodeSetItem(nodes2, 0)));
2150}
2151
Owen Taylor3473f882001-02-23 17:55:21 +00002152/************************************************************************
2153 * *
2154 * Routines to handle extra functions *
2155 * *
2156 ************************************************************************/
2157
2158/**
2159 * xmlXPathRegisterFunc:
2160 * @ctxt: the XPath context
2161 * @name: the function name
2162 * @f: the function implementation or NULL
2163 *
2164 * Register a new function. If @f is NULL it unregisters the function
2165 *
2166 * Returns 0 in case of success, -1 in case of error
2167 */
2168int
2169xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2170 xmlXPathFunction f) {
2171 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2172}
2173
2174/**
2175 * xmlXPathRegisterFuncNS:
2176 * @ctxt: the XPath context
2177 * @name: the function name
2178 * @ns_uri: the function namespace URI
2179 * @f: the function implementation or NULL
2180 *
2181 * Register a new function. If @f is NULL it unregisters the function
2182 *
2183 * Returns 0 in case of success, -1 in case of error
2184 */
2185int
2186xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2187 const xmlChar *ns_uri, xmlXPathFunction f) {
2188 if (ctxt == NULL)
2189 return(-1);
2190 if (name == NULL)
2191 return(-1);
2192
2193 if (ctxt->funcHash == NULL)
2194 ctxt->funcHash = xmlHashCreate(0);
2195 if (ctxt->funcHash == NULL)
2196 return(-1);
2197 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2198}
2199
2200/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002201 * xmlXPathRegisterFuncLookup:
2202 * @ctxt: the XPath context
2203 * @f: the lookup function
2204 * @data: the lookup data
2205 *
2206 * Registers an external mecanism to do function lookup.
2207 */
2208void
2209xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2210 xmlXPathFuncLookupFunc f,
2211 void *funcCtxt) {
2212 if (ctxt == NULL)
2213 return;
2214 ctxt->funcLookupFunc = (void *) f;
2215 ctxt->funcLookupData = funcCtxt;
2216}
2217
2218/**
Owen Taylor3473f882001-02-23 17:55:21 +00002219 * xmlXPathFunctionLookup:
2220 * @ctxt: the XPath context
2221 * @name: the function name
2222 *
2223 * Search in the Function array of the context for the given
2224 * function.
2225 *
2226 * Returns the xmlXPathFunction or NULL if not found
2227 */
2228xmlXPathFunction
2229xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002230 if (ctxt == NULL)
2231 return (NULL);
2232
2233 if (ctxt->funcLookupFunc != NULL) {
2234 xmlXPathFunction ret;
2235
2236 ret = ((xmlXPathFuncLookupFunc) ctxt->funcLookupFunc)
2237 (ctxt->funcLookupData, name, NULL);
2238 if (ret != NULL)
2239 return(ret);
2240 }
Owen Taylor3473f882001-02-23 17:55:21 +00002241 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2242}
2243
2244/**
2245 * xmlXPathFunctionLookupNS:
2246 * @ctxt: the XPath context
2247 * @name: the function name
2248 * @ns_uri: the function namespace URI
2249 *
2250 * Search in the Function array of the context for the given
2251 * function.
2252 *
2253 * Returns the xmlXPathFunction or NULL if not found
2254 */
2255xmlXPathFunction
2256xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2257 const xmlChar *ns_uri) {
2258 if (ctxt == NULL)
2259 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002260 if (name == NULL)
2261 return(NULL);
2262
Thomas Broyerba4ad322001-07-26 16:55:21 +00002263 if (ctxt->funcLookupFunc != NULL) {
2264 xmlXPathFunction ret;
2265
2266 ret = ((xmlXPathFuncLookupFunc) ctxt->funcLookupFunc)
2267 (ctxt->funcLookupData, name, ns_uri);
2268 if (ret != NULL)
2269 return(ret);
2270 }
2271
2272 if (ctxt->funcHash == NULL)
2273 return(NULL);
2274
Owen Taylor3473f882001-02-23 17:55:21 +00002275 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2276}
2277
2278/**
2279 * xmlXPathRegisteredFuncsCleanup:
2280 * @ctxt: the XPath context
2281 *
2282 * Cleanup the XPath context data associated to registered functions
2283 */
2284void
2285xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2286 if (ctxt == NULL)
2287 return;
2288
2289 xmlHashFree(ctxt->funcHash, NULL);
2290 ctxt->funcHash = NULL;
2291}
2292
2293/************************************************************************
2294 * *
2295 * Routines to handle Variable *
2296 * *
2297 ************************************************************************/
2298
2299/**
2300 * xmlXPathRegisterVariable:
2301 * @ctxt: the XPath context
2302 * @name: the variable name
2303 * @value: the variable value or NULL
2304 *
2305 * Register a new variable value. If @value is NULL it unregisters
2306 * the variable
2307 *
2308 * Returns 0 in case of success, -1 in case of error
2309 */
2310int
2311xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2312 xmlXPathObjectPtr value) {
2313 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2314}
2315
2316/**
2317 * xmlXPathRegisterVariableNS:
2318 * @ctxt: the XPath context
2319 * @name: the variable name
2320 * @ns_uri: the variable namespace URI
2321 * @value: the variable value or NULL
2322 *
2323 * Register a new variable value. If @value is NULL it unregisters
2324 * the variable
2325 *
2326 * Returns 0 in case of success, -1 in case of error
2327 */
2328int
2329xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2330 const xmlChar *ns_uri,
2331 xmlXPathObjectPtr value) {
2332 if (ctxt == NULL)
2333 return(-1);
2334 if (name == NULL)
2335 return(-1);
2336
2337 if (ctxt->varHash == NULL)
2338 ctxt->varHash = xmlHashCreate(0);
2339 if (ctxt->varHash == NULL)
2340 return(-1);
2341 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2342 (void *) value,
2343 (xmlHashDeallocator)xmlXPathFreeObject));
2344}
2345
2346/**
2347 * xmlXPathRegisterVariableLookup:
2348 * @ctxt: the XPath context
2349 * @f: the lookup function
2350 * @data: the lookup data
2351 *
2352 * register an external mechanism to do variable lookup
2353 */
2354void
2355xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2356 xmlXPathVariableLookupFunc f, void *data) {
2357 if (ctxt == NULL)
2358 return;
2359 ctxt->varLookupFunc = (void *) f;
2360 ctxt->varLookupData = data;
2361}
2362
2363/**
2364 * xmlXPathVariableLookup:
2365 * @ctxt: the XPath context
2366 * @name: the variable name
2367 *
2368 * Search in the Variable array of the context for the given
2369 * variable value.
2370 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002371 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002372 */
2373xmlXPathObjectPtr
2374xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2375 if (ctxt == NULL)
2376 return(NULL);
2377
2378 if (ctxt->varLookupFunc != NULL) {
2379 xmlXPathObjectPtr ret;
2380
2381 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2382 (ctxt->varLookupData, name, NULL);
2383 if (ret != NULL) return(ret);
2384 }
2385 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2386}
2387
2388/**
2389 * xmlXPathVariableLookupNS:
2390 * @ctxt: the XPath context
2391 * @name: the variable name
2392 * @ns_uri: the variable namespace URI
2393 *
2394 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002395 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002396 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002397 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002398 */
2399xmlXPathObjectPtr
2400xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2401 const xmlChar *ns_uri) {
2402 if (ctxt == NULL)
2403 return(NULL);
2404
2405 if (ctxt->varLookupFunc != NULL) {
2406 xmlXPathObjectPtr ret;
2407
2408 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2409 (ctxt->varLookupData, name, ns_uri);
2410 if (ret != NULL) return(ret);
2411 }
2412
2413 if (ctxt->varHash == NULL)
2414 return(NULL);
2415 if (name == NULL)
2416 return(NULL);
2417
Daniel Veillard8c357d52001-07-03 23:43:33 +00002418 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2419 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002420}
2421
2422/**
2423 * xmlXPathRegisteredVariablesCleanup:
2424 * @ctxt: the XPath context
2425 *
2426 * Cleanup the XPath context data associated to registered variables
2427 */
2428void
2429xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2430 if (ctxt == NULL)
2431 return;
2432
Daniel Veillard76d66f42001-05-16 21:05:17 +00002433 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002434 ctxt->varHash = NULL;
2435}
2436
2437/**
2438 * xmlXPathRegisterNs:
2439 * @ctxt: the XPath context
2440 * @prefix: the namespace prefix
2441 * @ns_uri: the namespace name
2442 *
2443 * Register a new namespace. If @ns_uri is NULL it unregisters
2444 * the namespace
2445 *
2446 * Returns 0 in case of success, -1 in case of error
2447 */
2448int
2449xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2450 const xmlChar *ns_uri) {
2451 if (ctxt == NULL)
2452 return(-1);
2453 if (prefix == NULL)
2454 return(-1);
2455
2456 if (ctxt->nsHash == NULL)
2457 ctxt->nsHash = xmlHashCreate(10);
2458 if (ctxt->nsHash == NULL)
2459 return(-1);
2460 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) ns_uri,
2461 (xmlHashDeallocator)xmlFree));
2462}
2463
2464/**
2465 * xmlXPathNsLookup:
2466 * @ctxt: the XPath context
2467 * @prefix: the namespace prefix value
2468 *
2469 * Search in the namespace declaration array of the context for the given
2470 * namespace name associated to the given prefix
2471 *
2472 * Returns the value or NULL if not found
2473 */
2474const xmlChar *
2475xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2476 if (ctxt == NULL)
2477 return(NULL);
2478 if (prefix == NULL)
2479 return(NULL);
2480
2481#ifdef XML_XML_NAMESPACE
2482 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
2483 return(XML_XML_NAMESPACE);
2484#endif
2485
Daniel Veillardc8f620b2001-04-30 20:31:33 +00002486 if (ctxt->namespaces != NULL) {
2487 int i;
2488
2489 for (i = 0;i < ctxt->nsNr;i++) {
2490 if ((ctxt->namespaces[i] != NULL) &&
2491 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
2492 return(ctxt->namespaces[i]->href);
2493 }
2494 }
Owen Taylor3473f882001-02-23 17:55:21 +00002495
2496 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
2497}
2498
2499/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002500 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00002501 * @ctxt: the XPath context
2502 *
2503 * Cleanup the XPath context data associated to registered variables
2504 */
2505void
2506xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2507 if (ctxt == NULL)
2508 return;
2509
2510 xmlHashFree(ctxt->nsHash, NULL);
2511 ctxt->nsHash = NULL;
2512}
2513
2514/************************************************************************
2515 * *
2516 * Routines to handle Values *
2517 * *
2518 ************************************************************************/
2519
2520/* Allocations are terrible, one need to optimize all this !!! */
2521
2522/**
2523 * xmlXPathNewFloat:
2524 * @val: the double value
2525 *
2526 * Create a new xmlXPathObjectPtr of type double and of value @val
2527 *
2528 * Returns the newly created object.
2529 */
2530xmlXPathObjectPtr
2531xmlXPathNewFloat(double val) {
2532 xmlXPathObjectPtr ret;
2533
2534 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2535 if (ret == NULL) {
2536 xmlGenericError(xmlGenericErrorContext,
2537 "xmlXPathNewFloat: out of memory\n");
2538 return(NULL);
2539 }
2540 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2541 ret->type = XPATH_NUMBER;
2542 ret->floatval = val;
2543 return(ret);
2544}
2545
2546/**
2547 * xmlXPathNewBoolean:
2548 * @val: the boolean value
2549 *
2550 * Create a new xmlXPathObjectPtr of type boolean and of value @val
2551 *
2552 * Returns the newly created object.
2553 */
2554xmlXPathObjectPtr
2555xmlXPathNewBoolean(int val) {
2556 xmlXPathObjectPtr ret;
2557
2558 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2559 if (ret == NULL) {
2560 xmlGenericError(xmlGenericErrorContext,
2561 "xmlXPathNewBoolean: out of memory\n");
2562 return(NULL);
2563 }
2564 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2565 ret->type = XPATH_BOOLEAN;
2566 ret->boolval = (val != 0);
2567 return(ret);
2568}
2569
2570/**
2571 * xmlXPathNewString:
2572 * @val: the xmlChar * value
2573 *
2574 * Create a new xmlXPathObjectPtr of type string and of value @val
2575 *
2576 * Returns the newly created object.
2577 */
2578xmlXPathObjectPtr
2579xmlXPathNewString(const xmlChar *val) {
2580 xmlXPathObjectPtr ret;
2581
2582 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2583 if (ret == NULL) {
2584 xmlGenericError(xmlGenericErrorContext,
2585 "xmlXPathNewString: out of memory\n");
2586 return(NULL);
2587 }
2588 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2589 ret->type = XPATH_STRING;
2590 if (val != NULL)
2591 ret->stringval = xmlStrdup(val);
2592 else
2593 ret->stringval = xmlStrdup((const xmlChar *)"");
2594 return(ret);
2595}
2596
2597/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002598 * xmlXPathWrapString:
2599 * @val: the xmlChar * value
2600 *
2601 * Wraps the @val string into an XPath object.
2602 *
2603 * Returns the newly created object.
2604 */
2605xmlXPathObjectPtr
2606xmlXPathWrapString (xmlChar *val) {
2607 xmlXPathObjectPtr ret;
2608
2609 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2610 if (ret == NULL) {
2611 xmlGenericError(xmlGenericErrorContext,
2612 "xmlXPathWrapString: out of memory\n");
2613 return(NULL);
2614 }
2615 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2616 ret->type = XPATH_STRING;
2617 ret->stringval = val;
2618 return(ret);
2619}
2620
2621/**
Owen Taylor3473f882001-02-23 17:55:21 +00002622 * xmlXPathNewCString:
2623 * @val: the char * value
2624 *
2625 * Create a new xmlXPathObjectPtr of type string and of value @val
2626 *
2627 * Returns the newly created object.
2628 */
2629xmlXPathObjectPtr
2630xmlXPathNewCString(const char *val) {
2631 xmlXPathObjectPtr ret;
2632
2633 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2634 if (ret == NULL) {
2635 xmlGenericError(xmlGenericErrorContext,
2636 "xmlXPathNewCString: out of memory\n");
2637 return(NULL);
2638 }
2639 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2640 ret->type = XPATH_STRING;
2641 ret->stringval = xmlStrdup(BAD_CAST val);
2642 return(ret);
2643}
2644
2645/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002646 * xmlXPathWrapCString:
2647 * @val: the char * value
2648 *
2649 * Wraps a string into an XPath object.
2650 *
2651 * Returns the newly created object.
2652 */
2653xmlXPathObjectPtr
2654xmlXPathWrapCString (char * val) {
2655 return(xmlXPathWrapString((xmlChar *)(val)));
2656}
2657
2658/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002659 * xmlXPathWrapExternal:
2660 * @val: the user data
2661 *
2662 * Wraps the @val data into an XPath object.
2663 *
2664 * Returns the newly created object.
2665 */
2666xmlXPathObjectPtr
2667xmlXPathWrapExternal (void *val) {
2668 xmlXPathObjectPtr ret;
2669
2670 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2671 if (ret == NULL) {
2672 xmlGenericError(xmlGenericErrorContext,
2673 "xmlXPathWrapString: out of memory\n");
2674 return(NULL);
2675 }
2676 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2677 ret->type = XPATH_USERS;
2678 ret->user = val;
2679 return(ret);
2680}
2681
2682/**
Owen Taylor3473f882001-02-23 17:55:21 +00002683 * xmlXPathObjectCopy:
2684 * @val: the original object
2685 *
2686 * allocate a new copy of a given object
2687 *
2688 * Returns the newly created object.
2689 */
2690xmlXPathObjectPtr
2691xmlXPathObjectCopy(xmlXPathObjectPtr val) {
2692 xmlXPathObjectPtr ret;
2693
2694 if (val == NULL)
2695 return(NULL);
2696
2697 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2698 if (ret == NULL) {
2699 xmlGenericError(xmlGenericErrorContext,
2700 "xmlXPathObjectCopy: out of memory\n");
2701 return(NULL);
2702 }
2703 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
2704 switch (val->type) {
2705 case XPATH_BOOLEAN:
2706 case XPATH_NUMBER:
2707 case XPATH_POINT:
2708 case XPATH_RANGE:
2709 break;
2710 case XPATH_STRING:
2711 ret->stringval = xmlStrdup(val->stringval);
2712 break;
2713 case XPATH_XSLT_TREE:
2714 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002715 (val->nodesetval->nodeTab != NULL)) {
2716 ret->boolval = 1;
2717 ret->user = xmlCopyNode(val->nodesetval->nodeTab[0], 1);
Owen Taylor3473f882001-02-23 17:55:21 +00002718 ret->nodesetval = xmlXPathNodeSetCreate(
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002719 (xmlNodePtr) ret->user);
2720 } else
Owen Taylor3473f882001-02-23 17:55:21 +00002721 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002722 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00002723 break;
2724 case XPATH_NODESET:
2725 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002726 /* Do not deallocate the copied tree value */
2727 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002728 break;
2729 case XPATH_LOCATIONSET:
2730#ifdef LIBXML_XPTR_ENABLED
2731 {
2732 xmlLocationSetPtr loc = val->user;
2733 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
2734 break;
2735 }
2736#endif
2737 case XPATH_UNDEFINED:
2738 case XPATH_USERS:
2739 xmlGenericError(xmlGenericErrorContext,
2740 "xmlXPathObjectCopy: unsupported type %d\n",
2741 val->type);
2742 break;
2743 }
2744 return(ret);
2745}
2746
2747/**
2748 * xmlXPathFreeObject:
2749 * @obj: the object to free
2750 *
2751 * Free up an xmlXPathObjectPtr object.
2752 */
2753void
2754xmlXPathFreeObject(xmlXPathObjectPtr obj) {
2755 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002756 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00002757 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002758 if (obj->user != NULL) {
2759 xmlFreeNodeList((xmlNodePtr) obj->user);
2760 xmlXPathFreeNodeSet(obj->nodesetval);
2761 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00002762 xmlXPathFreeValueTree(obj->nodesetval);
2763 } else {
2764 if (obj->nodesetval != NULL)
2765 xmlXPathFreeNodeSet(obj->nodesetval);
2766 }
Owen Taylor3473f882001-02-23 17:55:21 +00002767#ifdef LIBXML_XPTR_ENABLED
2768 } else if (obj->type == XPATH_LOCATIONSET) {
2769 if (obj->user != NULL)
2770 xmlXPtrFreeLocationSet(obj->user);
2771#endif
2772 } else if (obj->type == XPATH_STRING) {
2773 if (obj->stringval != NULL)
2774 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00002775 }
2776
Owen Taylor3473f882001-02-23 17:55:21 +00002777 xmlFree(obj);
2778}
2779
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002780
2781/************************************************************************
2782 * *
2783 * Type Casting Routines *
2784 * *
2785 ************************************************************************/
2786
2787/**
2788 * xmlXPathCastBooleanToString:
2789 * @val: a boolean
2790 *
2791 * Converts a boolean to its string value.
2792 *
2793 * Returns a newly allocated string.
2794 */
2795xmlChar *
2796xmlXPathCastBooleanToString (int val) {
2797 xmlChar *ret;
2798 if (val)
2799 ret = xmlStrdup((const xmlChar *) "true");
2800 else
2801 ret = xmlStrdup((const xmlChar *) "false");
2802 return(ret);
2803}
2804
2805/**
2806 * xmlXPathCastNumberToString:
2807 * @val: a number
2808 *
2809 * Converts a number to its string value.
2810 *
2811 * Returns a newly allocated string.
2812 */
2813xmlChar *
2814xmlXPathCastNumberToString (double val) {
2815 xmlChar *ret;
Bjorn Reese45029602001-08-21 09:23:53 +00002816 switch (trio_isinf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002817 case 1:
2818 ret = xmlStrdup((const xmlChar *) "+Infinity");
2819 break;
2820 case -1:
2821 ret = xmlStrdup((const xmlChar *) "-Infinity");
2822 break;
2823 default:
Bjorn Reese45029602001-08-21 09:23:53 +00002824 if (trio_isnan(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002825 ret = xmlStrdup((const xmlChar *) "NaN");
2826 } else {
2827 /* could be improved */
2828 char buf[100];
2829 xmlXPathFormatNumber(val, buf, 100);
2830 ret = xmlStrdup((const xmlChar *) buf);
2831 }
2832 }
2833 return(ret);
2834}
2835
2836/**
2837 * xmlXPathCastNodeToString:
2838 * @node: a node
2839 *
2840 * Converts a node to its string value.
2841 *
2842 * Returns a newly allocated string.
2843 */
2844xmlChar *
2845xmlXPathCastNodeToString (xmlNodePtr node) {
2846 return(xmlNodeGetContent(node));
2847}
2848
2849/**
2850 * xmlXPathCastNodeSetToString:
2851 * @ns: a node-set
2852 *
2853 * Converts a node-set to its string value.
2854 *
2855 * Returns a newly allocated string.
2856 */
2857xmlChar *
2858xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
2859 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
2860 return(xmlStrdup((const xmlChar *) ""));
2861
2862 xmlXPathNodeSetSort(ns);
2863 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
2864}
2865
2866/**
2867 * xmlXPathCastToString:
2868 * @val: an XPath object
2869 *
2870 * Converts an existing object to its string() equivalent
2871 *
2872 * Returns the string value of the object, NULL in case of error.
2873 * A new string is allocated only if needed (val isn't a
2874 * string object).
2875 */
2876xmlChar *
2877xmlXPathCastToString(xmlXPathObjectPtr val) {
2878 xmlChar *ret = NULL;
2879
2880 if (val == NULL)
2881 return(xmlStrdup((const xmlChar *) ""));
2882 switch (val->type) {
2883 case XPATH_UNDEFINED:
2884#ifdef DEBUG_EXPR
2885 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
2886#endif
2887 ret = xmlStrdup((const xmlChar *) "");
2888 break;
2889 case XPATH_XSLT_TREE:
2890 case XPATH_NODESET:
2891 ret = xmlXPathCastNodeSetToString(val->nodesetval);
2892 break;
2893 case XPATH_STRING:
2894 return(val->stringval);
2895 case XPATH_BOOLEAN:
2896 ret = xmlXPathCastBooleanToString(val->boolval);
2897 break;
2898 case XPATH_NUMBER: {
2899 ret = xmlXPathCastNumberToString(val->floatval);
2900 break;
2901 }
2902 case XPATH_USERS:
2903 case XPATH_POINT:
2904 case XPATH_RANGE:
2905 case XPATH_LOCATIONSET:
2906 TODO
2907 ret = xmlStrdup((const xmlChar *) "");
2908 break;
2909 }
2910 return(ret);
2911}
2912
2913/**
2914 * xmlXPathConvertString:
2915 * @val: an XPath object
2916 *
2917 * Converts an existing object to its string() equivalent
2918 *
2919 * Returns the new object, the old one is freed (or the operation
2920 * is done directly on @val)
2921 */
2922xmlXPathObjectPtr
2923xmlXPathConvertString(xmlXPathObjectPtr val) {
2924 xmlChar *res = NULL;
2925
2926 if (val == NULL)
2927 return(xmlXPathNewCString(""));
2928
2929 switch (val->type) {
2930 case XPATH_UNDEFINED:
2931#ifdef DEBUG_EXPR
2932 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2933#endif
2934 break;
2935 case XPATH_XSLT_TREE:
2936 case XPATH_NODESET:
2937 res = xmlXPathCastNodeSetToString(val->nodesetval);
2938 break;
2939 case XPATH_STRING:
2940 return(val);
2941 case XPATH_BOOLEAN:
2942 res = xmlXPathCastBooleanToString(val->boolval);
2943 break;
2944 case XPATH_NUMBER:
2945 res = xmlXPathCastNumberToString(val->floatval);
2946 break;
2947 case XPATH_USERS:
2948 case XPATH_POINT:
2949 case XPATH_RANGE:
2950 case XPATH_LOCATIONSET:
2951 TODO;
2952 break;
2953 }
2954 xmlXPathFreeObject(val);
2955 if (res == NULL)
2956 return(xmlXPathNewCString(""));
2957 return(xmlXPathWrapString(res));
2958}
2959
2960/**
2961 * xmlXPathCastBooleanToNumber:
2962 * @val: a boolean
2963 *
2964 * Converts a boolean to its number value
2965 *
2966 * Returns the number value
2967 */
2968double
2969xmlXPathCastBooleanToNumber(int val) {
2970 if (val)
2971 return(1.0);
2972 return(0.0);
2973}
2974
2975/**
2976 * xmlXPathCastStringToNumber:
2977 * @val: a string
2978 *
2979 * Converts a string to its number value
2980 *
2981 * Returns the number value
2982 */
2983double
2984xmlXPathCastStringToNumber(const xmlChar * val) {
2985 return(xmlXPathStringEvalNumber(val));
2986}
2987
2988/**
2989 * xmlXPathCastNodeToNumber:
2990 * @node: a node
2991 *
2992 * Converts a node to its number value
2993 *
2994 * Returns the number value
2995 */
2996double
2997xmlXPathCastNodeToNumber (xmlNodePtr node) {
2998 xmlChar *strval;
2999 double ret;
3000
3001 if (node == NULL)
3002 return(xmlXPathNAN);
3003 strval = xmlXPathCastNodeToString(node);
3004 if (strval == NULL)
3005 return(xmlXPathNAN);
3006 ret = xmlXPathCastStringToNumber(strval);
3007 xmlFree(strval);
3008
3009 return(ret);
3010}
3011
3012/**
3013 * xmlXPathCastNodeSetToNumber:
3014 * @ns: a node-set
3015 *
3016 * Converts a node-set to its number value
3017 *
3018 * Returns the number value
3019 */
3020double
3021xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3022 xmlChar *str;
3023 double ret;
3024
3025 if (ns == NULL)
3026 return(xmlXPathNAN);
3027 str = xmlXPathCastNodeSetToString(ns);
3028 ret = xmlXPathCastStringToNumber(str);
3029 xmlFree(str);
3030 return(ret);
3031}
3032
3033/**
3034 * xmlXPathCastToNumber:
3035 * @val: an XPath object
3036 *
3037 * Converts an XPath object to its number value
3038 *
3039 * Returns the number value
3040 */
3041double
3042xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3043 double ret = 0.0;
3044
3045 if (val == NULL)
3046 return(xmlXPathNAN);
3047 switch (val->type) {
3048 case XPATH_UNDEFINED:
3049#ifdef DEGUB_EXPR
3050 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3051#endif
3052 ret = xmlXPathNAN;
3053 break;
3054 case XPATH_XSLT_TREE:
3055 case XPATH_NODESET:
3056 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3057 break;
3058 case XPATH_STRING:
3059 ret = xmlXPathCastStringToNumber(val->stringval);
3060 break;
3061 case XPATH_NUMBER:
3062 ret = val->floatval;
3063 break;
3064 case XPATH_BOOLEAN:
3065 ret = xmlXPathCastBooleanToNumber(val->boolval);
3066 break;
3067 case XPATH_USERS:
3068 case XPATH_POINT:
3069 case XPATH_RANGE:
3070 case XPATH_LOCATIONSET:
3071 TODO;
3072 ret = xmlXPathNAN;
3073 break;
3074 }
3075 return(ret);
3076}
3077
3078/**
3079 * xmlXPathConvertNumber:
3080 * @val: an XPath object
3081 *
3082 * Converts an existing object to its number() equivalent
3083 *
3084 * Returns the new object, the old one is freed (or the operation
3085 * is done directly on @val)
3086 */
3087xmlXPathObjectPtr
3088xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3089 xmlXPathObjectPtr ret;
3090
3091 if (val == NULL)
3092 return(xmlXPathNewFloat(0.0));
3093 if (val->type == XPATH_NUMBER)
3094 return(val);
3095 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3096 xmlXPathFreeObject(val);
3097 return(ret);
3098}
3099
3100/**
3101 * xmlXPathCastNumberToBoolean:
3102 * @val: a number
3103 *
3104 * Converts a number to its boolean value
3105 *
3106 * Returns the boolean value
3107 */
3108int
3109xmlXPathCastNumberToBoolean (double val) {
Bjorn Reese45029602001-08-21 09:23:53 +00003110 if (trio_isnan(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003111 return(0);
3112 return(1);
3113}
3114
3115/**
3116 * xmlXPathCastStringToBoolean:
3117 * @val: a string
3118 *
3119 * Converts a string to its boolean value
3120 *
3121 * Returns the boolean value
3122 */
3123int
3124xmlXPathCastStringToBoolean (const xmlChar *val) {
3125 if ((val == NULL) || (xmlStrlen(val) == 0))
3126 return(0);
3127 return(1);
3128}
3129
3130/**
3131 * xmlXPathCastNodeSetToBoolean:
3132 * @ns: a node-set
3133 *
3134 * Converts a node-set to its boolean value
3135 *
3136 * Returns the boolean value
3137 */
3138int
3139xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3140 if ((ns == NULL) || (ns->nodeNr == 0))
3141 return(0);
3142 return(1);
3143}
3144
3145/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003146 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003147 * @val: an XPath object
3148 *
3149 * Converts an XPath object to its boolean value
3150 *
3151 * Returns the boolean value
3152 */
3153int
3154xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3155 int ret = 0;
3156
3157 if (val == NULL)
3158 return(0);
3159 switch (val->type) {
3160 case XPATH_UNDEFINED:
3161#ifdef DEBUG_EXPR
3162 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3163#endif
3164 ret = 0;
3165 break;
3166 case XPATH_XSLT_TREE:
3167 case XPATH_NODESET:
3168 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3169 break;
3170 case XPATH_STRING:
3171 ret = xmlXPathCastStringToBoolean(val->stringval);
3172 break;
3173 case XPATH_NUMBER:
3174 ret = xmlXPathCastNumberToBoolean(val->floatval);
3175 break;
3176 case XPATH_BOOLEAN:
3177 ret = val->boolval;
3178 break;
3179 case XPATH_USERS:
3180 case XPATH_POINT:
3181 case XPATH_RANGE:
3182 case XPATH_LOCATIONSET:
3183 TODO;
3184 ret = 0;
3185 break;
3186 }
3187 return(ret);
3188}
3189
3190
3191/**
3192 * xmlXPathConvertBoolean:
3193 * @val: an XPath object
3194 *
3195 * Converts an existing object to its boolean() equivalent
3196 *
3197 * Returns the new object, the old one is freed (or the operation
3198 * is done directly on @val)
3199 */
3200xmlXPathObjectPtr
3201xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3202 xmlXPathObjectPtr ret;
3203
3204 if (val == NULL)
3205 return(xmlXPathNewBoolean(0));
3206 if (val->type == XPATH_BOOLEAN)
3207 return(val);
3208 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3209 xmlXPathFreeObject(val);
3210 return(ret);
3211}
3212
Owen Taylor3473f882001-02-23 17:55:21 +00003213/************************************************************************
3214 * *
3215 * Routines to handle XPath contexts *
3216 * *
3217 ************************************************************************/
3218
3219/**
3220 * xmlXPathNewContext:
3221 * @doc: the XML document
3222 *
3223 * Create a new xmlXPathContext
3224 *
3225 * Returns the xmlXPathContext just allocated.
3226 */
3227xmlXPathContextPtr
3228xmlXPathNewContext(xmlDocPtr doc) {
3229 xmlXPathContextPtr ret;
3230
3231 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3232 if (ret == NULL) {
3233 xmlGenericError(xmlGenericErrorContext,
3234 "xmlXPathNewContext: out of memory\n");
3235 return(NULL);
3236 }
3237 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3238 ret->doc = doc;
3239 ret->node = NULL;
3240
3241 ret->varHash = NULL;
3242
3243 ret->nb_types = 0;
3244 ret->max_types = 0;
3245 ret->types = NULL;
3246
3247 ret->funcHash = xmlHashCreate(0);
3248
3249 ret->nb_axis = 0;
3250 ret->max_axis = 0;
3251 ret->axis = NULL;
3252
3253 ret->nsHash = NULL;
3254 ret->user = NULL;
3255
3256 ret->contextSize = -1;
3257 ret->proximityPosition = -1;
3258
3259 xmlXPathRegisterAllFunctions(ret);
3260
3261 return(ret);
3262}
3263
3264/**
3265 * xmlXPathFreeContext:
3266 * @ctxt: the context to free
3267 *
3268 * Free up an xmlXPathContext
3269 */
3270void
3271xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3272 xmlXPathRegisteredNsCleanup(ctxt);
3273 xmlXPathRegisteredFuncsCleanup(ctxt);
3274 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003275 xmlFree(ctxt);
3276}
3277
3278/************************************************************************
3279 * *
3280 * Routines to handle XPath parser contexts *
3281 * *
3282 ************************************************************************/
3283
3284#define CHECK_CTXT(ctxt) \
3285 if (ctxt == NULL) { \
3286 xmlGenericError(xmlGenericErrorContext, \
3287 "%s:%d Internal error: ctxt == NULL\n", \
3288 __FILE__, __LINE__); \
3289 } \
3290
3291
3292#define CHECK_CONTEXT(ctxt) \
3293 if (ctxt == NULL) { \
3294 xmlGenericError(xmlGenericErrorContext, \
3295 "%s:%d Internal error: no context\n", \
3296 __FILE__, __LINE__); \
3297 } \
3298 else if (ctxt->doc == NULL) { \
3299 xmlGenericError(xmlGenericErrorContext, \
3300 "%s:%d Internal error: no document\n", \
3301 __FILE__, __LINE__); \
3302 } \
3303 else if (ctxt->doc->children == NULL) { \
3304 xmlGenericError(xmlGenericErrorContext, \
3305 "%s:%d Internal error: document without root\n", \
3306 __FILE__, __LINE__); \
3307 } \
3308
3309
3310/**
3311 * xmlXPathNewParserContext:
3312 * @str: the XPath expression
3313 * @ctxt: the XPath context
3314 *
3315 * Create a new xmlXPathParserContext
3316 *
3317 * Returns the xmlXPathParserContext just allocated.
3318 */
3319xmlXPathParserContextPtr
3320xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3321 xmlXPathParserContextPtr ret;
3322
3323 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3324 if (ret == NULL) {
3325 xmlGenericError(xmlGenericErrorContext,
3326 "xmlXPathNewParserContext: out of memory\n");
3327 return(NULL);
3328 }
3329 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3330 ret->cur = ret->base = str;
3331 ret->context = ctxt;
3332
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003333 ret->comp = xmlXPathNewCompExpr();
3334 if (ret->comp == NULL) {
3335 xmlFree(ret->valueTab);
3336 xmlFree(ret);
3337 return(NULL);
3338 }
3339
3340 return(ret);
3341}
3342
3343/**
3344 * xmlXPathCompParserContext:
3345 * @comp: the XPath compiled expression
3346 * @ctxt: the XPath context
3347 *
3348 * Create a new xmlXPathParserContext when processing a compiled expression
3349 *
3350 * Returns the xmlXPathParserContext just allocated.
3351 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003352static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003353xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3354 xmlXPathParserContextPtr ret;
3355
3356 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3357 if (ret == NULL) {
3358 xmlGenericError(xmlGenericErrorContext,
3359 "xmlXPathNewParserContext: out of memory\n");
3360 return(NULL);
3361 }
3362 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3363
Owen Taylor3473f882001-02-23 17:55:21 +00003364 /* Allocate the value stack */
3365 ret->valueTab = (xmlXPathObjectPtr *)
3366 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003367 if (ret->valueTab == NULL) {
3368 xmlFree(ret);
3369 xmlGenericError(xmlGenericErrorContext,
3370 "xmlXPathNewParserContext: out of memory\n");
3371 return(NULL);
3372 }
Owen Taylor3473f882001-02-23 17:55:21 +00003373 ret->valueNr = 0;
3374 ret->valueMax = 10;
3375 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003376
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003377 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003378 ret->comp = comp;
3379
Owen Taylor3473f882001-02-23 17:55:21 +00003380 return(ret);
3381}
3382
3383/**
3384 * xmlXPathFreeParserContext:
3385 * @ctxt: the context to free
3386 *
3387 * Free up an xmlXPathParserContext
3388 */
3389void
3390xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3391 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003392 xmlFree(ctxt->valueTab);
3393 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003394 if (ctxt->comp)
3395 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003396 xmlFree(ctxt);
3397}
3398
3399/************************************************************************
3400 * *
3401 * The implicit core function library *
3402 * *
3403 ************************************************************************/
3404
Owen Taylor3473f882001-02-23 17:55:21 +00003405/**
Daniel Veillardf06307e2001-07-03 10:35:50 +00003406 * xmlXPathNodeStringHash:
3407 * @node: a node pointer
3408 *
3409 * Function computing the beginning of the string value of the node,
3410 * used to speed up comparisons
3411 *
3412 * Returns an int usable as a hash
3413 */
3414static unsigned int
3415xmlXPathNodeValHash(xmlNodePtr node) {
3416 int len = 2;
3417 const xmlChar * string = NULL;
3418 xmlNodePtr tmp = NULL;
3419 unsigned int ret = 0;
3420
3421 if (node == NULL)
3422 return(0);
3423
3424
3425 switch (node->type) {
3426 case XML_COMMENT_NODE:
3427 case XML_PI_NODE:
3428 case XML_CDATA_SECTION_NODE:
3429 case XML_TEXT_NODE:
3430 string = node->content;
3431 if (string == NULL)
3432 return(0);
3433 if (string[0] == 0)
3434 return(0);
3435 return(((unsigned int) string[0]) +
3436 (((unsigned int) string[1]) << 8));
3437 case XML_NAMESPACE_DECL:
3438 string = ((xmlNsPtr)node)->href;
3439 if (string == NULL)
3440 return(0);
3441 if (string[0] == 0)
3442 return(0);
3443 return(((unsigned int) string[0]) +
3444 (((unsigned int) string[1]) << 8));
3445 case XML_ATTRIBUTE_NODE:
3446 tmp = ((xmlAttrPtr) node)->children;
3447 break;
3448 case XML_ELEMENT_NODE:
3449 tmp = node->children;
3450 break;
3451 default:
3452 return(0);
3453 }
3454 while (tmp != NULL) {
3455 switch (tmp->type) {
3456 case XML_COMMENT_NODE:
3457 case XML_PI_NODE:
3458 case XML_CDATA_SECTION_NODE:
3459 case XML_TEXT_NODE:
3460 string = tmp->content;
3461 break;
3462 case XML_NAMESPACE_DECL:
3463 string = ((xmlNsPtr)tmp)->href;
3464 break;
3465 default:
3466 break;
3467 }
3468 if ((string != NULL) && (string[0] != 0)) {
3469 if (string[0] == 0)
3470 return(0);
3471 if (len == 1) {
3472 return(ret + (((unsigned int) string[0]) << 8));
3473 }
3474 if (string[1] == 0) {
3475 len = 1;
3476 ret = (unsigned int) string[0];
3477 } else {
3478 return(((unsigned int) string[0]) +
3479 (((unsigned int) string[1]) << 8));
3480 }
3481 }
3482 /*
3483 * Skip to next node
3484 */
3485 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
3486 if (tmp->children->type != XML_ENTITY_DECL) {
3487 tmp = tmp->children;
3488 continue;
3489 }
3490 }
3491 if (tmp == node)
3492 break;
3493
3494 if (tmp->next != NULL) {
3495 tmp = tmp->next;
3496 continue;
3497 }
3498
3499 do {
3500 tmp = tmp->parent;
3501 if (tmp == NULL)
3502 break;
3503 if (tmp == node) {
3504 tmp = NULL;
3505 break;
3506 }
3507 if (tmp->next != NULL) {
3508 tmp = tmp->next;
3509 break;
3510 }
3511 } while (tmp != NULL);
3512 }
3513 return(ret);
3514}
3515
3516/**
3517 * xmlXPathStringHash:
3518 * @string: a string
3519 *
3520 * Function computing the beginning of the string value of the node,
3521 * used to speed up comparisons
3522 *
3523 * Returns an int usable as a hash
3524 */
3525static unsigned int
3526xmlXPathStringHash(const xmlChar * string) {
3527 if (string == NULL)
3528 return((unsigned int) 0);
3529 if (string[0] == 0)
3530 return(0);
3531 return(((unsigned int) string[0]) +
3532 (((unsigned int) string[1]) << 8));
3533}
3534
3535/**
Owen Taylor3473f882001-02-23 17:55:21 +00003536 * xmlXPathCompareNodeSetFloat:
3537 * @ctxt: the XPath Parser context
3538 * @inf: less than (1) or greater than (0)
3539 * @strict: is the comparison strict
3540 * @arg: the node set
3541 * @f: the value
3542 *
3543 * Implement the compare operation between a nodeset and a number
3544 * @ns < @val (1, 1, ...
3545 * @ns <= @val (1, 0, ...
3546 * @ns > @val (0, 1, ...
3547 * @ns >= @val (0, 0, ...
3548 *
3549 * If one object to be compared is a node-set and the other is a number,
3550 * then the comparison will be true if and only if there is a node in the
3551 * node-set such that the result of performing the comparison on the number
3552 * to be compared and on the result of converting the string-value of that
3553 * node to a number using the number function is true.
3554 *
3555 * Returns 0 or 1 depending on the results of the test.
3556 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003557static int
Owen Taylor3473f882001-02-23 17:55:21 +00003558xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
3559 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
3560 int i, ret = 0;
3561 xmlNodeSetPtr ns;
3562 xmlChar *str2;
3563
3564 if ((f == NULL) || (arg == NULL) ||
3565 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3566 xmlXPathFreeObject(arg);
3567 xmlXPathFreeObject(f);
3568 return(0);
3569 }
3570 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003571 if (ns != NULL) {
3572 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003573 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003574 if (str2 != NULL) {
3575 valuePush(ctxt,
3576 xmlXPathNewString(str2));
3577 xmlFree(str2);
3578 xmlXPathNumberFunction(ctxt, 1);
3579 valuePush(ctxt, xmlXPathObjectCopy(f));
3580 ret = xmlXPathCompareValues(ctxt, inf, strict);
3581 if (ret)
3582 break;
3583 }
3584 }
Owen Taylor3473f882001-02-23 17:55:21 +00003585 }
3586 xmlXPathFreeObject(arg);
3587 xmlXPathFreeObject(f);
3588 return(ret);
3589}
3590
3591/**
3592 * xmlXPathCompareNodeSetString:
3593 * @ctxt: the XPath Parser context
3594 * @inf: less than (1) or greater than (0)
3595 * @strict: is the comparison strict
3596 * @arg: the node set
3597 * @s: the value
3598 *
3599 * Implement the compare operation between a nodeset and a string
3600 * @ns < @val (1, 1, ...
3601 * @ns <= @val (1, 0, ...
3602 * @ns > @val (0, 1, ...
3603 * @ns >= @val (0, 0, ...
3604 *
3605 * If one object to be compared is a node-set and the other is a string,
3606 * then the comparison will be true if and only if there is a node in
3607 * the node-set such that the result of performing the comparison on the
3608 * string-value of the node and the other string is true.
3609 *
3610 * Returns 0 or 1 depending on the results of the test.
3611 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003612static int
Owen Taylor3473f882001-02-23 17:55:21 +00003613xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
3614 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
3615 int i, ret = 0;
3616 xmlNodeSetPtr ns;
3617 xmlChar *str2;
3618
3619 if ((s == NULL) || (arg == NULL) ||
3620 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3621 xmlXPathFreeObject(arg);
3622 xmlXPathFreeObject(s);
3623 return(0);
3624 }
3625 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003626 if (ns != NULL) {
3627 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003628 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003629 if (str2 != NULL) {
3630 valuePush(ctxt,
3631 xmlXPathNewString(str2));
3632 xmlFree(str2);
3633 valuePush(ctxt, xmlXPathObjectCopy(s));
3634 ret = xmlXPathCompareValues(ctxt, inf, strict);
3635 if (ret)
3636 break;
3637 }
3638 }
Owen Taylor3473f882001-02-23 17:55:21 +00003639 }
3640 xmlXPathFreeObject(arg);
3641 xmlXPathFreeObject(s);
3642 return(ret);
3643}
3644
3645/**
3646 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003647 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00003648 * @strict: is the comparison strict
3649 * @arg1: the fist node set object
3650 * @arg2: the second node set object
3651 *
3652 * Implement the compare operation on nodesets:
3653 *
3654 * If both objects to be compared are node-sets, then the comparison
3655 * will be true if and only if there is a node in the first node-set
3656 * and a node in the second node-set such that the result of performing
3657 * the comparison on the string-values of the two nodes is true.
3658 * ....
3659 * When neither object to be compared is a node-set and the operator
3660 * is <=, <, >= or >, then the objects are compared by converting both
3661 * objects to numbers and comparing the numbers according to IEEE 754.
3662 * ....
3663 * The number function converts its argument to a number as follows:
3664 * - a string that consists of optional whitespace followed by an
3665 * optional minus sign followed by a Number followed by whitespace
3666 * is converted to the IEEE 754 number that is nearest (according
3667 * to the IEEE 754 round-to-nearest rule) to the mathematical value
3668 * represented by the string; any other string is converted to NaN
3669 *
3670 * Conclusion all nodes need to be converted first to their string value
3671 * and then the comparison must be done when possible
3672 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003673static int
3674xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00003675 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3676 int i, j, init = 0;
3677 double val1;
3678 double *values2;
3679 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003680 xmlNodeSetPtr ns1;
3681 xmlNodeSetPtr ns2;
3682
3683 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003684 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
3685 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003686 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003687 }
Owen Taylor3473f882001-02-23 17:55:21 +00003688 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003689 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
3690 xmlXPathFreeObject(arg1);
3691 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003692 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003693 }
Owen Taylor3473f882001-02-23 17:55:21 +00003694
3695 ns1 = arg1->nodesetval;
3696 ns2 = arg2->nodesetval;
3697
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003698 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003699 xmlXPathFreeObject(arg1);
3700 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003701 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003702 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003703 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003704 xmlXPathFreeObject(arg1);
3705 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003706 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003707 }
Owen Taylor3473f882001-02-23 17:55:21 +00003708
3709 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
3710 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003711 xmlXPathFreeObject(arg1);
3712 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003713 return(0);
3714 }
3715 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003716 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Bjorn Reese45029602001-08-21 09:23:53 +00003717 if (trio_isnan(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00003718 continue;
3719 for (j = 0;j < ns2->nodeNr;j++) {
3720 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003721 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00003722 }
Bjorn Reese45029602001-08-21 09:23:53 +00003723 if (trio_isnan(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00003724 continue;
3725 if (inf && strict)
3726 ret = (val1 < values2[j]);
3727 else if (inf && !strict)
3728 ret = (val1 <= values2[j]);
3729 else if (!inf && strict)
3730 ret = (val1 > values2[j]);
3731 else if (!inf && !strict)
3732 ret = (val1 >= values2[j]);
3733 if (ret)
3734 break;
3735 }
3736 if (ret)
3737 break;
3738 init = 1;
3739 }
3740 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003741 xmlXPathFreeObject(arg1);
3742 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003743 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003744}
3745
3746/**
3747 * xmlXPathCompareNodeSetValue:
3748 * @ctxt: the XPath Parser context
3749 * @inf: less than (1) or greater than (0)
3750 * @strict: is the comparison strict
3751 * @arg: the node set
3752 * @val: the value
3753 *
3754 * Implement the compare operation between a nodeset and a value
3755 * @ns < @val (1, 1, ...
3756 * @ns <= @val (1, 0, ...
3757 * @ns > @val (0, 1, ...
3758 * @ns >= @val (0, 0, ...
3759 *
3760 * If one object to be compared is a node-set and the other is a boolean,
3761 * then the comparison will be true if and only if the result of performing
3762 * the comparison on the boolean and on the result of converting
3763 * the node-set to a boolean using the boolean function is true.
3764 *
3765 * Returns 0 or 1 depending on the results of the test.
3766 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003767static int
Owen Taylor3473f882001-02-23 17:55:21 +00003768xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
3769 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
3770 if ((val == NULL) || (arg == NULL) ||
3771 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3772 return(0);
3773
3774 switch(val->type) {
3775 case XPATH_NUMBER:
3776 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
3777 case XPATH_NODESET:
3778 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003779 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00003780 case XPATH_STRING:
3781 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
3782 case XPATH_BOOLEAN:
3783 valuePush(ctxt, arg);
3784 xmlXPathBooleanFunction(ctxt, 1);
3785 valuePush(ctxt, val);
3786 return(xmlXPathCompareValues(ctxt, inf, strict));
3787 default:
3788 TODO
3789 return(0);
3790 }
3791 return(0);
3792}
3793
3794/**
3795 * xmlXPathEqualNodeSetString
3796 * @arg: the nodeset object argument
3797 * @str: the string to compare to.
3798 *
3799 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3800 * If one object to be compared is a node-set and the other is a string,
3801 * then the comparison will be true if and only if there is a node in
3802 * the node-set such that the result of performing the comparison on the
3803 * string-value of the node and the other string is true.
3804 *
3805 * Returns 0 or 1 depending on the results of the test.
3806 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003807static int
Daniel Veillardf06307e2001-07-03 10:35:50 +00003808xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str)
3809{
Owen Taylor3473f882001-02-23 17:55:21 +00003810 int i;
3811 xmlNodeSetPtr ns;
3812 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003813 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00003814
3815 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00003816 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3817 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00003818 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003819 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003820 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00003821 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00003822 if (ns->nodeNr <= 0) {
3823 if (hash == 0)
3824 return(1);
3825 return(0);
3826 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003827 for (i = 0; i < ns->nodeNr; i++) {
3828 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
3829 str2 = xmlNodeGetContent(ns->nodeTab[i]);
3830 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
3831 xmlFree(str2);
3832 return (1);
3833 }
3834 if (str2 != NULL)
3835 xmlFree(str2);
3836 }
Owen Taylor3473f882001-02-23 17:55:21 +00003837 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003838 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00003839}
3840
3841/**
3842 * xmlXPathEqualNodeSetFloat
3843 * @arg: the nodeset object argument
3844 * @f: the float to compare to
3845 *
3846 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3847 * If one object to be compared is a node-set and the other is a number,
3848 * then the comparison will be true if and only if there is a node in
3849 * the node-set such that the result of performing the comparison on the
3850 * number to be compared and on the result of converting the string-value
3851 * of that node to a number using the number function is true.
3852 *
3853 * Returns 0 or 1 depending on the results of the test.
3854 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003855static int
Owen Taylor3473f882001-02-23 17:55:21 +00003856xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) {
3857 char buf[100] = "";
3858
3859 if ((arg == NULL) ||
3860 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3861 return(0);
3862
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003863 xmlXPathFormatNumber(f, buf, sizeof(buf));
Owen Taylor3473f882001-02-23 17:55:21 +00003864 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
3865}
3866
3867
3868/**
3869 * xmlXPathEqualNodeSets
3870 * @arg1: first nodeset object argument
3871 * @arg2: second nodeset object argument
3872 *
3873 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
3874 * If both objects to be compared are node-sets, then the comparison
3875 * will be true if and only if there is a node in the first node-set and
3876 * a node in the second node-set such that the result of performing the
3877 * comparison on the string-values of the two nodes is true.
3878 *
3879 * (needless to say, this is a costly operation)
3880 *
3881 * Returns 0 or 1 depending on the results of the test.
3882 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003883static int
Owen Taylor3473f882001-02-23 17:55:21 +00003884xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3885 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003886 unsigned int *hashs1;
3887 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00003888 xmlChar **values1;
3889 xmlChar **values2;
3890 int ret = 0;
3891 xmlNodeSetPtr ns1;
3892 xmlNodeSetPtr ns2;
3893
3894 if ((arg1 == NULL) ||
3895 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
3896 return(0);
3897 if ((arg2 == NULL) ||
3898 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
3899 return(0);
3900
3901 ns1 = arg1->nodesetval;
3902 ns2 = arg2->nodesetval;
3903
Daniel Veillard911f49a2001-04-07 15:39:35 +00003904 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00003905 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003906 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00003907 return(0);
3908
3909 /*
3910 * check if there is a node pertaining to both sets
3911 */
3912 for (i = 0;i < ns1->nodeNr;i++)
3913 for (j = 0;j < ns2->nodeNr;j++)
3914 if (ns1->nodeTab[i] == ns2->nodeTab[j])
3915 return(1);
3916
3917 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
3918 if (values1 == NULL)
3919 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00003920 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
3921 if (hashs1 == NULL) {
3922 xmlFree(values1);
3923 return(0);
3924 }
Owen Taylor3473f882001-02-23 17:55:21 +00003925 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
3926 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
3927 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00003928 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00003929 xmlFree(values1);
3930 return(0);
3931 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003932 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
3933 if (hashs2 == NULL) {
3934 xmlFree(hashs1);
3935 xmlFree(values1);
3936 xmlFree(values2);
3937 return(0);
3938 }
Owen Taylor3473f882001-02-23 17:55:21 +00003939 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
3940 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00003941 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00003942 for (j = 0;j < ns2->nodeNr;j++) {
3943 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00003944 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
3945 if (hashs1[i] == hashs2[j]) {
3946 if (values1[i] == NULL)
3947 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
3948 if (values2[j] == NULL)
3949 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
3950 ret = xmlStrEqual(values1[i], values2[j]);
3951 if (ret)
3952 break;
3953 }
Owen Taylor3473f882001-02-23 17:55:21 +00003954 }
3955 if (ret)
3956 break;
3957 }
3958 for (i = 0;i < ns1->nodeNr;i++)
3959 if (values1[i] != NULL)
3960 xmlFree(values1[i]);
3961 for (j = 0;j < ns2->nodeNr;j++)
3962 if (values2[j] != NULL)
3963 xmlFree(values2[j]);
3964 xmlFree(values1);
3965 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00003966 xmlFree(hashs1);
3967 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00003968 return(ret);
3969}
3970
3971/**
3972 * xmlXPathEqualValues:
3973 * @ctxt: the XPath Parser context
3974 *
3975 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3976 *
3977 * Returns 0 or 1 depending on the results of the test.
3978 */
3979int
3980xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
3981 xmlXPathObjectPtr arg1, arg2;
3982 int ret = 0;
3983
3984 arg1 = valuePop(ctxt);
3985 if (arg1 == NULL)
3986 XP_ERROR0(XPATH_INVALID_OPERAND);
3987
3988 arg2 = valuePop(ctxt);
3989 if (arg2 == NULL) {
3990 xmlXPathFreeObject(arg1);
3991 XP_ERROR0(XPATH_INVALID_OPERAND);
3992 }
3993
3994 if (arg1 == arg2) {
3995#ifdef DEBUG_EXPR
3996 xmlGenericError(xmlGenericErrorContext,
3997 "Equal: by pointer\n");
3998#endif
3999 return(1);
4000 }
4001
4002 switch (arg1->type) {
4003 case XPATH_UNDEFINED:
4004#ifdef DEBUG_EXPR
4005 xmlGenericError(xmlGenericErrorContext,
4006 "Equal: undefined\n");
4007#endif
4008 break;
4009 case XPATH_XSLT_TREE:
4010 case XPATH_NODESET:
4011 switch (arg2->type) {
4012 case XPATH_UNDEFINED:
4013#ifdef DEBUG_EXPR
4014 xmlGenericError(xmlGenericErrorContext,
4015 "Equal: undefined\n");
4016#endif
4017 break;
4018 case XPATH_XSLT_TREE:
4019 case XPATH_NODESET:
4020 ret = xmlXPathEqualNodeSets(arg1, arg2);
4021 break;
4022 case XPATH_BOOLEAN:
4023 if ((arg1->nodesetval == NULL) ||
4024 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4025 else
4026 ret = 1;
4027 ret = (ret == arg2->boolval);
4028 break;
4029 case XPATH_NUMBER:
4030 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
4031 break;
4032 case XPATH_STRING:
4033 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
4034 break;
4035 case XPATH_USERS:
4036 case XPATH_POINT:
4037 case XPATH_RANGE:
4038 case XPATH_LOCATIONSET:
4039 TODO
4040 break;
4041 }
4042 break;
4043 case XPATH_BOOLEAN:
4044 switch (arg2->type) {
4045 case XPATH_UNDEFINED:
4046#ifdef DEBUG_EXPR
4047 xmlGenericError(xmlGenericErrorContext,
4048 "Equal: undefined\n");
4049#endif
4050 break;
4051 case XPATH_NODESET:
4052 case XPATH_XSLT_TREE:
4053 if ((arg2->nodesetval == NULL) ||
4054 (arg2->nodesetval->nodeNr == 0)) ret = 0;
4055 else
4056 ret = 1;
4057 break;
4058 case XPATH_BOOLEAN:
4059#ifdef DEBUG_EXPR
4060 xmlGenericError(xmlGenericErrorContext,
4061 "Equal: %d boolean %d \n",
4062 arg1->boolval, arg2->boolval);
4063#endif
4064 ret = (arg1->boolval == arg2->boolval);
4065 break;
4066 case XPATH_NUMBER:
4067 if (arg2->floatval) ret = 1;
4068 else ret = 0;
4069 ret = (arg1->boolval == ret);
4070 break;
4071 case XPATH_STRING:
4072 if ((arg2->stringval == NULL) ||
4073 (arg2->stringval[0] == 0)) ret = 0;
4074 else
4075 ret = 1;
4076 ret = (arg1->boolval == ret);
4077 break;
4078 case XPATH_USERS:
4079 case XPATH_POINT:
4080 case XPATH_RANGE:
4081 case XPATH_LOCATIONSET:
4082 TODO
4083 break;
4084 }
4085 break;
4086 case XPATH_NUMBER:
4087 switch (arg2->type) {
4088 case XPATH_UNDEFINED:
4089#ifdef DEBUG_EXPR
4090 xmlGenericError(xmlGenericErrorContext,
4091 "Equal: undefined\n");
4092#endif
4093 break;
4094 case XPATH_NODESET:
4095 case XPATH_XSLT_TREE:
4096 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
4097 break;
4098 case XPATH_BOOLEAN:
4099 if (arg1->floatval) ret = 1;
4100 else ret = 0;
4101 ret = (arg2->boolval == ret);
4102 break;
4103 case XPATH_STRING:
4104 valuePush(ctxt, arg2);
4105 xmlXPathNumberFunction(ctxt, 1);
4106 arg2 = valuePop(ctxt);
4107 /* no break on purpose */
4108 case XPATH_NUMBER:
4109 ret = (arg1->floatval == arg2->floatval);
4110 break;
4111 case XPATH_USERS:
4112 case XPATH_POINT:
4113 case XPATH_RANGE:
4114 case XPATH_LOCATIONSET:
4115 TODO
4116 break;
4117 }
4118 break;
4119 case XPATH_STRING:
4120 switch (arg2->type) {
4121 case XPATH_UNDEFINED:
4122#ifdef DEBUG_EXPR
4123 xmlGenericError(xmlGenericErrorContext,
4124 "Equal: undefined\n");
4125#endif
4126 break;
4127 case XPATH_NODESET:
4128 case XPATH_XSLT_TREE:
4129 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
4130 break;
4131 case XPATH_BOOLEAN:
4132 if ((arg1->stringval == NULL) ||
4133 (arg1->stringval[0] == 0)) ret = 0;
4134 else
4135 ret = 1;
4136 ret = (arg2->boolval == ret);
4137 break;
4138 case XPATH_STRING:
4139 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4140 break;
4141 case XPATH_NUMBER:
4142 valuePush(ctxt, arg1);
4143 xmlXPathNumberFunction(ctxt, 1);
4144 arg1 = valuePop(ctxt);
4145 ret = (arg1->floatval == arg2->floatval);
4146 break;
4147 case XPATH_USERS:
4148 case XPATH_POINT:
4149 case XPATH_RANGE:
4150 case XPATH_LOCATIONSET:
4151 TODO
4152 break;
4153 }
4154 break;
4155 case XPATH_USERS:
4156 case XPATH_POINT:
4157 case XPATH_RANGE:
4158 case XPATH_LOCATIONSET:
4159 TODO
4160 break;
4161 }
4162 xmlXPathFreeObject(arg1);
4163 xmlXPathFreeObject(arg2);
4164 return(ret);
4165}
4166
4167
4168/**
4169 * xmlXPathCompareValues:
4170 * @ctxt: the XPath Parser context
4171 * @inf: less than (1) or greater than (0)
4172 * @strict: is the comparison strict
4173 *
4174 * Implement the compare operation on XPath objects:
4175 * @arg1 < @arg2 (1, 1, ...
4176 * @arg1 <= @arg2 (1, 0, ...
4177 * @arg1 > @arg2 (0, 1, ...
4178 * @arg1 >= @arg2 (0, 0, ...
4179 *
4180 * When neither object to be compared is a node-set and the operator is
4181 * <=, <, >=, >, then the objects are compared by converted both objects
4182 * to numbers and comparing the numbers according to IEEE 754. The <
4183 * comparison will be true if and only if the first number is less than the
4184 * second number. The <= comparison will be true if and only if the first
4185 * number is less than or equal to the second number. The > comparison
4186 * will be true if and only if the first number is greater than the second
4187 * number. The >= comparison will be true if and only if the first number
4188 * is greater than or equal to the second number.
4189 *
4190 * Returns 1 if the comparaison succeeded, 0 if it failed
4191 */
4192int
4193xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
4194 int ret = 0;
4195 xmlXPathObjectPtr arg1, arg2;
4196
4197 arg2 = valuePop(ctxt);
4198 if (arg2 == NULL) {
4199 XP_ERROR0(XPATH_INVALID_OPERAND);
4200 }
4201
4202 arg1 = valuePop(ctxt);
4203 if (arg1 == NULL) {
4204 xmlXPathFreeObject(arg2);
4205 XP_ERROR0(XPATH_INVALID_OPERAND);
4206 }
4207
4208 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
4209 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004210 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004211 } else {
4212 if (arg1->type == XPATH_NODESET) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004213 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4214 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004215 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004216 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4217 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004218 }
4219 }
4220 return(ret);
4221 }
4222
4223 if (arg1->type != XPATH_NUMBER) {
4224 valuePush(ctxt, arg1);
4225 xmlXPathNumberFunction(ctxt, 1);
4226 arg1 = valuePop(ctxt);
4227 }
4228 if (arg1->type != XPATH_NUMBER) {
4229 xmlXPathFreeObject(arg1);
4230 xmlXPathFreeObject(arg2);
4231 XP_ERROR0(XPATH_INVALID_OPERAND);
4232 }
4233 if (arg2->type != XPATH_NUMBER) {
4234 valuePush(ctxt, arg2);
4235 xmlXPathNumberFunction(ctxt, 1);
4236 arg2 = valuePop(ctxt);
4237 }
4238 if (arg2->type != XPATH_NUMBER) {
4239 xmlXPathFreeObject(arg1);
4240 xmlXPathFreeObject(arg2);
4241 XP_ERROR0(XPATH_INVALID_OPERAND);
4242 }
4243 /*
4244 * Add tests for infinity and nan
4245 * => feedback on 3.4 for Inf and NaN
4246 */
4247 if (inf && strict)
4248 ret = (arg1->floatval < arg2->floatval);
4249 else if (inf && !strict)
4250 ret = (arg1->floatval <= arg2->floatval);
4251 else if (!inf && strict)
4252 ret = (arg1->floatval > arg2->floatval);
4253 else if (!inf && !strict)
4254 ret = (arg1->floatval >= arg2->floatval);
4255 xmlXPathFreeObject(arg1);
4256 xmlXPathFreeObject(arg2);
4257 return(ret);
4258}
4259
4260/**
4261 * xmlXPathValueFlipSign:
4262 * @ctxt: the XPath Parser context
4263 *
4264 * Implement the unary - operation on an XPath object
4265 * The numeric operators convert their operands to numbers as if
4266 * by calling the number function.
4267 */
4268void
4269xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004270 CAST_TO_NUMBER;
4271 CHECK_TYPE(XPATH_NUMBER);
4272 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00004273}
4274
4275/**
4276 * xmlXPathAddValues:
4277 * @ctxt: the XPath Parser context
4278 *
4279 * Implement the add operation on XPath objects:
4280 * The numeric operators convert their operands to numbers as if
4281 * by calling the number function.
4282 */
4283void
4284xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
4285 xmlXPathObjectPtr arg;
4286 double val;
4287
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004288 arg = valuePop(ctxt);
4289 if (arg == NULL)
4290 XP_ERROR(XPATH_INVALID_OPERAND);
4291 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004292 xmlXPathFreeObject(arg);
4293
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004294 CAST_TO_NUMBER;
4295 CHECK_TYPE(XPATH_NUMBER);
4296 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00004297}
4298
4299/**
4300 * xmlXPathSubValues:
4301 * @ctxt: the XPath Parser context
4302 *
4303 * Implement the substraction operation on XPath objects:
4304 * The numeric operators convert their operands to numbers as if
4305 * by calling the number function.
4306 */
4307void
4308xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
4309 xmlXPathObjectPtr arg;
4310 double val;
4311
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004312 arg = valuePop(ctxt);
4313 if (arg == NULL)
4314 XP_ERROR(XPATH_INVALID_OPERAND);
4315 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004316 xmlXPathFreeObject(arg);
4317
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004318 CAST_TO_NUMBER;
4319 CHECK_TYPE(XPATH_NUMBER);
4320 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004321}
4322
4323/**
4324 * xmlXPathMultValues:
4325 * @ctxt: the XPath Parser context
4326 *
4327 * Implement the multiply operation on XPath objects:
4328 * The numeric operators convert their operands to numbers as if
4329 * by calling the number function.
4330 */
4331void
4332xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
4333 xmlXPathObjectPtr arg;
4334 double val;
4335
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004336 arg = valuePop(ctxt);
4337 if (arg == NULL)
4338 XP_ERROR(XPATH_INVALID_OPERAND);
4339 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004340 xmlXPathFreeObject(arg);
4341
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004342 CAST_TO_NUMBER;
4343 CHECK_TYPE(XPATH_NUMBER);
4344 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004345}
4346
4347/**
4348 * xmlXPathDivValues:
4349 * @ctxt: the XPath Parser context
4350 *
4351 * Implement the div operation on XPath objects @arg1 / @arg2:
4352 * The numeric operators convert their operands to numbers as if
4353 * by calling the number function.
4354 */
4355void
4356xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
4357 xmlXPathObjectPtr arg;
4358 double val;
4359
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004360 arg = valuePop(ctxt);
4361 if (arg == NULL)
4362 XP_ERROR(XPATH_INVALID_OPERAND);
4363 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004364 xmlXPathFreeObject(arg);
4365
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004366 CAST_TO_NUMBER;
4367 CHECK_TYPE(XPATH_NUMBER);
4368 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004369}
4370
4371/**
4372 * xmlXPathModValues:
4373 * @ctxt: the XPath Parser context
4374 *
4375 * Implement the mod operation on XPath objects: @arg1 / @arg2
4376 * The numeric operators convert their operands to numbers as if
4377 * by calling the number function.
4378 */
4379void
4380xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
4381 xmlXPathObjectPtr arg;
4382 int arg1, arg2;
4383
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004384 arg = valuePop(ctxt);
4385 if (arg == NULL)
4386 XP_ERROR(XPATH_INVALID_OPERAND);
4387 arg2 = (int) xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004388 xmlXPathFreeObject(arg);
4389
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004390 CAST_TO_NUMBER;
4391 CHECK_TYPE(XPATH_NUMBER);
4392 arg1 = (int) ctxt->value->floatval;
4393 ctxt->value->floatval = arg1 % arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00004394}
4395
4396/************************************************************************
4397 * *
4398 * The traversal functions *
4399 * *
4400 ************************************************************************/
4401
Owen Taylor3473f882001-02-23 17:55:21 +00004402/*
4403 * A traversal function enumerates nodes along an axis.
4404 * Initially it must be called with NULL, and it indicates
4405 * termination on the axis by returning NULL.
4406 */
4407typedef xmlNodePtr (*xmlXPathTraversalFunction)
4408 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
4409
4410/**
4411 * xmlXPathNextSelf:
4412 * @ctxt: the XPath Parser context
4413 * @cur: the current node in the traversal
4414 *
4415 * Traversal function for the "self" direction
4416 * The self axis contains just the context node itself
4417 *
4418 * Returns the next element following that axis
4419 */
4420xmlNodePtr
4421xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4422 if (cur == NULL)
4423 return(ctxt->context->node);
4424 return(NULL);
4425}
4426
4427/**
4428 * xmlXPathNextChild:
4429 * @ctxt: the XPath Parser context
4430 * @cur: the current node in the traversal
4431 *
4432 * Traversal function for the "child" direction
4433 * The child axis contains the children of the context node in document order.
4434 *
4435 * Returns the next element following that axis
4436 */
4437xmlNodePtr
4438xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4439 if (cur == NULL) {
4440 if (ctxt->context->node == NULL) return(NULL);
4441 switch (ctxt->context->node->type) {
4442 case XML_ELEMENT_NODE:
4443 case XML_TEXT_NODE:
4444 case XML_CDATA_SECTION_NODE:
4445 case XML_ENTITY_REF_NODE:
4446 case XML_ENTITY_NODE:
4447 case XML_PI_NODE:
4448 case XML_COMMENT_NODE:
4449 case XML_NOTATION_NODE:
4450 case XML_DTD_NODE:
4451 return(ctxt->context->node->children);
4452 case XML_DOCUMENT_NODE:
4453 case XML_DOCUMENT_TYPE_NODE:
4454 case XML_DOCUMENT_FRAG_NODE:
4455 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004456#ifdef LIBXML_DOCB_ENABLED
4457 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004458#endif
4459 return(((xmlDocPtr) ctxt->context->node)->children);
4460 case XML_ELEMENT_DECL:
4461 case XML_ATTRIBUTE_DECL:
4462 case XML_ENTITY_DECL:
4463 case XML_ATTRIBUTE_NODE:
4464 case XML_NAMESPACE_DECL:
4465 case XML_XINCLUDE_START:
4466 case XML_XINCLUDE_END:
4467 return(NULL);
4468 }
4469 return(NULL);
4470 }
4471 if ((cur->type == XML_DOCUMENT_NODE) ||
4472 (cur->type == XML_HTML_DOCUMENT_NODE))
4473 return(NULL);
4474 return(cur->next);
4475}
4476
4477/**
4478 * xmlXPathNextDescendant:
4479 * @ctxt: the XPath Parser context
4480 * @cur: the current node in the traversal
4481 *
4482 * Traversal function for the "descendant" direction
4483 * the descendant axis contains the descendants of the context node in document
4484 * order; a descendant is a child or a child of a child and so on.
4485 *
4486 * Returns the next element following that axis
4487 */
4488xmlNodePtr
4489xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4490 if (cur == NULL) {
4491 if (ctxt->context->node == NULL)
4492 return(NULL);
4493 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4494 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4495 return(NULL);
4496
4497 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
4498 return(ctxt->context->doc->children);
4499 return(ctxt->context->node->children);
4500 }
4501
Daniel Veillard567e1b42001-08-01 15:53:47 +00004502 if (cur->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004503 if (cur->children->type != XML_ENTITY_DECL)
Daniel Veillard567e1b42001-08-01 15:53:47 +00004504 return(cur->children);
4505 }
4506
4507 if (cur == ctxt->context->node) return(NULL);
4508
Owen Taylor3473f882001-02-23 17:55:21 +00004509 if (cur->next != NULL) return(cur->next);
4510
4511 do {
4512 cur = cur->parent;
4513 if (cur == NULL) return(NULL);
4514 if (cur == ctxt->context->node) return(NULL);
4515 if (cur->next != NULL) {
4516 cur = cur->next;
4517 return(cur);
4518 }
4519 } while (cur != NULL);
4520 return(cur);
4521}
4522
4523/**
4524 * xmlXPathNextDescendantOrSelf:
4525 * @ctxt: the XPath Parser context
4526 * @cur: the current node in the traversal
4527 *
4528 * Traversal function for the "descendant-or-self" direction
4529 * the descendant-or-self axis contains the context node and the descendants
4530 * of the context node in document order; thus the context node is the first
4531 * node on the axis, and the first child of the context node is the second node
4532 * on the axis
4533 *
4534 * Returns the next element following that axis
4535 */
4536xmlNodePtr
4537xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4538 if (cur == NULL) {
4539 if (ctxt->context->node == NULL)
4540 return(NULL);
4541 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4542 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4543 return(NULL);
4544 return(ctxt->context->node);
4545 }
4546
4547 return(xmlXPathNextDescendant(ctxt, cur));
4548}
4549
4550/**
4551 * xmlXPathNextParent:
4552 * @ctxt: the XPath Parser context
4553 * @cur: the current node in the traversal
4554 *
4555 * Traversal function for the "parent" direction
4556 * The parent axis contains the parent of the context node, if there is one.
4557 *
4558 * Returns the next element following that axis
4559 */
4560xmlNodePtr
4561xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4562 /*
4563 * the parent of an attribute or namespace node is the element
4564 * to which the attribute or namespace node is attached
4565 * Namespace handling !!!
4566 */
4567 if (cur == NULL) {
4568 if (ctxt->context->node == NULL) return(NULL);
4569 switch (ctxt->context->node->type) {
4570 case XML_ELEMENT_NODE:
4571 case XML_TEXT_NODE:
4572 case XML_CDATA_SECTION_NODE:
4573 case XML_ENTITY_REF_NODE:
4574 case XML_ENTITY_NODE:
4575 case XML_PI_NODE:
4576 case XML_COMMENT_NODE:
4577 case XML_NOTATION_NODE:
4578 case XML_DTD_NODE:
4579 case XML_ELEMENT_DECL:
4580 case XML_ATTRIBUTE_DECL:
4581 case XML_XINCLUDE_START:
4582 case XML_XINCLUDE_END:
4583 case XML_ENTITY_DECL:
4584 if (ctxt->context->node->parent == NULL)
4585 return((xmlNodePtr) ctxt->context->doc);
4586 return(ctxt->context->node->parent);
4587 case XML_ATTRIBUTE_NODE: {
4588 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4589
4590 return(att->parent);
4591 }
4592 case XML_DOCUMENT_NODE:
4593 case XML_DOCUMENT_TYPE_NODE:
4594 case XML_DOCUMENT_FRAG_NODE:
4595 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004596#ifdef LIBXML_DOCB_ENABLED
4597 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004598#endif
4599 return(NULL);
4600 case XML_NAMESPACE_DECL:
4601 /*
4602 * TODO !!! may require extending struct _xmlNs with
4603 * parent field
4604 * C.f. Infoset case...
4605 */
4606 return(NULL);
4607 }
4608 }
4609 return(NULL);
4610}
4611
4612/**
4613 * xmlXPathNextAncestor:
4614 * @ctxt: the XPath Parser context
4615 * @cur: the current node in the traversal
4616 *
4617 * Traversal function for the "ancestor" direction
4618 * the ancestor axis contains the ancestors of the context node; the ancestors
4619 * of the context node consist of the parent of context node and the parent's
4620 * parent and so on; the nodes are ordered in reverse document order; thus the
4621 * parent is the first node on the axis, and the parent's parent is the second
4622 * node on the axis
4623 *
4624 * Returns the next element following that axis
4625 */
4626xmlNodePtr
4627xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4628 /*
4629 * the parent of an attribute or namespace node is the element
4630 * to which the attribute or namespace node is attached
4631 * !!!!!!!!!!!!!
4632 */
4633 if (cur == NULL) {
4634 if (ctxt->context->node == NULL) return(NULL);
4635 switch (ctxt->context->node->type) {
4636 case XML_ELEMENT_NODE:
4637 case XML_TEXT_NODE:
4638 case XML_CDATA_SECTION_NODE:
4639 case XML_ENTITY_REF_NODE:
4640 case XML_ENTITY_NODE:
4641 case XML_PI_NODE:
4642 case XML_COMMENT_NODE:
4643 case XML_DTD_NODE:
4644 case XML_ELEMENT_DECL:
4645 case XML_ATTRIBUTE_DECL:
4646 case XML_ENTITY_DECL:
4647 case XML_NOTATION_NODE:
4648 case XML_XINCLUDE_START:
4649 case XML_XINCLUDE_END:
4650 if (ctxt->context->node->parent == NULL)
4651 return((xmlNodePtr) ctxt->context->doc);
4652 return(ctxt->context->node->parent);
4653 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004654 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00004655
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004656 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00004657 }
4658 case XML_DOCUMENT_NODE:
4659 case XML_DOCUMENT_TYPE_NODE:
4660 case XML_DOCUMENT_FRAG_NODE:
4661 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004662#ifdef LIBXML_DOCB_ENABLED
4663 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004664#endif
4665 return(NULL);
4666 case XML_NAMESPACE_DECL:
4667 /*
4668 * TODO !!! may require extending struct _xmlNs with
4669 * parent field
4670 * C.f. Infoset case...
4671 */
4672 return(NULL);
4673 }
4674 return(NULL);
4675 }
4676 if (cur == ctxt->context->doc->children)
4677 return((xmlNodePtr) ctxt->context->doc);
4678 if (cur == (xmlNodePtr) ctxt->context->doc)
4679 return(NULL);
4680 switch (cur->type) {
4681 case XML_ELEMENT_NODE:
4682 case XML_TEXT_NODE:
4683 case XML_CDATA_SECTION_NODE:
4684 case XML_ENTITY_REF_NODE:
4685 case XML_ENTITY_NODE:
4686 case XML_PI_NODE:
4687 case XML_COMMENT_NODE:
4688 case XML_NOTATION_NODE:
4689 case XML_DTD_NODE:
4690 case XML_ELEMENT_DECL:
4691 case XML_ATTRIBUTE_DECL:
4692 case XML_ENTITY_DECL:
4693 case XML_XINCLUDE_START:
4694 case XML_XINCLUDE_END:
4695 return(cur->parent);
4696 case XML_ATTRIBUTE_NODE: {
4697 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4698
4699 return(att->parent);
4700 }
4701 case XML_DOCUMENT_NODE:
4702 case XML_DOCUMENT_TYPE_NODE:
4703 case XML_DOCUMENT_FRAG_NODE:
4704 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004705#ifdef LIBXML_DOCB_ENABLED
4706 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004707#endif
4708 return(NULL);
4709 case XML_NAMESPACE_DECL:
4710 /*
4711 * TODO !!! may require extending struct _xmlNs with
4712 * parent field
4713 * C.f. Infoset case...
4714 */
4715 return(NULL);
4716 }
4717 return(NULL);
4718}
4719
4720/**
4721 * xmlXPathNextAncestorOrSelf:
4722 * @ctxt: the XPath Parser context
4723 * @cur: the current node in the traversal
4724 *
4725 * Traversal function for the "ancestor-or-self" direction
4726 * he ancestor-or-self axis contains the context node and ancestors of
4727 * the context node in reverse document order; thus the context node is
4728 * the first node on the axis, and the context node's parent the second;
4729 * parent here is defined the same as with the parent axis.
4730 *
4731 * Returns the next element following that axis
4732 */
4733xmlNodePtr
4734xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4735 if (cur == NULL)
4736 return(ctxt->context->node);
4737 return(xmlXPathNextAncestor(ctxt, cur));
4738}
4739
4740/**
4741 * xmlXPathNextFollowingSibling:
4742 * @ctxt: the XPath Parser context
4743 * @cur: the current node in the traversal
4744 *
4745 * Traversal function for the "following-sibling" direction
4746 * The following-sibling axis contains the following siblings of the context
4747 * node in document order.
4748 *
4749 * Returns the next element following that axis
4750 */
4751xmlNodePtr
4752xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4753 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4754 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4755 return(NULL);
4756 if (cur == (xmlNodePtr) ctxt->context->doc)
4757 return(NULL);
4758 if (cur == NULL)
4759 return(ctxt->context->node->next);
4760 return(cur->next);
4761}
4762
4763/**
4764 * xmlXPathNextPrecedingSibling:
4765 * @ctxt: the XPath Parser context
4766 * @cur: the current node in the traversal
4767 *
4768 * Traversal function for the "preceding-sibling" direction
4769 * The preceding-sibling axis contains the preceding siblings of the context
4770 * node in reverse document order; the first preceding sibling is first on the
4771 * axis; the sibling preceding that node is the second on the axis and so on.
4772 *
4773 * Returns the next element following that axis
4774 */
4775xmlNodePtr
4776xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4777 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4778 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4779 return(NULL);
4780 if (cur == (xmlNodePtr) ctxt->context->doc)
4781 return(NULL);
4782 if (cur == NULL)
4783 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004784 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
4785 cur = cur->prev;
4786 if (cur == NULL)
4787 return(ctxt->context->node->prev);
4788 }
Owen Taylor3473f882001-02-23 17:55:21 +00004789 return(cur->prev);
4790}
4791
4792/**
4793 * xmlXPathNextFollowing:
4794 * @ctxt: the XPath Parser context
4795 * @cur: the current node in the traversal
4796 *
4797 * Traversal function for the "following" direction
4798 * The following axis contains all nodes in the same document as the context
4799 * node that are after the context node in document order, excluding any
4800 * descendants and excluding attribute nodes and namespace nodes; the nodes
4801 * are ordered in document order
4802 *
4803 * Returns the next element following that axis
4804 */
4805xmlNodePtr
4806xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4807 if (cur != NULL && cur->children != NULL)
4808 return cur->children ;
4809 if (cur == NULL) cur = ctxt->context->node;
4810 if (cur == NULL) return(NULL) ; /* ERROR */
4811 if (cur->next != NULL) return(cur->next) ;
4812 do {
4813 cur = cur->parent;
4814 if (cur == NULL) return(NULL);
4815 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
4816 if (cur->next != NULL) return(cur->next);
4817 } while (cur != NULL);
4818 return(cur);
4819}
4820
4821/*
4822 * xmlXPathIsAncestor:
4823 * @ancestor: the ancestor node
4824 * @node: the current node
4825 *
4826 * Check that @ancestor is a @node's ancestor
4827 *
4828 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
4829 */
4830static int
4831xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
4832 if ((ancestor == NULL) || (node == NULL)) return(0);
4833 /* nodes need to be in the same document */
4834 if (ancestor->doc != node->doc) return(0);
4835 /* avoid searching if ancestor or node is the root node */
4836 if (ancestor == (xmlNodePtr) node->doc) return(1);
4837 if (node == (xmlNodePtr) ancestor->doc) return(0);
4838 while (node->parent != NULL) {
4839 if (node->parent == ancestor)
4840 return(1);
4841 node = node->parent;
4842 }
4843 return(0);
4844}
4845
4846/**
4847 * xmlXPathNextPreceding:
4848 * @ctxt: the XPath Parser context
4849 * @cur: the current node in the traversal
4850 *
4851 * Traversal function for the "preceding" direction
4852 * the preceding axis contains all nodes in the same document as the context
4853 * node that are before the context node in document order, excluding any
4854 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4855 * ordered in reverse document order
4856 *
4857 * Returns the next element following that axis
4858 */
4859xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00004860xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
4861{
Owen Taylor3473f882001-02-23 17:55:21 +00004862 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004863 cur = ctxt->context->node;
4864 if (cur == NULL)
4865 return (NULL);
4866 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
4867 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00004868 do {
4869 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004870 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
4871 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004872 }
4873
4874 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004875 if (cur == NULL)
4876 return (NULL);
4877 if (cur == ctxt->context->doc->children)
4878 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004879 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00004880 return (cur);
4881}
4882
4883/**
4884 * xmlXPathNextPrecedingInternal:
4885 * @ctxt: the XPath Parser context
4886 * @cur: the current node in the traversal
4887 *
4888 * Traversal function for the "preceding" direction
4889 * the preceding axis contains all nodes in the same document as the context
4890 * node that are before the context node in document order, excluding any
4891 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4892 * ordered in reverse document order
4893 * This is a faster implementation but internal only since it requires a
4894 * state kept in the parser context: ctxt->ancestor.
4895 *
4896 * Returns the next element following that axis
4897 */
4898static xmlNodePtr
4899xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
4900 xmlNodePtr cur)
4901{
4902 if (cur == NULL) {
4903 cur = ctxt->context->node;
4904 if (cur == NULL)
4905 return (NULL);
4906 ctxt->ancestor = cur->parent;
4907 }
4908 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
4909 cur = cur->prev;
4910 while (cur->prev == NULL) {
4911 cur = cur->parent;
4912 if (cur == NULL)
4913 return (NULL);
4914 if (cur == ctxt->context->doc->children)
4915 return (NULL);
4916 if (cur != ctxt->ancestor)
4917 return (cur);
4918 ctxt->ancestor = cur->parent;
4919 }
4920 cur = cur->prev;
4921 while (cur->last != NULL)
4922 cur = cur->last;
4923 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004924}
4925
4926/**
4927 * xmlXPathNextNamespace:
4928 * @ctxt: the XPath Parser context
4929 * @cur: the current attribute in the traversal
4930 *
4931 * Traversal function for the "namespace" direction
4932 * the namespace axis contains the namespace nodes of the context node;
4933 * the order of nodes on this axis is implementation-defined; the axis will
4934 * be empty unless the context node is an element
4935 *
4936 * Returns the next element following that axis
4937 */
4938xmlNodePtr
4939xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00004940 xmlNodePtr ret;
4941
Owen Taylor3473f882001-02-23 17:55:21 +00004942 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00004943 if ((cur == NULL) || (ctxt->context->tmpNsList == NULL)) {
4944 if (ctxt->context->tmpNsList != NULL)
4945 xmlFree(ctxt->context->tmpNsList);
4946 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00004947 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00004948 if (ctxt->context->tmpNsList == NULL) return(NULL);
4949 ctxt->context->tmpNsNr = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004950 }
Daniel Veillard7d7e3792001-07-30 13:42:13 +00004951 ret = (xmlNodePtr)ctxt->context->tmpNsList[ctxt->context->tmpNsNr++];
4952 if (ret == NULL) {
4953 xmlFree(ctxt->context->tmpNsList);
4954 ctxt->context->tmpNsList = NULL;
4955 }
4956 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004957}
4958
4959/**
4960 * xmlXPathNextAttribute:
4961 * @ctxt: the XPath Parser context
4962 * @cur: the current attribute in the traversal
4963 *
4964 * Traversal function for the "attribute" direction
4965 * TODO: support DTD inherited default attributes
4966 *
4967 * Returns the next element following that axis
4968 */
4969xmlNodePtr
4970xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00004971 if (ctxt->context->node == NULL)
4972 return(NULL);
4973 if (ctxt->context->node->type != XML_ELEMENT_NODE)
4974 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004975 if (cur == NULL) {
4976 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
4977 return(NULL);
4978 return((xmlNodePtr)ctxt->context->node->properties);
4979 }
4980 return((xmlNodePtr)cur->next);
4981}
4982
4983/************************************************************************
4984 * *
4985 * NodeTest Functions *
4986 * *
4987 ************************************************************************/
4988
Owen Taylor3473f882001-02-23 17:55:21 +00004989#define IS_FUNCTION 200
4990
Owen Taylor3473f882001-02-23 17:55:21 +00004991
4992/************************************************************************
4993 * *
4994 * Implicit tree core function library *
4995 * *
4996 ************************************************************************/
4997
4998/**
4999 * xmlXPathRoot:
5000 * @ctxt: the XPath Parser context
5001 *
5002 * Initialize the context to the root of the document
5003 */
5004void
5005xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5006 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5007 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5008}
5009
5010/************************************************************************
5011 * *
5012 * The explicit core function library *
5013 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5014 * *
5015 ************************************************************************/
5016
5017
5018/**
5019 * xmlXPathLastFunction:
5020 * @ctxt: the XPath Parser context
5021 * @nargs: the number of arguments
5022 *
5023 * Implement the last() XPath function
5024 * number last()
5025 * The last function returns the number of nodes in the context node list.
5026 */
5027void
5028xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5029 CHECK_ARITY(0);
5030 if (ctxt->context->contextSize >= 0) {
5031 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5032#ifdef DEBUG_EXPR
5033 xmlGenericError(xmlGenericErrorContext,
5034 "last() : %d\n", ctxt->context->contextSize);
5035#endif
5036 } else {
5037 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5038 }
5039}
5040
5041/**
5042 * xmlXPathPositionFunction:
5043 * @ctxt: the XPath Parser context
5044 * @nargs: the number of arguments
5045 *
5046 * Implement the position() XPath function
5047 * number position()
5048 * The position function returns the position of the context node in the
5049 * context node list. The first position is 1, and so the last positionr
5050 * will be equal to last().
5051 */
5052void
5053xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5054 CHECK_ARITY(0);
5055 if (ctxt->context->proximityPosition >= 0) {
5056 valuePush(ctxt,
5057 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5058#ifdef DEBUG_EXPR
5059 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5060 ctxt->context->proximityPosition);
5061#endif
5062 } else {
5063 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5064 }
5065}
5066
5067/**
5068 * xmlXPathCountFunction:
5069 * @ctxt: the XPath Parser context
5070 * @nargs: the number of arguments
5071 *
5072 * Implement the count() XPath function
5073 * number count(node-set)
5074 */
5075void
5076xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5077 xmlXPathObjectPtr cur;
5078
5079 CHECK_ARITY(1);
5080 if ((ctxt->value == NULL) ||
5081 ((ctxt->value->type != XPATH_NODESET) &&
5082 (ctxt->value->type != XPATH_XSLT_TREE)))
5083 XP_ERROR(XPATH_INVALID_TYPE);
5084 cur = valuePop(ctxt);
5085
Daniel Veillard911f49a2001-04-07 15:39:35 +00005086 if ((cur == NULL) || (cur->nodesetval == NULL))
5087 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00005088 else if (cur->type == XPATH_NODESET) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005089 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005090 } else {
5091 if ((cur->nodesetval->nodeNr != 1) ||
5092 (cur->nodesetval->nodeTab == NULL)) {
5093 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5094 } else {
5095 xmlNodePtr tmp;
5096 int i = 0;
5097
5098 tmp = cur->nodesetval->nodeTab[0];
5099 if (tmp != NULL) {
5100 tmp = tmp->children;
5101 while (tmp != NULL) {
5102 tmp = tmp->next;
5103 i++;
5104 }
5105 }
5106 valuePush(ctxt, xmlXPathNewFloat((double) i));
5107 }
5108 }
Owen Taylor3473f882001-02-23 17:55:21 +00005109 xmlXPathFreeObject(cur);
5110}
5111
5112/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005113 * xmlXPathGetElementsByIds:
5114 * @doc: the document
5115 * @ids: a whitespace separated list of IDs
5116 *
5117 * Selects elements by their unique ID.
5118 *
5119 * Returns a node-set of selected elements.
5120 */
5121static xmlNodeSetPtr
5122xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5123 xmlNodeSetPtr ret;
5124 const xmlChar *cur = ids;
5125 xmlChar *ID;
5126 xmlAttrPtr attr;
5127 xmlNodePtr elem = NULL;
5128
5129 ret = xmlXPathNodeSetCreate(NULL);
5130
5131 while (IS_BLANK(*cur)) cur++;
5132 while (*cur != 0) {
5133 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
5134 (*cur == '.') || (*cur == '-') ||
5135 (*cur == '_') || (*cur == ':') ||
5136 (IS_COMBINING(*cur)) ||
5137 (IS_EXTENDER(*cur)))
5138 cur++;
5139
5140 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
5141
5142 ID = xmlStrndup(ids, cur - ids);
5143 attr = xmlGetID(doc, ID);
5144 if (attr != NULL) {
5145 elem = attr->parent;
5146 xmlXPathNodeSetAdd(ret, elem);
5147 }
5148 if (ID != NULL)
5149 xmlFree(ID);
5150
5151 while (IS_BLANK(*cur)) cur++;
5152 ids = cur;
5153 }
5154 return(ret);
5155}
5156
5157/**
Owen Taylor3473f882001-02-23 17:55:21 +00005158 * xmlXPathIdFunction:
5159 * @ctxt: the XPath Parser context
5160 * @nargs: the number of arguments
5161 *
5162 * Implement the id() XPath function
5163 * node-set id(object)
5164 * The id function selects elements by their unique ID
5165 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5166 * then the result is the union of the result of applying id to the
5167 * string value of each of the nodes in the argument node-set. When the
5168 * argument to id is of any other type, the argument is converted to a
5169 * string as if by a call to the string function; the string is split
5170 * into a whitespace-separated list of tokens (whitespace is any sequence
5171 * of characters matching the production S); the result is a node-set
5172 * containing the elements in the same document as the context node that
5173 * have a unique ID equal to any of the tokens in the list.
5174 */
5175void
5176xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005177 xmlChar *tokens;
5178 xmlNodeSetPtr ret;
5179 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00005180
5181 CHECK_ARITY(1);
5182 obj = valuePop(ctxt);
5183 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
5184 if (obj->type == XPATH_NODESET) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005185 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00005186 int i;
5187
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005188 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005189
Daniel Veillard911f49a2001-04-07 15:39:35 +00005190 if (obj->nodesetval != NULL) {
5191 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005192 tokens =
5193 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
5194 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
5195 ret = xmlXPathNodeSetMerge(ret, ns);
5196 xmlXPathFreeNodeSet(ns);
5197 if (tokens != NULL)
5198 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00005199 }
Owen Taylor3473f882001-02-23 17:55:21 +00005200 }
5201
5202 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005203 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005204 return;
5205 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005206 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00005207
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005208 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
5209 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005210
Owen Taylor3473f882001-02-23 17:55:21 +00005211 xmlXPathFreeObject(obj);
5212 return;
5213}
5214
5215/**
5216 * xmlXPathLocalNameFunction:
5217 * @ctxt: the XPath Parser context
5218 * @nargs: the number of arguments
5219 *
5220 * Implement the local-name() XPath function
5221 * string local-name(node-set?)
5222 * The local-name function returns a string containing the local part
5223 * of the name of the node in the argument node-set that is first in
5224 * document order. If the node-set is empty or the first node has no
5225 * name, an empty string is returned. If the argument is omitted it
5226 * defaults to the context node.
5227 */
5228void
5229xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5230 xmlXPathObjectPtr cur;
5231
5232 if (nargs == 0) {
5233 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5234 nargs = 1;
5235 }
5236
5237 CHECK_ARITY(1);
5238 if ((ctxt->value == NULL) ||
5239 ((ctxt->value->type != XPATH_NODESET) &&
5240 (ctxt->value->type != XPATH_XSLT_TREE)))
5241 XP_ERROR(XPATH_INVALID_TYPE);
5242 cur = valuePop(ctxt);
5243
Daniel Veillard911f49a2001-04-07 15:39:35 +00005244 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005245 valuePush(ctxt, xmlXPathNewCString(""));
5246 } else {
5247 int i = 0; /* Should be first in document order !!!!! */
5248 switch (cur->nodesetval->nodeTab[i]->type) {
5249 case XML_ELEMENT_NODE:
5250 case XML_ATTRIBUTE_NODE:
5251 case XML_PI_NODE:
5252 valuePush(ctxt,
5253 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
5254 break;
5255 case XML_NAMESPACE_DECL:
5256 valuePush(ctxt, xmlXPathNewString(
5257 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
5258 break;
5259 default:
5260 valuePush(ctxt, xmlXPathNewCString(""));
5261 }
5262 }
5263 xmlXPathFreeObject(cur);
5264}
5265
5266/**
5267 * xmlXPathNamespaceURIFunction:
5268 * @ctxt: the XPath Parser context
5269 * @nargs: the number of arguments
5270 *
5271 * Implement the namespace-uri() XPath function
5272 * string namespace-uri(node-set?)
5273 * The namespace-uri function returns a string containing the
5274 * namespace URI of the expanded name of the node in the argument
5275 * node-set that is first in document order. If the node-set is empty,
5276 * the first node has no name, or the expanded name has no namespace
5277 * URI, an empty string is returned. If the argument is omitted it
5278 * defaults to the context node.
5279 */
5280void
5281xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5282 xmlXPathObjectPtr cur;
5283
5284 if (nargs == 0) {
5285 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5286 nargs = 1;
5287 }
5288 CHECK_ARITY(1);
5289 if ((ctxt->value == NULL) ||
5290 ((ctxt->value->type != XPATH_NODESET) &&
5291 (ctxt->value->type != XPATH_XSLT_TREE)))
5292 XP_ERROR(XPATH_INVALID_TYPE);
5293 cur = valuePop(ctxt);
5294
Daniel Veillard911f49a2001-04-07 15:39:35 +00005295 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005296 valuePush(ctxt, xmlXPathNewCString(""));
5297 } else {
5298 int i = 0; /* Should be first in document order !!!!! */
5299 switch (cur->nodesetval->nodeTab[i]->type) {
5300 case XML_ELEMENT_NODE:
5301 case XML_ATTRIBUTE_NODE:
5302 if (cur->nodesetval->nodeTab[i]->ns == NULL)
5303 valuePush(ctxt, xmlXPathNewCString(""));
5304 else
5305 valuePush(ctxt, xmlXPathNewString(
5306 cur->nodesetval->nodeTab[i]->ns->href));
5307 break;
5308 default:
5309 valuePush(ctxt, xmlXPathNewCString(""));
5310 }
5311 }
5312 xmlXPathFreeObject(cur);
5313}
5314
5315/**
5316 * xmlXPathNameFunction:
5317 * @ctxt: the XPath Parser context
5318 * @nargs: the number of arguments
5319 *
5320 * Implement the name() XPath function
5321 * string name(node-set?)
5322 * The name function returns a string containing a QName representing
5323 * the name of the node in the argument node-set that is first in documenti
5324 * order. The QName must represent the name with respect to the namespace
5325 * declarations in effect on the node whose name is being represented.
5326 * Typically, this will be the form in which the name occurred in the XML
5327 * source. This need not be the case if there are namespace declarations
5328 * in effect on the node that associate multiple prefixes with the same
5329 * namespace. However, an implementation may include information about
5330 * the original prefix in its representation of nodes; in this case, an
5331 * implementation can ensure that the returned string is always the same
5332 * as the QName used in the XML source. If the argument it omitted it
5333 * defaults to the context node.
5334 * Libxml keep the original prefix so the "real qualified name" used is
5335 * returned.
5336 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005337static void
Daniel Veillard04383752001-07-08 14:27:15 +00005338xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
5339{
Owen Taylor3473f882001-02-23 17:55:21 +00005340 xmlXPathObjectPtr cur;
5341
5342 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00005343 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5344 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00005345 }
5346
5347 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00005348 if ((ctxt->value == NULL) ||
5349 ((ctxt->value->type != XPATH_NODESET) &&
5350 (ctxt->value->type != XPATH_XSLT_TREE)))
5351 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00005352 cur = valuePop(ctxt);
5353
Daniel Veillard911f49a2001-04-07 15:39:35 +00005354 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00005355 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00005356 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00005357 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005358
Daniel Veillard04383752001-07-08 14:27:15 +00005359 switch (cur->nodesetval->nodeTab[i]->type) {
5360 case XML_ELEMENT_NODE:
5361 case XML_ATTRIBUTE_NODE:
5362 if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
5363 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL))
5364 valuePush(ctxt,
5365 xmlXPathNewString(cur->nodesetval->
5366 nodeTab[i]->name));
5367
5368 else {
5369 char name[2000];
5370
5371 snprintf(name, sizeof(name), "%s:%s",
5372 (char *) cur->nodesetval->nodeTab[i]->ns->
5373 prefix,
5374 (char *) cur->nodesetval->nodeTab[i]->name);
5375 name[sizeof(name) - 1] = 0;
5376 valuePush(ctxt, xmlXPathNewCString(name));
5377 }
5378 break;
5379 default:
5380 valuePush(ctxt,
5381 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
5382 xmlXPathLocalNameFunction(ctxt, 1);
5383 }
Owen Taylor3473f882001-02-23 17:55:21 +00005384 }
5385 xmlXPathFreeObject(cur);
5386}
5387
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005388
5389/**
Owen Taylor3473f882001-02-23 17:55:21 +00005390 * xmlXPathStringFunction:
5391 * @ctxt: the XPath Parser context
5392 * @nargs: the number of arguments
5393 *
5394 * Implement the string() XPath function
5395 * string string(object?)
5396 * he string function converts an object to a string as follows:
5397 * - A node-set is converted to a string by returning the value of
5398 * the node in the node-set that is first in document order.
5399 * If the node-set is empty, an empty string is returned.
5400 * - A number is converted to a string as follows
5401 * + NaN is converted to the string NaN
5402 * + positive zero is converted to the string 0
5403 * + negative zero is converted to the string 0
5404 * + positive infinity is converted to the string Infinity
5405 * + negative infinity is converted to the string -Infinity
5406 * + if the number is an integer, the number is represented in
5407 * decimal form as a Number with no decimal point and no leading
5408 * zeros, preceded by a minus sign (-) if the number is negative
5409 * + otherwise, the number is represented in decimal form as a
5410 * Number including a decimal point with at least one digit
5411 * before the decimal point and at least one digit after the
5412 * decimal point, preceded by a minus sign (-) if the number
5413 * is negative; there must be no leading zeros before the decimal
5414 * point apart possibly from the one required digit immediatelyi
5415 * before the decimal point; beyond the one required digit
5416 * after the decimal point there must be as many, but only as
5417 * many, more digits as are needed to uniquely distinguish the
5418 * number from all other IEEE 754 numeric values.
5419 * - The boolean false value is converted to the string false.
5420 * The boolean true value is converted to the string true.
5421 *
5422 * If the argument is omitted, it defaults to a node-set with the
5423 * context node as its only member.
5424 */
5425void
5426xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5427 xmlXPathObjectPtr cur;
5428
5429 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005430 valuePush(ctxt,
5431 xmlXPathWrapString(
5432 xmlXPathCastNodeToString(ctxt->context->node)));
5433 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005434 }
5435
5436 CHECK_ARITY(1);
5437 cur = valuePop(ctxt);
5438 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005439 cur = xmlXPathConvertString(cur);
5440 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005441}
5442
5443/**
5444 * xmlXPathStringLengthFunction:
5445 * @ctxt: the XPath Parser context
5446 * @nargs: the number of arguments
5447 *
5448 * Implement the string-length() XPath function
5449 * number string-length(string?)
5450 * The string-length returns the number of characters in the string
5451 * (see [3.6 Strings]). If the argument is omitted, it defaults to
5452 * the context node converted to a string, in other words the value
5453 * of the context node.
5454 */
5455void
5456xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5457 xmlXPathObjectPtr cur;
5458
5459 if (nargs == 0) {
5460 if (ctxt->context->node == NULL) {
5461 valuePush(ctxt, xmlXPathNewFloat(0));
5462 } else {
5463 xmlChar *content;
5464
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005465 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005466 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00005467 xmlFree(content);
5468 }
5469 return;
5470 }
5471 CHECK_ARITY(1);
5472 CAST_TO_STRING;
5473 CHECK_TYPE(XPATH_STRING);
5474 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005475 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00005476 xmlXPathFreeObject(cur);
5477}
5478
5479/**
5480 * xmlXPathConcatFunction:
5481 * @ctxt: the XPath Parser context
5482 * @nargs: the number of arguments
5483 *
5484 * Implement the concat() XPath function
5485 * string concat(string, string, string*)
5486 * The concat function returns the concatenation of its arguments.
5487 */
5488void
5489xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5490 xmlXPathObjectPtr cur, newobj;
5491 xmlChar *tmp;
5492
5493 if (nargs < 2) {
5494 CHECK_ARITY(2);
5495 }
5496
5497 CAST_TO_STRING;
5498 cur = valuePop(ctxt);
5499 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
5500 xmlXPathFreeObject(cur);
5501 return;
5502 }
5503 nargs--;
5504
5505 while (nargs > 0) {
5506 CAST_TO_STRING;
5507 newobj = valuePop(ctxt);
5508 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
5509 xmlXPathFreeObject(newobj);
5510 xmlXPathFreeObject(cur);
5511 XP_ERROR(XPATH_INVALID_TYPE);
5512 }
5513 tmp = xmlStrcat(newobj->stringval, cur->stringval);
5514 newobj->stringval = cur->stringval;
5515 cur->stringval = tmp;
5516
5517 xmlXPathFreeObject(newobj);
5518 nargs--;
5519 }
5520 valuePush(ctxt, cur);
5521}
5522
5523/**
5524 * xmlXPathContainsFunction:
5525 * @ctxt: the XPath Parser context
5526 * @nargs: the number of arguments
5527 *
5528 * Implement the contains() XPath function
5529 * boolean contains(string, string)
5530 * The contains function returns true if the first argument string
5531 * contains the second argument string, and otherwise returns false.
5532 */
5533void
5534xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5535 xmlXPathObjectPtr hay, needle;
5536
5537 CHECK_ARITY(2);
5538 CAST_TO_STRING;
5539 CHECK_TYPE(XPATH_STRING);
5540 needle = valuePop(ctxt);
5541 CAST_TO_STRING;
5542 hay = valuePop(ctxt);
5543 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5544 xmlXPathFreeObject(hay);
5545 xmlXPathFreeObject(needle);
5546 XP_ERROR(XPATH_INVALID_TYPE);
5547 }
5548 if (xmlStrstr(hay->stringval, needle->stringval))
5549 valuePush(ctxt, xmlXPathNewBoolean(1));
5550 else
5551 valuePush(ctxt, xmlXPathNewBoolean(0));
5552 xmlXPathFreeObject(hay);
5553 xmlXPathFreeObject(needle);
5554}
5555
5556/**
5557 * xmlXPathStartsWithFunction:
5558 * @ctxt: the XPath Parser context
5559 * @nargs: the number of arguments
5560 *
5561 * Implement the starts-with() XPath function
5562 * boolean starts-with(string, string)
5563 * The starts-with function returns true if the first argument string
5564 * starts with the second argument string, and otherwise returns false.
5565 */
5566void
5567xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5568 xmlXPathObjectPtr hay, needle;
5569 int n;
5570
5571 CHECK_ARITY(2);
5572 CAST_TO_STRING;
5573 CHECK_TYPE(XPATH_STRING);
5574 needle = valuePop(ctxt);
5575 CAST_TO_STRING;
5576 hay = valuePop(ctxt);
5577 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5578 xmlXPathFreeObject(hay);
5579 xmlXPathFreeObject(needle);
5580 XP_ERROR(XPATH_INVALID_TYPE);
5581 }
5582 n = xmlStrlen(needle->stringval);
5583 if (xmlStrncmp(hay->stringval, needle->stringval, n))
5584 valuePush(ctxt, xmlXPathNewBoolean(0));
5585 else
5586 valuePush(ctxt, xmlXPathNewBoolean(1));
5587 xmlXPathFreeObject(hay);
5588 xmlXPathFreeObject(needle);
5589}
5590
5591/**
5592 * xmlXPathSubstringFunction:
5593 * @ctxt: the XPath Parser context
5594 * @nargs: the number of arguments
5595 *
5596 * Implement the substring() XPath function
5597 * string substring(string, number, number?)
5598 * The substring function returns the substring of the first argument
5599 * starting at the position specified in the second argument with
5600 * length specified in the third argument. For example,
5601 * substring("12345",2,3) returns "234". If the third argument is not
5602 * specified, it returns the substring starting at the position specified
5603 * in the second argument and continuing to the end of the string. For
5604 * example, substring("12345",2) returns "2345". More precisely, each
5605 * character in the string (see [3.6 Strings]) is considered to have a
5606 * numeric position: the position of the first character is 1, the position
5607 * of the second character is 2 and so on. The returned substring contains
5608 * those characters for which the position of the character is greater than
5609 * or equal to the second argument and, if the third argument is specified,
5610 * less than the sum of the second and third arguments; the comparisons
5611 * and addition used for the above follow the standard IEEE 754 rules. Thus:
5612 * - substring("12345", 1.5, 2.6) returns "234"
5613 * - substring("12345", 0, 3) returns "12"
5614 * - substring("12345", 0 div 0, 3) returns ""
5615 * - substring("12345", 1, 0 div 0) returns ""
5616 * - substring("12345", -42, 1 div 0) returns "12345"
5617 * - substring("12345", -1 div 0, 1 div 0) returns ""
5618 */
5619void
5620xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5621 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005622 double le=0, in;
5623 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00005624 xmlChar *ret;
5625
Owen Taylor3473f882001-02-23 17:55:21 +00005626 if (nargs < 2) {
5627 CHECK_ARITY(2);
5628 }
5629 if (nargs > 3) {
5630 CHECK_ARITY(3);
5631 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005632 /*
5633 * take care of possible last (position) argument
5634 */
Owen Taylor3473f882001-02-23 17:55:21 +00005635 if (nargs == 3) {
5636 CAST_TO_NUMBER;
5637 CHECK_TYPE(XPATH_NUMBER);
5638 len = valuePop(ctxt);
5639 le = len->floatval;
5640 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00005641 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005642
Owen Taylor3473f882001-02-23 17:55:21 +00005643 CAST_TO_NUMBER;
5644 CHECK_TYPE(XPATH_NUMBER);
5645 start = valuePop(ctxt);
5646 in = start->floatval;
5647 xmlXPathFreeObject(start);
5648 CAST_TO_STRING;
5649 CHECK_TYPE(XPATH_STRING);
5650 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00005651 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005652
Daniel Veillard97ac1312001-05-30 19:14:17 +00005653 /*
5654 * If last pos not present, calculate last position
5655 */
5656 if (nargs != 3)
5657 le = m;
5658
5659 /*
5660 * To meet our requirements, initial index calculations
5661 * must be done before we convert to integer format
5662 *
5663 * First we normalize indices
5664 */
5665 in -= 1.0;
5666 le += in;
5667 if (in < 0.0)
5668 in = 0.0;
5669 if (le > (double)m)
5670 le = (double)m;
5671
5672 /*
5673 * Now we go to integer form, rounding up
5674 */
Owen Taylor3473f882001-02-23 17:55:21 +00005675 i = (int) in;
5676 if (((double)i) != in) i++;
5677
Owen Taylor3473f882001-02-23 17:55:21 +00005678 l = (int) le;
5679 if (((double)l) != le) l++;
5680
Daniel Veillard97ac1312001-05-30 19:14:17 +00005681 if (l > m) l=m;
Owen Taylor3473f882001-02-23 17:55:21 +00005682
5683 /* number of chars to copy */
5684 l -= i;
5685
Daniel Veillard97ac1312001-05-30 19:14:17 +00005686 ret = xmlUTF8Strsub(str->stringval, i, l);
Owen Taylor3473f882001-02-23 17:55:21 +00005687 if (ret == NULL)
5688 valuePush(ctxt, xmlXPathNewCString(""));
5689 else {
5690 valuePush(ctxt, xmlXPathNewString(ret));
5691 xmlFree(ret);
5692 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005693
Owen Taylor3473f882001-02-23 17:55:21 +00005694 xmlXPathFreeObject(str);
5695}
5696
5697/**
5698 * xmlXPathSubstringBeforeFunction:
5699 * @ctxt: the XPath Parser context
5700 * @nargs: the number of arguments
5701 *
5702 * Implement the substring-before() XPath function
5703 * string substring-before(string, string)
5704 * The substring-before function returns the substring of the first
5705 * argument string that precedes the first occurrence of the second
5706 * argument string in the first argument string, or the empty string
5707 * if the first argument string does not contain the second argument
5708 * string. For example, substring-before("1999/04/01","/") returns 1999.
5709 */
5710void
5711xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5712 xmlXPathObjectPtr str;
5713 xmlXPathObjectPtr find;
5714 xmlBufferPtr target;
5715 const xmlChar *point;
5716 int offset;
5717
5718 CHECK_ARITY(2);
5719 CAST_TO_STRING;
5720 find = valuePop(ctxt);
5721 CAST_TO_STRING;
5722 str = valuePop(ctxt);
5723
5724 target = xmlBufferCreate();
5725 if (target) {
5726 point = xmlStrstr(str->stringval, find->stringval);
5727 if (point) {
5728 offset = (int)(point - str->stringval);
5729 xmlBufferAdd(target, str->stringval, offset);
5730 }
5731 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5732 xmlBufferFree(target);
5733 }
5734
5735 xmlXPathFreeObject(str);
5736 xmlXPathFreeObject(find);
5737}
5738
5739/**
5740 * xmlXPathSubstringAfterFunction:
5741 * @ctxt: the XPath Parser context
5742 * @nargs: the number of arguments
5743 *
5744 * Implement the substring-after() XPath function
5745 * string substring-after(string, string)
5746 * The substring-after function returns the substring of the first
5747 * argument string that follows the first occurrence of the second
5748 * argument string in the first argument string, or the empty stringi
5749 * if the first argument string does not contain the second argument
5750 * string. For example, substring-after("1999/04/01","/") returns 04/01,
5751 * and substring-after("1999/04/01","19") returns 99/04/01.
5752 */
5753void
5754xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5755 xmlXPathObjectPtr str;
5756 xmlXPathObjectPtr find;
5757 xmlBufferPtr target;
5758 const xmlChar *point;
5759 int offset;
5760
5761 CHECK_ARITY(2);
5762 CAST_TO_STRING;
5763 find = valuePop(ctxt);
5764 CAST_TO_STRING;
5765 str = valuePop(ctxt);
5766
5767 target = xmlBufferCreate();
5768 if (target) {
5769 point = xmlStrstr(str->stringval, find->stringval);
5770 if (point) {
5771 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
5772 xmlBufferAdd(target, &str->stringval[offset],
5773 xmlStrlen(str->stringval) - offset);
5774 }
5775 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5776 xmlBufferFree(target);
5777 }
5778
5779 xmlXPathFreeObject(str);
5780 xmlXPathFreeObject(find);
5781}
5782
5783/**
5784 * xmlXPathNormalizeFunction:
5785 * @ctxt: the XPath Parser context
5786 * @nargs: the number of arguments
5787 *
5788 * Implement the normalize-space() XPath function
5789 * string normalize-space(string?)
5790 * The normalize-space function returns the argument string with white
5791 * space normalized by stripping leading and trailing whitespace
5792 * and replacing sequences of whitespace characters by a single
5793 * space. Whitespace characters are the same allowed by the S production
5794 * in XML. If the argument is omitted, it defaults to the context
5795 * node converted to a string, in other words the value of the context node.
5796 */
5797void
5798xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5799 xmlXPathObjectPtr obj = NULL;
5800 xmlChar *source = NULL;
5801 xmlBufferPtr target;
5802 xmlChar blank;
5803
5804 if (nargs == 0) {
5805 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005806 valuePush(ctxt,
5807 xmlXPathWrapString(
5808 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00005809 nargs = 1;
5810 }
5811
5812 CHECK_ARITY(1);
5813 CAST_TO_STRING;
5814 CHECK_TYPE(XPATH_STRING);
5815 obj = valuePop(ctxt);
5816 source = obj->stringval;
5817
5818 target = xmlBufferCreate();
5819 if (target && source) {
5820
5821 /* Skip leading whitespaces */
5822 while (IS_BLANK(*source))
5823 source++;
5824
5825 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
5826 blank = 0;
5827 while (*source) {
5828 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005829 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00005830 } else {
5831 if (blank) {
5832 xmlBufferAdd(target, &blank, 1);
5833 blank = 0;
5834 }
5835 xmlBufferAdd(target, source, 1);
5836 }
5837 source++;
5838 }
5839
5840 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5841 xmlBufferFree(target);
5842 }
5843 xmlXPathFreeObject(obj);
5844}
5845
5846/**
5847 * xmlXPathTranslateFunction:
5848 * @ctxt: the XPath Parser context
5849 * @nargs: the number of arguments
5850 *
5851 * Implement the translate() XPath function
5852 * string translate(string, string, string)
5853 * The translate function returns the first argument string with
5854 * occurrences of characters in the second argument string replaced
5855 * by the character at the corresponding position in the third argument
5856 * string. For example, translate("bar","abc","ABC") returns the string
5857 * BAr. If there is a character in the second argument string with no
5858 * character at a corresponding position in the third argument string
5859 * (because the second argument string is longer than the third argument
5860 * string), then occurrences of that character in the first argument
5861 * string are removed. For example, translate("--aaa--","abc-","ABC")
5862 * returns "AAA". If a character occurs more than once in second
5863 * argument string, then the first occurrence determines the replacement
5864 * character. If the third argument string is longer than the second
5865 * argument string, then excess characters are ignored.
5866 */
5867void
5868xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00005869 xmlXPathObjectPtr str;
5870 xmlXPathObjectPtr from;
5871 xmlXPathObjectPtr to;
5872 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005873 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00005874 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005875 xmlChar *point;
5876 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00005877
Daniel Veillarde043ee12001-04-16 14:08:07 +00005878 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00005879
Daniel Veillarde043ee12001-04-16 14:08:07 +00005880 CAST_TO_STRING;
5881 to = valuePop(ctxt);
5882 CAST_TO_STRING;
5883 from = valuePop(ctxt);
5884 CAST_TO_STRING;
5885 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005886
Daniel Veillarde043ee12001-04-16 14:08:07 +00005887 target = xmlBufferCreate();
5888 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005889 max = xmlUTF8Strlen(to->stringval);
5890 for (cptr = str->stringval; (ch=*cptr); ) {
5891 offset = xmlUTF8Strloc(from->stringval, cptr);
5892 if (offset >= 0) {
5893 if (offset < max) {
5894 point = xmlUTF8Strpos(to->stringval, offset);
5895 if (point)
5896 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
5897 }
5898 } else
5899 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
5900
5901 /* Step to next character in input */
5902 cptr++;
5903 if ( ch & 0x80 ) {
5904 /* if not simple ascii, verify proper format */
5905 if ( (ch & 0xc0) != 0xc0 ) {
5906 xmlGenericError(xmlGenericErrorContext,
5907 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5908 break;
5909 }
5910 /* then skip over remaining bytes for this char */
5911 while ( (ch <<= 1) & 0x80 )
5912 if ( (*cptr++ & 0xc0) != 0x80 ) {
5913 xmlGenericError(xmlGenericErrorContext,
5914 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5915 break;
5916 }
5917 if (ch & 0x80) /* must have had error encountered */
5918 break;
5919 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005920 }
Owen Taylor3473f882001-02-23 17:55:21 +00005921 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005922 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5923 xmlBufferFree(target);
5924 xmlXPathFreeObject(str);
5925 xmlXPathFreeObject(from);
5926 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00005927}
5928
5929/**
5930 * xmlXPathBooleanFunction:
5931 * @ctxt: the XPath Parser context
5932 * @nargs: the number of arguments
5933 *
5934 * Implement the boolean() XPath function
5935 * boolean boolean(object)
5936 * he boolean function converts its argument to a boolean as follows:
5937 * - a number is true if and only if it is neither positive or
5938 * negative zero nor NaN
5939 * - a node-set is true if and only if it is non-empty
5940 * - a string is true if and only if its length is non-zero
5941 */
5942void
5943xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5944 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00005945
5946 CHECK_ARITY(1);
5947 cur = valuePop(ctxt);
5948 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005949 cur = xmlXPathConvertBoolean(cur);
5950 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005951}
5952
5953/**
5954 * xmlXPathNotFunction:
5955 * @ctxt: the XPath Parser context
5956 * @nargs: the number of arguments
5957 *
5958 * Implement the not() XPath function
5959 * boolean not(boolean)
5960 * The not function returns true if its argument is false,
5961 * and false otherwise.
5962 */
5963void
5964xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5965 CHECK_ARITY(1);
5966 CAST_TO_BOOLEAN;
5967 CHECK_TYPE(XPATH_BOOLEAN);
5968 ctxt->value->boolval = ! ctxt->value->boolval;
5969}
5970
5971/**
5972 * xmlXPathTrueFunction:
5973 * @ctxt: the XPath Parser context
5974 * @nargs: the number of arguments
5975 *
5976 * Implement the true() XPath function
5977 * boolean true()
5978 */
5979void
5980xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5981 CHECK_ARITY(0);
5982 valuePush(ctxt, xmlXPathNewBoolean(1));
5983}
5984
5985/**
5986 * xmlXPathFalseFunction:
5987 * @ctxt: the XPath Parser context
5988 * @nargs: the number of arguments
5989 *
5990 * Implement the false() XPath function
5991 * boolean false()
5992 */
5993void
5994xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5995 CHECK_ARITY(0);
5996 valuePush(ctxt, xmlXPathNewBoolean(0));
5997}
5998
5999/**
6000 * xmlXPathLangFunction:
6001 * @ctxt: the XPath Parser context
6002 * @nargs: the number of arguments
6003 *
6004 * Implement the lang() XPath function
6005 * boolean lang(string)
6006 * The lang function returns true or false depending on whether the
6007 * language of the context node as specified by xml:lang attributes
6008 * is the same as or is a sublanguage of the language specified by
6009 * the argument string. The language of the context node is determined
6010 * by the value of the xml:lang attribute on the context node, or, if
6011 * the context node has no xml:lang attribute, by the value of the
6012 * xml:lang attribute on the nearest ancestor of the context node that
6013 * has an xml:lang attribute. If there is no such attribute, then lang
6014 * returns false. If there is such an attribute, then lang returns
6015 * true if the attribute value is equal to the argument ignoring case,
6016 * or if there is some suffix starting with - such that the attribute
6017 * value is equal to the argument ignoring that suffix of the attribute
6018 * value and ignoring case.
6019 */
6020void
6021xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6022 xmlXPathObjectPtr val;
6023 const xmlChar *theLang;
6024 const xmlChar *lang;
6025 int ret = 0;
6026 int i;
6027
6028 CHECK_ARITY(1);
6029 CAST_TO_STRING;
6030 CHECK_TYPE(XPATH_STRING);
6031 val = valuePop(ctxt);
6032 lang = val->stringval;
6033 theLang = xmlNodeGetLang(ctxt->context->node);
6034 if ((theLang != NULL) && (lang != NULL)) {
6035 for (i = 0;lang[i] != 0;i++)
6036 if (toupper(lang[i]) != toupper(theLang[i]))
6037 goto not_equal;
6038 ret = 1;
6039 }
6040not_equal:
6041 xmlXPathFreeObject(val);
6042 valuePush(ctxt, xmlXPathNewBoolean(ret));
6043}
6044
6045/**
6046 * xmlXPathNumberFunction:
6047 * @ctxt: the XPath Parser context
6048 * @nargs: the number of arguments
6049 *
6050 * Implement the number() XPath function
6051 * number number(object?)
6052 */
6053void
6054xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6055 xmlXPathObjectPtr cur;
6056 double res;
6057
6058 if (nargs == 0) {
6059 if (ctxt->context->node == NULL) {
6060 valuePush(ctxt, xmlXPathNewFloat(0.0));
6061 } else {
6062 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6063
6064 res = xmlXPathStringEvalNumber(content);
6065 valuePush(ctxt, xmlXPathNewFloat(res));
6066 xmlFree(content);
6067 }
6068 return;
6069 }
6070
6071 CHECK_ARITY(1);
6072 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006073 cur = xmlXPathConvertNumber(cur);
6074 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006075}
6076
6077/**
6078 * xmlXPathSumFunction:
6079 * @ctxt: the XPath Parser context
6080 * @nargs: the number of arguments
6081 *
6082 * Implement the sum() XPath function
6083 * number sum(node-set)
6084 * The sum function returns the sum of the values of the nodes in
6085 * the argument node-set.
6086 */
6087void
6088xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6089 xmlXPathObjectPtr cur;
6090 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006091 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006092
6093 CHECK_ARITY(1);
6094 if ((ctxt->value == NULL) ||
6095 ((ctxt->value->type != XPATH_NODESET) &&
6096 (ctxt->value->type != XPATH_XSLT_TREE)))
6097 XP_ERROR(XPATH_INVALID_TYPE);
6098 cur = valuePop(ctxt);
6099
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006100 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006101 valuePush(ctxt, xmlXPathNewFloat(0.0));
6102 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006103 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6104 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006105 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006106 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006107 }
6108 xmlXPathFreeObject(cur);
6109}
6110
6111/**
6112 * xmlXPathFloorFunction:
6113 * @ctxt: the XPath Parser context
6114 * @nargs: the number of arguments
6115 *
6116 * Implement the floor() XPath function
6117 * number floor(number)
6118 * The floor function returns the largest (closest to positive infinity)
6119 * number that is not greater than the argument and that is an integer.
6120 */
6121void
6122xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6123 CHECK_ARITY(1);
6124 CAST_TO_NUMBER;
6125 CHECK_TYPE(XPATH_NUMBER);
6126#if 0
6127 ctxt->value->floatval = floor(ctxt->value->floatval);
6128#else
6129 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
6130 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
6131#endif
6132}
6133
6134/**
6135 * xmlXPathCeilingFunction:
6136 * @ctxt: the XPath Parser context
6137 * @nargs: the number of arguments
6138 *
6139 * Implement the ceiling() XPath function
6140 * number ceiling(number)
6141 * The ceiling function returns the smallest (closest to negative infinity)
6142 * number that is not less than the argument and that is an integer.
6143 */
6144void
6145xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6146 double f;
6147
6148 CHECK_ARITY(1);
6149 CAST_TO_NUMBER;
6150 CHECK_TYPE(XPATH_NUMBER);
6151
6152#if 0
6153 ctxt->value->floatval = ceil(ctxt->value->floatval);
6154#else
6155 f = (double)((int) ctxt->value->floatval);
6156 if (f != ctxt->value->floatval)
6157 ctxt->value->floatval = f + 1;
6158#endif
6159}
6160
6161/**
6162 * xmlXPathRoundFunction:
6163 * @ctxt: the XPath Parser context
6164 * @nargs: the number of arguments
6165 *
6166 * Implement the round() XPath function
6167 * number round(number)
6168 * The round function returns the number that is closest to the
6169 * argument and that is an integer. If there are two such numbers,
6170 * then the one that is even is returned.
6171 */
6172void
6173xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6174 double f;
6175
6176 CHECK_ARITY(1);
6177 CAST_TO_NUMBER;
6178 CHECK_TYPE(XPATH_NUMBER);
6179
Bjorn Reese45029602001-08-21 09:23:53 +00006180 if ((trio_isnan(ctxt->value->floatval)) ||
6181 (trio_isinf(ctxt->value->floatval) == 1) ||
6182 (trio_isinf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00006183 (ctxt->value->floatval == 0.0))
6184 return;
6185
6186#if 0
6187 f = floor(ctxt->value->floatval);
6188#else
6189 f = (double)((int) ctxt->value->floatval);
6190#endif
6191 if (ctxt->value->floatval < f + 0.5)
6192 ctxt->value->floatval = f;
6193 else
6194 ctxt->value->floatval = f + 1;
6195}
6196
6197/************************************************************************
6198 * *
6199 * The Parser *
6200 * *
6201 ************************************************************************/
6202
6203/*
6204 * a couple of forward declarations since we use a recursive call based
6205 * implementation.
6206 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006207static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006208static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006209static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006210#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006211static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
6212#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006213#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006214static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006215#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00006216static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
6217 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00006218
6219/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00006220 * xmlXPathCurrentChar:
6221 * @ctxt: the XPath parser context
6222 * @cur: pointer to the beginning of the char
6223 * @len: pointer to the length of the char read
6224 *
6225 * The current char value, if using UTF-8 this may actaully span multiple
6226 * bytes in the input buffer.
6227 *
6228 * Returns the current char value and its lenght
6229 */
6230
6231static int
6232xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
6233 unsigned char c;
6234 unsigned int val;
6235 const xmlChar *cur;
6236
6237 if (ctxt == NULL)
6238 return(0);
6239 cur = ctxt->cur;
6240
6241 /*
6242 * We are supposed to handle UTF8, check it's valid
6243 * From rfc2044: encoding of the Unicode values on UTF-8:
6244 *
6245 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
6246 * 0000 0000-0000 007F 0xxxxxxx
6247 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
6248 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
6249 *
6250 * Check for the 0x110000 limit too
6251 */
6252 c = *cur;
6253 if (c & 0x80) {
6254 if ((cur[1] & 0xc0) != 0x80)
6255 goto encoding_error;
6256 if ((c & 0xe0) == 0xe0) {
6257
6258 if ((cur[2] & 0xc0) != 0x80)
6259 goto encoding_error;
6260 if ((c & 0xf0) == 0xf0) {
6261 if (((c & 0xf8) != 0xf0) ||
6262 ((cur[3] & 0xc0) != 0x80))
6263 goto encoding_error;
6264 /* 4-byte code */
6265 *len = 4;
6266 val = (cur[0] & 0x7) << 18;
6267 val |= (cur[1] & 0x3f) << 12;
6268 val |= (cur[2] & 0x3f) << 6;
6269 val |= cur[3] & 0x3f;
6270 } else {
6271 /* 3-byte code */
6272 *len = 3;
6273 val = (cur[0] & 0xf) << 12;
6274 val |= (cur[1] & 0x3f) << 6;
6275 val |= cur[2] & 0x3f;
6276 }
6277 } else {
6278 /* 2-byte code */
6279 *len = 2;
6280 val = (cur[0] & 0x1f) << 6;
6281 val |= cur[1] & 0x3f;
6282 }
6283 if (!IS_CHAR(val)) {
6284 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
6285 }
6286 return(val);
6287 } else {
6288 /* 1-byte code */
6289 *len = 1;
6290 return((int) *cur);
6291 }
6292encoding_error:
6293 /*
6294 * If we detect an UTF8 error that probably mean that the
6295 * input encoding didn't get properly advertized in the
6296 * declaration header. Report the error and switch the encoding
6297 * to ISO-Latin-1 (if you don't like this policy, just declare the
6298 * encoding !)
6299 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00006300 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00006301 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006302}
6303
6304/**
Owen Taylor3473f882001-02-23 17:55:21 +00006305 * xmlXPathParseNCName:
6306 * @ctxt: the XPath Parser context
6307 *
6308 * parse an XML namespace non qualified name.
6309 *
6310 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
6311 *
6312 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
6313 * CombiningChar | Extender
6314 *
6315 * Returns the namespace name or NULL
6316 */
6317
6318xmlChar *
6319xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00006320 const xmlChar *in;
6321 xmlChar *ret;
6322 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006323
Daniel Veillard2156a562001-04-28 12:24:34 +00006324 /*
6325 * Accelerator for simple ASCII names
6326 */
6327 in = ctxt->cur;
6328 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6329 ((*in >= 0x41) && (*in <= 0x5A)) ||
6330 (*in == '_')) {
6331 in++;
6332 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6333 ((*in >= 0x41) && (*in <= 0x5A)) ||
6334 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00006335 (*in == '_') || (*in == '.') ||
6336 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00006337 in++;
6338 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
6339 (*in == '[') || (*in == ']') || (*in == ':') ||
6340 (*in == '@') || (*in == '*')) {
6341 count = in - ctxt->cur;
6342 if (count == 0)
6343 return(NULL);
6344 ret = xmlStrndup(ctxt->cur, count);
6345 ctxt->cur = in;
6346 return(ret);
6347 }
6348 }
6349 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00006350}
6351
Daniel Veillard2156a562001-04-28 12:24:34 +00006352
Owen Taylor3473f882001-02-23 17:55:21 +00006353/**
6354 * xmlXPathParseQName:
6355 * @ctxt: the XPath Parser context
6356 * @prefix: a xmlChar **
6357 *
6358 * parse an XML qualified name
6359 *
6360 * [NS 5] QName ::= (Prefix ':')? LocalPart
6361 *
6362 * [NS 6] Prefix ::= NCName
6363 *
6364 * [NS 7] LocalPart ::= NCName
6365 *
6366 * Returns the function returns the local part, and prefix is updated
6367 * to get the Prefix if any.
6368 */
6369
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006370static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006371xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
6372 xmlChar *ret = NULL;
6373
6374 *prefix = NULL;
6375 ret = xmlXPathParseNCName(ctxt);
6376 if (CUR == ':') {
6377 *prefix = ret;
6378 NEXT;
6379 ret = xmlXPathParseNCName(ctxt);
6380 }
6381 return(ret);
6382}
6383
6384/**
6385 * xmlXPathParseName:
6386 * @ctxt: the XPath Parser context
6387 *
6388 * parse an XML name
6389 *
6390 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6391 * CombiningChar | Extender
6392 *
6393 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6394 *
6395 * Returns the namespace name or NULL
6396 */
6397
6398xmlChar *
6399xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006400 const xmlChar *in;
6401 xmlChar *ret;
6402 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006403
Daniel Veillard61d80a22001-04-27 17:13:01 +00006404 /*
6405 * Accelerator for simple ASCII names
6406 */
6407 in = ctxt->cur;
6408 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6409 ((*in >= 0x41) && (*in <= 0x5A)) ||
6410 (*in == '_') || (*in == ':')) {
6411 in++;
6412 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6413 ((*in >= 0x41) && (*in <= 0x5A)) ||
6414 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00006415 (*in == '_') || (*in == '-') ||
6416 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00006417 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00006418 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006419 count = in - ctxt->cur;
6420 ret = xmlStrndup(ctxt->cur, count);
6421 ctxt->cur = in;
6422 return(ret);
6423 }
6424 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006425 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00006426}
6427
Daniel Veillard61d80a22001-04-27 17:13:01 +00006428static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00006429xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006430 xmlChar buf[XML_MAX_NAMELEN + 5];
6431 int len = 0, l;
6432 int c;
6433
6434 /*
6435 * Handler for more complex cases
6436 */
6437 c = CUR_CHAR(l);
6438 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00006439 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
6440 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00006441 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00006442 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006443 return(NULL);
6444 }
6445
6446 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
6447 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
6448 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006449 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006450 (IS_COMBINING(c)) ||
6451 (IS_EXTENDER(c)))) {
6452 COPY_BUF(l,buf,len,c);
6453 NEXTL(l);
6454 c = CUR_CHAR(l);
6455 if (len >= XML_MAX_NAMELEN) {
6456 /*
6457 * Okay someone managed to make a huge name, so he's ready to pay
6458 * for the processing speed.
6459 */
6460 xmlChar *buffer;
6461 int max = len * 2;
6462
6463 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
6464 if (buffer == NULL) {
6465 XP_ERROR0(XPATH_MEMORY_ERROR);
6466 }
6467 memcpy(buffer, buf, len);
6468 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
6469 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006470 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006471 (IS_COMBINING(c)) ||
6472 (IS_EXTENDER(c))) {
6473 if (len + 10 > max) {
6474 max *= 2;
6475 buffer = (xmlChar *) xmlRealloc(buffer,
6476 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00006477 if (buffer == NULL) {
6478 XP_ERROR0(XPATH_MEMORY_ERROR);
6479 }
6480 }
6481 COPY_BUF(l,buffer,len,c);
6482 NEXTL(l);
6483 c = CUR_CHAR(l);
6484 }
6485 buffer[len] = 0;
6486 return(buffer);
6487 }
6488 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006489 if (len == 0)
6490 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006491 return(xmlStrndup(buf, len));
6492}
Owen Taylor3473f882001-02-23 17:55:21 +00006493/**
6494 * xmlXPathStringEvalNumber:
6495 * @str: A string to scan
6496 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00006497 * [30a] Float ::= Number ('e' Digits?)?
6498 *
Owen Taylor3473f882001-02-23 17:55:21 +00006499 * [30] Number ::= Digits ('.' Digits?)?
6500 * | '.' Digits
6501 * [31] Digits ::= [0-9]+
6502 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006503 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00006504 * In complement of the Number expression, this function also handles
6505 * negative values : '-' Number.
6506 *
6507 * Returns the double value.
6508 */
6509double
6510xmlXPathStringEvalNumber(const xmlChar *str) {
6511 const xmlChar *cur = str;
6512 double ret = 0.0;
6513 double mult = 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006514 int ok = 0, tmp = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006515 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006516 int exponent = 0;
6517 int is_exponent_negative = 0;
6518
Owen Taylor3473f882001-02-23 17:55:21 +00006519 while (IS_BLANK(*cur)) cur++;
6520 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
6521 return(xmlXPathNAN);
6522 }
6523 if (*cur == '-') {
6524 isneg = 1;
6525 cur++;
6526 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006527 /*
6528 * tmp is a workaroudn against a gcc compiler bug
6529 */
Owen Taylor3473f882001-02-23 17:55:21 +00006530 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006531 tmp = tmp * 10 + (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00006532 ok = 1;
6533 cur++;
6534 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006535 ret = (double) tmp;
6536
Owen Taylor3473f882001-02-23 17:55:21 +00006537 if (*cur == '.') {
6538 cur++;
6539 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
6540 return(xmlXPathNAN);
6541 }
6542 while ((*cur >= '0') && (*cur <= '9')) {
6543 mult /= 10;
6544 ret = ret + (*cur - '0') * mult;
6545 cur++;
6546 }
6547 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006548 if ((*cur == 'e') || (*cur == 'E')) {
6549 cur++;
6550 if (*cur == '-') {
6551 is_exponent_negative = 1;
6552 cur++;
6553 }
6554 while ((*cur >= '0') && (*cur <= '9')) {
6555 exponent = exponent * 10 + (*cur - '0');
6556 cur++;
6557 }
6558 }
Owen Taylor3473f882001-02-23 17:55:21 +00006559 while (IS_BLANK(*cur)) cur++;
6560 if (*cur != 0) return(xmlXPathNAN);
6561 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006562 if (is_exponent_negative) exponent = -exponent;
6563 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00006564 return(ret);
6565}
6566
6567/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006568 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00006569 * @ctxt: the XPath Parser context
6570 *
6571 * [30] Number ::= Digits ('.' Digits?)?
6572 * | '.' Digits
6573 * [31] Digits ::= [0-9]+
6574 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006575 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00006576 *
6577 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006578static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006579xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
6580{
Owen Taylor3473f882001-02-23 17:55:21 +00006581 double ret = 0.0;
6582 double mult = 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006583 int ok = 0, tmp = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006584 int exponent = 0;
6585 int is_exponent_negative = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006586
6587 CHECK_ERROR;
6588 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
6589 XP_ERROR(XPATH_NUMBER_ERROR);
6590 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006591 /*
6592 * Try to work around a gcc optimizer bug
6593 */
Owen Taylor3473f882001-02-23 17:55:21 +00006594 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006595 tmp = tmp * 10 + (CUR - '0');
6596 ok = 1;
6597 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +00006598 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006599 ret = (double) tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00006600 if (CUR == '.') {
6601 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006602 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
6603 XP_ERROR(XPATH_NUMBER_ERROR);
6604 }
6605 while ((CUR >= '0') && (CUR <= '9')) {
6606 mult /= 10;
6607 ret = ret + (CUR - '0') * mult;
6608 NEXT;
6609 }
Owen Taylor3473f882001-02-23 17:55:21 +00006610 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006611 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006612 NEXT;
6613 if (CUR == '-') {
6614 is_exponent_negative = 1;
6615 NEXT;
6616 }
6617 while ((CUR >= '0') && (CUR <= '9')) {
6618 exponent = exponent * 10 + (CUR - '0');
6619 NEXT;
6620 }
6621 if (is_exponent_negative)
6622 exponent = -exponent;
6623 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006624 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006625 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006626 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006627}
6628
6629/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006630 * xmlXPathParseLiteral:
6631 * @ctxt: the XPath Parser context
6632 *
6633 * Parse a Literal
6634 *
6635 * [29] Literal ::= '"' [^"]* '"'
6636 * | "'" [^']* "'"
6637 *
6638 * Returns the value found or NULL in case of error
6639 */
6640static xmlChar *
6641xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
6642 const xmlChar *q;
6643 xmlChar *ret = NULL;
6644
6645 if (CUR == '"') {
6646 NEXT;
6647 q = CUR_PTR;
6648 while ((IS_CHAR(CUR)) && (CUR != '"'))
6649 NEXT;
6650 if (!IS_CHAR(CUR)) {
6651 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6652 } else {
6653 ret = xmlStrndup(q, CUR_PTR - q);
6654 NEXT;
6655 }
6656 } else if (CUR == '\'') {
6657 NEXT;
6658 q = CUR_PTR;
6659 while ((IS_CHAR(CUR)) && (CUR != '\''))
6660 NEXT;
6661 if (!IS_CHAR(CUR)) {
6662 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6663 } else {
6664 ret = xmlStrndup(q, CUR_PTR - q);
6665 NEXT;
6666 }
6667 } else {
6668 XP_ERROR0(XPATH_START_LITERAL_ERROR);
6669 }
6670 return(ret);
6671}
6672
6673/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006674 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00006675 * @ctxt: the XPath Parser context
6676 *
6677 * Parse a Literal and push it on the stack.
6678 *
6679 * [29] Literal ::= '"' [^"]* '"'
6680 * | "'" [^']* "'"
6681 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006682 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00006683 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006684static void
6685xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006686 const xmlChar *q;
6687 xmlChar *ret = NULL;
6688
6689 if (CUR == '"') {
6690 NEXT;
6691 q = CUR_PTR;
6692 while ((IS_CHAR(CUR)) && (CUR != '"'))
6693 NEXT;
6694 if (!IS_CHAR(CUR)) {
6695 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
6696 } else {
6697 ret = xmlStrndup(q, CUR_PTR - q);
6698 NEXT;
6699 }
6700 } else if (CUR == '\'') {
6701 NEXT;
6702 q = CUR_PTR;
6703 while ((IS_CHAR(CUR)) && (CUR != '\''))
6704 NEXT;
6705 if (!IS_CHAR(CUR)) {
6706 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
6707 } else {
6708 ret = xmlStrndup(q, CUR_PTR - q);
6709 NEXT;
6710 }
6711 } else {
6712 XP_ERROR(XPATH_START_LITERAL_ERROR);
6713 }
6714 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006715 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
6716 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006717 xmlFree(ret);
6718}
6719
6720/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006721 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00006722 * @ctxt: the XPath Parser context
6723 *
6724 * Parse a VariableReference, evaluate it and push it on the stack.
6725 *
6726 * The variable bindings consist of a mapping from variable names
6727 * to variable values. The value of a variable is an object, which
6728 * of any of the types that are possible for the value of an expression,
6729 * and may also be of additional types not specified here.
6730 *
6731 * Early evaluation is possible since:
6732 * The variable bindings [...] used to evaluate a subexpression are
6733 * always the same as those used to evaluate the containing expression.
6734 *
6735 * [36] VariableReference ::= '$' QName
6736 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006737static void
6738xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006739 xmlChar *name;
6740 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006741
6742 SKIP_BLANKS;
6743 if (CUR != '$') {
6744 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
6745 }
6746 NEXT;
6747 name = xmlXPathParseQName(ctxt, &prefix);
6748 if (name == NULL) {
6749 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
6750 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006751 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006752 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
6753 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006754 SKIP_BLANKS;
6755}
6756
6757/**
6758 * xmlXPathIsNodeType:
6759 * @ctxt: the XPath Parser context
6760 * @name: a name string
6761 *
6762 * Is the name given a NodeType one.
6763 *
6764 * [38] NodeType ::= 'comment'
6765 * | 'text'
6766 * | 'processing-instruction'
6767 * | 'node'
6768 *
6769 * Returns 1 if true 0 otherwise
6770 */
6771int
6772xmlXPathIsNodeType(const xmlChar *name) {
6773 if (name == NULL)
6774 return(0);
6775
6776 if (xmlStrEqual(name, BAD_CAST "comment"))
6777 return(1);
6778 if (xmlStrEqual(name, BAD_CAST "text"))
6779 return(1);
6780 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
6781 return(1);
6782 if (xmlStrEqual(name, BAD_CAST "node"))
6783 return(1);
6784 return(0);
6785}
6786
6787/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006788 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00006789 * @ctxt: the XPath Parser context
6790 *
6791 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
6792 * [17] Argument ::= Expr
6793 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006794 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00006795 * pushed on the stack
6796 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006797static void
6798xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006799 xmlChar *name;
6800 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006801 int nbargs = 0;
6802
6803 name = xmlXPathParseQName(ctxt, &prefix);
6804 if (name == NULL) {
6805 XP_ERROR(XPATH_EXPR_ERROR);
6806 }
6807 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006808#ifdef DEBUG_EXPR
6809 if (prefix == NULL)
6810 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
6811 name);
6812 else
6813 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
6814 prefix, name);
6815#endif
6816
Owen Taylor3473f882001-02-23 17:55:21 +00006817 if (CUR != '(') {
6818 XP_ERROR(XPATH_EXPR_ERROR);
6819 }
6820 NEXT;
6821 SKIP_BLANKS;
6822
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006823 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006824 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006825 int op1 = ctxt->comp->last;
6826 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006827 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006828 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006829 nbargs++;
6830 if (CUR == ')') break;
6831 if (CUR != ',') {
6832 XP_ERROR(XPATH_EXPR_ERROR);
6833 }
6834 NEXT;
6835 SKIP_BLANKS;
6836 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006837 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
6838 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006839 NEXT;
6840 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006841}
6842
6843/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006844 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006845 * @ctxt: the XPath Parser context
6846 *
6847 * [15] PrimaryExpr ::= VariableReference
6848 * | '(' Expr ')'
6849 * | Literal
6850 * | Number
6851 * | FunctionCall
6852 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006853 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006854 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006855static void
6856xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006857 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006858 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006859 else if (CUR == '(') {
6860 NEXT;
6861 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006862 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006863 if (CUR != ')') {
6864 XP_ERROR(XPATH_EXPR_ERROR);
6865 }
6866 NEXT;
6867 SKIP_BLANKS;
6868 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006869 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006870 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006871 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006872 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006873 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006874 }
6875 SKIP_BLANKS;
6876}
6877
6878/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006879 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006880 * @ctxt: the XPath Parser context
6881 *
6882 * [20] FilterExpr ::= PrimaryExpr
6883 * | FilterExpr Predicate
6884 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006885 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006886 * Square brackets are used to filter expressions in the same way that
6887 * they are used in location paths. It is an error if the expression to
6888 * be filtered does not evaluate to a node-set. The context node list
6889 * used for evaluating the expression in square brackets is the node-set
6890 * to be filtered listed in document order.
6891 */
6892
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006893static void
6894xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
6895 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006896 CHECK_ERROR;
6897 SKIP_BLANKS;
6898
6899 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006900 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00006901 SKIP_BLANKS;
6902 }
6903
6904
6905}
6906
6907/**
6908 * xmlXPathScanName:
6909 * @ctxt: the XPath Parser context
6910 *
6911 * Trickery: parse an XML name but without consuming the input flow
6912 * Needed to avoid insanity in the parser state.
6913 *
6914 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6915 * CombiningChar | Extender
6916 *
6917 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6918 *
6919 * [6] Names ::= Name (S Name)*
6920 *
6921 * Returns the Name parsed or NULL
6922 */
6923
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006924static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006925xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
6926 xmlChar buf[XML_MAX_NAMELEN];
6927 int len = 0;
6928
6929 SKIP_BLANKS;
6930 if (!IS_LETTER(CUR) && (CUR != '_') &&
6931 (CUR != ':')) {
6932 return(NULL);
6933 }
6934
6935 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
6936 (NXT(len) == '.') || (NXT(len) == '-') ||
6937 (NXT(len) == '_') || (NXT(len) == ':') ||
6938 (IS_COMBINING(NXT(len))) ||
6939 (IS_EXTENDER(NXT(len)))) {
6940 buf[len] = NXT(len);
6941 len++;
6942 if (len >= XML_MAX_NAMELEN) {
6943 xmlGenericError(xmlGenericErrorContext,
6944 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
6945 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
6946 (NXT(len) == '.') || (NXT(len) == '-') ||
6947 (NXT(len) == '_') || (NXT(len) == ':') ||
6948 (IS_COMBINING(NXT(len))) ||
6949 (IS_EXTENDER(NXT(len))))
6950 len++;
6951 break;
6952 }
6953 }
6954 return(xmlStrndup(buf, len));
6955}
6956
6957/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006958 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006959 * @ctxt: the XPath Parser context
6960 *
6961 * [19] PathExpr ::= LocationPath
6962 * | FilterExpr
6963 * | FilterExpr '/' RelativeLocationPath
6964 * | FilterExpr '//' RelativeLocationPath
6965 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006966 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006967 * The / operator and // operators combine an arbitrary expression
6968 * and a relative location path. It is an error if the expression
6969 * does not evaluate to a node-set.
6970 * The / operator does composition in the same way as when / is
6971 * used in a location path. As in location paths, // is short for
6972 * /descendant-or-self::node()/.
6973 */
6974
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006975static void
6976xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006977 int lc = 1; /* Should we branch to LocationPath ? */
6978 xmlChar *name = NULL; /* we may have to preparse a name to find out */
6979
6980 SKIP_BLANKS;
6981 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
6982 (CUR == '\'') || (CUR == '"')) {
6983 lc = 0;
6984 } else if (CUR == '*') {
6985 /* relative or absolute location path */
6986 lc = 1;
6987 } else if (CUR == '/') {
6988 /* relative or absolute location path */
6989 lc = 1;
6990 } else if (CUR == '@') {
6991 /* relative abbreviated attribute location path */
6992 lc = 1;
6993 } else if (CUR == '.') {
6994 /* relative abbreviated attribute location path */
6995 lc = 1;
6996 } else {
6997 /*
6998 * Problem is finding if we have a name here whether it's:
6999 * - a nodetype
7000 * - a function call in which case it's followed by '('
7001 * - an axis in which case it's followed by ':'
7002 * - a element name
7003 * We do an a priori analysis here rather than having to
7004 * maintain parsed token content through the recursive function
7005 * calls. This looks uglier but makes the code quite easier to
7006 * read/write/debug.
7007 */
7008 SKIP_BLANKS;
7009 name = xmlXPathScanName(ctxt);
7010 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7011#ifdef DEBUG_STEP
7012 xmlGenericError(xmlGenericErrorContext,
7013 "PathExpr: Axis\n");
7014#endif
7015 lc = 1;
7016 xmlFree(name);
7017 } else if (name != NULL) {
7018 int len =xmlStrlen(name);
7019 int blank = 0;
7020
7021
7022 while (NXT(len) != 0) {
7023 if (NXT(len) == '/') {
7024 /* element name */
7025#ifdef DEBUG_STEP
7026 xmlGenericError(xmlGenericErrorContext,
7027 "PathExpr: AbbrRelLocation\n");
7028#endif
7029 lc = 1;
7030 break;
7031 } else if (IS_BLANK(NXT(len))) {
7032 /* skip to next */
7033 blank = 1;
7034 } else if (NXT(len) == ':') {
7035#ifdef DEBUG_STEP
7036 xmlGenericError(xmlGenericErrorContext,
7037 "PathExpr: AbbrRelLocation\n");
7038#endif
7039 lc = 1;
7040 break;
7041 } else if ((NXT(len) == '(')) {
7042 /* Note Type or Function */
7043 if (xmlXPathIsNodeType(name)) {
7044#ifdef DEBUG_STEP
7045 xmlGenericError(xmlGenericErrorContext,
7046 "PathExpr: Type search\n");
7047#endif
7048 lc = 1;
7049 } else {
7050#ifdef DEBUG_STEP
7051 xmlGenericError(xmlGenericErrorContext,
7052 "PathExpr: function call\n");
7053#endif
7054 lc = 0;
7055 }
7056 break;
7057 } else if ((NXT(len) == '[')) {
7058 /* element name */
7059#ifdef DEBUG_STEP
7060 xmlGenericError(xmlGenericErrorContext,
7061 "PathExpr: AbbrRelLocation\n");
7062#endif
7063 lc = 1;
7064 break;
7065 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7066 (NXT(len) == '=')) {
7067 lc = 1;
7068 break;
7069 } else {
7070 lc = 1;
7071 break;
7072 }
7073 len++;
7074 }
7075 if (NXT(len) == 0) {
7076#ifdef DEBUG_STEP
7077 xmlGenericError(xmlGenericErrorContext,
7078 "PathExpr: AbbrRelLocation\n");
7079#endif
7080 /* element name */
7081 lc = 1;
7082 }
7083 xmlFree(name);
7084 } else {
7085 /* make sure all cases are covered explicitely */
7086 XP_ERROR(XPATH_EXPR_ERROR);
7087 }
7088 }
7089
7090 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007091 if (CUR == '/') {
7092 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7093 } else {
7094 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007095 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007096 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007097 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007098 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007099 CHECK_ERROR;
7100 if ((CUR == '/') && (NXT(1) == '/')) {
7101 SKIP(2);
7102 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007103
7104 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7105 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7106 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7107
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007108 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007109 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007110 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007111 }
7112 }
7113 SKIP_BLANKS;
7114}
7115
7116/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007117 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007118 * @ctxt: the XPath Parser context
7119 *
7120 * [18] UnionExpr ::= PathExpr
7121 * | UnionExpr '|' PathExpr
7122 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007123 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007124 */
7125
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007126static void
7127xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7128 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007129 CHECK_ERROR;
7130 SKIP_BLANKS;
7131 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007132 int op1 = ctxt->comp->last;
7133 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007134
7135 NEXT;
7136 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007137 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007138
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007139 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
7140
Owen Taylor3473f882001-02-23 17:55:21 +00007141 SKIP_BLANKS;
7142 }
Owen Taylor3473f882001-02-23 17:55:21 +00007143}
7144
7145/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007146 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007147 * @ctxt: the XPath Parser context
7148 *
7149 * [27] UnaryExpr ::= UnionExpr
7150 * | '-' UnaryExpr
7151 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007152 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007153 */
7154
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007155static void
7156xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007157 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007158 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007159
7160 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00007161 while (CUR == '-') {
7162 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007163 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007164 NEXT;
7165 SKIP_BLANKS;
7166 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007167
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007168 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007169 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007170 if (found) {
7171 if (minus)
7172 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
7173 else
7174 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007175 }
7176}
7177
7178/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007179 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007180 * @ctxt: the XPath Parser context
7181 *
7182 * [26] MultiplicativeExpr ::= UnaryExpr
7183 * | MultiplicativeExpr MultiplyOperator UnaryExpr
7184 * | MultiplicativeExpr 'div' UnaryExpr
7185 * | MultiplicativeExpr 'mod' UnaryExpr
7186 * [34] MultiplyOperator ::= '*'
7187 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007188 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007189 */
7190
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007191static void
7192xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
7193 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007194 CHECK_ERROR;
7195 SKIP_BLANKS;
7196 while ((CUR == '*') ||
7197 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
7198 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
7199 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007200 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007201
7202 if (CUR == '*') {
7203 op = 0;
7204 NEXT;
7205 } else if (CUR == 'd') {
7206 op = 1;
7207 SKIP(3);
7208 } else if (CUR == 'm') {
7209 op = 2;
7210 SKIP(3);
7211 }
7212 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007213 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007214 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007215 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007216 SKIP_BLANKS;
7217 }
7218}
7219
7220/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007221 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007222 * @ctxt: the XPath Parser context
7223 *
7224 * [25] AdditiveExpr ::= MultiplicativeExpr
7225 * | AdditiveExpr '+' MultiplicativeExpr
7226 * | AdditiveExpr '-' MultiplicativeExpr
7227 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007228 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007229 */
7230
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007231static void
7232xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007233
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007234 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007235 CHECK_ERROR;
7236 SKIP_BLANKS;
7237 while ((CUR == '+') || (CUR == '-')) {
7238 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007239 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007240
7241 if (CUR == '+') plus = 1;
7242 else plus = 0;
7243 NEXT;
7244 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007245 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007246 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007247 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007248 SKIP_BLANKS;
7249 }
7250}
7251
7252/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007253 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007254 * @ctxt: the XPath Parser context
7255 *
7256 * [24] RelationalExpr ::= AdditiveExpr
7257 * | RelationalExpr '<' AdditiveExpr
7258 * | RelationalExpr '>' AdditiveExpr
7259 * | RelationalExpr '<=' AdditiveExpr
7260 * | RelationalExpr '>=' AdditiveExpr
7261 *
7262 * A <= B > C is allowed ? Answer from James, yes with
7263 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
7264 * which is basically what got implemented.
7265 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007266 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00007267 * on the stack
7268 */
7269
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007270static void
7271xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
7272 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007273 CHECK_ERROR;
7274 SKIP_BLANKS;
7275 while ((CUR == '<') ||
7276 (CUR == '>') ||
7277 ((CUR == '<') && (NXT(1) == '=')) ||
7278 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007279 int inf, strict;
7280 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007281
7282 if (CUR == '<') inf = 1;
7283 else inf = 0;
7284 if (NXT(1) == '=') strict = 0;
7285 else strict = 1;
7286 NEXT;
7287 if (!strict) NEXT;
7288 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007289 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007290 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007291 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00007292 SKIP_BLANKS;
7293 }
7294}
7295
7296/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007297 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007298 * @ctxt: the XPath Parser context
7299 *
7300 * [23] EqualityExpr ::= RelationalExpr
7301 * | EqualityExpr '=' RelationalExpr
7302 * | EqualityExpr '!=' RelationalExpr
7303 *
7304 * A != B != C is allowed ? Answer from James, yes with
7305 * (RelationalExpr = RelationalExpr) = RelationalExpr
7306 * (RelationalExpr != RelationalExpr) != RelationalExpr
7307 * which is basically what got implemented.
7308 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007309 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007310 *
7311 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007312static void
7313xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
7314 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007315 CHECK_ERROR;
7316 SKIP_BLANKS;
7317 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007318 int eq;
7319 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007320
7321 if (CUR == '=') eq = 1;
7322 else eq = 0;
7323 NEXT;
7324 if (!eq) NEXT;
7325 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007326 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007327 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007328 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007329 SKIP_BLANKS;
7330 }
7331}
7332
7333/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007334 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007335 * @ctxt: the XPath Parser context
7336 *
7337 * [22] AndExpr ::= EqualityExpr
7338 * | AndExpr 'and' EqualityExpr
7339 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007340 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007341 *
7342 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007343static void
7344xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
7345 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007346 CHECK_ERROR;
7347 SKIP_BLANKS;
7348 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007349 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007350 SKIP(3);
7351 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007352 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007353 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007354 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007355 SKIP_BLANKS;
7356 }
7357}
7358
7359/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007360 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007361 * @ctxt: the XPath Parser context
7362 *
7363 * [14] Expr ::= OrExpr
7364 * [21] OrExpr ::= AndExpr
7365 * | OrExpr 'or' AndExpr
7366 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007367 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00007368 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007369static void
7370xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
7371 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007372 CHECK_ERROR;
7373 SKIP_BLANKS;
7374 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007375 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007376 SKIP(2);
7377 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007378 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007379 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007380 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
7381 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00007382 SKIP_BLANKS;
7383 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007384 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
7385 /* more ops could be optimized too */
7386 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
7387 }
Owen Taylor3473f882001-02-23 17:55:21 +00007388}
7389
7390/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007391 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00007392 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007393 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00007394 *
7395 * [8] Predicate ::= '[' PredicateExpr ']'
7396 * [9] PredicateExpr ::= Expr
7397 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007398 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00007399 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007400static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007401xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007402 int op1 = ctxt->comp->last;
7403
7404 SKIP_BLANKS;
7405 if (CUR != '[') {
7406 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7407 }
7408 NEXT;
7409 SKIP_BLANKS;
7410
7411 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007412 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007413 CHECK_ERROR;
7414
7415 if (CUR != ']') {
7416 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7417 }
7418
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007419 if (filter)
7420 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
7421 else
7422 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007423
7424 NEXT;
7425 SKIP_BLANKS;
7426}
7427
7428/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007429 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00007430 * @ctxt: the XPath Parser context
7431 * @test: pointer to a xmlXPathTestVal
7432 * @type: pointer to a xmlXPathTypeVal
7433 * @prefix: placeholder for a possible name prefix
7434 *
7435 * [7] NodeTest ::= NameTest
7436 * | NodeType '(' ')'
7437 * | 'processing-instruction' '(' Literal ')'
7438 *
7439 * [37] NameTest ::= '*'
7440 * | NCName ':' '*'
7441 * | QName
7442 * [38] NodeType ::= 'comment'
7443 * | 'text'
7444 * | 'processing-instruction'
7445 * | 'node'
7446 *
7447 * Returns the name found and update @test, @type and @prefix appropriately
7448 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007449static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007450xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
7451 xmlXPathTypeVal *type, const xmlChar **prefix,
7452 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00007453 int blanks;
7454
7455 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
7456 STRANGE;
7457 return(NULL);
7458 }
7459 *type = 0;
7460 *test = 0;
7461 *prefix = NULL;
7462 SKIP_BLANKS;
7463
7464 if ((name == NULL) && (CUR == '*')) {
7465 /*
7466 * All elements
7467 */
7468 NEXT;
7469 *test = NODE_TEST_ALL;
7470 return(NULL);
7471 }
7472
7473 if (name == NULL)
7474 name = xmlXPathParseNCName(ctxt);
7475 if (name == NULL) {
7476 XP_ERROR0(XPATH_EXPR_ERROR);
7477 }
7478
7479 blanks = IS_BLANK(CUR);
7480 SKIP_BLANKS;
7481 if (CUR == '(') {
7482 NEXT;
7483 /*
7484 * NodeType or PI search
7485 */
7486 if (xmlStrEqual(name, BAD_CAST "comment"))
7487 *type = NODE_TYPE_COMMENT;
7488 else if (xmlStrEqual(name, BAD_CAST "node"))
7489 *type = NODE_TYPE_NODE;
7490 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
7491 *type = NODE_TYPE_PI;
7492 else if (xmlStrEqual(name, BAD_CAST "text"))
7493 *type = NODE_TYPE_TEXT;
7494 else {
7495 if (name != NULL)
7496 xmlFree(name);
7497 XP_ERROR0(XPATH_EXPR_ERROR);
7498 }
7499
7500 *test = NODE_TEST_TYPE;
7501
7502 SKIP_BLANKS;
7503 if (*type == NODE_TYPE_PI) {
7504 /*
7505 * Specific case: search a PI by name.
7506 */
Owen Taylor3473f882001-02-23 17:55:21 +00007507 if (name != NULL)
7508 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00007509 name = NULL;
7510 if (CUR != ')') {
7511 name = xmlXPathParseLiteral(ctxt);
7512 CHECK_ERROR 0;
7513 SKIP_BLANKS;
7514 }
Owen Taylor3473f882001-02-23 17:55:21 +00007515 }
7516 if (CUR != ')') {
7517 if (name != NULL)
7518 xmlFree(name);
7519 XP_ERROR0(XPATH_UNCLOSED_ERROR);
7520 }
7521 NEXT;
7522 return(name);
7523 }
7524 *test = NODE_TEST_NAME;
7525 if ((!blanks) && (CUR == ':')) {
7526 NEXT;
7527
7528 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007529 * Since currently the parser context don't have a
7530 * namespace list associated:
7531 * The namespace name for this prefix can be computed
7532 * only at evaluation time. The compilation is done
7533 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00007534 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007535#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00007536 *prefix = xmlXPathNsLookup(ctxt->context, name);
7537 if (name != NULL)
7538 xmlFree(name);
7539 if (*prefix == NULL) {
7540 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
7541 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007542#else
7543 *prefix = name;
7544#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007545
7546 if (CUR == '*') {
7547 /*
7548 * All elements
7549 */
7550 NEXT;
7551 *test = NODE_TEST_ALL;
7552 return(NULL);
7553 }
7554
7555 name = xmlXPathParseNCName(ctxt);
7556 if (name == NULL) {
7557 XP_ERROR0(XPATH_EXPR_ERROR);
7558 }
7559 }
7560 return(name);
7561}
7562
7563/**
7564 * xmlXPathIsAxisName:
7565 * @name: a preparsed name token
7566 *
7567 * [6] AxisName ::= 'ancestor'
7568 * | 'ancestor-or-self'
7569 * | 'attribute'
7570 * | 'child'
7571 * | 'descendant'
7572 * | 'descendant-or-self'
7573 * | 'following'
7574 * | 'following-sibling'
7575 * | 'namespace'
7576 * | 'parent'
7577 * | 'preceding'
7578 * | 'preceding-sibling'
7579 * | 'self'
7580 *
7581 * Returns the axis or 0
7582 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007583static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00007584xmlXPathIsAxisName(const xmlChar *name) {
7585 xmlXPathAxisVal ret = 0;
7586 switch (name[0]) {
7587 case 'a':
7588 if (xmlStrEqual(name, BAD_CAST "ancestor"))
7589 ret = AXIS_ANCESTOR;
7590 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
7591 ret = AXIS_ANCESTOR_OR_SELF;
7592 if (xmlStrEqual(name, BAD_CAST "attribute"))
7593 ret = AXIS_ATTRIBUTE;
7594 break;
7595 case 'c':
7596 if (xmlStrEqual(name, BAD_CAST "child"))
7597 ret = AXIS_CHILD;
7598 break;
7599 case 'd':
7600 if (xmlStrEqual(name, BAD_CAST "descendant"))
7601 ret = AXIS_DESCENDANT;
7602 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
7603 ret = AXIS_DESCENDANT_OR_SELF;
7604 break;
7605 case 'f':
7606 if (xmlStrEqual(name, BAD_CAST "following"))
7607 ret = AXIS_FOLLOWING;
7608 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
7609 ret = AXIS_FOLLOWING_SIBLING;
7610 break;
7611 case 'n':
7612 if (xmlStrEqual(name, BAD_CAST "namespace"))
7613 ret = AXIS_NAMESPACE;
7614 break;
7615 case 'p':
7616 if (xmlStrEqual(name, BAD_CAST "parent"))
7617 ret = AXIS_PARENT;
7618 if (xmlStrEqual(name, BAD_CAST "preceding"))
7619 ret = AXIS_PRECEDING;
7620 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
7621 ret = AXIS_PRECEDING_SIBLING;
7622 break;
7623 case 's':
7624 if (xmlStrEqual(name, BAD_CAST "self"))
7625 ret = AXIS_SELF;
7626 break;
7627 }
7628 return(ret);
7629}
7630
7631/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007632 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00007633 * @ctxt: the XPath Parser context
7634 *
7635 * [4] Step ::= AxisSpecifier NodeTest Predicate*
7636 * | AbbreviatedStep
7637 *
7638 * [12] AbbreviatedStep ::= '.' | '..'
7639 *
7640 * [5] AxisSpecifier ::= AxisName '::'
7641 * | AbbreviatedAxisSpecifier
7642 *
7643 * [13] AbbreviatedAxisSpecifier ::= '@'?
7644 *
7645 * Modified for XPtr range support as:
7646 *
7647 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
7648 * | AbbreviatedStep
7649 * | 'range-to' '(' Expr ')' Predicate*
7650 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007651 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00007652 * A location step of . is short for self::node(). This is
7653 * particularly useful in conjunction with //. For example, the
7654 * location path .//para is short for
7655 * self::node()/descendant-or-self::node()/child::para
7656 * and so will select all para descendant elements of the context
7657 * node.
7658 * Similarly, a location step of .. is short for parent::node().
7659 * For example, ../title is short for parent::node()/child::title
7660 * and so will select the title children of the parent of the context
7661 * node.
7662 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007663static void
7664xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007665#ifdef LIBXML_XPTR_ENABLED
7666 int rangeto = 0;
7667 int op2 = -1;
7668#endif
7669
Owen Taylor3473f882001-02-23 17:55:21 +00007670 SKIP_BLANKS;
7671 if ((CUR == '.') && (NXT(1) == '.')) {
7672 SKIP(2);
7673 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007674 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
7675 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007676 } else if (CUR == '.') {
7677 NEXT;
7678 SKIP_BLANKS;
7679 } else {
7680 xmlChar *name = NULL;
7681 const xmlChar *prefix = NULL;
7682 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007683 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007684 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007685 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00007686
7687 /*
7688 * The modification needed for XPointer change to the production
7689 */
7690#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007691 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00007692 name = xmlXPathParseNCName(ctxt);
7693 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007694 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007695 xmlFree(name);
7696 SKIP_BLANKS;
7697 if (CUR != '(') {
7698 XP_ERROR(XPATH_EXPR_ERROR);
7699 }
7700 NEXT;
7701 SKIP_BLANKS;
7702
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007703 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007704 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00007705 CHECK_ERROR;
7706
7707 SKIP_BLANKS;
7708 if (CUR != ')') {
7709 XP_ERROR(XPATH_EXPR_ERROR);
7710 }
7711 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007712 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007713 goto eval_predicates;
7714 }
7715 }
7716#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00007717 if (CUR == '*') {
7718 axis = AXIS_CHILD;
7719 } else {
7720 if (name == NULL)
7721 name = xmlXPathParseNCName(ctxt);
7722 if (name != NULL) {
7723 axis = xmlXPathIsAxisName(name);
7724 if (axis != 0) {
7725 SKIP_BLANKS;
7726 if ((CUR == ':') && (NXT(1) == ':')) {
7727 SKIP(2);
7728 xmlFree(name);
7729 name = NULL;
7730 } else {
7731 /* an element name can conflict with an axis one :-\ */
7732 axis = AXIS_CHILD;
7733 }
Owen Taylor3473f882001-02-23 17:55:21 +00007734 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00007735 axis = AXIS_CHILD;
7736 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007737 } else if (CUR == '@') {
7738 NEXT;
7739 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00007740 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00007741 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00007742 }
Owen Taylor3473f882001-02-23 17:55:21 +00007743 }
7744
7745 CHECK_ERROR;
7746
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007747 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00007748 if (test == 0)
7749 return;
7750
7751#ifdef DEBUG_STEP
7752 xmlGenericError(xmlGenericErrorContext,
7753 "Basis : computing new set\n");
7754#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007755
Owen Taylor3473f882001-02-23 17:55:21 +00007756#ifdef DEBUG_STEP
7757 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007758 if (ctxt->value == NULL)
7759 xmlGenericError(xmlGenericErrorContext, "no value\n");
7760 else if (ctxt->value->nodesetval == NULL)
7761 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7762 else
7763 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007764#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007765
7766eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007767 op1 = ctxt->comp->last;
7768 ctxt->comp->last = -1;
7769
Owen Taylor3473f882001-02-23 17:55:21 +00007770 SKIP_BLANKS;
7771 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007772 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007773 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007774
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007775#ifdef LIBXML_XPTR_ENABLED
7776 if (rangeto) {
7777 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
7778 } else
7779#endif
7780 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
7781 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007782
Owen Taylor3473f882001-02-23 17:55:21 +00007783 }
7784#ifdef DEBUG_STEP
7785 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007786 if (ctxt->value == NULL)
7787 xmlGenericError(xmlGenericErrorContext, "no value\n");
7788 else if (ctxt->value->nodesetval == NULL)
7789 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7790 else
7791 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
7792 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007793#endif
7794}
7795
7796/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007797 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007798 * @ctxt: the XPath Parser context
7799 *
7800 * [3] RelativeLocationPath ::= Step
7801 * | RelativeLocationPath '/' Step
7802 * | AbbreviatedRelativeLocationPath
7803 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
7804 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007805 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00007806 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007807static void
Owen Taylor3473f882001-02-23 17:55:21 +00007808#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007809xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007810#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007811xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007812#endif
7813(xmlXPathParserContextPtr ctxt) {
7814 SKIP_BLANKS;
7815 if ((CUR == '/') && (NXT(1) == '/')) {
7816 SKIP(2);
7817 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007818 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7819 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007820 } else if (CUR == '/') {
7821 NEXT;
7822 SKIP_BLANKS;
7823 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007824 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007825 SKIP_BLANKS;
7826 while (CUR == '/') {
7827 if ((CUR == '/') && (NXT(1) == '/')) {
7828 SKIP(2);
7829 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007830 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00007831 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007832 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007833 } else if (CUR == '/') {
7834 NEXT;
7835 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007836 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007837 }
7838 SKIP_BLANKS;
7839 }
7840}
7841
7842/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007843 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007844 * @ctxt: the XPath Parser context
7845 *
7846 * [1] LocationPath ::= RelativeLocationPath
7847 * | AbsoluteLocationPath
7848 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
7849 * | AbbreviatedAbsoluteLocationPath
7850 * [10] AbbreviatedAbsoluteLocationPath ::=
7851 * '//' RelativeLocationPath
7852 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007853 * Compile a location path
7854 *
Owen Taylor3473f882001-02-23 17:55:21 +00007855 * // is short for /descendant-or-self::node()/. For example,
7856 * //para is short for /descendant-or-self::node()/child::para and
7857 * so will select any para element in the document (even a para element
7858 * that is a document element will be selected by //para since the
7859 * document element node is a child of the root node); div//para is
7860 * short for div/descendant-or-self::node()/child::para and so will
7861 * select all para descendants of div children.
7862 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007863static void
7864xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007865 SKIP_BLANKS;
7866 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007867 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007868 } else {
7869 while (CUR == '/') {
7870 if ((CUR == '/') && (NXT(1) == '/')) {
7871 SKIP(2);
7872 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007873 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7874 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007875 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007876 } else if (CUR == '/') {
7877 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00007878 SKIP_BLANKS;
7879 if ((CUR != 0 ) &&
7880 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
7881 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007882 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007883 }
7884 }
7885 }
7886}
7887
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007888/************************************************************************
7889 * *
7890 * XPath precompiled expression evaluation *
7891 * *
7892 ************************************************************************/
7893
Daniel Veillardf06307e2001-07-03 10:35:50 +00007894static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007895xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
7896
7897/**
7898 * xmlXPathNodeCollectAndTest:
7899 * @ctxt: the XPath Parser context
7900 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00007901 * @first: pointer to the first element in document order
7902 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007903 *
7904 * This is the function implementing a step: based on the current list
7905 * of nodes, it builds up a new list, looking at all nodes under that
7906 * axis and selecting them it also do the predicate filtering
7907 *
7908 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00007909 *
7910 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007911 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00007912static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007913xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00007914 xmlXPathStepOpPtr op,
7915 xmlNodePtr * first, xmlNodePtr * last)
7916{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007917 xmlXPathAxisVal axis = op->value;
7918 xmlXPathTestVal test = op->value2;
7919 xmlXPathTypeVal type = op->value3;
7920 const xmlChar *prefix = op->value4;
7921 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00007922 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007923
7924#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007925 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007926#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007927 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007928 xmlNodeSetPtr ret, list;
7929 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00007930 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007931 xmlNodePtr cur = NULL;
7932 xmlXPathObjectPtr obj;
7933 xmlNodeSetPtr nodelist;
7934 xmlNodePtr tmp;
7935
Daniel Veillardf06307e2001-07-03 10:35:50 +00007936 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007937 obj = valuePop(ctxt);
7938 addNode = xmlXPathNodeSetAdd;
Daniel Veillarde043ee12001-04-16 14:08:07 +00007939 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00007940 URI = xmlXPathNsLookup(ctxt->context, prefix);
7941 if (URI == NULL)
7942 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00007943 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007944#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007945 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007946#endif
7947 switch (axis) {
7948 case AXIS_ANCESTOR:
7949#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007950 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007951#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007952 first = NULL;
7953 next = xmlXPathNextAncestor;
7954 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007955 case AXIS_ANCESTOR_OR_SELF:
7956#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007957 xmlGenericError(xmlGenericErrorContext,
7958 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007959#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007960 first = NULL;
7961 next = xmlXPathNextAncestorOrSelf;
7962 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007963 case AXIS_ATTRIBUTE:
7964#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007965 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007966#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007967 first = NULL;
7968 last = NULL;
7969 next = xmlXPathNextAttribute;
7970 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007971 case AXIS_CHILD:
7972#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007973 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007974#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007975 last = NULL;
7976 next = xmlXPathNextChild;
7977 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007978 case AXIS_DESCENDANT:
7979#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007980 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007981#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007982 last = NULL;
7983 next = xmlXPathNextDescendant;
7984 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007985 case AXIS_DESCENDANT_OR_SELF:
7986#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007987 xmlGenericError(xmlGenericErrorContext,
7988 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007989#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007990 last = NULL;
7991 next = xmlXPathNextDescendantOrSelf;
7992 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007993 case AXIS_FOLLOWING:
7994#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007995 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007996#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007997 last = NULL;
7998 next = xmlXPathNextFollowing;
7999 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008000 case AXIS_FOLLOWING_SIBLING:
8001#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008002 xmlGenericError(xmlGenericErrorContext,
8003 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008004#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008005 last = NULL;
8006 next = xmlXPathNextFollowingSibling;
8007 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008008 case AXIS_NAMESPACE:
8009#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008010 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008011#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008012 first = NULL;
8013 last = NULL;
8014 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8015 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008016 case AXIS_PARENT:
8017#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008018 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008019#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008020 first = NULL;
8021 next = xmlXPathNextParent;
8022 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008023 case AXIS_PRECEDING:
8024#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008025 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008026#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008027 first = NULL;
8028 next = xmlXPathNextPrecedingInternal;
8029 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008030 case AXIS_PRECEDING_SIBLING:
8031#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008032 xmlGenericError(xmlGenericErrorContext,
8033 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008034#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008035 first = NULL;
8036 next = xmlXPathNextPrecedingSibling;
8037 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008038 case AXIS_SELF:
8039#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008040 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008041#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008042 first = NULL;
8043 last = NULL;
8044 next = xmlXPathNextSelf;
8045 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008046 }
8047 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008048 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008049
8050 nodelist = obj->nodesetval;
8051 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008052 xmlXPathFreeObject(obj);
8053 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8054 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008055 }
8056 addNode = xmlXPathNodeSetAddUnique;
8057 ret = NULL;
8058#ifdef DEBUG_STEP
8059 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008060 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008061 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008062 case NODE_TEST_NONE:
8063 xmlGenericError(xmlGenericErrorContext,
8064 " searching for none !!!\n");
8065 break;
8066 case NODE_TEST_TYPE:
8067 xmlGenericError(xmlGenericErrorContext,
8068 " searching for type %d\n", type);
8069 break;
8070 case NODE_TEST_PI:
8071 xmlGenericError(xmlGenericErrorContext,
8072 " searching for PI !!!\n");
8073 break;
8074 case NODE_TEST_ALL:
8075 xmlGenericError(xmlGenericErrorContext,
8076 " searching for *\n");
8077 break;
8078 case NODE_TEST_NS:
8079 xmlGenericError(xmlGenericErrorContext,
8080 " searching for namespace %s\n",
8081 prefix);
8082 break;
8083 case NODE_TEST_NAME:
8084 xmlGenericError(xmlGenericErrorContext,
8085 " searching for name %s\n", name);
8086 if (prefix != NULL)
8087 xmlGenericError(xmlGenericErrorContext,
8088 " with namespace %s\n", prefix);
8089 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008090 }
8091 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8092#endif
8093 /*
8094 * 2.3 Node Tests
8095 * - For the attribute axis, the principal node type is attribute.
8096 * - For the namespace axis, the principal node type is namespace.
8097 * - For other axes, the principal node type is element.
8098 *
8099 * A node test * is true for any node of the
8100 * principal node type. For example, child::* willi
8101 * select all element children of the context node
8102 */
8103 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008104 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008105 ctxt->context->node = nodelist->nodeTab[i];
8106
Daniel Veillardf06307e2001-07-03 10:35:50 +00008107 cur = NULL;
8108 list = xmlXPathNodeSetCreate(NULL);
8109 do {
8110 cur = next(ctxt, cur);
8111 if (cur == NULL)
8112 break;
8113 if ((first != NULL) && (*first == cur))
8114 break;
8115 if (((t % 256) == 0) &&
8116 (first != NULL) && (*first != NULL) &&
8117 (xmlXPathCmpNodes(*first, cur) >= 0))
8118 break;
8119 if ((last != NULL) && (*last == cur))
8120 break;
8121 if (((t % 256) == 0) &&
8122 (last != NULL) && (*last != NULL) &&
8123 (xmlXPathCmpNodes(cur, *last) >= 0))
8124 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008125 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008126#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008127 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8128#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008129 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008130 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008131 ctxt->context->node = tmp;
8132 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008133 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008134 if ((cur->type == type) ||
8135 ((type == NODE_TYPE_NODE) &&
8136 ((cur->type == XML_DOCUMENT_NODE) ||
8137 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8138 (cur->type == XML_ELEMENT_NODE) ||
8139 (cur->type == XML_PI_NODE) ||
8140 (cur->type == XML_COMMENT_NODE) ||
8141 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00008142 (cur->type == XML_TEXT_NODE))) ||
8143 ((type == NODE_TYPE_TEXT) &&
8144 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008145#ifdef DEBUG_STEP
8146 n++;
8147#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008148 addNode(list, cur);
8149 }
8150 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008151 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008152 if (cur->type == XML_PI_NODE) {
8153 if ((name != NULL) &&
8154 (!xmlStrEqual(name, cur->name)))
8155 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008156#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008157 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008158#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008159 addNode(list, cur);
8160 }
8161 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008162 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008163 if (axis == AXIS_ATTRIBUTE) {
8164 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008165#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008166 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008167#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008168 addNode(list, cur);
8169 }
8170 } else if (axis == AXIS_NAMESPACE) {
8171 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008172#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008173 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008174#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008175 addNode(list, cur);
8176 }
8177 } else {
8178 if (cur->type == XML_ELEMENT_NODE) {
8179 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008180#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008181 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008182#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008183 addNode(list, cur);
8184 } else if ((cur->ns != NULL) &&
8185 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008186#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008187 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008188#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008189 addNode(list, cur);
8190 }
8191 }
8192 }
8193 break;
8194 case NODE_TEST_NS:{
8195 TODO;
8196 break;
8197 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008198 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008199 switch (cur->type) {
8200 case XML_ELEMENT_NODE:
8201 if (xmlStrEqual(name, cur->name)) {
8202 if (prefix == NULL) {
8203 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008204#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008205 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008206#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008207 addNode(list, cur);
8208 }
8209 } else {
8210 if ((cur->ns != NULL) &&
8211 (xmlStrEqual(URI,
8212 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008213#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008214 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008215#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008216 addNode(list, cur);
8217 }
8218 }
8219 }
8220 break;
8221 case XML_ATTRIBUTE_NODE:{
8222 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008223
Daniel Veillardf06307e2001-07-03 10:35:50 +00008224 if (xmlStrEqual(name, attr->name)) {
8225 if (prefix == NULL) {
8226 if ((attr->ns == NULL) ||
8227 (attr->ns->prefix == NULL)) {
8228#ifdef DEBUG_STEP
8229 n++;
8230#endif
8231 addNode(list,
8232 (xmlNodePtr) attr);
8233 }
8234 } else {
8235 if ((attr->ns != NULL) &&
8236 (xmlStrEqual(URI,
8237 attr->ns->
8238 href))) {
8239#ifdef DEBUG_STEP
8240 n++;
8241#endif
8242 addNode(list,
8243 (xmlNodePtr) attr);
8244 }
8245 }
8246 }
8247 break;
8248 }
8249 case XML_NAMESPACE_DECL:
8250 if (cur->type == XML_NAMESPACE_DECL) {
8251 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008252
Daniel Veillardf06307e2001-07-03 10:35:50 +00008253 if ((ns->prefix != NULL) && (name != NULL)
8254 && (xmlStrEqual(ns->prefix, name))) {
8255#ifdef DEBUG_STEP
8256 n++;
8257#endif
8258 addNode(list, cur);
8259 }
8260 }
8261 break;
8262 default:
8263 break;
8264 }
8265 break;
8266 break;
8267 }
8268 } while (cur != NULL);
8269
8270 /*
8271 * If there is some predicate filtering do it now
8272 */
8273 if (op->ch2 != -1) {
8274 xmlXPathObjectPtr obj2;
8275
8276 valuePush(ctxt, xmlXPathWrapNodeSet(list));
8277 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
8278 CHECK_TYPE0(XPATH_NODESET);
8279 obj2 = valuePop(ctxt);
8280 list = obj2->nodesetval;
8281 obj2->nodesetval = NULL;
8282 xmlXPathFreeObject(obj2);
8283 }
8284 if (ret == NULL) {
8285 ret = list;
8286 } else {
8287 ret = xmlXPathNodeSetMerge(ret, list);
8288 xmlXPathFreeNodeSet(list);
8289 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008290 }
8291 ctxt->context->node = tmp;
8292#ifdef DEBUG_STEP
8293 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008294 "\nExamined %d nodes, found %d nodes at that step\n",
8295 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008296#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008297 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00008298 if ((obj->boolval) && (obj->user != NULL)) {
8299 ctxt->value->boolval = 1;
8300 ctxt->value->user = obj->user;
8301 obj->user = NULL;
8302 obj->boolval = 0;
8303 }
8304 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008305 return(t);
8306}
8307
8308/**
8309 * xmlXPathNodeCollectAndTestNth:
8310 * @ctxt: the XPath Parser context
8311 * @op: the XPath precompiled step operation
8312 * @indx: the index to collect
8313 * @first: pointer to the first element in document order
8314 * @last: pointer to the last element in document order
8315 *
8316 * This is the function implementing a step: based on the current list
8317 * of nodes, it builds up a new list, looking at all nodes under that
8318 * axis and selecting them it also do the predicate filtering
8319 *
8320 * Pushes the new NodeSet resulting from the search.
8321 * Returns the number of node traversed
8322 */
8323static int
8324xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
8325 xmlXPathStepOpPtr op, int indx,
8326 xmlNodePtr * first, xmlNodePtr * last)
8327{
8328 xmlXPathAxisVal axis = op->value;
8329 xmlXPathTestVal test = op->value2;
8330 xmlXPathTypeVal type = op->value3;
8331 const xmlChar *prefix = op->value4;
8332 const xmlChar *name = op->value5;
8333 const xmlChar *URI = NULL;
8334 int n = 0, t = 0;
8335
8336 int i;
8337 xmlNodeSetPtr list;
8338 xmlXPathTraversalFunction next = NULL;
8339 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
8340 xmlNodePtr cur = NULL;
8341 xmlXPathObjectPtr obj;
8342 xmlNodeSetPtr nodelist;
8343 xmlNodePtr tmp;
8344
8345 CHECK_TYPE0(XPATH_NODESET);
8346 obj = valuePop(ctxt);
8347 addNode = xmlXPathNodeSetAdd;
8348 if (prefix != NULL) {
8349 URI = xmlXPathNsLookup(ctxt->context, prefix);
8350 if (URI == NULL)
8351 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8352 }
8353#ifdef DEBUG_STEP_NTH
8354 xmlGenericError(xmlGenericErrorContext, "new step : ");
8355 if (first != NULL) {
8356 if (*first != NULL)
8357 xmlGenericError(xmlGenericErrorContext, "first = %s ",
8358 (*first)->name);
8359 else
8360 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
8361 }
8362 if (last != NULL) {
8363 if (*last != NULL)
8364 xmlGenericError(xmlGenericErrorContext, "last = %s ",
8365 (*last)->name);
8366 else
8367 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
8368 }
8369#endif
8370 switch (axis) {
8371 case AXIS_ANCESTOR:
8372#ifdef DEBUG_STEP_NTH
8373 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
8374#endif
8375 first = NULL;
8376 next = xmlXPathNextAncestor;
8377 break;
8378 case AXIS_ANCESTOR_OR_SELF:
8379#ifdef DEBUG_STEP_NTH
8380 xmlGenericError(xmlGenericErrorContext,
8381 "axis 'ancestors-or-self' ");
8382#endif
8383 first = NULL;
8384 next = xmlXPathNextAncestorOrSelf;
8385 break;
8386 case AXIS_ATTRIBUTE:
8387#ifdef DEBUG_STEP_NTH
8388 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
8389#endif
8390 first = NULL;
8391 last = NULL;
8392 next = xmlXPathNextAttribute;
8393 break;
8394 case AXIS_CHILD:
8395#ifdef DEBUG_STEP_NTH
8396 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
8397#endif
8398 last = NULL;
8399 next = xmlXPathNextChild;
8400 break;
8401 case AXIS_DESCENDANT:
8402#ifdef DEBUG_STEP_NTH
8403 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
8404#endif
8405 last = NULL;
8406 next = xmlXPathNextDescendant;
8407 break;
8408 case AXIS_DESCENDANT_OR_SELF:
8409#ifdef DEBUG_STEP_NTH
8410 xmlGenericError(xmlGenericErrorContext,
8411 "axis 'descendant-or-self' ");
8412#endif
8413 last = NULL;
8414 next = xmlXPathNextDescendantOrSelf;
8415 break;
8416 case AXIS_FOLLOWING:
8417#ifdef DEBUG_STEP_NTH
8418 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
8419#endif
8420 last = NULL;
8421 next = xmlXPathNextFollowing;
8422 break;
8423 case AXIS_FOLLOWING_SIBLING:
8424#ifdef DEBUG_STEP_NTH
8425 xmlGenericError(xmlGenericErrorContext,
8426 "axis 'following-siblings' ");
8427#endif
8428 last = NULL;
8429 next = xmlXPathNextFollowingSibling;
8430 break;
8431 case AXIS_NAMESPACE:
8432#ifdef DEBUG_STEP_NTH
8433 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
8434#endif
8435 last = NULL;
8436 first = NULL;
8437 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8438 break;
8439 case AXIS_PARENT:
8440#ifdef DEBUG_STEP_NTH
8441 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
8442#endif
8443 first = NULL;
8444 next = xmlXPathNextParent;
8445 break;
8446 case AXIS_PRECEDING:
8447#ifdef DEBUG_STEP_NTH
8448 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
8449#endif
8450 first = NULL;
8451 next = xmlXPathNextPrecedingInternal;
8452 break;
8453 case AXIS_PRECEDING_SIBLING:
8454#ifdef DEBUG_STEP_NTH
8455 xmlGenericError(xmlGenericErrorContext,
8456 "axis 'preceding-sibling' ");
8457#endif
8458 first = NULL;
8459 next = xmlXPathNextPrecedingSibling;
8460 break;
8461 case AXIS_SELF:
8462#ifdef DEBUG_STEP_NTH
8463 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
8464#endif
8465 first = NULL;
8466 last = NULL;
8467 next = xmlXPathNextSelf;
8468 break;
8469 }
8470 if (next == NULL)
8471 return(0);
8472
8473 nodelist = obj->nodesetval;
8474 if (nodelist == NULL) {
8475 xmlXPathFreeObject(obj);
8476 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8477 return(0);
8478 }
8479 addNode = xmlXPathNodeSetAddUnique;
8480#ifdef DEBUG_STEP_NTH
8481 xmlGenericError(xmlGenericErrorContext,
8482 " context contains %d nodes\n", nodelist->nodeNr);
8483 switch (test) {
8484 case NODE_TEST_NONE:
8485 xmlGenericError(xmlGenericErrorContext,
8486 " searching for none !!!\n");
8487 break;
8488 case NODE_TEST_TYPE:
8489 xmlGenericError(xmlGenericErrorContext,
8490 " searching for type %d\n", type);
8491 break;
8492 case NODE_TEST_PI:
8493 xmlGenericError(xmlGenericErrorContext,
8494 " searching for PI !!!\n");
8495 break;
8496 case NODE_TEST_ALL:
8497 xmlGenericError(xmlGenericErrorContext,
8498 " searching for *\n");
8499 break;
8500 case NODE_TEST_NS:
8501 xmlGenericError(xmlGenericErrorContext,
8502 " searching for namespace %s\n",
8503 prefix);
8504 break;
8505 case NODE_TEST_NAME:
8506 xmlGenericError(xmlGenericErrorContext,
8507 " searching for name %s\n", name);
8508 if (prefix != NULL)
8509 xmlGenericError(xmlGenericErrorContext,
8510 " with namespace %s\n", prefix);
8511 break;
8512 }
8513 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8514#endif
8515 /*
8516 * 2.3 Node Tests
8517 * - For the attribute axis, the principal node type is attribute.
8518 * - For the namespace axis, the principal node type is namespace.
8519 * - For other axes, the principal node type is element.
8520 *
8521 * A node test * is true for any node of the
8522 * principal node type. For example, child::* willi
8523 * select all element children of the context node
8524 */
8525 tmp = ctxt->context->node;
8526 list = xmlXPathNodeSetCreate(NULL);
8527 for (i = 0; i < nodelist->nodeNr; i++) {
8528 ctxt->context->node = nodelist->nodeTab[i];
8529
8530 cur = NULL;
8531 n = 0;
8532 do {
8533 cur = next(ctxt, cur);
8534 if (cur == NULL)
8535 break;
8536 if ((first != NULL) && (*first == cur))
8537 break;
8538 if (((t % 256) == 0) &&
8539 (first != NULL) && (*first != NULL) &&
8540 (xmlXPathCmpNodes(*first, cur) >= 0))
8541 break;
8542 if ((last != NULL) && (*last == cur))
8543 break;
8544 if (((t % 256) == 0) &&
8545 (last != NULL) && (*last != NULL) &&
8546 (xmlXPathCmpNodes(cur, *last) >= 0))
8547 break;
8548 t++;
8549 switch (test) {
8550 case NODE_TEST_NONE:
8551 ctxt->context->node = tmp;
8552 STRANGE return(0);
8553 case NODE_TEST_TYPE:
8554 if ((cur->type == type) ||
8555 ((type == NODE_TYPE_NODE) &&
8556 ((cur->type == XML_DOCUMENT_NODE) ||
8557 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8558 (cur->type == XML_ELEMENT_NODE) ||
8559 (cur->type == XML_PI_NODE) ||
8560 (cur->type == XML_COMMENT_NODE) ||
8561 (cur->type == XML_CDATA_SECTION_NODE) ||
8562 (cur->type == XML_TEXT_NODE)))) {
8563 n++;
8564 if (n == indx)
8565 addNode(list, cur);
8566 }
8567 break;
8568 case NODE_TEST_PI:
8569 if (cur->type == XML_PI_NODE) {
8570 if ((name != NULL) &&
8571 (!xmlStrEqual(name, cur->name)))
8572 break;
8573 n++;
8574 if (n == indx)
8575 addNode(list, cur);
8576 }
8577 break;
8578 case NODE_TEST_ALL:
8579 if (axis == AXIS_ATTRIBUTE) {
8580 if (cur->type == XML_ATTRIBUTE_NODE) {
8581 n++;
8582 if (n == indx)
8583 addNode(list, cur);
8584 }
8585 } else if (axis == AXIS_NAMESPACE) {
8586 if (cur->type == XML_NAMESPACE_DECL) {
8587 n++;
8588 if (n == indx)
8589 addNode(list, cur);
8590 }
8591 } else {
8592 if (cur->type == XML_ELEMENT_NODE) {
8593 if (prefix == NULL) {
8594 n++;
8595 if (n == indx)
8596 addNode(list, cur);
8597 } else if ((cur->ns != NULL) &&
8598 (xmlStrEqual(URI, cur->ns->href))) {
8599 n++;
8600 if (n == indx)
8601 addNode(list, cur);
8602 }
8603 }
8604 }
8605 break;
8606 case NODE_TEST_NS:{
8607 TODO;
8608 break;
8609 }
8610 case NODE_TEST_NAME:
8611 switch (cur->type) {
8612 case XML_ELEMENT_NODE:
8613 if (xmlStrEqual(name, cur->name)) {
8614 if (prefix == NULL) {
8615 if (cur->ns == NULL) {
8616 n++;
8617 if (n == indx)
8618 addNode(list, cur);
8619 }
8620 } else {
8621 if ((cur->ns != NULL) &&
8622 (xmlStrEqual(URI,
8623 cur->ns->href))) {
8624 n++;
8625 if (n == indx)
8626 addNode(list, cur);
8627 }
8628 }
8629 }
8630 break;
8631 case XML_ATTRIBUTE_NODE:{
8632 xmlAttrPtr attr = (xmlAttrPtr) cur;
8633
8634 if (xmlStrEqual(name, attr->name)) {
8635 if (prefix == NULL) {
8636 if ((attr->ns == NULL) ||
8637 (attr->ns->prefix == NULL)) {
8638 n++;
8639 if (n == indx)
8640 addNode(list, cur);
8641 }
8642 } else {
8643 if ((attr->ns != NULL) &&
8644 (xmlStrEqual(URI,
8645 attr->ns->
8646 href))) {
8647 n++;
8648 if (n == indx)
8649 addNode(list, cur);
8650 }
8651 }
8652 }
8653 break;
8654 }
8655 case XML_NAMESPACE_DECL:
8656 if (cur->type == XML_NAMESPACE_DECL) {
8657 xmlNsPtr ns = (xmlNsPtr) cur;
8658
8659 if ((ns->prefix != NULL) && (name != NULL)
8660 && (xmlStrEqual(ns->prefix, name))) {
8661 n++;
8662 if (n == indx)
8663 addNode(list, cur);
8664 }
8665 }
8666 break;
8667 default:
8668 break;
8669 }
8670 break;
8671 break;
8672 }
8673 } while (n < indx);
8674 }
8675 ctxt->context->node = tmp;
8676#ifdef DEBUG_STEP_NTH
8677 xmlGenericError(xmlGenericErrorContext,
8678 "\nExamined %d nodes, found %d nodes at that step\n",
8679 t, list->nodeNr);
8680#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008681 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00008682 if ((obj->boolval) && (obj->user != NULL)) {
8683 ctxt->value->boolval = 1;
8684 ctxt->value->user = obj->user;
8685 obj->user = NULL;
8686 obj->boolval = 0;
8687 }
8688 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008689 return(t);
8690}
8691
8692/**
8693 * xmlXPathCompOpEvalFirst:
8694 * @ctxt: the XPath parser context with the compiled expression
8695 * @op: an XPath compiled operation
8696 * @first: the first elem found so far
8697 *
8698 * Evaluate the Precompiled XPath operation searching only the first
8699 * element in document order
8700 *
8701 * Returns the number of examined objects.
8702 */
8703static int
8704xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
8705 xmlXPathStepOpPtr op, xmlNodePtr * first)
8706{
8707 int total = 0, cur;
8708 xmlXPathCompExprPtr comp;
8709 xmlXPathObjectPtr arg1, arg2;
8710
8711 comp = ctxt->comp;
8712 switch (op->op) {
8713 case XPATH_OP_END:
8714 return (0);
8715 case XPATH_OP_UNION:
8716 total =
8717 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
8718 first);
8719 if ((ctxt->value != NULL)
8720 && (ctxt->value->type == XPATH_NODESET)
8721 && (ctxt->value->nodesetval != NULL)
8722 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8723 /*
8724 * limit tree traversing to first node in the result
8725 */
8726 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8727 *first = ctxt->value->nodesetval->nodeTab[0];
8728 }
8729 cur =
8730 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
8731 first);
8732 CHECK_TYPE0(XPATH_NODESET);
8733 arg2 = valuePop(ctxt);
8734
8735 CHECK_TYPE0(XPATH_NODESET);
8736 arg1 = valuePop(ctxt);
8737
8738 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8739 arg2->nodesetval);
8740 valuePush(ctxt, arg1);
8741 xmlXPathFreeObject(arg2);
8742 /* optimizer */
8743 if (total > cur)
8744 xmlXPathCompSwap(op);
8745 return (total + cur);
8746 case XPATH_OP_ROOT:
8747 xmlXPathRoot(ctxt);
8748 return (0);
8749 case XPATH_OP_NODE:
8750 if (op->ch1 != -1)
8751 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8752 if (op->ch2 != -1)
8753 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8754 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8755 return (total);
8756 case XPATH_OP_RESET:
8757 if (op->ch1 != -1)
8758 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8759 if (op->ch2 != -1)
8760 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8761 ctxt->context->node = NULL;
8762 return (total);
8763 case XPATH_OP_COLLECT:{
8764 if (op->ch1 == -1)
8765 return (total);
8766
8767 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8768
8769 /*
8770 * Optimization for [n] selection where n is a number
8771 */
8772 if ((op->ch2 != -1) &&
8773 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8774 (comp->steps[op->ch2].ch1 == -1) &&
8775 (comp->steps[op->ch2].ch2 != -1) &&
8776 (comp->steps[comp->steps[op->ch2].ch2].op ==
8777 XPATH_OP_VALUE)) {
8778 xmlXPathObjectPtr val;
8779
8780 val = comp->steps[comp->steps[op->ch2].ch2].value4;
8781 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
8782 int indx = (int) val->floatval;
8783
8784 if (val->floatval == (float) indx) {
8785 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
8786 first, NULL);
8787 return (total);
8788 }
8789 }
8790 }
8791 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
8792 return (total);
8793 }
8794 case XPATH_OP_VALUE:
8795 valuePush(ctxt,
8796 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
8797 return (0);
8798 case XPATH_OP_SORT:
8799 if (op->ch1 != -1)
8800 total +=
8801 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
8802 first);
8803 if ((ctxt->value != NULL)
8804 && (ctxt->value->type == XPATH_NODESET)
8805 && (ctxt->value->nodesetval != NULL))
8806 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8807 return (total);
8808 default:
8809 return (xmlXPathCompOpEval(ctxt, op));
8810 }
8811}
8812
8813/**
8814 * xmlXPathCompOpEvalLast:
8815 * @ctxt: the XPath parser context with the compiled expression
8816 * @op: an XPath compiled operation
8817 * @last: the last elem found so far
8818 *
8819 * Evaluate the Precompiled XPath operation searching only the last
8820 * element in document order
8821 *
8822 * Returns the number of node traversed
8823 */
8824static int
8825xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
8826 xmlNodePtr * last)
8827{
8828 int total = 0, cur;
8829 xmlXPathCompExprPtr comp;
8830 xmlXPathObjectPtr arg1, arg2;
8831
8832 comp = ctxt->comp;
8833 switch (op->op) {
8834 case XPATH_OP_END:
8835 return (0);
8836 case XPATH_OP_UNION:
8837 total =
8838 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
8839 if ((ctxt->value != NULL)
8840 && (ctxt->value->type == XPATH_NODESET)
8841 && (ctxt->value->nodesetval != NULL)
8842 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8843 /*
8844 * limit tree traversing to first node in the result
8845 */
8846 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8847 *last =
8848 ctxt->value->nodesetval->nodeTab[ctxt->value->
8849 nodesetval->nodeNr -
8850 1];
8851 }
8852 cur =
8853 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
8854 if ((ctxt->value != NULL)
8855 && (ctxt->value->type == XPATH_NODESET)
8856 && (ctxt->value->nodesetval != NULL)
8857 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8858 }
8859 CHECK_TYPE0(XPATH_NODESET);
8860 arg2 = valuePop(ctxt);
8861
8862 CHECK_TYPE0(XPATH_NODESET);
8863 arg1 = valuePop(ctxt);
8864
8865 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8866 arg2->nodesetval);
8867 valuePush(ctxt, arg1);
8868 xmlXPathFreeObject(arg2);
8869 /* optimizer */
8870 if (total > cur)
8871 xmlXPathCompSwap(op);
8872 return (total + cur);
8873 case XPATH_OP_ROOT:
8874 xmlXPathRoot(ctxt);
8875 return (0);
8876 case XPATH_OP_NODE:
8877 if (op->ch1 != -1)
8878 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8879 if (op->ch2 != -1)
8880 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8881 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8882 return (total);
8883 case XPATH_OP_RESET:
8884 if (op->ch1 != -1)
8885 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8886 if (op->ch2 != -1)
8887 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8888 ctxt->context->node = NULL;
8889 return (total);
8890 case XPATH_OP_COLLECT:{
8891 if (op->ch1 == -1)
8892 return (0);
8893
8894 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8895
8896 /*
8897 * Optimization for [n] selection where n is a number
8898 */
8899 if ((op->ch2 != -1) &&
8900 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8901 (comp->steps[op->ch2].ch1 == -1) &&
8902 (comp->steps[op->ch2].ch2 != -1) &&
8903 (comp->steps[comp->steps[op->ch2].ch2].op ==
8904 XPATH_OP_VALUE)) {
8905 xmlXPathObjectPtr val;
8906
8907 val = comp->steps[comp->steps[op->ch2].ch2].value4;
8908 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
8909 int indx = (int) val->floatval;
8910
8911 if (val->floatval == (float) indx) {
8912 total +=
8913 xmlXPathNodeCollectAndTestNth(ctxt, op,
8914 indx, NULL,
8915 last);
8916 return (total);
8917 }
8918 }
8919 }
8920 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
8921 return (total);
8922 }
8923 case XPATH_OP_VALUE:
8924 valuePush(ctxt,
8925 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
8926 return (0);
8927 case XPATH_OP_SORT:
8928 if (op->ch1 != -1)
8929 total +=
8930 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
8931 last);
8932 if ((ctxt->value != NULL)
8933 && (ctxt->value->type == XPATH_NODESET)
8934 && (ctxt->value->nodesetval != NULL))
8935 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8936 return (total);
8937 default:
8938 return (xmlXPathCompOpEval(ctxt, op));
8939 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008940}
8941
Owen Taylor3473f882001-02-23 17:55:21 +00008942/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008943 * xmlXPathCompOpEval:
8944 * @ctxt: the XPath parser context with the compiled expression
8945 * @op: an XPath compiled operation
8946 *
8947 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008948 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008949 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008950static int
8951xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
8952{
8953 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008954 int equal, ret;
8955 xmlXPathCompExprPtr comp;
8956 xmlXPathObjectPtr arg1, arg2;
8957
8958 comp = ctxt->comp;
8959 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008960 case XPATH_OP_END:
8961 return (0);
8962 case XPATH_OP_AND:
8963 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8964 xmlXPathBooleanFunction(ctxt, 1);
8965 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
8966 return (total);
8967 arg2 = valuePop(ctxt);
8968 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8969 xmlXPathBooleanFunction(ctxt, 1);
8970 arg1 = valuePop(ctxt);
8971 arg1->boolval &= arg2->boolval;
8972 valuePush(ctxt, arg1);
8973 xmlXPathFreeObject(arg2);
8974 return (total);
8975 case XPATH_OP_OR:
8976 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8977 xmlXPathBooleanFunction(ctxt, 1);
8978 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
8979 return (total);
8980 arg2 = valuePop(ctxt);
8981 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8982 xmlXPathBooleanFunction(ctxt, 1);
8983 arg1 = valuePop(ctxt);
8984 arg1->boolval |= arg2->boolval;
8985 valuePush(ctxt, arg1);
8986 xmlXPathFreeObject(arg2);
8987 return (total);
8988 case XPATH_OP_EQUAL:
8989 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8990 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8991 equal = xmlXPathEqualValues(ctxt);
8992 if (op->value)
8993 valuePush(ctxt, xmlXPathNewBoolean(equal));
8994 else
8995 valuePush(ctxt, xmlXPathNewBoolean(!equal));
8996 return (total);
8997 case XPATH_OP_CMP:
8998 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8999 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9000 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9001 valuePush(ctxt, xmlXPathNewBoolean(ret));
9002 return (total);
9003 case XPATH_OP_PLUS:
9004 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9005 if (op->ch2 != -1)
9006 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9007 if (op->value == 0)
9008 xmlXPathSubValues(ctxt);
9009 else if (op->value == 1)
9010 xmlXPathAddValues(ctxt);
9011 else if (op->value == 2)
9012 xmlXPathValueFlipSign(ctxt);
9013 else if (op->value == 3) {
9014 CAST_TO_NUMBER;
9015 CHECK_TYPE0(XPATH_NUMBER);
9016 }
9017 return (total);
9018 case XPATH_OP_MULT:
9019 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9020 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9021 if (op->value == 0)
9022 xmlXPathMultValues(ctxt);
9023 else if (op->value == 1)
9024 xmlXPathDivValues(ctxt);
9025 else if (op->value == 2)
9026 xmlXPathModValues(ctxt);
9027 return (total);
9028 case XPATH_OP_UNION:
9029 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9030 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9031 CHECK_TYPE0(XPATH_NODESET);
9032 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009033
Daniel Veillardf06307e2001-07-03 10:35:50 +00009034 CHECK_TYPE0(XPATH_NODESET);
9035 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009036
Daniel Veillardf06307e2001-07-03 10:35:50 +00009037 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9038 arg2->nodesetval);
9039 valuePush(ctxt, arg1);
9040 xmlXPathFreeObject(arg2);
9041 return (total);
9042 case XPATH_OP_ROOT:
9043 xmlXPathRoot(ctxt);
9044 return (total);
9045 case XPATH_OP_NODE:
9046 if (op->ch1 != -1)
9047 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9048 if (op->ch2 != -1)
9049 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9050 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9051 return (total);
9052 case XPATH_OP_RESET:
9053 if (op->ch1 != -1)
9054 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9055 if (op->ch2 != -1)
9056 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9057 ctxt->context->node = NULL;
9058 return (total);
9059 case XPATH_OP_COLLECT:{
9060 if (op->ch1 == -1)
9061 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009062
Daniel Veillardf06307e2001-07-03 10:35:50 +00009063 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009064
Daniel Veillardf06307e2001-07-03 10:35:50 +00009065 /*
9066 * Optimization for [n] selection where n is a number
9067 */
9068 if ((op->ch2 != -1) &&
9069 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9070 (comp->steps[op->ch2].ch1 == -1) &&
9071 (comp->steps[op->ch2].ch2 != -1) &&
9072 (comp->steps[comp->steps[op->ch2].ch2].op ==
9073 XPATH_OP_VALUE)) {
9074 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00009075
Daniel Veillardf06307e2001-07-03 10:35:50 +00009076 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9077 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9078 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009079
Daniel Veillardf06307e2001-07-03 10:35:50 +00009080 if (val->floatval == (float) indx) {
9081 total +=
9082 xmlXPathNodeCollectAndTestNth(ctxt, op,
9083 indx, NULL,
9084 NULL);
9085 return (total);
9086 }
9087 }
9088 }
9089 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
9090 return (total);
9091 }
9092 case XPATH_OP_VALUE:
9093 valuePush(ctxt,
9094 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9095 return (total);
9096 case XPATH_OP_VARIABLE:{
9097 if (op->ch1 != -1)
9098 total +=
9099 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9100 if (op->value5 == NULL)
9101 valuePush(ctxt,
9102 xmlXPathVariableLookup(ctxt->context,
9103 op->value4));
9104 else {
9105 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009106
Daniel Veillardf06307e2001-07-03 10:35:50 +00009107 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9108 if (URI == NULL) {
9109 xmlGenericError(xmlGenericErrorContext,
9110 "xmlXPathRunEval: variable %s bound to undefined prefix %s\n",
9111 op->value4, op->value5);
9112 return (total);
9113 }
9114 valuePush(ctxt,
9115 xmlXPathVariableLookupNS(ctxt->context,
9116 op->value4, URI));
9117 }
9118 return (total);
9119 }
9120 case XPATH_OP_FUNCTION:{
9121 xmlXPathFunction func;
9122 const xmlChar *oldFunc, *oldFuncURI;
9123
9124 if (op->ch1 != -1)
9125 total +=
9126 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9127 if (op->cache != NULL)
9128 func = (xmlXPathFunction) op->cache;
9129 else {
9130 const xmlChar *URI = NULL;
9131
9132 if (op->value5 == NULL)
9133 func =
9134 xmlXPathFunctionLookup(ctxt->context,
9135 op->value4);
9136 else {
9137 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9138 if (URI == NULL) {
9139 xmlGenericError(xmlGenericErrorContext,
9140 "xmlXPathRunEval: function %s bound to undefined prefix %s\n",
9141 op->value4, op->value5);
9142 return (total);
9143 }
9144 func = xmlXPathFunctionLookupNS(ctxt->context,
9145 op->value4, URI);
9146 }
9147 if (func == NULL) {
9148 xmlGenericError(xmlGenericErrorContext,
9149 "xmlXPathRunEval: function %s not found\n",
9150 op->value4);
9151 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
9152 return (total);
9153 }
9154 op->cache = (void *) func;
9155 op->cacheURI = (void *) URI;
9156 }
9157 oldFunc = ctxt->context->function;
9158 oldFuncURI = ctxt->context->functionURI;
9159 ctxt->context->function = op->value4;
9160 ctxt->context->functionURI = op->cacheURI;
9161 func(ctxt, op->value);
9162 ctxt->context->function = oldFunc;
9163 ctxt->context->functionURI = oldFuncURI;
9164 return (total);
9165 }
9166 case XPATH_OP_ARG:
9167 if (op->ch1 != -1)
9168 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9169 if (op->ch2 != -1)
9170 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9171 return (total);
9172 case XPATH_OP_PREDICATE:
9173 case XPATH_OP_FILTER:{
9174 xmlXPathObjectPtr res;
9175 xmlXPathObjectPtr obj, tmp;
9176 xmlNodeSetPtr newset = NULL;
9177 xmlNodeSetPtr oldset;
9178 xmlNodePtr oldnode;
9179 int i;
9180
9181 /*
9182 * Optimization for ()[1] selection i.e. the first elem
9183 */
9184 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9185 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9186 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
9187 xmlXPathObjectPtr val;
9188
9189 val = comp->steps[op->ch2].value4;
9190 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
9191 (val->floatval == 1.0)) {
9192 xmlNodePtr first = NULL;
9193
9194 total +=
9195 xmlXPathCompOpEvalFirst(ctxt,
9196 &comp->steps[op->ch1],
9197 &first);
9198 /*
9199 * The nodeset should be in document order,
9200 * Keep only the first value
9201 */
9202 if ((ctxt->value != NULL) &&
9203 (ctxt->value->type == XPATH_NODESET) &&
9204 (ctxt->value->nodesetval != NULL) &&
9205 (ctxt->value->nodesetval->nodeNr > 1))
9206 ctxt->value->nodesetval->nodeNr = 1;
9207 return (total);
9208 }
9209 }
9210 /*
9211 * Optimization for ()[last()] selection i.e. the last elem
9212 */
9213 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9214 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9215 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
9216 int f = comp->steps[op->ch2].ch1;
9217
9218 if ((f != -1) &&
9219 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
9220 (comp->steps[f].value5 == NULL) &&
9221 (comp->steps[f].value == 0) &&
9222 (comp->steps[f].value4 != NULL) &&
9223 (xmlStrEqual
9224 (comp->steps[f].value4, BAD_CAST "last"))) {
9225 xmlNodePtr last = NULL;
9226
9227 total +=
9228 xmlXPathCompOpEvalLast(ctxt,
9229 &comp->steps[op->ch1],
9230 &last);
9231 /*
9232 * The nodeset should be in document order,
9233 * Keep only the last value
9234 */
9235 if ((ctxt->value != NULL) &&
9236 (ctxt->value->type == XPATH_NODESET) &&
9237 (ctxt->value->nodesetval != NULL) &&
9238 (ctxt->value->nodesetval->nodeTab != NULL) &&
9239 (ctxt->value->nodesetval->nodeNr > 1)) {
9240 ctxt->value->nodesetval->nodeTab[0] =
9241 ctxt->value->nodesetval->nodeTab[ctxt->
9242 value->
9243 nodesetval->
9244 nodeNr -
9245 1];
9246 ctxt->value->nodesetval->nodeNr = 1;
9247 }
9248 return (total);
9249 }
9250 }
9251
9252 if (op->ch1 != -1)
9253 total +=
9254 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9255 if (op->ch2 == -1)
9256 return (total);
9257 if (ctxt->value == NULL)
9258 return (total);
9259
9260 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009261
9262#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009263 /*
9264 * Hum are we filtering the result of an XPointer expression
9265 */
9266 if (ctxt->value->type == XPATH_LOCATIONSET) {
9267 xmlLocationSetPtr newlocset = NULL;
9268 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009269
Daniel Veillardf06307e2001-07-03 10:35:50 +00009270 /*
9271 * Extract the old locset, and then evaluate the result of the
9272 * expression for all the element in the locset. use it to grow
9273 * up a new locset.
9274 */
9275 CHECK_TYPE0(XPATH_LOCATIONSET);
9276 obj = valuePop(ctxt);
9277 oldlocset = obj->user;
9278 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009279
Daniel Veillardf06307e2001-07-03 10:35:50 +00009280 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
9281 ctxt->context->contextSize = 0;
9282 ctxt->context->proximityPosition = 0;
9283 if (op->ch2 != -1)
9284 total +=
9285 xmlXPathCompOpEval(ctxt,
9286 &comp->steps[op->ch2]);
9287 res = valuePop(ctxt);
9288 if (res != NULL)
9289 xmlXPathFreeObject(res);
9290 valuePush(ctxt, obj);
9291 CHECK_ERROR0;
9292 return (total);
9293 }
9294 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009295
Daniel Veillardf06307e2001-07-03 10:35:50 +00009296 for (i = 0; i < oldlocset->locNr; i++) {
9297 /*
9298 * Run the evaluation with a node list made of a
9299 * single item in the nodelocset.
9300 */
9301 ctxt->context->node = oldlocset->locTab[i]->user;
9302 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9303 valuePush(ctxt, tmp);
9304 ctxt->context->contextSize = oldlocset->locNr;
9305 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009306
Daniel Veillardf06307e2001-07-03 10:35:50 +00009307 if (op->ch2 != -1)
9308 total +=
9309 xmlXPathCompOpEval(ctxt,
9310 &comp->steps[op->ch2]);
9311 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009312
Daniel Veillardf06307e2001-07-03 10:35:50 +00009313 /*
9314 * The result of the evaluation need to be tested to
9315 * decided whether the filter succeeded or not
9316 */
9317 res = valuePop(ctxt);
9318 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9319 xmlXPtrLocationSetAdd(newlocset,
9320 xmlXPathObjectCopy
9321 (oldlocset->locTab[i]));
9322 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009323
Daniel Veillardf06307e2001-07-03 10:35:50 +00009324 /*
9325 * Cleanup
9326 */
9327 if (res != NULL)
9328 xmlXPathFreeObject(res);
9329 if (ctxt->value == tmp) {
9330 res = valuePop(ctxt);
9331 xmlXPathFreeObject(res);
9332 }
9333
9334 ctxt->context->node = NULL;
9335 }
9336
9337 /*
9338 * The result is used as the new evaluation locset.
9339 */
9340 xmlXPathFreeObject(obj);
9341 ctxt->context->node = NULL;
9342 ctxt->context->contextSize = -1;
9343 ctxt->context->proximityPosition = -1;
9344 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
9345 ctxt->context->node = oldnode;
9346 return (total);
9347 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009348#endif /* LIBXML_XPTR_ENABLED */
9349
Daniel Veillardf06307e2001-07-03 10:35:50 +00009350 /*
9351 * Extract the old set, and then evaluate the result of the
9352 * expression for all the element in the set. use it to grow
9353 * up a new set.
9354 */
9355 CHECK_TYPE0(XPATH_NODESET);
9356 obj = valuePop(ctxt);
9357 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00009358
Daniel Veillardf06307e2001-07-03 10:35:50 +00009359 oldnode = ctxt->context->node;
9360 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009361
Daniel Veillardf06307e2001-07-03 10:35:50 +00009362 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
9363 ctxt->context->contextSize = 0;
9364 ctxt->context->proximityPosition = 0;
9365 if (op->ch2 != -1)
9366 total +=
9367 xmlXPathCompOpEval(ctxt,
9368 &comp->steps[op->ch2]);
9369 res = valuePop(ctxt);
9370 if (res != NULL)
9371 xmlXPathFreeObject(res);
9372 valuePush(ctxt, obj);
9373 ctxt->context->node = oldnode;
9374 CHECK_ERROR0;
9375 } else {
9376 /*
9377 * Initialize the new set.
9378 */
9379 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009380
Daniel Veillardf06307e2001-07-03 10:35:50 +00009381 for (i = 0; i < oldset->nodeNr; i++) {
9382 /*
9383 * Run the evaluation with a node list made of
9384 * a single item in the nodeset.
9385 */
9386 ctxt->context->node = oldset->nodeTab[i];
9387 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9388 valuePush(ctxt, tmp);
9389 ctxt->context->contextSize = oldset->nodeNr;
9390 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009391
Daniel Veillardf06307e2001-07-03 10:35:50 +00009392 if (op->ch2 != -1)
9393 total +=
9394 xmlXPathCompOpEval(ctxt,
9395 &comp->steps[op->ch2]);
9396 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009397
Daniel Veillardf06307e2001-07-03 10:35:50 +00009398 /*
9399 * The result of the evaluation need to be tested to
9400 * decided whether the filter succeeded or not
9401 */
9402 res = valuePop(ctxt);
9403 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9404 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
9405 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009406
Daniel Veillardf06307e2001-07-03 10:35:50 +00009407 /*
9408 * Cleanup
9409 */
9410 if (res != NULL)
9411 xmlXPathFreeObject(res);
9412 if (ctxt->value == tmp) {
9413 res = valuePop(ctxt);
9414 xmlXPathFreeObject(res);
9415 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009416
Daniel Veillardf06307e2001-07-03 10:35:50 +00009417 ctxt->context->node = NULL;
9418 }
9419
9420 /*
9421 * The result is used as the new evaluation set.
9422 */
9423 xmlXPathFreeObject(obj);
9424 ctxt->context->node = NULL;
9425 ctxt->context->contextSize = -1;
9426 ctxt->context->proximityPosition = -1;
9427 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
9428 }
9429 ctxt->context->node = oldnode;
9430 return (total);
9431 }
9432 case XPATH_OP_SORT:
9433 if (op->ch1 != -1)
9434 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9435 if ((ctxt->value != NULL) &&
9436 (ctxt->value->type == XPATH_NODESET) &&
9437 (ctxt->value->nodesetval != NULL))
9438 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9439 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009440#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009441 case XPATH_OP_RANGETO:{
9442 xmlXPathObjectPtr range;
9443 xmlXPathObjectPtr res, obj;
9444 xmlXPathObjectPtr tmp;
9445 xmlLocationSetPtr newset = NULL;
9446 xmlNodeSetPtr oldset;
9447 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009448
Daniel Veillardf06307e2001-07-03 10:35:50 +00009449 if (op->ch1 != -1)
9450 total +=
9451 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9452 if (op->ch2 == -1)
9453 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009454
Daniel Veillardf06307e2001-07-03 10:35:50 +00009455 CHECK_TYPE0(XPATH_NODESET);
9456 obj = valuePop(ctxt);
9457 oldset = obj->nodesetval;
9458 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009459
Daniel Veillardf06307e2001-07-03 10:35:50 +00009460 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009461
Daniel Veillardf06307e2001-07-03 10:35:50 +00009462 if (oldset != NULL) {
9463 for (i = 0; i < oldset->nodeNr; i++) {
9464 /*
9465 * Run the evaluation with a node list made of a single item
9466 * in the nodeset.
9467 */
9468 ctxt->context->node = oldset->nodeTab[i];
9469 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9470 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009471
Daniel Veillardf06307e2001-07-03 10:35:50 +00009472 if (op->ch2 != -1)
9473 total +=
9474 xmlXPathCompOpEval(ctxt,
9475 &comp->steps[op->ch2]);
9476 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009477
Daniel Veillardf06307e2001-07-03 10:35:50 +00009478 /*
9479 * The result of the evaluation need to be tested to
9480 * decided whether the filter succeeded or not
9481 */
9482 res = valuePop(ctxt);
9483 range =
9484 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
9485 res);
9486 if (range != NULL) {
9487 xmlXPtrLocationSetAdd(newset, range);
9488 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009489
Daniel Veillardf06307e2001-07-03 10:35:50 +00009490 /*
9491 * Cleanup
9492 */
9493 if (res != NULL)
9494 xmlXPathFreeObject(res);
9495 if (ctxt->value == tmp) {
9496 res = valuePop(ctxt);
9497 xmlXPathFreeObject(res);
9498 }
9499
9500 ctxt->context->node = NULL;
9501 }
9502 }
9503
9504 /*
9505 * The result is used as the new evaluation set.
9506 */
9507 xmlXPathFreeObject(obj);
9508 ctxt->context->node = NULL;
9509 ctxt->context->contextSize = -1;
9510 ctxt->context->proximityPosition = -1;
9511 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
9512 return (total);
9513 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009514#endif /* LIBXML_XPTR_ENABLED */
9515 }
9516 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009517 "XPath: unknown precompiled operation %d\n", op->op);
9518 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009519}
9520
9521/**
9522 * xmlXPathRunEval:
9523 * @ctxt: the XPath parser context with the compiled expression
9524 *
9525 * Evaluate the Precompiled XPath expression in the given context.
9526 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009527static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009528xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
9529 xmlXPathCompExprPtr comp;
9530
9531 if ((ctxt == NULL) || (ctxt->comp == NULL))
9532 return;
9533
9534 if (ctxt->valueTab == NULL) {
9535 /* Allocate the value stack */
9536 ctxt->valueTab = (xmlXPathObjectPtr *)
9537 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
9538 if (ctxt->valueTab == NULL) {
9539 xmlFree(ctxt);
9540 xmlGenericError(xmlGenericErrorContext,
9541 "xmlXPathRunEval: out of memory\n");
9542 return;
9543 }
9544 ctxt->valueNr = 0;
9545 ctxt->valueMax = 10;
9546 ctxt->value = NULL;
9547 }
9548 comp = ctxt->comp;
9549 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
9550}
9551
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009552/************************************************************************
9553 * *
9554 * Public interfaces *
9555 * *
9556 ************************************************************************/
9557
9558/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009559 * xmlXPathEvalPredicate:
9560 * @ctxt: the XPath context
9561 * @res: the Predicate Expression evaluation result
9562 *
9563 * Evaluate a predicate result for the current node.
9564 * A PredicateExpr is evaluated by evaluating the Expr and converting
9565 * the result to a boolean. If the result is a number, the result will
9566 * be converted to true if the number is equal to the position of the
9567 * context node in the context node list (as returned by the position
9568 * function) and will be converted to false otherwise; if the result
9569 * is not a number, then the result will be converted as if by a call
9570 * to the boolean function.
9571 *
9572 * Return 1 if predicate is true, 0 otherwise
9573 */
9574int
9575xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
9576 if (res == NULL) return(0);
9577 switch (res->type) {
9578 case XPATH_BOOLEAN:
9579 return(res->boolval);
9580 case XPATH_NUMBER:
9581 return(res->floatval == ctxt->proximityPosition);
9582 case XPATH_NODESET:
9583 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009584 if (res->nodesetval == NULL)
9585 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009586 return(res->nodesetval->nodeNr != 0);
9587 case XPATH_STRING:
9588 return((res->stringval != NULL) &&
9589 (xmlStrlen(res->stringval) != 0));
9590 default:
9591 STRANGE
9592 }
9593 return(0);
9594}
9595
9596/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009597 * xmlXPathEvaluatePredicateResult:
9598 * @ctxt: the XPath Parser context
9599 * @res: the Predicate Expression evaluation result
9600 *
9601 * Evaluate a predicate result for the current node.
9602 * A PredicateExpr is evaluated by evaluating the Expr and converting
9603 * the result to a boolean. If the result is a number, the result will
9604 * be converted to true if the number is equal to the position of the
9605 * context node in the context node list (as returned by the position
9606 * function) and will be converted to false otherwise; if the result
9607 * is not a number, then the result will be converted as if by a call
9608 * to the boolean function.
9609 *
9610 * Return 1 if predicate is true, 0 otherwise
9611 */
9612int
9613xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
9614 xmlXPathObjectPtr res) {
9615 if (res == NULL) return(0);
9616 switch (res->type) {
9617 case XPATH_BOOLEAN:
9618 return(res->boolval);
9619 case XPATH_NUMBER:
9620 return(res->floatval == ctxt->context->proximityPosition);
9621 case XPATH_NODESET:
9622 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +00009623 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +00009624 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009625 return(res->nodesetval->nodeNr != 0);
9626 case XPATH_STRING:
9627 return((res->stringval != NULL) &&
9628 (xmlStrlen(res->stringval) != 0));
9629 default:
9630 STRANGE
9631 }
9632 return(0);
9633}
9634
9635/**
9636 * xmlXPathCompile:
9637 * @str: the XPath expression
9638 *
9639 * Compile an XPath expression
9640 *
9641 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9642 * the caller has to free the object.
9643 */
9644xmlXPathCompExprPtr
9645xmlXPathCompile(const xmlChar *str) {
9646 xmlXPathParserContextPtr ctxt;
9647 xmlXPathCompExprPtr comp;
9648
9649 xmlXPathInit();
9650
9651 ctxt = xmlXPathNewParserContext(str, NULL);
9652 xmlXPathCompileExpr(ctxt);
9653
Daniel Veillard40af6492001-04-22 08:50:55 +00009654 if (*ctxt->cur != 0) {
9655 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9656 comp = NULL;
9657 } else {
9658 comp = ctxt->comp;
9659 ctxt->comp = NULL;
9660 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009661 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009662#ifdef DEBUG_EVAL_COUNTS
9663 if (comp != NULL) {
9664 comp->string = xmlStrdup(str);
9665 comp->nb = 0;
9666 }
9667#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009668 return(comp);
9669}
9670
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009671/**
9672 * xmlXPathCompiledEval:
9673 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +00009674 * @ctx: the XPath context
9675 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009676 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +00009677 *
9678 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9679 * the caller has to free the object.
9680 */
9681xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009682xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +00009683 xmlXPathParserContextPtr ctxt;
9684 xmlXPathObjectPtr res, tmp, init = NULL;
9685 int stack = 0;
9686
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009687 if ((comp == NULL) || (ctx == NULL))
9688 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00009689 xmlXPathInit();
9690
9691 CHECK_CONTEXT(ctx)
9692
Daniel Veillardf06307e2001-07-03 10:35:50 +00009693#ifdef DEBUG_EVAL_COUNTS
9694 comp->nb++;
9695 if ((comp->string != NULL) && (comp->nb > 100)) {
9696 fprintf(stderr, "100 x %s\n", comp->string);
9697 comp->nb = 0;
9698 }
9699#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009700 ctxt = xmlXPathCompParserContext(comp, ctx);
9701 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009702
9703 if (ctxt->value == NULL) {
9704 xmlGenericError(xmlGenericErrorContext,
9705 "xmlXPathEval: evaluation failed\n");
9706 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009707 } else {
9708 res = valuePop(ctxt);
9709 }
9710
Daniel Veillardf06307e2001-07-03 10:35:50 +00009711
Owen Taylor3473f882001-02-23 17:55:21 +00009712 do {
9713 tmp = valuePop(ctxt);
9714 if (tmp != NULL) {
9715 if (tmp != init)
9716 stack++;
9717 xmlXPathFreeObject(tmp);
9718 }
9719 } while (tmp != NULL);
9720 if ((stack != 0) && (res != NULL)) {
9721 xmlGenericError(xmlGenericErrorContext,
9722 "xmlXPathEval: %d object left on the stack\n",
9723 stack);
9724 }
9725 if (ctxt->error != XPATH_EXPRESSION_OK) {
9726 xmlXPathFreeObject(res);
9727 res = NULL;
9728 }
9729
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009730
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009731 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009732 xmlXPathFreeParserContext(ctxt);
9733 return(res);
9734}
9735
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009736/**
9737 * xmlXPathEvalExpr:
9738 * @ctxt: the XPath Parser context
9739 *
9740 * Parse and evaluate an XPath expression in the given context,
9741 * then push the result on the context stack
9742 */
9743void
9744xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
9745 xmlXPathCompileExpr(ctxt);
9746 xmlXPathRunEval(ctxt);
9747}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009748
9749/**
9750 * xmlXPathEval:
9751 * @str: the XPath expression
9752 * @ctx: the XPath context
9753 *
9754 * Evaluate the XPath Location Path in the given context.
9755 *
9756 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9757 * the caller has to free the object.
9758 */
9759xmlXPathObjectPtr
9760xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
9761 xmlXPathParserContextPtr ctxt;
9762 xmlXPathObjectPtr res, tmp, init = NULL;
9763 int stack = 0;
9764
9765 xmlXPathInit();
9766
9767 CHECK_CONTEXT(ctx)
9768
9769 ctxt = xmlXPathNewParserContext(str, ctx);
9770 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009771
9772 if (ctxt->value == NULL) {
9773 xmlGenericError(xmlGenericErrorContext,
9774 "xmlXPathEval: evaluation failed\n");
9775 res = NULL;
9776 } else if (*ctxt->cur != 0) {
9777 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9778 res = NULL;
9779 } else {
9780 res = valuePop(ctxt);
9781 }
9782
9783 do {
9784 tmp = valuePop(ctxt);
9785 if (tmp != NULL) {
9786 if (tmp != init)
9787 stack++;
9788 xmlXPathFreeObject(tmp);
9789 }
9790 } while (tmp != NULL);
9791 if ((stack != 0) && (res != NULL)) {
9792 xmlGenericError(xmlGenericErrorContext,
9793 "xmlXPathEval: %d object left on the stack\n",
9794 stack);
9795 }
9796 if (ctxt->error != XPATH_EXPRESSION_OK) {
9797 xmlXPathFreeObject(res);
9798 res = NULL;
9799 }
9800
Owen Taylor3473f882001-02-23 17:55:21 +00009801 xmlXPathFreeParserContext(ctxt);
9802 return(res);
9803}
9804
9805/**
9806 * xmlXPathEvalExpression:
9807 * @str: the XPath expression
9808 * @ctxt: the XPath context
9809 *
9810 * Evaluate the XPath expression in the given context.
9811 *
9812 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
9813 * the caller has to free the object.
9814 */
9815xmlXPathObjectPtr
9816xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
9817 xmlXPathParserContextPtr pctxt;
9818 xmlXPathObjectPtr res, tmp;
9819 int stack = 0;
9820
9821 xmlXPathInit();
9822
9823 CHECK_CONTEXT(ctxt)
9824
9825 pctxt = xmlXPathNewParserContext(str, ctxt);
9826 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009827
9828 if (*pctxt->cur != 0) {
9829 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9830 res = NULL;
9831 } else {
9832 res = valuePop(pctxt);
9833 }
9834 do {
9835 tmp = valuePop(pctxt);
9836 if (tmp != NULL) {
9837 xmlXPathFreeObject(tmp);
9838 stack++;
9839 }
9840 } while (tmp != NULL);
9841 if ((stack != 0) && (res != NULL)) {
9842 xmlGenericError(xmlGenericErrorContext,
9843 "xmlXPathEvalExpression: %d object left on the stack\n",
9844 stack);
9845 }
9846 xmlXPathFreeParserContext(pctxt);
9847 return(res);
9848}
9849
9850/**
9851 * xmlXPathRegisterAllFunctions:
9852 * @ctxt: the XPath context
9853 *
9854 * Registers all default XPath functions in this context
9855 */
9856void
9857xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
9858{
9859 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
9860 xmlXPathBooleanFunction);
9861 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
9862 xmlXPathCeilingFunction);
9863 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
9864 xmlXPathCountFunction);
9865 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
9866 xmlXPathConcatFunction);
9867 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
9868 xmlXPathContainsFunction);
9869 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
9870 xmlXPathIdFunction);
9871 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
9872 xmlXPathFalseFunction);
9873 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
9874 xmlXPathFloorFunction);
9875 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
9876 xmlXPathLastFunction);
9877 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
9878 xmlXPathLangFunction);
9879 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
9880 xmlXPathLocalNameFunction);
9881 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
9882 xmlXPathNotFunction);
9883 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
9884 xmlXPathNameFunction);
9885 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
9886 xmlXPathNamespaceURIFunction);
9887 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
9888 xmlXPathNormalizeFunction);
9889 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
9890 xmlXPathNumberFunction);
9891 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
9892 xmlXPathPositionFunction);
9893 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
9894 xmlXPathRoundFunction);
9895 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
9896 xmlXPathStringFunction);
9897 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
9898 xmlXPathStringLengthFunction);
9899 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
9900 xmlXPathStartsWithFunction);
9901 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
9902 xmlXPathSubstringFunction);
9903 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
9904 xmlXPathSubstringBeforeFunction);
9905 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
9906 xmlXPathSubstringAfterFunction);
9907 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
9908 xmlXPathSumFunction);
9909 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
9910 xmlXPathTrueFunction);
9911 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
9912 xmlXPathTranslateFunction);
9913}
9914
9915#endif /* LIBXML_XPATH_ENABLED */