blob: 0dba1f02acb22c46b91b36fc1f43e66e11593ca9 [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>
54
55/* #define DEBUG */
56/* #define DEBUG_STEP */
Daniel Veillardf06307e2001-07-03 10:35:50 +000057/* #define DEBUG_STEP_NTH */
Owen Taylor3473f882001-02-23 17:55:21 +000058/* #define DEBUG_EXPR */
Daniel Veillardf06307e2001-07-03 10:35:50 +000059/* #define DEBUG_EVAL_COUNTS */
Owen Taylor3473f882001-02-23 17:55:21 +000060
61void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
62double xmlXPathStringEvalNumber(const xmlChar *str);
Daniel Veillard5792e162001-04-30 17:44:45 +000063double xmlXPathDivideBy(double f, double fzero);
Owen Taylor3473f882001-02-23 17:55:21 +000064
Daniel Veillard9e7160d2001-03-18 23:17:47 +000065/************************************************************************
66 * *
67 * Floating point stuff *
68 * *
69 ************************************************************************/
70
Daniel Veillardcda96922001-08-21 10:56:31 +000071#define TRIO_PUBLIC static
72#include "trionan.c"
73
Owen Taylor3473f882001-02-23 17:55:21 +000074/*
Owen Taylor3473f882001-02-23 17:55:21 +000075 * The lack of portability of this section of the libc is annoying !
76 */
77double xmlXPathNAN = 0;
78double xmlXPathPINF = 1;
79double xmlXPathNINF = -1;
80
Owen Taylor3473f882001-02-23 17:55:21 +000081/**
82 * xmlXPathInit:
83 *
84 * Initialize the XPath environment
85 */
86void
87xmlXPathInit(void) {
88 static int initialized = 0;
89
90 if (initialized) return;
91
Bjorn Reese45029602001-08-21 09:23:53 +000092 xmlXPathPINF = trio_pinf();
93 xmlXPathNINF = trio_ninf();
94 xmlXPathNAN = trio_nan();
Owen Taylor3473f882001-02-23 17:55:21 +000095
96 initialized = 1;
97}
98
Daniel Veillardcda96922001-08-21 10:56:31 +000099/**
100 * xmlXPathIsNaN:
101 * @val: a double value
102 *
103 * Provides a portable isnan() function to detect whether a double
104 * is a NotaNumber. Based on trio code
105 * http://sourceforge.net/projects/ctrio/
106 *
107 * Returns 1 if the value is a NaN, 0 otherwise
108 */
109int
110xmlXPathIsNaN(double val) {
111 return(trio_isnan(val));
112}
113
114/**
115 * xmlXPathIsInf:
116 * @val: a double value
117 *
118 * Provides a portable isinf() function to detect whether a double
119 * is a +Infinite or -Infinite. Based on trio code
120 * http://sourceforge.net/projects/ctrio/
121 *
122 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
123 */
124int
125xmlXPathIsInf(double val) {
126 return(trio_isinf(val));
127}
128
Owen Taylor3473f882001-02-23 17:55:21 +0000129/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000130 * *
131 * Parser Types *
132 * *
133 ************************************************************************/
134
135/*
136 * Types are private:
137 */
138
139typedef enum {
140 XPATH_OP_END=0,
141 XPATH_OP_AND,
142 XPATH_OP_OR,
143 XPATH_OP_EQUAL,
144 XPATH_OP_CMP,
145 XPATH_OP_PLUS,
146 XPATH_OP_MULT,
147 XPATH_OP_UNION,
148 XPATH_OP_ROOT,
149 XPATH_OP_NODE,
150 XPATH_OP_RESET,
151 XPATH_OP_COLLECT,
152 XPATH_OP_VALUE,
153 XPATH_OP_VARIABLE,
154 XPATH_OP_FUNCTION,
155 XPATH_OP_ARG,
156 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000157 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000158 XPATH_OP_SORT
159#ifdef LIBXML_XPTR_ENABLED
160 ,XPATH_OP_RANGETO
161#endif
162} xmlXPathOp;
163
164typedef enum {
165 AXIS_ANCESTOR = 1,
166 AXIS_ANCESTOR_OR_SELF,
167 AXIS_ATTRIBUTE,
168 AXIS_CHILD,
169 AXIS_DESCENDANT,
170 AXIS_DESCENDANT_OR_SELF,
171 AXIS_FOLLOWING,
172 AXIS_FOLLOWING_SIBLING,
173 AXIS_NAMESPACE,
174 AXIS_PARENT,
175 AXIS_PRECEDING,
176 AXIS_PRECEDING_SIBLING,
177 AXIS_SELF
178} xmlXPathAxisVal;
179
180typedef enum {
181 NODE_TEST_NONE = 0,
182 NODE_TEST_TYPE = 1,
183 NODE_TEST_PI = 2,
184 NODE_TEST_ALL = 3,
185 NODE_TEST_NS = 4,
186 NODE_TEST_NAME = 5
187} xmlXPathTestVal;
188
189typedef enum {
190 NODE_TYPE_NODE = 0,
191 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
192 NODE_TYPE_TEXT = XML_TEXT_NODE,
193 NODE_TYPE_PI = XML_PI_NODE
194} xmlXPathTypeVal;
195
196
197typedef struct _xmlXPathStepOp xmlXPathStepOp;
198typedef xmlXPathStepOp *xmlXPathStepOpPtr;
199struct _xmlXPathStepOp {
200 xmlXPathOp op;
201 int ch1;
202 int ch2;
203 int value;
204 int value2;
205 int value3;
206 void *value4;
207 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000208 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000209 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000210};
211
212struct _xmlXPathCompExpr {
213 int nbStep;
214 int maxStep;
215 xmlXPathStepOp *steps; /* ops for computation */
216 int last;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000217#ifdef DEBUG_EVAL_COUNTS
218 int nb;
219 xmlChar *string;
220#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000221};
222
223/************************************************************************
224 * *
225 * Parser Type functions *
226 * *
227 ************************************************************************/
228
229/**
230 * xmlXPathNewCompExpr:
231 *
232 * Create a new Xpath component
233 *
234 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
235 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000236static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000237xmlXPathNewCompExpr(void) {
238 xmlXPathCompExprPtr cur;
239
240 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
241 if (cur == NULL) {
242 xmlGenericError(xmlGenericErrorContext,
243 "xmlXPathNewCompExpr : malloc failed\n");
244 return(NULL);
245 }
246 memset(cur, 0, sizeof(xmlXPathCompExpr));
247 cur->maxStep = 10;
248 cur->nbStep = 0;
249 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
250 sizeof(xmlXPathStepOp));
251 if (cur->steps == NULL) {
252 xmlGenericError(xmlGenericErrorContext,
253 "xmlXPathNewCompExpr : malloc failed\n");
254 xmlFree(cur);
255 return(NULL);
256 }
257 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
258 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000259#ifdef DEBUG_EVAL_COUNTS
260 cur->nb = 0;
261#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000262 return(cur);
263}
264
265/**
266 * xmlXPathFreeCompExpr:
267 * @comp: an XPATH comp
268 *
269 * Free up the memory allocated by @comp
270 */
271void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000272xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
273{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000274 xmlXPathStepOpPtr op;
275 int i;
276
277 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000278 return;
279 for (i = 0; i < comp->nbStep; i++) {
280 op = &comp->steps[i];
281 if (op->value4 != NULL) {
282 if (op->op == XPATH_OP_VALUE)
283 xmlXPathFreeObject(op->value4);
284 else
285 xmlFree(op->value4);
286 }
287 if (op->value5 != NULL)
288 xmlFree(op->value5);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000289 }
290 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000291 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000292 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000293#ifdef DEBUG_EVAL_COUNTS
294 if (comp->string != NULL) {
295 xmlFree(comp->string);
296 }
297#endif
298
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000299 xmlFree(comp);
300}
301
302/**
303 * xmlXPathCompExprAdd:
304 * @comp: the compiled expression
305 * @ch1: first child index
306 * @ch2: second child index
307 * @op: an op
308 * @value: the first int value
309 * @value2: the second int value
310 * @value3: the third int value
311 * @value4: the first string value
312 * @value5: the second string value
313 *
314 * Add an step to an XPath Compiled Expression
315 *
316 * Returns -1 in case of failure, the index otherwise
317 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000318static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000319xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
320 xmlXPathOp op, int value,
321 int value2, int value3, void *value4, void *value5) {
322 if (comp->nbStep >= comp->maxStep) {
323 xmlXPathStepOp *real;
324
325 comp->maxStep *= 2;
326 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
327 comp->maxStep * sizeof(xmlXPathStepOp));
328 if (real == NULL) {
329 comp->maxStep /= 2;
330 xmlGenericError(xmlGenericErrorContext,
331 "xmlXPathCompExprAdd : realloc failed\n");
332 return(-1);
333 }
334 comp->steps = real;
335 }
336 comp->last = comp->nbStep;
337 comp->steps[comp->nbStep].ch1 = ch1;
338 comp->steps[comp->nbStep].ch2 = ch2;
339 comp->steps[comp->nbStep].op = op;
340 comp->steps[comp->nbStep].value = value;
341 comp->steps[comp->nbStep].value2 = value2;
342 comp->steps[comp->nbStep].value3 = value3;
343 comp->steps[comp->nbStep].value4 = value4;
344 comp->steps[comp->nbStep].value5 = value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000345 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000346 return(comp->nbStep++);
347}
348
Daniel Veillardf06307e2001-07-03 10:35:50 +0000349/**
350 * xmlXPathCompSwap:
351 * @comp: the compiled expression
352 * @op: operation index
353 *
354 * Swaps 2 operations in the compiled expression
355 * TODO: not thread safe, disable for multi-thread operations
356 *
357 * Returns -1 in case of failure, the index otherwise
358 */
359static void
360xmlXPathCompSwap(xmlXPathStepOpPtr op) {
361 int tmp;
362
363 tmp = op->ch1;
364 op->ch1 = op->ch2;
365 op->ch2 = tmp;
366}
367
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000368#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
369 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
370 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000371#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
372 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
373 (op), (val), (val2), (val3), (val4), (val5))
374
375#define PUSH_LEAVE_EXPR(op, val, val2) \
376xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
377
378#define PUSH_UNARY_EXPR(op, ch, val, val2) \
379xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
380
381#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
382xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
383
384/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000385 * *
386 * Debugging related functions *
387 * *
388 ************************************************************************/
389
390#define TODO \
391 xmlGenericError(xmlGenericErrorContext, \
392 "Unimplemented block at %s:%d\n", \
393 __FILE__, __LINE__);
394
395#define STRANGE \
396 xmlGenericError(xmlGenericErrorContext, \
397 "Internal error at %s:%d\n", \
398 __FILE__, __LINE__);
399
400#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000401static void
402xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000403 int i;
404 char shift[100];
405
406 for (i = 0;((i < depth) && (i < 25));i++)
407 shift[2 * i] = shift[2 * i + 1] = ' ';
408 shift[2 * i] = shift[2 * i + 1] = 0;
409 if (cur == NULL) {
410 fprintf(output, shift);
411 fprintf(output, "Node is NULL !\n");
412 return;
413
414 }
415
416 if ((cur->type == XML_DOCUMENT_NODE) ||
417 (cur->type == XML_HTML_DOCUMENT_NODE)) {
418 fprintf(output, shift);
419 fprintf(output, " /\n");
420 } else if (cur->type == XML_ATTRIBUTE_NODE)
421 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
422 else
423 xmlDebugDumpOneNode(output, cur, depth);
424}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000425static void
426xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000427 xmlNodePtr tmp;
428 int i;
429 char shift[100];
430
431 for (i = 0;((i < depth) && (i < 25));i++)
432 shift[2 * i] = shift[2 * i + 1] = ' ';
433 shift[2 * i] = shift[2 * i + 1] = 0;
434 if (cur == NULL) {
435 fprintf(output, shift);
436 fprintf(output, "Node is NULL !\n");
437 return;
438
439 }
440
441 while (cur != NULL) {
442 tmp = cur;
443 cur = cur->next;
444 xmlDebugDumpOneNode(output, tmp, depth);
445 }
446}
Owen Taylor3473f882001-02-23 17:55:21 +0000447
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000448static void
449xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000450 int i;
451 char shift[100];
452
453 for (i = 0;((i < depth) && (i < 25));i++)
454 shift[2 * i] = shift[2 * i + 1] = ' ';
455 shift[2 * i] = shift[2 * i + 1] = 0;
456
457 if (cur == NULL) {
458 fprintf(output, shift);
459 fprintf(output, "NodeSet is NULL !\n");
460 return;
461
462 }
463
Daniel Veillard911f49a2001-04-07 15:39:35 +0000464 if (cur != NULL) {
465 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
466 for (i = 0;i < cur->nodeNr;i++) {
467 fprintf(output, shift);
468 fprintf(output, "%d", i + 1);
469 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
470 }
Owen Taylor3473f882001-02-23 17:55:21 +0000471 }
472}
473
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000474static void
475xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000476 int i;
477 char shift[100];
478
479 for (i = 0;((i < depth) && (i < 25));i++)
480 shift[2 * i] = shift[2 * i + 1] = ' ';
481 shift[2 * i] = shift[2 * i + 1] = 0;
482
483 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
484 fprintf(output, shift);
485 fprintf(output, "Value Tree is NULL !\n");
486 return;
487
488 }
489
490 fprintf(output, shift);
491 fprintf(output, "%d", i + 1);
492 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
493}
Owen Taylor3473f882001-02-23 17:55:21 +0000494#if defined(LIBXML_XPTR_ENABLED)
495void xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth);
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000496static void
497xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr 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 if (cur == NULL) {
506 fprintf(output, shift);
507 fprintf(output, "LocationSet is NULL !\n");
508 return;
509
510 }
511
512 for (i = 0;i < cur->locNr;i++) {
513 fprintf(output, shift);
514 fprintf(output, "%d : ", i + 1);
515 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
516 }
517}
Daniel Veillard017b1082001-06-21 11:20:21 +0000518#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000519
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000520/**
521 * xmlXPathDebugDumpObject:
522 * @output: the FILE * to dump the output
523 * @cur: the object to inspect
524 * @depth: indentation level
525 *
526 * Dump the content of the object for debugging purposes
527 */
528void
529xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000530 int i;
531 char shift[100];
532
533 for (i = 0;((i < depth) && (i < 25));i++)
534 shift[2 * i] = shift[2 * i + 1] = ' ';
535 shift[2 * i] = shift[2 * i + 1] = 0;
536
537 fprintf(output, shift);
538
539 if (cur == NULL) {
540 fprintf(output, "Object is empty (NULL)\n");
541 return;
542 }
543 switch(cur->type) {
544 case XPATH_UNDEFINED:
545 fprintf(output, "Object is uninitialized\n");
546 break;
547 case XPATH_NODESET:
548 fprintf(output, "Object is a Node Set :\n");
549 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
550 break;
551 case XPATH_XSLT_TREE:
552 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000553 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000554 break;
555 case XPATH_BOOLEAN:
556 fprintf(output, "Object is a Boolean : ");
557 if (cur->boolval) fprintf(output, "true\n");
558 else fprintf(output, "false\n");
559 break;
560 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000561 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000562 case 1:
563 fprintf(output, "Object is a number : +Infinity\n");
564 break;
565 case -1:
566 fprintf(output, "Object is a number : -Infinity\n");
567 break;
568 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000569 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000570 fprintf(output, "Object is a number : NaN\n");
571 } else {
572 fprintf(output, "Object is a number : %0g\n", cur->floatval);
573 }
574 }
Owen Taylor3473f882001-02-23 17:55:21 +0000575 break;
576 case XPATH_STRING:
577 fprintf(output, "Object is a string : ");
578 xmlDebugDumpString(output, cur->stringval);
579 fprintf(output, "\n");
580 break;
581 case XPATH_POINT:
582 fprintf(output, "Object is a point : index %d in node", cur->index);
583 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
584 fprintf(output, "\n");
585 break;
586 case XPATH_RANGE:
587 if ((cur->user2 == NULL) ||
588 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
589 fprintf(output, "Object is a collapsed range :\n");
590 fprintf(output, shift);
591 if (cur->index >= 0)
592 fprintf(output, "index %d in ", cur->index);
593 fprintf(output, "node\n");
594 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
595 depth + 1);
596 } else {
597 fprintf(output, "Object is a range :\n");
598 fprintf(output, shift);
599 fprintf(output, "From ");
600 if (cur->index >= 0)
601 fprintf(output, "index %d in ", cur->index);
602 fprintf(output, "node\n");
603 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
604 depth + 1);
605 fprintf(output, shift);
606 fprintf(output, "To ");
607 if (cur->index2 >= 0)
608 fprintf(output, "index %d in ", cur->index2);
609 fprintf(output, "node\n");
610 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
611 depth + 1);
612 fprintf(output, "\n");
613 }
614 break;
615 case XPATH_LOCATIONSET:
616#if defined(LIBXML_XPTR_ENABLED)
617 fprintf(output, "Object is a Location Set:\n");
618 xmlXPathDebugDumpLocationSet(output,
619 (xmlLocationSetPtr) cur->user, depth);
620#endif
621 break;
622 case XPATH_USERS:
623 fprintf(output, "Object is user defined\n");
624 break;
625 }
626}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000627
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000628static void
629xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000630 xmlXPathStepOpPtr op, int depth) {
631 int i;
632 char shift[100];
633
634 for (i = 0;((i < depth) && (i < 25));i++)
635 shift[2 * i] = shift[2 * i + 1] = ' ';
636 shift[2 * i] = shift[2 * i + 1] = 0;
637
638 fprintf(output, shift);
639 if (op == NULL) {
640 fprintf(output, "Step is NULL\n");
641 return;
642 }
643 switch (op->op) {
644 case XPATH_OP_END:
645 fprintf(output, "END"); break;
646 case XPATH_OP_AND:
647 fprintf(output, "AND"); break;
648 case XPATH_OP_OR:
649 fprintf(output, "OR"); break;
650 case XPATH_OP_EQUAL:
651 if (op->value)
652 fprintf(output, "EQUAL =");
653 else
654 fprintf(output, "EQUAL !=");
655 break;
656 case XPATH_OP_CMP:
657 if (op->value)
658 fprintf(output, "CMP <");
659 else
660 fprintf(output, "CMP >");
661 if (!op->value2)
662 fprintf(output, "=");
663 break;
664 case XPATH_OP_PLUS:
665 if (op->value == 0)
666 fprintf(output, "PLUS -");
667 else if (op->value == 1)
668 fprintf(output, "PLUS +");
669 else if (op->value == 2)
670 fprintf(output, "PLUS unary -");
671 else if (op->value == 3)
672 fprintf(output, "PLUS unary - -");
673 break;
674 case XPATH_OP_MULT:
675 if (op->value == 0)
676 fprintf(output, "MULT *");
677 else if (op->value == 1)
678 fprintf(output, "MULT div");
679 else
680 fprintf(output, "MULT mod");
681 break;
682 case XPATH_OP_UNION:
683 fprintf(output, "UNION"); break;
684 case XPATH_OP_ROOT:
685 fprintf(output, "ROOT"); break;
686 case XPATH_OP_NODE:
687 fprintf(output, "NODE"); break;
688 case XPATH_OP_RESET:
689 fprintf(output, "RESET"); break;
690 case XPATH_OP_SORT:
691 fprintf(output, "SORT"); break;
692 case XPATH_OP_COLLECT: {
693 xmlXPathAxisVal axis = op->value;
694 xmlXPathTestVal test = op->value2;
695 xmlXPathTypeVal type = op->value3;
696 const xmlChar *prefix = op->value4;
697 const xmlChar *name = op->value5;
698
699 fprintf(output, "COLLECT ");
700 switch (axis) {
701 case AXIS_ANCESTOR:
702 fprintf(output, " 'ancestors' "); break;
703 case AXIS_ANCESTOR_OR_SELF:
704 fprintf(output, " 'ancestors-or-self' "); break;
705 case AXIS_ATTRIBUTE:
706 fprintf(output, " 'attributes' "); break;
707 case AXIS_CHILD:
708 fprintf(output, " 'child' "); break;
709 case AXIS_DESCENDANT:
710 fprintf(output, " 'descendant' "); break;
711 case AXIS_DESCENDANT_OR_SELF:
712 fprintf(output, " 'descendant-or-self' "); break;
713 case AXIS_FOLLOWING:
714 fprintf(output, " 'following' "); break;
715 case AXIS_FOLLOWING_SIBLING:
716 fprintf(output, " 'following-siblings' "); break;
717 case AXIS_NAMESPACE:
718 fprintf(output, " 'namespace' "); break;
719 case AXIS_PARENT:
720 fprintf(output, " 'parent' "); break;
721 case AXIS_PRECEDING:
722 fprintf(output, " 'preceding' "); break;
723 case AXIS_PRECEDING_SIBLING:
724 fprintf(output, " 'preceding-sibling' "); break;
725 case AXIS_SELF:
726 fprintf(output, " 'self' "); break;
727 }
728 switch (test) {
729 case NODE_TEST_NONE:
730 fprintf(output, "'none' "); break;
731 case NODE_TEST_TYPE:
732 fprintf(output, "'type' "); break;
733 case NODE_TEST_PI:
734 fprintf(output, "'PI' "); break;
735 case NODE_TEST_ALL:
736 fprintf(output, "'all' "); break;
737 case NODE_TEST_NS:
738 fprintf(output, "'namespace' "); break;
739 case NODE_TEST_NAME:
740 fprintf(output, "'name' "); break;
741 }
742 switch (type) {
743 case NODE_TYPE_NODE:
744 fprintf(output, "'node' "); break;
745 case NODE_TYPE_COMMENT:
746 fprintf(output, "'comment' "); break;
747 case NODE_TYPE_TEXT:
748 fprintf(output, "'text' "); break;
749 case NODE_TYPE_PI:
750 fprintf(output, "'PI' "); break;
751 }
752 if (prefix != NULL)
753 fprintf(output, "%s:", prefix);
754 if (name != NULL)
755 fprintf(output, "%s", name);
756 break;
757
758 }
759 case XPATH_OP_VALUE: {
760 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
761
762 fprintf(output, "ELEM ");
763 xmlXPathDebugDumpObject(output, object, 0);
764 goto finish;
765 }
766 case XPATH_OP_VARIABLE: {
767 const xmlChar *prefix = op->value5;
768 const xmlChar *name = op->value4;
769
770 if (prefix != NULL)
771 fprintf(output, "VARIABLE %s:%s", prefix, name);
772 else
773 fprintf(output, "VARIABLE %s", name);
774 break;
775 }
776 case XPATH_OP_FUNCTION: {
777 int nbargs = op->value;
778 const xmlChar *prefix = op->value5;
779 const xmlChar *name = op->value4;
780
781 if (prefix != NULL)
782 fprintf(output, "FUNCTION %s:%s(%d args)",
783 prefix, name, nbargs);
784 else
785 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
786 break;
787 }
788 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
789 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000790 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +0000791#ifdef LIBXML_XPTR_ENABLED
792 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
793#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000794 default:
795 fprintf(output, "UNKNOWN %d\n", op->op); return;
796 }
797 fprintf(output, "\n");
798finish:
799 if (op->ch1 >= 0)
800 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
801 if (op->ch2 >= 0)
802 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
803}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000804
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000805/**
806 * xmlXPathDebugDumpCompExpr:
807 * @output: the FILE * for the output
808 * @comp: the precompiled XPath expression
809 * @depth: the indentation level.
810 *
811 * Dumps the tree of the compiled XPath expression.
812 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000813void
814xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
815 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000816 int i;
817 char shift[100];
818
819 for (i = 0;((i < depth) && (i < 25));i++)
820 shift[2 * i] = shift[2 * i + 1] = ' ';
821 shift[2 * i] = shift[2 * i + 1] = 0;
822
823 fprintf(output, shift);
824
825 if (comp == NULL) {
826 fprintf(output, "Compiled Expression is NULL\n");
827 return;
828 }
829 fprintf(output, "Compiled Expression : %d elements\n",
830 comp->nbStep);
831 i = comp->last;
832 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
833}
Daniel Veillard017b1082001-06-21 11:20:21 +0000834#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000835
836/************************************************************************
837 * *
838 * Parser stacks related functions and macros *
839 * *
840 ************************************************************************/
841
842/*
843 * Generic function for accessing stacks in the Parser Context
844 */
845
846#define PUSH_AND_POP(type, name) \
847extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
848 if (ctxt->name##Nr >= ctxt->name##Max) { \
849 ctxt->name##Max *= 2; \
850 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
851 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
852 if (ctxt->name##Tab == NULL) { \
853 xmlGenericError(xmlGenericErrorContext, \
854 "realloc failed !\n"); \
855 return(0); \
856 } \
857 } \
858 ctxt->name##Tab[ctxt->name##Nr] = value; \
859 ctxt->name = value; \
860 return(ctxt->name##Nr++); \
861} \
862extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
863 type ret; \
864 if (ctxt->name##Nr <= 0) return(0); \
865 ctxt->name##Nr--; \
866 if (ctxt->name##Nr > 0) \
867 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
868 else \
869 ctxt->name = NULL; \
870 ret = ctxt->name##Tab[ctxt->name##Nr]; \
871 ctxt->name##Tab[ctxt->name##Nr] = 0; \
872 return(ret); \
873} \
874
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000875/**
876 * valuePop:
877 * @ctxt: an XPath evaluation context
878 *
879 * Pops the top XPath object from the value stack
880 *
881 * Returns the XPath object just removed
882 */
883/**
884 * valuePush:
885 * @ctxt: an XPath evaluation context
886 * @value: the XPath object
887 *
888 * Pushes a new XPath object on top of the value stack
889 */
Owen Taylor3473f882001-02-23 17:55:21 +0000890PUSH_AND_POP(xmlXPathObjectPtr, value)
891
Thomas Broyerf06a3d82001-07-16 04:52:57 +0000892/**
893 * xmlXPathPopBoolean:
894 * @ctxt: an XPath parser context
895 *
896 * Pops a boolean from the stack, handling conversion if needed.
897 * Check error with #xmlXPathCheckError.
898 *
899 * Returns the boolean
900 */
901int
902xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
903 xmlXPathObjectPtr obj;
904 int ret;
905
906 obj = valuePop(ctxt);
907 if (obj == NULL) {
908 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
909 return(0);
910 }
911 ret = xmlXPathCastToBoolean(obj);
912 xmlXPathFreeObject(obj);
913 return(ret);
914}
915
916/**
917 * xmlXPathPopNumber:
918 * @ctxt: an XPath parser context
919 *
920 * Pops a number from the stack, handling conversion if needed.
921 * Check error with #xmlXPathCheckError.
922 *
923 * Returns the number
924 */
925double
926xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
927 xmlXPathObjectPtr obj;
928 double ret;
929
930 obj = valuePop(ctxt);
931 if (obj == NULL) {
932 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
933 return(0);
934 }
935 ret = xmlXPathCastToNumber(obj);
936 xmlXPathFreeObject(obj);
937 return(ret);
938}
939
940/**
941 * xmlXPathPopString:
942 * @ctxt: an XPath parser context
943 *
944 * Pops a string from the stack, handling conversion if needed.
945 * Check error with #xmlXPathCheckError.
946 *
947 * Returns the string
948 */
949xmlChar *
950xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
951 xmlXPathObjectPtr obj;
952 xmlChar * ret;
953
954 obj = valuePop(ctxt);
955 if (obj == NULL) {
956 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
957 return(NULL);
958 }
959 ret = xmlXPathCastToString(obj);
960 /* TODO: needs refactoring somewhere else */
961 if (obj->stringval == ret)
962 obj->stringval = NULL;
963 xmlXPathFreeObject(obj);
964 return(ret);
965}
966
967/**
968 * xmlXPathPopNodeSet:
969 * @ctxt: an XPath parser context
970 *
971 * Pops a node-set from the stack, handling conversion if needed.
972 * Check error with #xmlXPathCheckError.
973 *
974 * Returns the node-set
975 */
976xmlNodeSetPtr
977xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
978 xmlXPathObjectPtr obj;
979 xmlNodeSetPtr ret;
980
981 if (ctxt->value == NULL) {
982 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
983 return(NULL);
984 }
985 if (!xmlXPathStackIsNodeSet(ctxt)) {
986 xmlXPathSetTypeError(ctxt);
987 return(NULL);
988 }
989 obj = valuePop(ctxt);
990 ret = obj->nodesetval;
991 xmlXPathFreeNodeSetList(obj);
992 return(ret);
993}
994
995/**
996 * xmlXPathPopExternal:
997 * @ctxt: an XPath parser context
998 *
999 * Pops an external oject from the stack, handling conversion if needed.
1000 * Check error with #xmlXPathCheckError.
1001 *
1002 * Returns the object
1003 */
1004void *
1005xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1006 xmlXPathObjectPtr obj;
1007 void * ret;
1008
1009 if (ctxt->value == NULL) {
1010 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1011 return(NULL);
1012 }
1013 if (ctxt->value->type != XPATH_USERS) {
1014 xmlXPathSetTypeError(ctxt);
1015 return(NULL);
1016 }
1017 obj = valuePop(ctxt);
1018 ret = obj->user;
1019 xmlXPathFreeObject(obj);
1020 return(ret);
1021}
1022
Owen Taylor3473f882001-02-23 17:55:21 +00001023/*
1024 * Macros for accessing the content. Those should be used only by the parser,
1025 * and not exported.
1026 *
1027 * Dirty macros, i.e. one need to make assumption on the context to use them
1028 *
1029 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1030 * CUR returns the current xmlChar value, i.e. a 8 bit value
1031 * in ISO-Latin or UTF-8.
1032 * This should be used internally by the parser
1033 * only to compare to ASCII values otherwise it would break when
1034 * running with UTF-8 encoding.
1035 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1036 * to compare on ASCII based substring.
1037 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1038 * strings within the parser.
1039 * CURRENT Returns the current char value, with the full decoding of
1040 * UTF-8 if we are using this mode. It returns an int.
1041 * NEXT Skip to the next character, this does the proper decoding
1042 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1043 * It returns the pointer to the current xmlChar.
1044 */
1045
1046#define CUR (*ctxt->cur)
1047#define SKIP(val) ctxt->cur += (val)
1048#define NXT(val) ctxt->cur[(val)]
1049#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001050#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1051
1052#define COPY_BUF(l,b,i,v) \
1053 if (l == 1) b[i++] = (xmlChar) v; \
1054 else i += xmlCopyChar(l,&b[i],v)
1055
1056#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001057
1058#define SKIP_BLANKS \
1059 while (IS_BLANK(*(ctxt->cur))) NEXT
1060
1061#define CURRENT (*ctxt->cur)
1062#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1063
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001064
1065#ifndef DBL_DIG
1066#define DBL_DIG 16
1067#endif
1068#ifndef DBL_EPSILON
1069#define DBL_EPSILON 1E-9
1070#endif
1071
1072#define UPPER_DOUBLE 1E9
1073#define LOWER_DOUBLE 1E-5
1074
1075#define INTEGER_DIGITS DBL_DIG
1076#define FRACTION_DIGITS (DBL_DIG + 1)
1077#define EXPONENT_DIGITS (3 + 2)
1078
1079/**
1080 * xmlXPathFormatNumber:
1081 * @number: number to format
1082 * @buffer: output buffer
1083 * @buffersize: size of output buffer
1084 *
1085 * Convert the number into a string representation.
1086 */
1087static void
1088xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1089{
Daniel Veillardcda96922001-08-21 10:56:31 +00001090 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001091 case 1:
1092 if (buffersize > (int)sizeof("+Infinity"))
1093 sprintf(buffer, "+Infinity");
1094 break;
1095 case -1:
1096 if (buffersize > (int)sizeof("-Infinity"))
1097 sprintf(buffer, "-Infinity");
1098 break;
1099 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001100 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001101 if (buffersize > (int)sizeof("NaN"))
1102 sprintf(buffer, "NaN");
1103 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001104 /* 3 is sign, decimal point, and terminating zero */
1105 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1106 int integer_place, fraction_place;
1107 char *ptr;
1108 char *after_fraction;
1109 double absolute_value;
1110 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001111
Bjorn Reese70a9da52001-04-21 16:57:29 +00001112 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001113
Bjorn Reese70a9da52001-04-21 16:57:29 +00001114 /*
1115 * First choose format - scientific or regular floating point.
1116 * In either case, result is in work, and after_fraction points
1117 * just past the fractional part.
1118 */
1119 if ( ((absolute_value > UPPER_DOUBLE) ||
1120 (absolute_value < LOWER_DOUBLE)) &&
1121 (absolute_value != 0.0) ) {
1122 /* Use scientific notation */
1123 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1124 fraction_place = DBL_DIG - 1;
1125 snprintf(work, sizeof(work),"%*.*e",
1126 integer_place, fraction_place, number);
1127 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001128 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001129 else {
1130 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001131 if (absolute_value > 0.0)
1132 integer_place = 1 + (int)log10(absolute_value);
1133 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001134 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001135 fraction_place = (integer_place > 0)
1136 ? DBL_DIG - integer_place
1137 : DBL_DIG;
1138 size = snprintf(work, sizeof(work), "%0.*f",
1139 fraction_place, number);
1140 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001141 }
1142
Bjorn Reese70a9da52001-04-21 16:57:29 +00001143 /* Remove fractional trailing zeroes */
1144 ptr = after_fraction;
1145 while (*(--ptr) == '0')
1146 ;
1147 if (*ptr != '.')
1148 ptr++;
1149 strcpy(ptr, after_fraction);
1150
1151 /* Finally copy result back to caller */
1152 size = strlen(work) + 1;
1153 if (size > buffersize) {
1154 work[buffersize - 1] = 0;
1155 size = buffersize;
1156 }
1157 memcpy(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001158 }
1159 break;
1160 }
1161}
1162
Owen Taylor3473f882001-02-23 17:55:21 +00001163/************************************************************************
1164 * *
1165 * Error handling routines *
1166 * *
1167 ************************************************************************/
1168
1169
1170const char *xmlXPathErrorMessages[] = {
1171 "Ok",
1172 "Number encoding",
1173 "Unfinished litteral",
1174 "Start of litteral",
1175 "Expected $ for variable reference",
1176 "Undefined variable",
1177 "Invalid predicate",
1178 "Invalid expression",
1179 "Missing closing curly brace",
1180 "Unregistered function",
1181 "Invalid operand",
1182 "Invalid type",
1183 "Invalid number of arguments",
1184 "Invalid context size",
1185 "Invalid context position",
1186 "Memory allocation error",
1187 "Syntax error",
1188 "Resource error",
1189 "Sub resource error",
Daniel Veillard61d80a22001-04-27 17:13:01 +00001190 "Undefined namespace prefix",
1191 "Encoding error",
1192 "Char out of XML range"
Owen Taylor3473f882001-02-23 17:55:21 +00001193};
1194
1195/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001196 * xmlXPatherror:
Owen Taylor3473f882001-02-23 17:55:21 +00001197 * @ctxt: the XPath Parser context
1198 * @file: the file name
1199 * @line: the line number
1200 * @no: the error number
1201 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001202 * Formats an error message.
Owen Taylor3473f882001-02-23 17:55:21 +00001203 */
1204void
1205xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
1206 int line, int no) {
1207 int n;
1208 const xmlChar *cur;
1209 const xmlChar *base;
1210
1211 xmlGenericError(xmlGenericErrorContext,
1212 "Error %s:%d: %s\n", file, line,
1213 xmlXPathErrorMessages[no]);
1214
1215 cur = ctxt->cur;
1216 base = ctxt->base;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001217 if ((cur == NULL) || (base == NULL))
1218 return;
1219
Owen Taylor3473f882001-02-23 17:55:21 +00001220 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
1221 cur--;
1222 }
1223 n = 0;
1224 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
1225 cur--;
1226 if ((*cur == '\n') || (*cur == '\r')) cur++;
1227 base = cur;
1228 n = 0;
1229 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1230 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
1231 n++;
1232 }
1233 xmlGenericError(xmlGenericErrorContext, "\n");
1234 cur = ctxt->cur;
1235 while ((*cur == '\n') || (*cur == '\r'))
1236 cur--;
1237 n = 0;
1238 while ((cur != base) && (n++ < 80)) {
1239 xmlGenericError(xmlGenericErrorContext, " ");
1240 base++;
1241 }
1242 xmlGenericError(xmlGenericErrorContext,"^\n");
1243}
1244
1245
1246/************************************************************************
1247 * *
1248 * Routines to handle NodeSets *
1249 * *
1250 ************************************************************************/
1251
1252/**
1253 * xmlXPathCmpNodes:
1254 * @node1: the first node
1255 * @node2: the second node
1256 *
1257 * Compare two nodes w.r.t document order
1258 *
1259 * Returns -2 in case of error 1 if first point < second point, 0 if
1260 * that's the same node, -1 otherwise
1261 */
1262int
1263xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1264 int depth1, depth2;
1265 xmlNodePtr cur, root;
1266
1267 if ((node1 == NULL) || (node2 == NULL))
1268 return(-2);
1269 /*
1270 * a couple of optimizations which will avoid computations in most cases
1271 */
1272 if (node1 == node2)
1273 return(0);
Daniel Veillardb33c2012001-04-25 12:59:04 +00001274 if ((node1->type == XML_NAMESPACE_DECL) ||
1275 (node2->type == XML_NAMESPACE_DECL))
1276 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001277 if (node1 == node2->prev)
1278 return(1);
1279 if (node1 == node2->next)
1280 return(-1);
1281
1282 /*
1283 * compute depth to root
1284 */
1285 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1286 if (cur == node1)
1287 return(1);
1288 depth2++;
1289 }
1290 root = cur;
1291 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1292 if (cur == node2)
1293 return(-1);
1294 depth1++;
1295 }
1296 /*
1297 * Distinct document (or distinct entities :-( ) case.
1298 */
1299 if (root != cur) {
1300 return(-2);
1301 }
1302 /*
1303 * get the nearest common ancestor.
1304 */
1305 while (depth1 > depth2) {
1306 depth1--;
1307 node1 = node1->parent;
1308 }
1309 while (depth2 > depth1) {
1310 depth2--;
1311 node2 = node2->parent;
1312 }
1313 while (node1->parent != node2->parent) {
1314 node1 = node1->parent;
1315 node2 = node2->parent;
1316 /* should not happen but just in case ... */
1317 if ((node1 == NULL) || (node2 == NULL))
1318 return(-2);
1319 }
1320 /*
1321 * Find who's first.
1322 */
1323 if (node1 == node2->next)
1324 return(-1);
1325 for (cur = node1->next;cur != NULL;cur = cur->next)
1326 if (cur == node2)
1327 return(1);
1328 return(-1); /* assume there is no sibling list corruption */
1329}
1330
1331/**
1332 * xmlXPathNodeSetSort:
1333 * @set: the node set
1334 *
1335 * Sort the node set in document order
1336 */
1337void
1338xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001339 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001340 xmlNodePtr tmp;
1341
1342 if (set == NULL)
1343 return;
1344
1345 /* Use Shell's sort to sort the node-set */
1346 len = set->nodeNr;
1347 for (incr = len / 2; incr > 0; incr /= 2) {
1348 for (i = incr; i < len; i++) {
1349 j = i - incr;
1350 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001351 if (xmlXPathCmpNodes(set->nodeTab[j],
1352 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001353 tmp = set->nodeTab[j];
1354 set->nodeTab[j] = set->nodeTab[j + incr];
1355 set->nodeTab[j + incr] = tmp;
1356 j -= incr;
1357 } else
1358 break;
1359 }
1360 }
1361 }
1362}
1363
1364#define XML_NODESET_DEFAULT 10
1365/**
1366 * xmlXPathNodeSetCreate:
1367 * @val: an initial xmlNodePtr, or NULL
1368 *
1369 * Create a new xmlNodeSetPtr of type double and of value @val
1370 *
1371 * Returns the newly created object.
1372 */
1373xmlNodeSetPtr
1374xmlXPathNodeSetCreate(xmlNodePtr val) {
1375 xmlNodeSetPtr ret;
1376
1377 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1378 if (ret == NULL) {
1379 xmlGenericError(xmlGenericErrorContext,
1380 "xmlXPathNewNodeSet: out of memory\n");
1381 return(NULL);
1382 }
1383 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1384 if (val != NULL) {
1385 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1386 sizeof(xmlNodePtr));
1387 if (ret->nodeTab == NULL) {
1388 xmlGenericError(xmlGenericErrorContext,
1389 "xmlXPathNewNodeSet: out of memory\n");
1390 return(NULL);
1391 }
1392 memset(ret->nodeTab, 0 ,
1393 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1394 ret->nodeMax = XML_NODESET_DEFAULT;
1395 ret->nodeTab[ret->nodeNr++] = val;
1396 }
1397 return(ret);
1398}
1399
1400/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001401 * xmlXPathNodeSetContains:
1402 * @cur: the node-set
1403 * @val: the node
1404 *
1405 * checks whether @cur contains @val
1406 *
1407 * Returns true (1) if @cur contains @val, false (0) otherwise
1408 */
1409int
1410xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1411 int i;
1412
1413 for (i = 0; i < cur->nodeNr; i++) {
1414 if (cur->nodeTab[i] == val)
1415 return(1);
1416 }
1417 return(0);
1418}
1419
1420/**
Owen Taylor3473f882001-02-23 17:55:21 +00001421 * xmlXPathNodeSetAdd:
1422 * @cur: the initial node set
1423 * @val: a new xmlNodePtr
1424 *
1425 * add a new xmlNodePtr ot an existing NodeSet
1426 */
1427void
1428xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1429 int i;
1430
1431 if (val == NULL) return;
1432
1433 /*
1434 * check against doublons
1435 */
1436 for (i = 0;i < cur->nodeNr;i++)
1437 if (cur->nodeTab[i] == val) return;
1438
1439 /*
1440 * grow the nodeTab if needed
1441 */
1442 if (cur->nodeMax == 0) {
1443 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1444 sizeof(xmlNodePtr));
1445 if (cur->nodeTab == NULL) {
1446 xmlGenericError(xmlGenericErrorContext,
1447 "xmlXPathNodeSetAdd: out of memory\n");
1448 return;
1449 }
1450 memset(cur->nodeTab, 0 ,
1451 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1452 cur->nodeMax = XML_NODESET_DEFAULT;
1453 } else if (cur->nodeNr == cur->nodeMax) {
1454 xmlNodePtr *temp;
1455
1456 cur->nodeMax *= 2;
1457 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1458 sizeof(xmlNodePtr));
1459 if (temp == NULL) {
1460 xmlGenericError(xmlGenericErrorContext,
1461 "xmlXPathNodeSetAdd: out of memory\n");
1462 return;
1463 }
1464 cur->nodeTab = temp;
1465 }
1466 cur->nodeTab[cur->nodeNr++] = val;
1467}
1468
1469/**
1470 * xmlXPathNodeSetAddUnique:
1471 * @cur: the initial node set
1472 * @val: a new xmlNodePtr
1473 *
1474 * add a new xmlNodePtr ot an existing NodeSet, optimized version
1475 * when we are sure the node is not already in the set.
1476 */
1477void
1478xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1479 if (val == NULL) return;
1480
1481 /*
1482 * grow the nodeTab if needed
1483 */
1484 if (cur->nodeMax == 0) {
1485 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1486 sizeof(xmlNodePtr));
1487 if (cur->nodeTab == NULL) {
1488 xmlGenericError(xmlGenericErrorContext,
1489 "xmlXPathNodeSetAddUnique: out of memory\n");
1490 return;
1491 }
1492 memset(cur->nodeTab, 0 ,
1493 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1494 cur->nodeMax = XML_NODESET_DEFAULT;
1495 } else if (cur->nodeNr == cur->nodeMax) {
1496 xmlNodePtr *temp;
1497
1498 cur->nodeMax *= 2;
1499 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1500 sizeof(xmlNodePtr));
1501 if (temp == NULL) {
1502 xmlGenericError(xmlGenericErrorContext,
1503 "xmlXPathNodeSetAddUnique: out of memory\n");
1504 return;
1505 }
1506 cur->nodeTab = temp;
1507 }
1508 cur->nodeTab[cur->nodeNr++] = val;
1509}
1510
1511/**
1512 * xmlXPathNodeSetMerge:
1513 * @val1: the first NodeSet or NULL
1514 * @val2: the second NodeSet
1515 *
1516 * Merges two nodesets, all nodes from @val2 are added to @val1
1517 * if @val1 is NULL, a new set is created and copied from @val2
1518 *
1519 * Returns val1 once extended or NULL in case of error.
1520 */
1521xmlNodeSetPtr
1522xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001523 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001524
1525 if (val2 == NULL) return(val1);
1526 if (val1 == NULL) {
1527 val1 = xmlXPathNodeSetCreate(NULL);
1528 }
1529
1530 initNr = val1->nodeNr;
1531
1532 for (i = 0;i < val2->nodeNr;i++) {
1533 /*
1534 * check against doublons
1535 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001536 skip = 0;
1537 for (j = 0; j < initNr; j++) {
1538 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1539 skip = 1;
1540 break;
1541 }
1542 }
1543 if (skip)
1544 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001545
1546 /*
1547 * grow the nodeTab if needed
1548 */
1549 if (val1->nodeMax == 0) {
1550 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1551 sizeof(xmlNodePtr));
1552 if (val1->nodeTab == NULL) {
1553 xmlGenericError(xmlGenericErrorContext,
1554 "xmlXPathNodeSetMerge: out of memory\n");
1555 return(NULL);
1556 }
1557 memset(val1->nodeTab, 0 ,
1558 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1559 val1->nodeMax = XML_NODESET_DEFAULT;
1560 } else if (val1->nodeNr == val1->nodeMax) {
1561 xmlNodePtr *temp;
1562
1563 val1->nodeMax *= 2;
1564 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1565 sizeof(xmlNodePtr));
1566 if (temp == NULL) {
1567 xmlGenericError(xmlGenericErrorContext,
1568 "xmlXPathNodeSetMerge: out of memory\n");
1569 return(NULL);
1570 }
1571 val1->nodeTab = temp;
1572 }
1573 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1574 }
1575
1576 return(val1);
1577}
1578
1579/**
1580 * xmlXPathNodeSetDel:
1581 * @cur: the initial node set
1582 * @val: an xmlNodePtr
1583 *
1584 * Removes an xmlNodePtr from an existing NodeSet
1585 */
1586void
1587xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
1588 int i;
1589
1590 if (cur == NULL) return;
1591 if (val == NULL) return;
1592
1593 /*
1594 * check against doublons
1595 */
1596 for (i = 0;i < cur->nodeNr;i++)
1597 if (cur->nodeTab[i] == val) break;
1598
1599 if (i >= cur->nodeNr) {
1600#ifdef DEBUG
1601 xmlGenericError(xmlGenericErrorContext,
1602 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
1603 val->name);
1604#endif
1605 return;
1606 }
1607 cur->nodeNr--;
1608 for (;i < cur->nodeNr;i++)
1609 cur->nodeTab[i] = cur->nodeTab[i + 1];
1610 cur->nodeTab[cur->nodeNr] = NULL;
1611}
1612
1613/**
1614 * xmlXPathNodeSetRemove:
1615 * @cur: the initial node set
1616 * @val: the index to remove
1617 *
1618 * Removes an entry from an existing NodeSet list.
1619 */
1620void
1621xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
1622 if (cur == NULL) return;
1623 if (val >= cur->nodeNr) return;
1624 cur->nodeNr--;
1625 for (;val < cur->nodeNr;val++)
1626 cur->nodeTab[val] = cur->nodeTab[val + 1];
1627 cur->nodeTab[cur->nodeNr] = NULL;
1628}
1629
1630/**
1631 * xmlXPathFreeNodeSet:
1632 * @obj: the xmlNodeSetPtr to free
1633 *
1634 * Free the NodeSet compound (not the actual nodes !).
1635 */
1636void
1637xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
1638 if (obj == NULL) return;
1639 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001640 xmlFree(obj->nodeTab);
1641 }
Owen Taylor3473f882001-02-23 17:55:21 +00001642 xmlFree(obj);
1643}
1644
1645/**
1646 * xmlXPathFreeValueTree:
1647 * @obj: the xmlNodeSetPtr to free
1648 *
1649 * Free the NodeSet compound and the actual tree, this is different
1650 * from xmlXPathFreeNodeSet()
1651 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001652static void
Owen Taylor3473f882001-02-23 17:55:21 +00001653xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
1654 int i;
1655
1656 if (obj == NULL) return;
1657 for (i = 0;i < obj->nodeNr;i++)
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00001658 if (obj->nodeTab[i] != NULL)
Daniel Veillardbbd51d52001-02-24 03:07:03 +00001659 xmlFreeNodeList(obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001660
1661 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001662 xmlFree(obj->nodeTab);
1663 }
Owen Taylor3473f882001-02-23 17:55:21 +00001664 xmlFree(obj);
1665}
1666
1667#if defined(DEBUG) || defined(DEBUG_STEP)
1668/**
1669 * xmlGenericErrorContextNodeSet:
1670 * @output: a FILE * for the output
1671 * @obj: the xmlNodeSetPtr to free
1672 *
1673 * Quick display of a NodeSet
1674 */
1675void
1676xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
1677 int i;
1678
1679 if (output == NULL) output = xmlGenericErrorContext;
1680 if (obj == NULL) {
1681 fprintf(output, "NodeSet == NULL !\n");
1682 return;
1683 }
1684 if (obj->nodeNr == 0) {
1685 fprintf(output, "NodeSet is empty\n");
1686 return;
1687 }
1688 if (obj->nodeTab == NULL) {
1689 fprintf(output, " nodeTab == NULL !\n");
1690 return;
1691 }
1692 for (i = 0; i < obj->nodeNr; i++) {
1693 if (obj->nodeTab[i] == NULL) {
1694 fprintf(output, " NULL !\n");
1695 return;
1696 }
1697 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
1698 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
1699 fprintf(output, " /");
1700 else if (obj->nodeTab[i]->name == NULL)
1701 fprintf(output, " noname!");
1702 else fprintf(output, " %s", obj->nodeTab[i]->name);
1703 }
1704 fprintf(output, "\n");
1705}
1706#endif
1707
1708/**
1709 * xmlXPathNewNodeSet:
1710 * @val: the NodePtr value
1711 *
1712 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1713 * it with the single Node @val
1714 *
1715 * Returns the newly created object.
1716 */
1717xmlXPathObjectPtr
1718xmlXPathNewNodeSet(xmlNodePtr val) {
1719 xmlXPathObjectPtr ret;
1720
1721 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1722 if (ret == NULL) {
1723 xmlGenericError(xmlGenericErrorContext,
1724 "xmlXPathNewNodeSet: out of memory\n");
1725 return(NULL);
1726 }
1727 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1728 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00001729 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001730 ret->nodesetval = xmlXPathNodeSetCreate(val);
1731 return(ret);
1732}
1733
1734/**
1735 * xmlXPathNewValueTree:
1736 * @val: the NodePtr value
1737 *
1738 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
1739 * it with the tree root @val
1740 *
1741 * Returns the newly created object.
1742 */
1743xmlXPathObjectPtr
1744xmlXPathNewValueTree(xmlNodePtr val) {
1745 xmlXPathObjectPtr ret;
1746
1747 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1748 if (ret == NULL) {
1749 xmlGenericError(xmlGenericErrorContext,
1750 "xmlXPathNewNodeSet: out of memory\n");
1751 return(NULL);
1752 }
1753 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1754 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00001755 ret->boolval = 1;
1756 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00001757 ret->nodesetval = xmlXPathNodeSetCreate(val);
1758 return(ret);
1759}
1760
1761/**
1762 * xmlXPathNewNodeSetList:
1763 * @val: an existing NodeSet
1764 *
1765 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1766 * it with the Nodeset @val
1767 *
1768 * Returns the newly created object.
1769 */
1770xmlXPathObjectPtr
1771xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
1772 xmlXPathObjectPtr ret;
1773 int i;
1774
1775 if (val == NULL)
1776 ret = NULL;
1777 else if (val->nodeTab == NULL)
1778 ret = xmlXPathNewNodeSet(NULL);
1779 else
1780 {
1781 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
1782 for (i = 1; i < val->nodeNr; ++i)
1783 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
1784 }
1785
1786 return(ret);
1787}
1788
1789/**
1790 * xmlXPathWrapNodeSet:
1791 * @val: the NodePtr value
1792 *
1793 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1794 *
1795 * Returns the newly created object.
1796 */
1797xmlXPathObjectPtr
1798xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
1799 xmlXPathObjectPtr ret;
1800
1801 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1802 if (ret == NULL) {
1803 xmlGenericError(xmlGenericErrorContext,
1804 "xmlXPathWrapNodeSet: out of memory\n");
1805 return(NULL);
1806 }
1807 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1808 ret->type = XPATH_NODESET;
1809 ret->nodesetval = val;
1810 return(ret);
1811}
1812
1813/**
1814 * xmlXPathFreeNodeSetList:
1815 * @obj: an existing NodeSetList object
1816 *
1817 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
1818 * the list contrary to xmlXPathFreeObject().
1819 */
1820void
1821xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
1822 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001823 xmlFree(obj);
1824}
1825
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001826/**
1827 * xmlXPathDifference:
1828 * @nodes1: a node-set
1829 * @nodes2: a node-set
1830 *
1831 * Implements the EXSLT - Sets difference() function:
1832 * node-set set:difference (node-set, node-set)
1833 *
1834 * Returns the difference between the two node sets, or nodes1 if
1835 * nodes2 is empty
1836 */
1837xmlNodeSetPtr
1838xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
1839 xmlNodeSetPtr ret;
1840 int i, l1;
1841 xmlNodePtr cur;
1842
1843 if (xmlXPathNodeSetIsEmpty(nodes2))
1844 return(nodes1);
1845
1846 ret = xmlXPathNodeSetCreate(NULL);
1847 if (xmlXPathNodeSetIsEmpty(nodes1))
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 * xmlXPathIntersection:
1862 * @nodes1: a node-set
1863 * @nodes2: a node-set
1864 *
1865 * Implements the EXSLT - Sets intersection() function:
1866 * node-set set:intersection (node-set, node-set)
1867 *
1868 * Returns a node set comprising the nodes that are within both the
1869 * node sets passed as arguments
1870 */
1871xmlNodeSetPtr
1872xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
1873 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
1874 int i, l1;
1875 xmlNodePtr cur;
1876
1877 if (xmlXPathNodeSetIsEmpty(nodes1))
1878 return(ret);
1879 if (xmlXPathNodeSetIsEmpty(nodes2))
1880 return(ret);
1881
1882 l1 = xmlXPathNodeSetGetLength(nodes1);
1883
1884 for (i = 0; i < l1; i++) {
1885 cur = xmlXPathNodeSetItem(nodes1, i);
1886 if (xmlXPathNodeSetContains(nodes2, cur))
1887 xmlXPathNodeSetAddUnique(ret, cur);
1888 }
1889 return(ret);
1890}
1891
1892/**
1893 * xmlXPathDistinctSorted:
1894 * @nodes: a node-set, sorted by document order
1895 *
1896 * Implements the EXSLT - Sets distinct() function:
1897 * node-set set:distinct (node-set)
1898 *
1899 * Returns a subset of the nodes contained in @nodes, or @nodes if
1900 * it is empty
1901 */
1902xmlNodeSetPtr
1903xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
1904 xmlNodeSetPtr ret;
1905 xmlHashTablePtr hash;
1906 int i, l;
1907 xmlChar * strval;
1908 xmlNodePtr cur;
1909
1910 if (xmlXPathNodeSetIsEmpty(nodes))
1911 return(nodes);
1912
1913 ret = xmlXPathNodeSetCreate(NULL);
1914 l = xmlXPathNodeSetGetLength(nodes);
1915 hash = xmlHashCreate (l);
1916 for (i = 0; i < l; i++) {
1917 cur = xmlXPathNodeSetItem(nodes, i);
1918 strval = xmlXPathCastNodeToString(cur);
1919 if (xmlHashLookup(hash, strval) == NULL) {
1920 xmlHashAddEntry(hash, strval, strval);
1921 xmlXPathNodeSetAddUnique(ret, cur);
1922 } else {
1923 xmlFree(strval);
1924 }
1925 }
1926 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
1927 return(ret);
1928}
1929
1930/**
1931 * xmlXPathDistinct:
1932 * @nodes: a node-set
1933 *
1934 * Implements the EXSLT - Sets distinct() function:
1935 * node-set set:distinct (node-set)
1936 * @nodes is sorted by document order, then #exslSetsDistinctSorted
1937 * is called with the sorted node-set
1938 *
1939 * Returns a subset of the nodes contained in @nodes, or @nodes if
1940 * it is empty
1941 */
1942xmlNodeSetPtr
1943xmlXPathDistinct (xmlNodeSetPtr nodes) {
1944 if (xmlXPathNodeSetIsEmpty(nodes))
1945 return(nodes);
1946
1947 xmlXPathNodeSetSort(nodes);
1948 return(xmlXPathDistinctSorted(nodes));
1949}
1950
1951/**
1952 * xmlXPathHasSameNodes:
1953 * @nodes1: a node-set
1954 * @nodes2: a node-set
1955 *
1956 * Implements the EXSLT - Sets has-same-nodes function:
1957 * boolean set:has-same-node(node-set, node-set)
1958 *
1959 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
1960 * otherwise
1961 */
1962int
1963xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
1964 int i, l;
1965 xmlNodePtr cur;
1966
1967 if (xmlXPathNodeSetIsEmpty(nodes1) ||
1968 xmlXPathNodeSetIsEmpty(nodes2))
1969 return(0);
1970
1971 l = xmlXPathNodeSetGetLength(nodes1);
1972 for (i = 0; i < l; i++) {
1973 cur = xmlXPathNodeSetItem(nodes1, i);
1974 if (xmlXPathNodeSetContains(nodes2, cur))
1975 return(1);
1976 }
1977 return(0);
1978}
1979
1980/**
1981 * xmlXPathNodeLeadingSorted:
1982 * @nodes: a node-set, sorted by document order
1983 * @node: a node
1984 *
1985 * Implements the EXSLT - Sets leading() function:
1986 * node-set set:leading (node-set, node-set)
1987 *
1988 * Returns the nodes in @nodes that precede @node in document order,
1989 * @nodes if @node is NULL or an empty node-set if @nodes
1990 * doesn't contain @node
1991 */
1992xmlNodeSetPtr
1993xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
1994 int i, l;
1995 xmlNodePtr cur;
1996 xmlNodeSetPtr ret;
1997
1998 if (node == NULL)
1999 return(nodes);
2000
2001 ret = xmlXPathNodeSetCreate(NULL);
2002 if (xmlXPathNodeSetIsEmpty(nodes) ||
2003 (!xmlXPathNodeSetContains(nodes, node)))
2004 return(ret);
2005
2006 l = xmlXPathNodeSetGetLength(nodes);
2007 for (i = 0; i < l; i++) {
2008 cur = xmlXPathNodeSetItem(nodes, i);
2009 if (cur == node)
2010 break;
2011 xmlXPathNodeSetAddUnique(ret, cur);
2012 }
2013 return(ret);
2014}
2015
2016/**
2017 * xmlXPathNodeLeading:
2018 * @nodes: a node-set
2019 * @node: a node
2020 *
2021 * Implements the EXSLT - Sets leading() function:
2022 * node-set set:leading (node-set, node-set)
2023 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2024 * is called.
2025 *
2026 * Returns the nodes in @nodes that precede @node in document order,
2027 * @nodes if @node is NULL or an empty node-set if @nodes
2028 * doesn't contain @node
2029 */
2030xmlNodeSetPtr
2031xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2032 xmlXPathNodeSetSort(nodes);
2033 return(xmlXPathNodeLeadingSorted(nodes, node));
2034}
2035
2036/**
2037 * xmlXPathLeadingSorted:
2038 * @nodes1: a node-set, sorted by document order
2039 * @nodes2: a node-set, sorted by document order
2040 *
2041 * Implements the EXSLT - Sets leading() function:
2042 * node-set set:leading (node-set, node-set)
2043 *
2044 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2045 * in document order, @nodes1 if @nodes2 is NULL or empty or
2046 * an empty node-set if @nodes1 doesn't contain @nodes2
2047 */
2048xmlNodeSetPtr
2049xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2050 if (xmlXPathNodeSetIsEmpty(nodes2))
2051 return(nodes1);
2052 return(xmlXPathNodeLeadingSorted(nodes1,
2053 xmlXPathNodeSetItem(nodes2, 1)));
2054}
2055
2056/**
2057 * xmlXPathLeading:
2058 * @nodes1: a node-set
2059 * @nodes2: a node-set
2060 *
2061 * Implements the EXSLT - Sets leading() function:
2062 * node-set set:leading (node-set, node-set)
2063 * @nodes1 and @nodes2 are sorted by document order, then
2064 * #exslSetsLeadingSorted is called.
2065 *
2066 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2067 * in document order, @nodes1 if @nodes2 is NULL or empty or
2068 * an empty node-set if @nodes1 doesn't contain @nodes2
2069 */
2070xmlNodeSetPtr
2071xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2072 if (xmlXPathNodeSetIsEmpty(nodes2))
2073 return(nodes1);
2074 if (xmlXPathNodeSetIsEmpty(nodes1))
2075 return(xmlXPathNodeSetCreate(NULL));
2076 xmlXPathNodeSetSort(nodes1);
2077 xmlXPathNodeSetSort(nodes2);
2078 return(xmlXPathNodeLeadingSorted(nodes1,
2079 xmlXPathNodeSetItem(nodes2, 1)));
2080}
2081
2082/**
2083 * xmlXPathNodeTrailingSorted:
2084 * @nodes: a node-set, sorted by document order
2085 * @node: a node
2086 *
2087 * Implements the EXSLT - Sets trailing() function:
2088 * node-set set:trailing (node-set, node-set)
2089 *
2090 * Returns the nodes in @nodes that follow @node in document order,
2091 * @nodes if @node is NULL or an empty node-set if @nodes
2092 * doesn't contain @node
2093 */
2094xmlNodeSetPtr
2095xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2096 int i, l;
2097 xmlNodePtr cur;
2098 xmlNodeSetPtr ret;
2099
2100 if (node == NULL)
2101 return(nodes);
2102
2103 ret = xmlXPathNodeSetCreate(NULL);
2104 if (xmlXPathNodeSetIsEmpty(nodes) ||
2105 (!xmlXPathNodeSetContains(nodes, node)))
2106 return(ret);
2107
2108 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002109 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002110 cur = xmlXPathNodeSetItem(nodes, i);
2111 if (cur == node)
2112 break;
2113 xmlXPathNodeSetAddUnique(ret, cur);
2114 }
2115 return(ret);
2116}
2117
2118/**
2119 * xmlXPathNodeTrailing:
2120 * @nodes: a node-set
2121 * @node: a node
2122 *
2123 * Implements the EXSLT - Sets trailing() function:
2124 * node-set set:trailing (node-set, node-set)
2125 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2126 * is called.
2127 *
2128 * Returns the nodes in @nodes that follow @node in document order,
2129 * @nodes if @node is NULL or an empty node-set if @nodes
2130 * doesn't contain @node
2131 */
2132xmlNodeSetPtr
2133xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2134 xmlXPathNodeSetSort(nodes);
2135 return(xmlXPathNodeTrailingSorted(nodes, node));
2136}
2137
2138/**
2139 * xmlXPathTrailingSorted:
2140 * @nodes1: a node-set, sorted by document order
2141 * @nodes2: a node-set, sorted by document order
2142 *
2143 * Implements the EXSLT - Sets trailing() function:
2144 * node-set set:trailing (node-set, node-set)
2145 *
2146 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2147 * in document order, @nodes1 if @nodes2 is NULL or empty or
2148 * an empty node-set if @nodes1 doesn't contain @nodes2
2149 */
2150xmlNodeSetPtr
2151xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2152 if (xmlXPathNodeSetIsEmpty(nodes2))
2153 return(nodes1);
2154 return(xmlXPathNodeTrailingSorted(nodes1,
2155 xmlXPathNodeSetItem(nodes2, 0)));
2156}
2157
2158/**
2159 * xmlXPathTrailing:
2160 * @nodes1: a node-set
2161 * @nodes2: a node-set
2162 *
2163 * Implements the EXSLT - Sets trailing() function:
2164 * node-set set:trailing (node-set, node-set)
2165 * @nodes1 and @nodes2 are sorted by document order, then
2166 * #xmlXPathTrailingSorted is called.
2167 *
2168 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2169 * in document order, @nodes1 if @nodes2 is NULL or empty or
2170 * an empty node-set if @nodes1 doesn't contain @nodes2
2171 */
2172xmlNodeSetPtr
2173xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2174 if (xmlXPathNodeSetIsEmpty(nodes2))
2175 return(nodes1);
2176 if (xmlXPathNodeSetIsEmpty(nodes1))
2177 return(xmlXPathNodeSetCreate(NULL));
2178 xmlXPathNodeSetSort(nodes1);
2179 xmlXPathNodeSetSort(nodes2);
2180 return(xmlXPathNodeTrailingSorted(nodes1,
2181 xmlXPathNodeSetItem(nodes2, 0)));
2182}
2183
Owen Taylor3473f882001-02-23 17:55:21 +00002184/************************************************************************
2185 * *
2186 * Routines to handle extra functions *
2187 * *
2188 ************************************************************************/
2189
2190/**
2191 * xmlXPathRegisterFunc:
2192 * @ctxt: the XPath context
2193 * @name: the function name
2194 * @f: the function implementation or NULL
2195 *
2196 * Register a new function. If @f is NULL it unregisters the function
2197 *
2198 * Returns 0 in case of success, -1 in case of error
2199 */
2200int
2201xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2202 xmlXPathFunction f) {
2203 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2204}
2205
2206/**
2207 * xmlXPathRegisterFuncNS:
2208 * @ctxt: the XPath context
2209 * @name: the function name
2210 * @ns_uri: the function namespace URI
2211 * @f: the function implementation or NULL
2212 *
2213 * Register a new function. If @f is NULL it unregisters the function
2214 *
2215 * Returns 0 in case of success, -1 in case of error
2216 */
2217int
2218xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2219 const xmlChar *ns_uri, xmlXPathFunction f) {
2220 if (ctxt == NULL)
2221 return(-1);
2222 if (name == NULL)
2223 return(-1);
2224
2225 if (ctxt->funcHash == NULL)
2226 ctxt->funcHash = xmlHashCreate(0);
2227 if (ctxt->funcHash == NULL)
2228 return(-1);
2229 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2230}
2231
2232/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002233 * xmlXPathRegisterFuncLookup:
2234 * @ctxt: the XPath context
2235 * @f: the lookup function
2236 * @data: the lookup data
2237 *
2238 * Registers an external mecanism to do function lookup.
2239 */
2240void
2241xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2242 xmlXPathFuncLookupFunc f,
2243 void *funcCtxt) {
2244 if (ctxt == NULL)
2245 return;
2246 ctxt->funcLookupFunc = (void *) f;
2247 ctxt->funcLookupData = funcCtxt;
2248}
2249
2250/**
Owen Taylor3473f882001-02-23 17:55:21 +00002251 * xmlXPathFunctionLookup:
2252 * @ctxt: the XPath context
2253 * @name: the function name
2254 *
2255 * Search in the Function array of the context for the given
2256 * function.
2257 *
2258 * Returns the xmlXPathFunction or NULL if not found
2259 */
2260xmlXPathFunction
2261xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002262 if (ctxt == NULL)
2263 return (NULL);
2264
2265 if (ctxt->funcLookupFunc != NULL) {
2266 xmlXPathFunction ret;
2267
2268 ret = ((xmlXPathFuncLookupFunc) ctxt->funcLookupFunc)
2269 (ctxt->funcLookupData, name, NULL);
2270 if (ret != NULL)
2271 return(ret);
2272 }
Owen Taylor3473f882001-02-23 17:55:21 +00002273 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2274}
2275
2276/**
2277 * xmlXPathFunctionLookupNS:
2278 * @ctxt: the XPath context
2279 * @name: the function name
2280 * @ns_uri: the function namespace URI
2281 *
2282 * Search in the Function array of the context for the given
2283 * function.
2284 *
2285 * Returns the xmlXPathFunction or NULL if not found
2286 */
2287xmlXPathFunction
2288xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2289 const xmlChar *ns_uri) {
2290 if (ctxt == NULL)
2291 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002292 if (name == NULL)
2293 return(NULL);
2294
Thomas Broyerba4ad322001-07-26 16:55:21 +00002295 if (ctxt->funcLookupFunc != NULL) {
2296 xmlXPathFunction ret;
2297
2298 ret = ((xmlXPathFuncLookupFunc) ctxt->funcLookupFunc)
2299 (ctxt->funcLookupData, name, ns_uri);
2300 if (ret != NULL)
2301 return(ret);
2302 }
2303
2304 if (ctxt->funcHash == NULL)
2305 return(NULL);
2306
Owen Taylor3473f882001-02-23 17:55:21 +00002307 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2308}
2309
2310/**
2311 * xmlXPathRegisteredFuncsCleanup:
2312 * @ctxt: the XPath context
2313 *
2314 * Cleanup the XPath context data associated to registered functions
2315 */
2316void
2317xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2318 if (ctxt == NULL)
2319 return;
2320
2321 xmlHashFree(ctxt->funcHash, NULL);
2322 ctxt->funcHash = NULL;
2323}
2324
2325/************************************************************************
2326 * *
2327 * Routines to handle Variable *
2328 * *
2329 ************************************************************************/
2330
2331/**
2332 * xmlXPathRegisterVariable:
2333 * @ctxt: the XPath context
2334 * @name: the variable name
2335 * @value: the variable value or NULL
2336 *
2337 * Register a new variable value. If @value is NULL it unregisters
2338 * the variable
2339 *
2340 * Returns 0 in case of success, -1 in case of error
2341 */
2342int
2343xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2344 xmlXPathObjectPtr value) {
2345 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2346}
2347
2348/**
2349 * xmlXPathRegisterVariableNS:
2350 * @ctxt: the XPath context
2351 * @name: the variable name
2352 * @ns_uri: the variable namespace URI
2353 * @value: the variable value or NULL
2354 *
2355 * Register a new variable value. If @value is NULL it unregisters
2356 * the variable
2357 *
2358 * Returns 0 in case of success, -1 in case of error
2359 */
2360int
2361xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2362 const xmlChar *ns_uri,
2363 xmlXPathObjectPtr value) {
2364 if (ctxt == NULL)
2365 return(-1);
2366 if (name == NULL)
2367 return(-1);
2368
2369 if (ctxt->varHash == NULL)
2370 ctxt->varHash = xmlHashCreate(0);
2371 if (ctxt->varHash == NULL)
2372 return(-1);
2373 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2374 (void *) value,
2375 (xmlHashDeallocator)xmlXPathFreeObject));
2376}
2377
2378/**
2379 * xmlXPathRegisterVariableLookup:
2380 * @ctxt: the XPath context
2381 * @f: the lookup function
2382 * @data: the lookup data
2383 *
2384 * register an external mechanism to do variable lookup
2385 */
2386void
2387xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2388 xmlXPathVariableLookupFunc f, void *data) {
2389 if (ctxt == NULL)
2390 return;
2391 ctxt->varLookupFunc = (void *) f;
2392 ctxt->varLookupData = data;
2393}
2394
2395/**
2396 * xmlXPathVariableLookup:
2397 * @ctxt: the XPath context
2398 * @name: the variable name
2399 *
2400 * Search in the Variable array of the context for the given
2401 * variable value.
2402 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002403 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002404 */
2405xmlXPathObjectPtr
2406xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2407 if (ctxt == NULL)
2408 return(NULL);
2409
2410 if (ctxt->varLookupFunc != NULL) {
2411 xmlXPathObjectPtr ret;
2412
2413 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2414 (ctxt->varLookupData, name, NULL);
2415 if (ret != NULL) return(ret);
2416 }
2417 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2418}
2419
2420/**
2421 * xmlXPathVariableLookupNS:
2422 * @ctxt: the XPath context
2423 * @name: the variable name
2424 * @ns_uri: the variable namespace URI
2425 *
2426 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002427 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002428 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002429 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002430 */
2431xmlXPathObjectPtr
2432xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2433 const xmlChar *ns_uri) {
2434 if (ctxt == NULL)
2435 return(NULL);
2436
2437 if (ctxt->varLookupFunc != NULL) {
2438 xmlXPathObjectPtr ret;
2439
2440 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2441 (ctxt->varLookupData, name, ns_uri);
2442 if (ret != NULL) return(ret);
2443 }
2444
2445 if (ctxt->varHash == NULL)
2446 return(NULL);
2447 if (name == NULL)
2448 return(NULL);
2449
Daniel Veillard8c357d52001-07-03 23:43:33 +00002450 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2451 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002452}
2453
2454/**
2455 * xmlXPathRegisteredVariablesCleanup:
2456 * @ctxt: the XPath context
2457 *
2458 * Cleanup the XPath context data associated to registered variables
2459 */
2460void
2461xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2462 if (ctxt == NULL)
2463 return;
2464
Daniel Veillard76d66f42001-05-16 21:05:17 +00002465 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002466 ctxt->varHash = NULL;
2467}
2468
2469/**
2470 * xmlXPathRegisterNs:
2471 * @ctxt: the XPath context
2472 * @prefix: the namespace prefix
2473 * @ns_uri: the namespace name
2474 *
2475 * Register a new namespace. If @ns_uri is NULL it unregisters
2476 * the namespace
2477 *
2478 * Returns 0 in case of success, -1 in case of error
2479 */
2480int
2481xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2482 const xmlChar *ns_uri) {
2483 if (ctxt == NULL)
2484 return(-1);
2485 if (prefix == NULL)
2486 return(-1);
2487
2488 if (ctxt->nsHash == NULL)
2489 ctxt->nsHash = xmlHashCreate(10);
2490 if (ctxt->nsHash == NULL)
2491 return(-1);
2492 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) ns_uri,
2493 (xmlHashDeallocator)xmlFree));
2494}
2495
2496/**
2497 * xmlXPathNsLookup:
2498 * @ctxt: the XPath context
2499 * @prefix: the namespace prefix value
2500 *
2501 * Search in the namespace declaration array of the context for the given
2502 * namespace name associated to the given prefix
2503 *
2504 * Returns the value or NULL if not found
2505 */
2506const xmlChar *
2507xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2508 if (ctxt == NULL)
2509 return(NULL);
2510 if (prefix == NULL)
2511 return(NULL);
2512
2513#ifdef XML_XML_NAMESPACE
2514 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
2515 return(XML_XML_NAMESPACE);
2516#endif
2517
Daniel Veillardc8f620b2001-04-30 20:31:33 +00002518 if (ctxt->namespaces != NULL) {
2519 int i;
2520
2521 for (i = 0;i < ctxt->nsNr;i++) {
2522 if ((ctxt->namespaces[i] != NULL) &&
2523 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
2524 return(ctxt->namespaces[i]->href);
2525 }
2526 }
Owen Taylor3473f882001-02-23 17:55:21 +00002527
2528 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
2529}
2530
2531/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002532 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00002533 * @ctxt: the XPath context
2534 *
2535 * Cleanup the XPath context data associated to registered variables
2536 */
2537void
2538xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2539 if (ctxt == NULL)
2540 return;
2541
2542 xmlHashFree(ctxt->nsHash, NULL);
2543 ctxt->nsHash = NULL;
2544}
2545
2546/************************************************************************
2547 * *
2548 * Routines to handle Values *
2549 * *
2550 ************************************************************************/
2551
2552/* Allocations are terrible, one need to optimize all this !!! */
2553
2554/**
2555 * xmlXPathNewFloat:
2556 * @val: the double value
2557 *
2558 * Create a new xmlXPathObjectPtr of type double and of value @val
2559 *
2560 * Returns the newly created object.
2561 */
2562xmlXPathObjectPtr
2563xmlXPathNewFloat(double val) {
2564 xmlXPathObjectPtr ret;
2565
2566 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2567 if (ret == NULL) {
2568 xmlGenericError(xmlGenericErrorContext,
2569 "xmlXPathNewFloat: out of memory\n");
2570 return(NULL);
2571 }
2572 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2573 ret->type = XPATH_NUMBER;
2574 ret->floatval = val;
2575 return(ret);
2576}
2577
2578/**
2579 * xmlXPathNewBoolean:
2580 * @val: the boolean value
2581 *
2582 * Create a new xmlXPathObjectPtr of type boolean and of value @val
2583 *
2584 * Returns the newly created object.
2585 */
2586xmlXPathObjectPtr
2587xmlXPathNewBoolean(int val) {
2588 xmlXPathObjectPtr ret;
2589
2590 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2591 if (ret == NULL) {
2592 xmlGenericError(xmlGenericErrorContext,
2593 "xmlXPathNewBoolean: out of memory\n");
2594 return(NULL);
2595 }
2596 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2597 ret->type = XPATH_BOOLEAN;
2598 ret->boolval = (val != 0);
2599 return(ret);
2600}
2601
2602/**
2603 * xmlXPathNewString:
2604 * @val: the xmlChar * value
2605 *
2606 * Create a new xmlXPathObjectPtr of type string and of value @val
2607 *
2608 * Returns the newly created object.
2609 */
2610xmlXPathObjectPtr
2611xmlXPathNewString(const xmlChar *val) {
2612 xmlXPathObjectPtr ret;
2613
2614 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2615 if (ret == NULL) {
2616 xmlGenericError(xmlGenericErrorContext,
2617 "xmlXPathNewString: out of memory\n");
2618 return(NULL);
2619 }
2620 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2621 ret->type = XPATH_STRING;
2622 if (val != NULL)
2623 ret->stringval = xmlStrdup(val);
2624 else
2625 ret->stringval = xmlStrdup((const xmlChar *)"");
2626 return(ret);
2627}
2628
2629/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002630 * xmlXPathWrapString:
2631 * @val: the xmlChar * value
2632 *
2633 * Wraps the @val string into an XPath object.
2634 *
2635 * Returns the newly created object.
2636 */
2637xmlXPathObjectPtr
2638xmlXPathWrapString (xmlChar *val) {
2639 xmlXPathObjectPtr ret;
2640
2641 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2642 if (ret == NULL) {
2643 xmlGenericError(xmlGenericErrorContext,
2644 "xmlXPathWrapString: out of memory\n");
2645 return(NULL);
2646 }
2647 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2648 ret->type = XPATH_STRING;
2649 ret->stringval = val;
2650 return(ret);
2651}
2652
2653/**
Owen Taylor3473f882001-02-23 17:55:21 +00002654 * xmlXPathNewCString:
2655 * @val: the char * value
2656 *
2657 * Create a new xmlXPathObjectPtr of type string and of value @val
2658 *
2659 * Returns the newly created object.
2660 */
2661xmlXPathObjectPtr
2662xmlXPathNewCString(const char *val) {
2663 xmlXPathObjectPtr ret;
2664
2665 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2666 if (ret == NULL) {
2667 xmlGenericError(xmlGenericErrorContext,
2668 "xmlXPathNewCString: out of memory\n");
2669 return(NULL);
2670 }
2671 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2672 ret->type = XPATH_STRING;
2673 ret->stringval = xmlStrdup(BAD_CAST val);
2674 return(ret);
2675}
2676
2677/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002678 * xmlXPathWrapCString:
2679 * @val: the char * value
2680 *
2681 * Wraps a string into an XPath object.
2682 *
2683 * Returns the newly created object.
2684 */
2685xmlXPathObjectPtr
2686xmlXPathWrapCString (char * val) {
2687 return(xmlXPathWrapString((xmlChar *)(val)));
2688}
2689
2690/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002691 * xmlXPathWrapExternal:
2692 * @val: the user data
2693 *
2694 * Wraps the @val data into an XPath object.
2695 *
2696 * Returns the newly created object.
2697 */
2698xmlXPathObjectPtr
2699xmlXPathWrapExternal (void *val) {
2700 xmlXPathObjectPtr ret;
2701
2702 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2703 if (ret == NULL) {
2704 xmlGenericError(xmlGenericErrorContext,
2705 "xmlXPathWrapString: out of memory\n");
2706 return(NULL);
2707 }
2708 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2709 ret->type = XPATH_USERS;
2710 ret->user = val;
2711 return(ret);
2712}
2713
2714/**
Owen Taylor3473f882001-02-23 17:55:21 +00002715 * xmlXPathObjectCopy:
2716 * @val: the original object
2717 *
2718 * allocate a new copy of a given object
2719 *
2720 * Returns the newly created object.
2721 */
2722xmlXPathObjectPtr
2723xmlXPathObjectCopy(xmlXPathObjectPtr val) {
2724 xmlXPathObjectPtr ret;
2725
2726 if (val == NULL)
2727 return(NULL);
2728
2729 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2730 if (ret == NULL) {
2731 xmlGenericError(xmlGenericErrorContext,
2732 "xmlXPathObjectCopy: out of memory\n");
2733 return(NULL);
2734 }
2735 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
2736 switch (val->type) {
2737 case XPATH_BOOLEAN:
2738 case XPATH_NUMBER:
2739 case XPATH_POINT:
2740 case XPATH_RANGE:
2741 break;
2742 case XPATH_STRING:
2743 ret->stringval = xmlStrdup(val->stringval);
2744 break;
2745 case XPATH_XSLT_TREE:
2746 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002747 (val->nodesetval->nodeTab != NULL)) {
2748 ret->boolval = 1;
2749 ret->user = xmlCopyNode(val->nodesetval->nodeTab[0], 1);
Owen Taylor3473f882001-02-23 17:55:21 +00002750 ret->nodesetval = xmlXPathNodeSetCreate(
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002751 (xmlNodePtr) ret->user);
2752 } else
Owen Taylor3473f882001-02-23 17:55:21 +00002753 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002754 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00002755 break;
2756 case XPATH_NODESET:
2757 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002758 /* Do not deallocate the copied tree value */
2759 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002760 break;
2761 case XPATH_LOCATIONSET:
2762#ifdef LIBXML_XPTR_ENABLED
2763 {
2764 xmlLocationSetPtr loc = val->user;
2765 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
2766 break;
2767 }
2768#endif
2769 case XPATH_UNDEFINED:
2770 case XPATH_USERS:
2771 xmlGenericError(xmlGenericErrorContext,
2772 "xmlXPathObjectCopy: unsupported type %d\n",
2773 val->type);
2774 break;
2775 }
2776 return(ret);
2777}
2778
2779/**
2780 * xmlXPathFreeObject:
2781 * @obj: the object to free
2782 *
2783 * Free up an xmlXPathObjectPtr object.
2784 */
2785void
2786xmlXPathFreeObject(xmlXPathObjectPtr obj) {
2787 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002788 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00002789 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002790 if (obj->user != NULL) {
2791 xmlFreeNodeList((xmlNodePtr) obj->user);
2792 xmlXPathFreeNodeSet(obj->nodesetval);
2793 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00002794 xmlXPathFreeValueTree(obj->nodesetval);
2795 } else {
2796 if (obj->nodesetval != NULL)
2797 xmlXPathFreeNodeSet(obj->nodesetval);
2798 }
Owen Taylor3473f882001-02-23 17:55:21 +00002799#ifdef LIBXML_XPTR_ENABLED
2800 } else if (obj->type == XPATH_LOCATIONSET) {
2801 if (obj->user != NULL)
2802 xmlXPtrFreeLocationSet(obj->user);
2803#endif
2804 } else if (obj->type == XPATH_STRING) {
2805 if (obj->stringval != NULL)
2806 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00002807 }
2808
Owen Taylor3473f882001-02-23 17:55:21 +00002809 xmlFree(obj);
2810}
2811
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002812
2813/************************************************************************
2814 * *
2815 * Type Casting Routines *
2816 * *
2817 ************************************************************************/
2818
2819/**
2820 * xmlXPathCastBooleanToString:
2821 * @val: a boolean
2822 *
2823 * Converts a boolean to its string value.
2824 *
2825 * Returns a newly allocated string.
2826 */
2827xmlChar *
2828xmlXPathCastBooleanToString (int val) {
2829 xmlChar *ret;
2830 if (val)
2831 ret = xmlStrdup((const xmlChar *) "true");
2832 else
2833 ret = xmlStrdup((const xmlChar *) "false");
2834 return(ret);
2835}
2836
2837/**
2838 * xmlXPathCastNumberToString:
2839 * @val: a number
2840 *
2841 * Converts a number to its string value.
2842 *
2843 * Returns a newly allocated string.
2844 */
2845xmlChar *
2846xmlXPathCastNumberToString (double val) {
2847 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00002848 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002849 case 1:
2850 ret = xmlStrdup((const xmlChar *) "+Infinity");
2851 break;
2852 case -1:
2853 ret = xmlStrdup((const xmlChar *) "-Infinity");
2854 break;
2855 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00002856 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002857 ret = xmlStrdup((const xmlChar *) "NaN");
2858 } else {
2859 /* could be improved */
2860 char buf[100];
2861 xmlXPathFormatNumber(val, buf, 100);
2862 ret = xmlStrdup((const xmlChar *) buf);
2863 }
2864 }
2865 return(ret);
2866}
2867
2868/**
2869 * xmlXPathCastNodeToString:
2870 * @node: a node
2871 *
2872 * Converts a node to its string value.
2873 *
2874 * Returns a newly allocated string.
2875 */
2876xmlChar *
2877xmlXPathCastNodeToString (xmlNodePtr node) {
2878 return(xmlNodeGetContent(node));
2879}
2880
2881/**
2882 * xmlXPathCastNodeSetToString:
2883 * @ns: a node-set
2884 *
2885 * Converts a node-set to its string value.
2886 *
2887 * Returns a newly allocated string.
2888 */
2889xmlChar *
2890xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
2891 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
2892 return(xmlStrdup((const xmlChar *) ""));
2893
2894 xmlXPathNodeSetSort(ns);
2895 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
2896}
2897
2898/**
2899 * xmlXPathCastToString:
2900 * @val: an XPath object
2901 *
2902 * Converts an existing object to its string() equivalent
2903 *
2904 * Returns the string value of the object, NULL in case of error.
2905 * A new string is allocated only if needed (val isn't a
2906 * string object).
2907 */
2908xmlChar *
2909xmlXPathCastToString(xmlXPathObjectPtr val) {
2910 xmlChar *ret = NULL;
2911
2912 if (val == NULL)
2913 return(xmlStrdup((const xmlChar *) ""));
2914 switch (val->type) {
2915 case XPATH_UNDEFINED:
2916#ifdef DEBUG_EXPR
2917 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
2918#endif
2919 ret = xmlStrdup((const xmlChar *) "");
2920 break;
2921 case XPATH_XSLT_TREE:
2922 case XPATH_NODESET:
2923 ret = xmlXPathCastNodeSetToString(val->nodesetval);
2924 break;
2925 case XPATH_STRING:
2926 return(val->stringval);
2927 case XPATH_BOOLEAN:
2928 ret = xmlXPathCastBooleanToString(val->boolval);
2929 break;
2930 case XPATH_NUMBER: {
2931 ret = xmlXPathCastNumberToString(val->floatval);
2932 break;
2933 }
2934 case XPATH_USERS:
2935 case XPATH_POINT:
2936 case XPATH_RANGE:
2937 case XPATH_LOCATIONSET:
2938 TODO
2939 ret = xmlStrdup((const xmlChar *) "");
2940 break;
2941 }
2942 return(ret);
2943}
2944
2945/**
2946 * xmlXPathConvertString:
2947 * @val: an XPath object
2948 *
2949 * Converts an existing object to its string() equivalent
2950 *
2951 * Returns the new object, the old one is freed (or the operation
2952 * is done directly on @val)
2953 */
2954xmlXPathObjectPtr
2955xmlXPathConvertString(xmlXPathObjectPtr val) {
2956 xmlChar *res = NULL;
2957
2958 if (val == NULL)
2959 return(xmlXPathNewCString(""));
2960
2961 switch (val->type) {
2962 case XPATH_UNDEFINED:
2963#ifdef DEBUG_EXPR
2964 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2965#endif
2966 break;
2967 case XPATH_XSLT_TREE:
2968 case XPATH_NODESET:
2969 res = xmlXPathCastNodeSetToString(val->nodesetval);
2970 break;
2971 case XPATH_STRING:
2972 return(val);
2973 case XPATH_BOOLEAN:
2974 res = xmlXPathCastBooleanToString(val->boolval);
2975 break;
2976 case XPATH_NUMBER:
2977 res = xmlXPathCastNumberToString(val->floatval);
2978 break;
2979 case XPATH_USERS:
2980 case XPATH_POINT:
2981 case XPATH_RANGE:
2982 case XPATH_LOCATIONSET:
2983 TODO;
2984 break;
2985 }
2986 xmlXPathFreeObject(val);
2987 if (res == NULL)
2988 return(xmlXPathNewCString(""));
2989 return(xmlXPathWrapString(res));
2990}
2991
2992/**
2993 * xmlXPathCastBooleanToNumber:
2994 * @val: a boolean
2995 *
2996 * Converts a boolean to its number value
2997 *
2998 * Returns the number value
2999 */
3000double
3001xmlXPathCastBooleanToNumber(int val) {
3002 if (val)
3003 return(1.0);
3004 return(0.0);
3005}
3006
3007/**
3008 * xmlXPathCastStringToNumber:
3009 * @val: a string
3010 *
3011 * Converts a string to its number value
3012 *
3013 * Returns the number value
3014 */
3015double
3016xmlXPathCastStringToNumber(const xmlChar * val) {
3017 return(xmlXPathStringEvalNumber(val));
3018}
3019
3020/**
3021 * xmlXPathCastNodeToNumber:
3022 * @node: a node
3023 *
3024 * Converts a node to its number value
3025 *
3026 * Returns the number value
3027 */
3028double
3029xmlXPathCastNodeToNumber (xmlNodePtr node) {
3030 xmlChar *strval;
3031 double ret;
3032
3033 if (node == NULL)
3034 return(xmlXPathNAN);
3035 strval = xmlXPathCastNodeToString(node);
3036 if (strval == NULL)
3037 return(xmlXPathNAN);
3038 ret = xmlXPathCastStringToNumber(strval);
3039 xmlFree(strval);
3040
3041 return(ret);
3042}
3043
3044/**
3045 * xmlXPathCastNodeSetToNumber:
3046 * @ns: a node-set
3047 *
3048 * Converts a node-set to its number value
3049 *
3050 * Returns the number value
3051 */
3052double
3053xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3054 xmlChar *str;
3055 double ret;
3056
3057 if (ns == NULL)
3058 return(xmlXPathNAN);
3059 str = xmlXPathCastNodeSetToString(ns);
3060 ret = xmlXPathCastStringToNumber(str);
3061 xmlFree(str);
3062 return(ret);
3063}
3064
3065/**
3066 * xmlXPathCastToNumber:
3067 * @val: an XPath object
3068 *
3069 * Converts an XPath object to its number value
3070 *
3071 * Returns the number value
3072 */
3073double
3074xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3075 double ret = 0.0;
3076
3077 if (val == NULL)
3078 return(xmlXPathNAN);
3079 switch (val->type) {
3080 case XPATH_UNDEFINED:
3081#ifdef DEGUB_EXPR
3082 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3083#endif
3084 ret = xmlXPathNAN;
3085 break;
3086 case XPATH_XSLT_TREE:
3087 case XPATH_NODESET:
3088 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3089 break;
3090 case XPATH_STRING:
3091 ret = xmlXPathCastStringToNumber(val->stringval);
3092 break;
3093 case XPATH_NUMBER:
3094 ret = val->floatval;
3095 break;
3096 case XPATH_BOOLEAN:
3097 ret = xmlXPathCastBooleanToNumber(val->boolval);
3098 break;
3099 case XPATH_USERS:
3100 case XPATH_POINT:
3101 case XPATH_RANGE:
3102 case XPATH_LOCATIONSET:
3103 TODO;
3104 ret = xmlXPathNAN;
3105 break;
3106 }
3107 return(ret);
3108}
3109
3110/**
3111 * xmlXPathConvertNumber:
3112 * @val: an XPath object
3113 *
3114 * Converts an existing object to its number() equivalent
3115 *
3116 * Returns the new object, the old one is freed (or the operation
3117 * is done directly on @val)
3118 */
3119xmlXPathObjectPtr
3120xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3121 xmlXPathObjectPtr ret;
3122
3123 if (val == NULL)
3124 return(xmlXPathNewFloat(0.0));
3125 if (val->type == XPATH_NUMBER)
3126 return(val);
3127 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3128 xmlXPathFreeObject(val);
3129 return(ret);
3130}
3131
3132/**
3133 * xmlXPathCastNumberToBoolean:
3134 * @val: a number
3135 *
3136 * Converts a number to its boolean value
3137 *
3138 * Returns the boolean value
3139 */
3140int
3141xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003142 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003143 return(0);
3144 return(1);
3145}
3146
3147/**
3148 * xmlXPathCastStringToBoolean:
3149 * @val: a string
3150 *
3151 * Converts a string to its boolean value
3152 *
3153 * Returns the boolean value
3154 */
3155int
3156xmlXPathCastStringToBoolean (const xmlChar *val) {
3157 if ((val == NULL) || (xmlStrlen(val) == 0))
3158 return(0);
3159 return(1);
3160}
3161
3162/**
3163 * xmlXPathCastNodeSetToBoolean:
3164 * @ns: a node-set
3165 *
3166 * Converts a node-set to its boolean value
3167 *
3168 * Returns the boolean value
3169 */
3170int
3171xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3172 if ((ns == NULL) || (ns->nodeNr == 0))
3173 return(0);
3174 return(1);
3175}
3176
3177/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003178 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003179 * @val: an XPath object
3180 *
3181 * Converts an XPath object to its boolean value
3182 *
3183 * Returns the boolean value
3184 */
3185int
3186xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3187 int ret = 0;
3188
3189 if (val == NULL)
3190 return(0);
3191 switch (val->type) {
3192 case XPATH_UNDEFINED:
3193#ifdef DEBUG_EXPR
3194 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3195#endif
3196 ret = 0;
3197 break;
3198 case XPATH_XSLT_TREE:
3199 case XPATH_NODESET:
3200 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3201 break;
3202 case XPATH_STRING:
3203 ret = xmlXPathCastStringToBoolean(val->stringval);
3204 break;
3205 case XPATH_NUMBER:
3206 ret = xmlXPathCastNumberToBoolean(val->floatval);
3207 break;
3208 case XPATH_BOOLEAN:
3209 ret = val->boolval;
3210 break;
3211 case XPATH_USERS:
3212 case XPATH_POINT:
3213 case XPATH_RANGE:
3214 case XPATH_LOCATIONSET:
3215 TODO;
3216 ret = 0;
3217 break;
3218 }
3219 return(ret);
3220}
3221
3222
3223/**
3224 * xmlXPathConvertBoolean:
3225 * @val: an XPath object
3226 *
3227 * Converts an existing object to its boolean() equivalent
3228 *
3229 * Returns the new object, the old one is freed (or the operation
3230 * is done directly on @val)
3231 */
3232xmlXPathObjectPtr
3233xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3234 xmlXPathObjectPtr ret;
3235
3236 if (val == NULL)
3237 return(xmlXPathNewBoolean(0));
3238 if (val->type == XPATH_BOOLEAN)
3239 return(val);
3240 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3241 xmlXPathFreeObject(val);
3242 return(ret);
3243}
3244
Owen Taylor3473f882001-02-23 17:55:21 +00003245/************************************************************************
3246 * *
3247 * Routines to handle XPath contexts *
3248 * *
3249 ************************************************************************/
3250
3251/**
3252 * xmlXPathNewContext:
3253 * @doc: the XML document
3254 *
3255 * Create a new xmlXPathContext
3256 *
3257 * Returns the xmlXPathContext just allocated.
3258 */
3259xmlXPathContextPtr
3260xmlXPathNewContext(xmlDocPtr doc) {
3261 xmlXPathContextPtr ret;
3262
3263 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3264 if (ret == NULL) {
3265 xmlGenericError(xmlGenericErrorContext,
3266 "xmlXPathNewContext: out of memory\n");
3267 return(NULL);
3268 }
3269 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3270 ret->doc = doc;
3271 ret->node = NULL;
3272
3273 ret->varHash = NULL;
3274
3275 ret->nb_types = 0;
3276 ret->max_types = 0;
3277 ret->types = NULL;
3278
3279 ret->funcHash = xmlHashCreate(0);
3280
3281 ret->nb_axis = 0;
3282 ret->max_axis = 0;
3283 ret->axis = NULL;
3284
3285 ret->nsHash = NULL;
3286 ret->user = NULL;
3287
3288 ret->contextSize = -1;
3289 ret->proximityPosition = -1;
3290
3291 xmlXPathRegisterAllFunctions(ret);
3292
3293 return(ret);
3294}
3295
3296/**
3297 * xmlXPathFreeContext:
3298 * @ctxt: the context to free
3299 *
3300 * Free up an xmlXPathContext
3301 */
3302void
3303xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3304 xmlXPathRegisteredNsCleanup(ctxt);
3305 xmlXPathRegisteredFuncsCleanup(ctxt);
3306 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003307 xmlFree(ctxt);
3308}
3309
3310/************************************************************************
3311 * *
3312 * Routines to handle XPath parser contexts *
3313 * *
3314 ************************************************************************/
3315
3316#define CHECK_CTXT(ctxt) \
3317 if (ctxt == NULL) { \
3318 xmlGenericError(xmlGenericErrorContext, \
3319 "%s:%d Internal error: ctxt == NULL\n", \
3320 __FILE__, __LINE__); \
3321 } \
3322
3323
3324#define CHECK_CONTEXT(ctxt) \
3325 if (ctxt == NULL) { \
3326 xmlGenericError(xmlGenericErrorContext, \
3327 "%s:%d Internal error: no context\n", \
3328 __FILE__, __LINE__); \
3329 } \
3330 else if (ctxt->doc == NULL) { \
3331 xmlGenericError(xmlGenericErrorContext, \
3332 "%s:%d Internal error: no document\n", \
3333 __FILE__, __LINE__); \
3334 } \
3335 else if (ctxt->doc->children == NULL) { \
3336 xmlGenericError(xmlGenericErrorContext, \
3337 "%s:%d Internal error: document without root\n", \
3338 __FILE__, __LINE__); \
3339 } \
3340
3341
3342/**
3343 * xmlXPathNewParserContext:
3344 * @str: the XPath expression
3345 * @ctxt: the XPath context
3346 *
3347 * Create a new xmlXPathParserContext
3348 *
3349 * Returns the xmlXPathParserContext just allocated.
3350 */
3351xmlXPathParserContextPtr
3352xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3353 xmlXPathParserContextPtr ret;
3354
3355 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3356 if (ret == NULL) {
3357 xmlGenericError(xmlGenericErrorContext,
3358 "xmlXPathNewParserContext: out of memory\n");
3359 return(NULL);
3360 }
3361 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3362 ret->cur = ret->base = str;
3363 ret->context = ctxt;
3364
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003365 ret->comp = xmlXPathNewCompExpr();
3366 if (ret->comp == NULL) {
3367 xmlFree(ret->valueTab);
3368 xmlFree(ret);
3369 return(NULL);
3370 }
3371
3372 return(ret);
3373}
3374
3375/**
3376 * xmlXPathCompParserContext:
3377 * @comp: the XPath compiled expression
3378 * @ctxt: the XPath context
3379 *
3380 * Create a new xmlXPathParserContext when processing a compiled expression
3381 *
3382 * Returns the xmlXPathParserContext just allocated.
3383 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003384static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003385xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3386 xmlXPathParserContextPtr ret;
3387
3388 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3389 if (ret == NULL) {
3390 xmlGenericError(xmlGenericErrorContext,
3391 "xmlXPathNewParserContext: out of memory\n");
3392 return(NULL);
3393 }
3394 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3395
Owen Taylor3473f882001-02-23 17:55:21 +00003396 /* Allocate the value stack */
3397 ret->valueTab = (xmlXPathObjectPtr *)
3398 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003399 if (ret->valueTab == NULL) {
3400 xmlFree(ret);
3401 xmlGenericError(xmlGenericErrorContext,
3402 "xmlXPathNewParserContext: out of memory\n");
3403 return(NULL);
3404 }
Owen Taylor3473f882001-02-23 17:55:21 +00003405 ret->valueNr = 0;
3406 ret->valueMax = 10;
3407 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003408
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003409 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003410 ret->comp = comp;
3411
Owen Taylor3473f882001-02-23 17:55:21 +00003412 return(ret);
3413}
3414
3415/**
3416 * xmlXPathFreeParserContext:
3417 * @ctxt: the context to free
3418 *
3419 * Free up an xmlXPathParserContext
3420 */
3421void
3422xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3423 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003424 xmlFree(ctxt->valueTab);
3425 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003426 if (ctxt->comp)
3427 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003428 xmlFree(ctxt);
3429}
3430
3431/************************************************************************
3432 * *
3433 * The implicit core function library *
3434 * *
3435 ************************************************************************/
3436
Owen Taylor3473f882001-02-23 17:55:21 +00003437/**
Daniel Veillardf06307e2001-07-03 10:35:50 +00003438 * xmlXPathNodeStringHash:
3439 * @node: a node pointer
3440 *
3441 * Function computing the beginning of the string value of the node,
3442 * used to speed up comparisons
3443 *
3444 * Returns an int usable as a hash
3445 */
3446static unsigned int
3447xmlXPathNodeValHash(xmlNodePtr node) {
3448 int len = 2;
3449 const xmlChar * string = NULL;
3450 xmlNodePtr tmp = NULL;
3451 unsigned int ret = 0;
3452
3453 if (node == NULL)
3454 return(0);
3455
3456
3457 switch (node->type) {
3458 case XML_COMMENT_NODE:
3459 case XML_PI_NODE:
3460 case XML_CDATA_SECTION_NODE:
3461 case XML_TEXT_NODE:
3462 string = node->content;
3463 if (string == NULL)
3464 return(0);
3465 if (string[0] == 0)
3466 return(0);
3467 return(((unsigned int) string[0]) +
3468 (((unsigned int) string[1]) << 8));
3469 case XML_NAMESPACE_DECL:
3470 string = ((xmlNsPtr)node)->href;
3471 if (string == NULL)
3472 return(0);
3473 if (string[0] == 0)
3474 return(0);
3475 return(((unsigned int) string[0]) +
3476 (((unsigned int) string[1]) << 8));
3477 case XML_ATTRIBUTE_NODE:
3478 tmp = ((xmlAttrPtr) node)->children;
3479 break;
3480 case XML_ELEMENT_NODE:
3481 tmp = node->children;
3482 break;
3483 default:
3484 return(0);
3485 }
3486 while (tmp != NULL) {
3487 switch (tmp->type) {
3488 case XML_COMMENT_NODE:
3489 case XML_PI_NODE:
3490 case XML_CDATA_SECTION_NODE:
3491 case XML_TEXT_NODE:
3492 string = tmp->content;
3493 break;
3494 case XML_NAMESPACE_DECL:
3495 string = ((xmlNsPtr)tmp)->href;
3496 break;
3497 default:
3498 break;
3499 }
3500 if ((string != NULL) && (string[0] != 0)) {
3501 if (string[0] == 0)
3502 return(0);
3503 if (len == 1) {
3504 return(ret + (((unsigned int) string[0]) << 8));
3505 }
3506 if (string[1] == 0) {
3507 len = 1;
3508 ret = (unsigned int) string[0];
3509 } else {
3510 return(((unsigned int) string[0]) +
3511 (((unsigned int) string[1]) << 8));
3512 }
3513 }
3514 /*
3515 * Skip to next node
3516 */
3517 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
3518 if (tmp->children->type != XML_ENTITY_DECL) {
3519 tmp = tmp->children;
3520 continue;
3521 }
3522 }
3523 if (tmp == node)
3524 break;
3525
3526 if (tmp->next != NULL) {
3527 tmp = tmp->next;
3528 continue;
3529 }
3530
3531 do {
3532 tmp = tmp->parent;
3533 if (tmp == NULL)
3534 break;
3535 if (tmp == node) {
3536 tmp = NULL;
3537 break;
3538 }
3539 if (tmp->next != NULL) {
3540 tmp = tmp->next;
3541 break;
3542 }
3543 } while (tmp != NULL);
3544 }
3545 return(ret);
3546}
3547
3548/**
3549 * xmlXPathStringHash:
3550 * @string: a string
3551 *
3552 * Function computing the beginning of the string value of the node,
3553 * used to speed up comparisons
3554 *
3555 * Returns an int usable as a hash
3556 */
3557static unsigned int
3558xmlXPathStringHash(const xmlChar * string) {
3559 if (string == NULL)
3560 return((unsigned int) 0);
3561 if (string[0] == 0)
3562 return(0);
3563 return(((unsigned int) string[0]) +
3564 (((unsigned int) string[1]) << 8));
3565}
3566
3567/**
Owen Taylor3473f882001-02-23 17:55:21 +00003568 * xmlXPathCompareNodeSetFloat:
3569 * @ctxt: the XPath Parser context
3570 * @inf: less than (1) or greater than (0)
3571 * @strict: is the comparison strict
3572 * @arg: the node set
3573 * @f: the value
3574 *
3575 * Implement the compare operation between a nodeset and a number
3576 * @ns < @val (1, 1, ...
3577 * @ns <= @val (1, 0, ...
3578 * @ns > @val (0, 1, ...
3579 * @ns >= @val (0, 0, ...
3580 *
3581 * If one object to be compared is a node-set and the other is a number,
3582 * then the comparison will be true if and only if there is a node in the
3583 * node-set such that the result of performing the comparison on the number
3584 * to be compared and on the result of converting the string-value of that
3585 * node to a number using the number function is true.
3586 *
3587 * Returns 0 or 1 depending on the results of the test.
3588 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003589static int
Owen Taylor3473f882001-02-23 17:55:21 +00003590xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
3591 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
3592 int i, ret = 0;
3593 xmlNodeSetPtr ns;
3594 xmlChar *str2;
3595
3596 if ((f == NULL) || (arg == NULL) ||
3597 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3598 xmlXPathFreeObject(arg);
3599 xmlXPathFreeObject(f);
3600 return(0);
3601 }
3602 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003603 if (ns != NULL) {
3604 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003605 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003606 if (str2 != NULL) {
3607 valuePush(ctxt,
3608 xmlXPathNewString(str2));
3609 xmlFree(str2);
3610 xmlXPathNumberFunction(ctxt, 1);
3611 valuePush(ctxt, xmlXPathObjectCopy(f));
3612 ret = xmlXPathCompareValues(ctxt, inf, strict);
3613 if (ret)
3614 break;
3615 }
3616 }
Owen Taylor3473f882001-02-23 17:55:21 +00003617 }
3618 xmlXPathFreeObject(arg);
3619 xmlXPathFreeObject(f);
3620 return(ret);
3621}
3622
3623/**
3624 * xmlXPathCompareNodeSetString:
3625 * @ctxt: the XPath Parser context
3626 * @inf: less than (1) or greater than (0)
3627 * @strict: is the comparison strict
3628 * @arg: the node set
3629 * @s: the value
3630 *
3631 * Implement the compare operation between a nodeset and a string
3632 * @ns < @val (1, 1, ...
3633 * @ns <= @val (1, 0, ...
3634 * @ns > @val (0, 1, ...
3635 * @ns >= @val (0, 0, ...
3636 *
3637 * If one object to be compared is a node-set and the other is a string,
3638 * then the comparison will be true if and only if there is a node in
3639 * the node-set such that the result of performing the comparison on the
3640 * string-value of the node and the other string is true.
3641 *
3642 * Returns 0 or 1 depending on the results of the test.
3643 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003644static int
Owen Taylor3473f882001-02-23 17:55:21 +00003645xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
3646 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
3647 int i, ret = 0;
3648 xmlNodeSetPtr ns;
3649 xmlChar *str2;
3650
3651 if ((s == NULL) || (arg == NULL) ||
3652 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
3653 xmlXPathFreeObject(arg);
3654 xmlXPathFreeObject(s);
3655 return(0);
3656 }
3657 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00003658 if (ns != NULL) {
3659 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003660 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003661 if (str2 != NULL) {
3662 valuePush(ctxt,
3663 xmlXPathNewString(str2));
3664 xmlFree(str2);
3665 valuePush(ctxt, xmlXPathObjectCopy(s));
3666 ret = xmlXPathCompareValues(ctxt, inf, strict);
3667 if (ret)
3668 break;
3669 }
3670 }
Owen Taylor3473f882001-02-23 17:55:21 +00003671 }
3672 xmlXPathFreeObject(arg);
3673 xmlXPathFreeObject(s);
3674 return(ret);
3675}
3676
3677/**
3678 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003679 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00003680 * @strict: is the comparison strict
3681 * @arg1: the fist node set object
3682 * @arg2: the second node set object
3683 *
3684 * Implement the compare operation on nodesets:
3685 *
3686 * If both objects to be compared are node-sets, then the comparison
3687 * will be true if and only if there is a node in the first node-set
3688 * and a node in the second node-set such that the result of performing
3689 * the comparison on the string-values of the two nodes is true.
3690 * ....
3691 * When neither object to be compared is a node-set and the operator
3692 * is <=, <, >= or >, then the objects are compared by converting both
3693 * objects to numbers and comparing the numbers according to IEEE 754.
3694 * ....
3695 * The number function converts its argument to a number as follows:
3696 * - a string that consists of optional whitespace followed by an
3697 * optional minus sign followed by a Number followed by whitespace
3698 * is converted to the IEEE 754 number that is nearest (according
3699 * to the IEEE 754 round-to-nearest rule) to the mathematical value
3700 * represented by the string; any other string is converted to NaN
3701 *
3702 * Conclusion all nodes need to be converted first to their string value
3703 * and then the comparison must be done when possible
3704 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003705static int
3706xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00003707 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3708 int i, j, init = 0;
3709 double val1;
3710 double *values2;
3711 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003712 xmlNodeSetPtr ns1;
3713 xmlNodeSetPtr ns2;
3714
3715 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003716 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
3717 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003718 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003719 }
Owen Taylor3473f882001-02-23 17:55:21 +00003720 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003721 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
3722 xmlXPathFreeObject(arg1);
3723 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003724 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003725 }
Owen Taylor3473f882001-02-23 17:55:21 +00003726
3727 ns1 = arg1->nodesetval;
3728 ns2 = arg2->nodesetval;
3729
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003730 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003731 xmlXPathFreeObject(arg1);
3732 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003733 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003734 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003735 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003736 xmlXPathFreeObject(arg1);
3737 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003738 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003739 }
Owen Taylor3473f882001-02-23 17:55:21 +00003740
3741 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
3742 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003743 xmlXPathFreeObject(arg1);
3744 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003745 return(0);
3746 }
3747 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003748 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00003749 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00003750 continue;
3751 for (j = 0;j < ns2->nodeNr;j++) {
3752 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003753 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00003754 }
Daniel Veillardcda96922001-08-21 10:56:31 +00003755 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00003756 continue;
3757 if (inf && strict)
3758 ret = (val1 < values2[j]);
3759 else if (inf && !strict)
3760 ret = (val1 <= values2[j]);
3761 else if (!inf && strict)
3762 ret = (val1 > values2[j]);
3763 else if (!inf && !strict)
3764 ret = (val1 >= values2[j]);
3765 if (ret)
3766 break;
3767 }
3768 if (ret)
3769 break;
3770 init = 1;
3771 }
3772 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003773 xmlXPathFreeObject(arg1);
3774 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003775 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003776}
3777
3778/**
3779 * xmlXPathCompareNodeSetValue:
3780 * @ctxt: the XPath Parser context
3781 * @inf: less than (1) or greater than (0)
3782 * @strict: is the comparison strict
3783 * @arg: the node set
3784 * @val: the value
3785 *
3786 * Implement the compare operation between a nodeset and a value
3787 * @ns < @val (1, 1, ...
3788 * @ns <= @val (1, 0, ...
3789 * @ns > @val (0, 1, ...
3790 * @ns >= @val (0, 0, ...
3791 *
3792 * If one object to be compared is a node-set and the other is a boolean,
3793 * then the comparison will be true if and only if the result of performing
3794 * the comparison on the boolean and on the result of converting
3795 * the node-set to a boolean using the boolean function is true.
3796 *
3797 * Returns 0 or 1 depending on the results of the test.
3798 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003799static int
Owen Taylor3473f882001-02-23 17:55:21 +00003800xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
3801 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
3802 if ((val == NULL) || (arg == NULL) ||
3803 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3804 return(0);
3805
3806 switch(val->type) {
3807 case XPATH_NUMBER:
3808 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
3809 case XPATH_NODESET:
3810 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003811 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00003812 case XPATH_STRING:
3813 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
3814 case XPATH_BOOLEAN:
3815 valuePush(ctxt, arg);
3816 xmlXPathBooleanFunction(ctxt, 1);
3817 valuePush(ctxt, val);
3818 return(xmlXPathCompareValues(ctxt, inf, strict));
3819 default:
3820 TODO
3821 return(0);
3822 }
3823 return(0);
3824}
3825
3826/**
3827 * xmlXPathEqualNodeSetString
3828 * @arg: the nodeset object argument
3829 * @str: the string to compare to.
3830 *
3831 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3832 * If one object to be compared is a node-set and the other is a string,
3833 * then the comparison will be true if and only if there is a node in
3834 * the node-set such that the result of performing the comparison on the
3835 * string-value of the node and the other string is true.
3836 *
3837 * Returns 0 or 1 depending on the results of the test.
3838 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003839static int
Daniel Veillardf06307e2001-07-03 10:35:50 +00003840xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str)
3841{
Owen Taylor3473f882001-02-23 17:55:21 +00003842 int i;
3843 xmlNodeSetPtr ns;
3844 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003845 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00003846
3847 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00003848 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3849 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00003850 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003851 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003852 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00003853 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00003854 if (ns->nodeNr <= 0) {
3855 if (hash == 0)
3856 return(1);
3857 return(0);
3858 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003859 for (i = 0; i < ns->nodeNr; i++) {
3860 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
3861 str2 = xmlNodeGetContent(ns->nodeTab[i]);
3862 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
3863 xmlFree(str2);
3864 return (1);
3865 }
3866 if (str2 != NULL)
3867 xmlFree(str2);
3868 }
Owen Taylor3473f882001-02-23 17:55:21 +00003869 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003870 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00003871}
3872
3873/**
3874 * xmlXPathEqualNodeSetFloat
3875 * @arg: the nodeset object argument
3876 * @f: the float to compare to
3877 *
3878 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3879 * If one object to be compared is a node-set and the other is a number,
3880 * then the comparison will be true if and only if there is a node in
3881 * the node-set such that the result of performing the comparison on the
3882 * number to be compared and on the result of converting the string-value
3883 * of that node to a number using the number function is true.
3884 *
3885 * Returns 0 or 1 depending on the results of the test.
3886 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003887static int
Owen Taylor3473f882001-02-23 17:55:21 +00003888xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) {
3889 char buf[100] = "";
3890
3891 if ((arg == NULL) ||
3892 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3893 return(0);
3894
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003895 xmlXPathFormatNumber(f, buf, sizeof(buf));
Owen Taylor3473f882001-02-23 17:55:21 +00003896 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
3897}
3898
3899
3900/**
3901 * xmlXPathEqualNodeSets
3902 * @arg1: first nodeset object argument
3903 * @arg2: second nodeset object argument
3904 *
3905 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
3906 * If both objects to be compared are node-sets, then the comparison
3907 * will be true if and only if there is a node in the first node-set and
3908 * a node in the second node-set such that the result of performing the
3909 * comparison on the string-values of the two nodes is true.
3910 *
3911 * (needless to say, this is a costly operation)
3912 *
3913 * Returns 0 or 1 depending on the results of the test.
3914 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003915static int
Owen Taylor3473f882001-02-23 17:55:21 +00003916xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3917 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00003918 unsigned int *hashs1;
3919 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00003920 xmlChar **values1;
3921 xmlChar **values2;
3922 int ret = 0;
3923 xmlNodeSetPtr ns1;
3924 xmlNodeSetPtr ns2;
3925
3926 if ((arg1 == NULL) ||
3927 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
3928 return(0);
3929 if ((arg2 == NULL) ||
3930 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
3931 return(0);
3932
3933 ns1 = arg1->nodesetval;
3934 ns2 = arg2->nodesetval;
3935
Daniel Veillard911f49a2001-04-07 15:39:35 +00003936 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00003937 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003938 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00003939 return(0);
3940
3941 /*
3942 * check if there is a node pertaining to both sets
3943 */
3944 for (i = 0;i < ns1->nodeNr;i++)
3945 for (j = 0;j < ns2->nodeNr;j++)
3946 if (ns1->nodeTab[i] == ns2->nodeTab[j])
3947 return(1);
3948
3949 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
3950 if (values1 == NULL)
3951 return(0);
Daniel Veillardf06307e2001-07-03 10:35:50 +00003952 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
3953 if (hashs1 == NULL) {
3954 xmlFree(values1);
3955 return(0);
3956 }
Owen Taylor3473f882001-02-23 17:55:21 +00003957 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
3958 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
3959 if (values2 == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00003960 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00003961 xmlFree(values1);
3962 return(0);
3963 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003964 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
3965 if (hashs2 == NULL) {
3966 xmlFree(hashs1);
3967 xmlFree(values1);
3968 xmlFree(values2);
3969 return(0);
3970 }
Owen Taylor3473f882001-02-23 17:55:21 +00003971 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
3972 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00003973 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00003974 for (j = 0;j < ns2->nodeNr;j++) {
3975 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00003976 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
3977 if (hashs1[i] == hashs2[j]) {
3978 if (values1[i] == NULL)
3979 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
3980 if (values2[j] == NULL)
3981 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
3982 ret = xmlStrEqual(values1[i], values2[j]);
3983 if (ret)
3984 break;
3985 }
Owen Taylor3473f882001-02-23 17:55:21 +00003986 }
3987 if (ret)
3988 break;
3989 }
3990 for (i = 0;i < ns1->nodeNr;i++)
3991 if (values1[i] != NULL)
3992 xmlFree(values1[i]);
3993 for (j = 0;j < ns2->nodeNr;j++)
3994 if (values2[j] != NULL)
3995 xmlFree(values2[j]);
3996 xmlFree(values1);
3997 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00003998 xmlFree(hashs1);
3999 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004000 return(ret);
4001}
4002
4003/**
4004 * xmlXPathEqualValues:
4005 * @ctxt: the XPath Parser context
4006 *
4007 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4008 *
4009 * Returns 0 or 1 depending on the results of the test.
4010 */
4011int
4012xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4013 xmlXPathObjectPtr arg1, arg2;
4014 int ret = 0;
4015
4016 arg1 = valuePop(ctxt);
4017 if (arg1 == NULL)
4018 XP_ERROR0(XPATH_INVALID_OPERAND);
4019
4020 arg2 = valuePop(ctxt);
4021 if (arg2 == NULL) {
4022 xmlXPathFreeObject(arg1);
4023 XP_ERROR0(XPATH_INVALID_OPERAND);
4024 }
4025
4026 if (arg1 == arg2) {
4027#ifdef DEBUG_EXPR
4028 xmlGenericError(xmlGenericErrorContext,
4029 "Equal: by pointer\n");
4030#endif
4031 return(1);
4032 }
4033
4034 switch (arg1->type) {
4035 case XPATH_UNDEFINED:
4036#ifdef DEBUG_EXPR
4037 xmlGenericError(xmlGenericErrorContext,
4038 "Equal: undefined\n");
4039#endif
4040 break;
4041 case XPATH_XSLT_TREE:
4042 case XPATH_NODESET:
4043 switch (arg2->type) {
4044 case XPATH_UNDEFINED:
4045#ifdef DEBUG_EXPR
4046 xmlGenericError(xmlGenericErrorContext,
4047 "Equal: undefined\n");
4048#endif
4049 break;
4050 case XPATH_XSLT_TREE:
4051 case XPATH_NODESET:
4052 ret = xmlXPathEqualNodeSets(arg1, arg2);
4053 break;
4054 case XPATH_BOOLEAN:
4055 if ((arg1->nodesetval == NULL) ||
4056 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4057 else
4058 ret = 1;
4059 ret = (ret == arg2->boolval);
4060 break;
4061 case XPATH_NUMBER:
4062 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
4063 break;
4064 case XPATH_STRING:
4065 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
4066 break;
4067 case XPATH_USERS:
4068 case XPATH_POINT:
4069 case XPATH_RANGE:
4070 case XPATH_LOCATIONSET:
4071 TODO
4072 break;
4073 }
4074 break;
4075 case XPATH_BOOLEAN:
4076 switch (arg2->type) {
4077 case XPATH_UNDEFINED:
4078#ifdef DEBUG_EXPR
4079 xmlGenericError(xmlGenericErrorContext,
4080 "Equal: undefined\n");
4081#endif
4082 break;
4083 case XPATH_NODESET:
4084 case XPATH_XSLT_TREE:
4085 if ((arg2->nodesetval == NULL) ||
4086 (arg2->nodesetval->nodeNr == 0)) ret = 0;
4087 else
4088 ret = 1;
4089 break;
4090 case XPATH_BOOLEAN:
4091#ifdef DEBUG_EXPR
4092 xmlGenericError(xmlGenericErrorContext,
4093 "Equal: %d boolean %d \n",
4094 arg1->boolval, arg2->boolval);
4095#endif
4096 ret = (arg1->boolval == arg2->boolval);
4097 break;
4098 case XPATH_NUMBER:
4099 if (arg2->floatval) ret = 1;
4100 else ret = 0;
4101 ret = (arg1->boolval == ret);
4102 break;
4103 case XPATH_STRING:
4104 if ((arg2->stringval == NULL) ||
4105 (arg2->stringval[0] == 0)) ret = 0;
4106 else
4107 ret = 1;
4108 ret = (arg1->boolval == ret);
4109 break;
4110 case XPATH_USERS:
4111 case XPATH_POINT:
4112 case XPATH_RANGE:
4113 case XPATH_LOCATIONSET:
4114 TODO
4115 break;
4116 }
4117 break;
4118 case XPATH_NUMBER:
4119 switch (arg2->type) {
4120 case XPATH_UNDEFINED:
4121#ifdef DEBUG_EXPR
4122 xmlGenericError(xmlGenericErrorContext,
4123 "Equal: undefined\n");
4124#endif
4125 break;
4126 case XPATH_NODESET:
4127 case XPATH_XSLT_TREE:
4128 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
4129 break;
4130 case XPATH_BOOLEAN:
4131 if (arg1->floatval) ret = 1;
4132 else ret = 0;
4133 ret = (arg2->boolval == ret);
4134 break;
4135 case XPATH_STRING:
4136 valuePush(ctxt, arg2);
4137 xmlXPathNumberFunction(ctxt, 1);
4138 arg2 = valuePop(ctxt);
4139 /* no break on purpose */
4140 case XPATH_NUMBER:
4141 ret = (arg1->floatval == arg2->floatval);
4142 break;
4143 case XPATH_USERS:
4144 case XPATH_POINT:
4145 case XPATH_RANGE:
4146 case XPATH_LOCATIONSET:
4147 TODO
4148 break;
4149 }
4150 break;
4151 case XPATH_STRING:
4152 switch (arg2->type) {
4153 case XPATH_UNDEFINED:
4154#ifdef DEBUG_EXPR
4155 xmlGenericError(xmlGenericErrorContext,
4156 "Equal: undefined\n");
4157#endif
4158 break;
4159 case XPATH_NODESET:
4160 case XPATH_XSLT_TREE:
4161 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
4162 break;
4163 case XPATH_BOOLEAN:
4164 if ((arg1->stringval == NULL) ||
4165 (arg1->stringval[0] == 0)) ret = 0;
4166 else
4167 ret = 1;
4168 ret = (arg2->boolval == ret);
4169 break;
4170 case XPATH_STRING:
4171 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4172 break;
4173 case XPATH_NUMBER:
4174 valuePush(ctxt, arg1);
4175 xmlXPathNumberFunction(ctxt, 1);
4176 arg1 = valuePop(ctxt);
4177 ret = (arg1->floatval == arg2->floatval);
4178 break;
4179 case XPATH_USERS:
4180 case XPATH_POINT:
4181 case XPATH_RANGE:
4182 case XPATH_LOCATIONSET:
4183 TODO
4184 break;
4185 }
4186 break;
4187 case XPATH_USERS:
4188 case XPATH_POINT:
4189 case XPATH_RANGE:
4190 case XPATH_LOCATIONSET:
4191 TODO
4192 break;
4193 }
4194 xmlXPathFreeObject(arg1);
4195 xmlXPathFreeObject(arg2);
4196 return(ret);
4197}
4198
4199
4200/**
4201 * xmlXPathCompareValues:
4202 * @ctxt: the XPath Parser context
4203 * @inf: less than (1) or greater than (0)
4204 * @strict: is the comparison strict
4205 *
4206 * Implement the compare operation on XPath objects:
4207 * @arg1 < @arg2 (1, 1, ...
4208 * @arg1 <= @arg2 (1, 0, ...
4209 * @arg1 > @arg2 (0, 1, ...
4210 * @arg1 >= @arg2 (0, 0, ...
4211 *
4212 * When neither object to be compared is a node-set and the operator is
4213 * <=, <, >=, >, then the objects are compared by converted both objects
4214 * to numbers and comparing the numbers according to IEEE 754. The <
4215 * comparison will be true if and only if the first number is less than the
4216 * second number. The <= comparison will be true if and only if the first
4217 * number is less than or equal to the second number. The > comparison
4218 * will be true if and only if the first number is greater than the second
4219 * number. The >= comparison will be true if and only if the first number
4220 * is greater than or equal to the second number.
4221 *
4222 * Returns 1 if the comparaison succeeded, 0 if it failed
4223 */
4224int
4225xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
4226 int ret = 0;
4227 xmlXPathObjectPtr arg1, arg2;
4228
4229 arg2 = valuePop(ctxt);
4230 if (arg2 == NULL) {
4231 XP_ERROR0(XPATH_INVALID_OPERAND);
4232 }
4233
4234 arg1 = valuePop(ctxt);
4235 if (arg1 == NULL) {
4236 xmlXPathFreeObject(arg2);
4237 XP_ERROR0(XPATH_INVALID_OPERAND);
4238 }
4239
4240 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
4241 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004242 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004243 } else {
4244 if (arg1->type == XPATH_NODESET) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004245 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4246 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004247 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004248 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4249 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004250 }
4251 }
4252 return(ret);
4253 }
4254
4255 if (arg1->type != XPATH_NUMBER) {
4256 valuePush(ctxt, arg1);
4257 xmlXPathNumberFunction(ctxt, 1);
4258 arg1 = valuePop(ctxt);
4259 }
4260 if (arg1->type != XPATH_NUMBER) {
4261 xmlXPathFreeObject(arg1);
4262 xmlXPathFreeObject(arg2);
4263 XP_ERROR0(XPATH_INVALID_OPERAND);
4264 }
4265 if (arg2->type != XPATH_NUMBER) {
4266 valuePush(ctxt, arg2);
4267 xmlXPathNumberFunction(ctxt, 1);
4268 arg2 = valuePop(ctxt);
4269 }
4270 if (arg2->type != XPATH_NUMBER) {
4271 xmlXPathFreeObject(arg1);
4272 xmlXPathFreeObject(arg2);
4273 XP_ERROR0(XPATH_INVALID_OPERAND);
4274 }
4275 /*
4276 * Add tests for infinity and nan
4277 * => feedback on 3.4 for Inf and NaN
4278 */
4279 if (inf && strict)
4280 ret = (arg1->floatval < arg2->floatval);
4281 else if (inf && !strict)
4282 ret = (arg1->floatval <= arg2->floatval);
4283 else if (!inf && strict)
4284 ret = (arg1->floatval > arg2->floatval);
4285 else if (!inf && !strict)
4286 ret = (arg1->floatval >= arg2->floatval);
4287 xmlXPathFreeObject(arg1);
4288 xmlXPathFreeObject(arg2);
4289 return(ret);
4290}
4291
4292/**
4293 * xmlXPathValueFlipSign:
4294 * @ctxt: the XPath Parser context
4295 *
4296 * Implement the unary - operation on an XPath object
4297 * The numeric operators convert their operands to numbers as if
4298 * by calling the number function.
4299 */
4300void
4301xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004302 CAST_TO_NUMBER;
4303 CHECK_TYPE(XPATH_NUMBER);
4304 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00004305}
4306
4307/**
4308 * xmlXPathAddValues:
4309 * @ctxt: the XPath Parser context
4310 *
4311 * Implement the add operation on XPath objects:
4312 * The numeric operators convert their operands to numbers as if
4313 * by calling the number function.
4314 */
4315void
4316xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
4317 xmlXPathObjectPtr arg;
4318 double val;
4319
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004320 arg = valuePop(ctxt);
4321 if (arg == NULL)
4322 XP_ERROR(XPATH_INVALID_OPERAND);
4323 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004324 xmlXPathFreeObject(arg);
4325
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004326 CAST_TO_NUMBER;
4327 CHECK_TYPE(XPATH_NUMBER);
4328 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00004329}
4330
4331/**
4332 * xmlXPathSubValues:
4333 * @ctxt: the XPath Parser context
4334 *
4335 * Implement the substraction operation on XPath objects:
4336 * The numeric operators convert their operands to numbers as if
4337 * by calling the number function.
4338 */
4339void
4340xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
4341 xmlXPathObjectPtr arg;
4342 double val;
4343
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004344 arg = valuePop(ctxt);
4345 if (arg == NULL)
4346 XP_ERROR(XPATH_INVALID_OPERAND);
4347 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004348 xmlXPathFreeObject(arg);
4349
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004350 CAST_TO_NUMBER;
4351 CHECK_TYPE(XPATH_NUMBER);
4352 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004353}
4354
4355/**
4356 * xmlXPathMultValues:
4357 * @ctxt: the XPath Parser context
4358 *
4359 * Implement the multiply operation on XPath objects:
4360 * The numeric operators convert their operands to numbers as if
4361 * by calling the number function.
4362 */
4363void
4364xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
4365 xmlXPathObjectPtr arg;
4366 double val;
4367
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004368 arg = valuePop(ctxt);
4369 if (arg == NULL)
4370 XP_ERROR(XPATH_INVALID_OPERAND);
4371 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004372 xmlXPathFreeObject(arg);
4373
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004374 CAST_TO_NUMBER;
4375 CHECK_TYPE(XPATH_NUMBER);
4376 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004377}
4378
4379/**
4380 * xmlXPathDivValues:
4381 * @ctxt: the XPath Parser context
4382 *
4383 * Implement the div operation on XPath objects @arg1 / @arg2:
4384 * The numeric operators convert their operands to numbers as if
4385 * by calling the number function.
4386 */
4387void
4388xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
4389 xmlXPathObjectPtr arg;
4390 double val;
4391
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004392 arg = valuePop(ctxt);
4393 if (arg == NULL)
4394 XP_ERROR(XPATH_INVALID_OPERAND);
4395 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004396 xmlXPathFreeObject(arg);
4397
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004398 CAST_TO_NUMBER;
4399 CHECK_TYPE(XPATH_NUMBER);
4400 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00004401}
4402
4403/**
4404 * xmlXPathModValues:
4405 * @ctxt: the XPath Parser context
4406 *
4407 * Implement the mod operation on XPath objects: @arg1 / @arg2
4408 * The numeric operators convert their operands to numbers as if
4409 * by calling the number function.
4410 */
4411void
4412xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
4413 xmlXPathObjectPtr arg;
4414 int arg1, arg2;
4415
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004416 arg = valuePop(ctxt);
4417 if (arg == NULL)
4418 XP_ERROR(XPATH_INVALID_OPERAND);
4419 arg2 = (int) xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00004420 xmlXPathFreeObject(arg);
4421
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004422 CAST_TO_NUMBER;
4423 CHECK_TYPE(XPATH_NUMBER);
4424 arg1 = (int) ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00004425 if (arg2 == 0)
4426 ctxt->value->floatval = xmlXPathNAN;
4427 else
4428 ctxt->value->floatval = arg1 % arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00004429}
4430
4431/************************************************************************
4432 * *
4433 * The traversal functions *
4434 * *
4435 ************************************************************************/
4436
Owen Taylor3473f882001-02-23 17:55:21 +00004437/*
4438 * A traversal function enumerates nodes along an axis.
4439 * Initially it must be called with NULL, and it indicates
4440 * termination on the axis by returning NULL.
4441 */
4442typedef xmlNodePtr (*xmlXPathTraversalFunction)
4443 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
4444
4445/**
4446 * xmlXPathNextSelf:
4447 * @ctxt: the XPath Parser context
4448 * @cur: the current node in the traversal
4449 *
4450 * Traversal function for the "self" direction
4451 * The self axis contains just the context node itself
4452 *
4453 * Returns the next element following that axis
4454 */
4455xmlNodePtr
4456xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4457 if (cur == NULL)
4458 return(ctxt->context->node);
4459 return(NULL);
4460}
4461
4462/**
4463 * xmlXPathNextChild:
4464 * @ctxt: the XPath Parser context
4465 * @cur: the current node in the traversal
4466 *
4467 * Traversal function for the "child" direction
4468 * The child axis contains the children of the context node in document order.
4469 *
4470 * Returns the next element following that axis
4471 */
4472xmlNodePtr
4473xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4474 if (cur == NULL) {
4475 if (ctxt->context->node == NULL) return(NULL);
4476 switch (ctxt->context->node->type) {
4477 case XML_ELEMENT_NODE:
4478 case XML_TEXT_NODE:
4479 case XML_CDATA_SECTION_NODE:
4480 case XML_ENTITY_REF_NODE:
4481 case XML_ENTITY_NODE:
4482 case XML_PI_NODE:
4483 case XML_COMMENT_NODE:
4484 case XML_NOTATION_NODE:
4485 case XML_DTD_NODE:
4486 return(ctxt->context->node->children);
4487 case XML_DOCUMENT_NODE:
4488 case XML_DOCUMENT_TYPE_NODE:
4489 case XML_DOCUMENT_FRAG_NODE:
4490 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004491#ifdef LIBXML_DOCB_ENABLED
4492 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004493#endif
4494 return(((xmlDocPtr) ctxt->context->node)->children);
4495 case XML_ELEMENT_DECL:
4496 case XML_ATTRIBUTE_DECL:
4497 case XML_ENTITY_DECL:
4498 case XML_ATTRIBUTE_NODE:
4499 case XML_NAMESPACE_DECL:
4500 case XML_XINCLUDE_START:
4501 case XML_XINCLUDE_END:
4502 return(NULL);
4503 }
4504 return(NULL);
4505 }
4506 if ((cur->type == XML_DOCUMENT_NODE) ||
4507 (cur->type == XML_HTML_DOCUMENT_NODE))
4508 return(NULL);
4509 return(cur->next);
4510}
4511
4512/**
4513 * xmlXPathNextDescendant:
4514 * @ctxt: the XPath Parser context
4515 * @cur: the current node in the traversal
4516 *
4517 * Traversal function for the "descendant" direction
4518 * the descendant axis contains the descendants of the context node in document
4519 * order; a descendant is a child or a child of a child and so on.
4520 *
4521 * Returns the next element following that axis
4522 */
4523xmlNodePtr
4524xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4525 if (cur == NULL) {
4526 if (ctxt->context->node == NULL)
4527 return(NULL);
4528 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4529 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4530 return(NULL);
4531
4532 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
4533 return(ctxt->context->doc->children);
4534 return(ctxt->context->node->children);
4535 }
4536
Daniel Veillard567e1b42001-08-01 15:53:47 +00004537 if (cur->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004538 if (cur->children->type != XML_ENTITY_DECL)
Daniel Veillard567e1b42001-08-01 15:53:47 +00004539 return(cur->children);
4540 }
4541
4542 if (cur == ctxt->context->node) return(NULL);
4543
Owen Taylor3473f882001-02-23 17:55:21 +00004544 if (cur->next != NULL) return(cur->next);
4545
4546 do {
4547 cur = cur->parent;
4548 if (cur == NULL) return(NULL);
4549 if (cur == ctxt->context->node) return(NULL);
4550 if (cur->next != NULL) {
4551 cur = cur->next;
4552 return(cur);
4553 }
4554 } while (cur != NULL);
4555 return(cur);
4556}
4557
4558/**
4559 * xmlXPathNextDescendantOrSelf:
4560 * @ctxt: the XPath Parser context
4561 * @cur: the current node in the traversal
4562 *
4563 * Traversal function for the "descendant-or-self" direction
4564 * the descendant-or-self axis contains the context node and the descendants
4565 * of the context node in document order; thus the context node is the first
4566 * node on the axis, and the first child of the context node is the second node
4567 * on the axis
4568 *
4569 * Returns the next element following that axis
4570 */
4571xmlNodePtr
4572xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4573 if (cur == NULL) {
4574 if (ctxt->context->node == NULL)
4575 return(NULL);
4576 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4577 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4578 return(NULL);
4579 return(ctxt->context->node);
4580 }
4581
4582 return(xmlXPathNextDescendant(ctxt, cur));
4583}
4584
4585/**
4586 * xmlXPathNextParent:
4587 * @ctxt: the XPath Parser context
4588 * @cur: the current node in the traversal
4589 *
4590 * Traversal function for the "parent" direction
4591 * The parent axis contains the parent of the context node, if there is one.
4592 *
4593 * Returns the next element following that axis
4594 */
4595xmlNodePtr
4596xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4597 /*
4598 * the parent of an attribute or namespace node is the element
4599 * to which the attribute or namespace node is attached
4600 * Namespace handling !!!
4601 */
4602 if (cur == NULL) {
4603 if (ctxt->context->node == NULL) return(NULL);
4604 switch (ctxt->context->node->type) {
4605 case XML_ELEMENT_NODE:
4606 case XML_TEXT_NODE:
4607 case XML_CDATA_SECTION_NODE:
4608 case XML_ENTITY_REF_NODE:
4609 case XML_ENTITY_NODE:
4610 case XML_PI_NODE:
4611 case XML_COMMENT_NODE:
4612 case XML_NOTATION_NODE:
4613 case XML_DTD_NODE:
4614 case XML_ELEMENT_DECL:
4615 case XML_ATTRIBUTE_DECL:
4616 case XML_XINCLUDE_START:
4617 case XML_XINCLUDE_END:
4618 case XML_ENTITY_DECL:
4619 if (ctxt->context->node->parent == NULL)
4620 return((xmlNodePtr) ctxt->context->doc);
4621 return(ctxt->context->node->parent);
4622 case XML_ATTRIBUTE_NODE: {
4623 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4624
4625 return(att->parent);
4626 }
4627 case XML_DOCUMENT_NODE:
4628 case XML_DOCUMENT_TYPE_NODE:
4629 case XML_DOCUMENT_FRAG_NODE:
4630 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004631#ifdef LIBXML_DOCB_ENABLED
4632 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004633#endif
4634 return(NULL);
4635 case XML_NAMESPACE_DECL:
4636 /*
4637 * TODO !!! may require extending struct _xmlNs with
4638 * parent field
4639 * C.f. Infoset case...
4640 */
4641 return(NULL);
4642 }
4643 }
4644 return(NULL);
4645}
4646
4647/**
4648 * xmlXPathNextAncestor:
4649 * @ctxt: the XPath Parser context
4650 * @cur: the current node in the traversal
4651 *
4652 * Traversal function for the "ancestor" direction
4653 * the ancestor axis contains the ancestors of the context node; the ancestors
4654 * of the context node consist of the parent of context node and the parent's
4655 * parent and so on; the nodes are ordered in reverse document order; thus the
4656 * parent is the first node on the axis, and the parent's parent is the second
4657 * node on the axis
4658 *
4659 * Returns the next element following that axis
4660 */
4661xmlNodePtr
4662xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4663 /*
4664 * the parent of an attribute or namespace node is the element
4665 * to which the attribute or namespace node is attached
4666 * !!!!!!!!!!!!!
4667 */
4668 if (cur == NULL) {
4669 if (ctxt->context->node == NULL) return(NULL);
4670 switch (ctxt->context->node->type) {
4671 case XML_ELEMENT_NODE:
4672 case XML_TEXT_NODE:
4673 case XML_CDATA_SECTION_NODE:
4674 case XML_ENTITY_REF_NODE:
4675 case XML_ENTITY_NODE:
4676 case XML_PI_NODE:
4677 case XML_COMMENT_NODE:
4678 case XML_DTD_NODE:
4679 case XML_ELEMENT_DECL:
4680 case XML_ATTRIBUTE_DECL:
4681 case XML_ENTITY_DECL:
4682 case XML_NOTATION_NODE:
4683 case XML_XINCLUDE_START:
4684 case XML_XINCLUDE_END:
4685 if (ctxt->context->node->parent == NULL)
4686 return((xmlNodePtr) ctxt->context->doc);
4687 return(ctxt->context->node->parent);
4688 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004689 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00004690
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004691 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00004692 }
4693 case XML_DOCUMENT_NODE:
4694 case XML_DOCUMENT_TYPE_NODE:
4695 case XML_DOCUMENT_FRAG_NODE:
4696 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004697#ifdef LIBXML_DOCB_ENABLED
4698 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004699#endif
4700 return(NULL);
4701 case XML_NAMESPACE_DECL:
4702 /*
4703 * TODO !!! may require extending struct _xmlNs with
4704 * parent field
4705 * C.f. Infoset case...
4706 */
4707 return(NULL);
4708 }
4709 return(NULL);
4710 }
4711 if (cur == ctxt->context->doc->children)
4712 return((xmlNodePtr) ctxt->context->doc);
4713 if (cur == (xmlNodePtr) ctxt->context->doc)
4714 return(NULL);
4715 switch (cur->type) {
4716 case XML_ELEMENT_NODE:
4717 case XML_TEXT_NODE:
4718 case XML_CDATA_SECTION_NODE:
4719 case XML_ENTITY_REF_NODE:
4720 case XML_ENTITY_NODE:
4721 case XML_PI_NODE:
4722 case XML_COMMENT_NODE:
4723 case XML_NOTATION_NODE:
4724 case XML_DTD_NODE:
4725 case XML_ELEMENT_DECL:
4726 case XML_ATTRIBUTE_DECL:
4727 case XML_ENTITY_DECL:
4728 case XML_XINCLUDE_START:
4729 case XML_XINCLUDE_END:
4730 return(cur->parent);
4731 case XML_ATTRIBUTE_NODE: {
4732 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4733
4734 return(att->parent);
4735 }
4736 case XML_DOCUMENT_NODE:
4737 case XML_DOCUMENT_TYPE_NODE:
4738 case XML_DOCUMENT_FRAG_NODE:
4739 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004740#ifdef LIBXML_DOCB_ENABLED
4741 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004742#endif
4743 return(NULL);
4744 case XML_NAMESPACE_DECL:
4745 /*
4746 * TODO !!! may require extending struct _xmlNs with
4747 * parent field
4748 * C.f. Infoset case...
4749 */
4750 return(NULL);
4751 }
4752 return(NULL);
4753}
4754
4755/**
4756 * xmlXPathNextAncestorOrSelf:
4757 * @ctxt: the XPath Parser context
4758 * @cur: the current node in the traversal
4759 *
4760 * Traversal function for the "ancestor-or-self" direction
4761 * he ancestor-or-self axis contains the context node and ancestors of
4762 * the context node in reverse document order; thus the context node is
4763 * the first node on the axis, and the context node's parent the second;
4764 * parent here is defined the same as with the parent axis.
4765 *
4766 * Returns the next element following that axis
4767 */
4768xmlNodePtr
4769xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4770 if (cur == NULL)
4771 return(ctxt->context->node);
4772 return(xmlXPathNextAncestor(ctxt, cur));
4773}
4774
4775/**
4776 * xmlXPathNextFollowingSibling:
4777 * @ctxt: the XPath Parser context
4778 * @cur: the current node in the traversal
4779 *
4780 * Traversal function for the "following-sibling" direction
4781 * The following-sibling axis contains the following siblings of the context
4782 * node in document order.
4783 *
4784 * Returns the next element following that axis
4785 */
4786xmlNodePtr
4787xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4788 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4789 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4790 return(NULL);
4791 if (cur == (xmlNodePtr) ctxt->context->doc)
4792 return(NULL);
4793 if (cur == NULL)
4794 return(ctxt->context->node->next);
4795 return(cur->next);
4796}
4797
4798/**
4799 * xmlXPathNextPrecedingSibling:
4800 * @ctxt: the XPath Parser context
4801 * @cur: the current node in the traversal
4802 *
4803 * Traversal function for the "preceding-sibling" direction
4804 * The preceding-sibling axis contains the preceding siblings of the context
4805 * node in reverse document order; the first preceding sibling is first on the
4806 * axis; the sibling preceding that node is the second on the axis and so on.
4807 *
4808 * Returns the next element following that axis
4809 */
4810xmlNodePtr
4811xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4812 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4813 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4814 return(NULL);
4815 if (cur == (xmlNodePtr) ctxt->context->doc)
4816 return(NULL);
4817 if (cur == NULL)
4818 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004819 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
4820 cur = cur->prev;
4821 if (cur == NULL)
4822 return(ctxt->context->node->prev);
4823 }
Owen Taylor3473f882001-02-23 17:55:21 +00004824 return(cur->prev);
4825}
4826
4827/**
4828 * xmlXPathNextFollowing:
4829 * @ctxt: the XPath Parser context
4830 * @cur: the current node in the traversal
4831 *
4832 * Traversal function for the "following" direction
4833 * The following axis contains all nodes in the same document as the context
4834 * node that are after the context node in document order, excluding any
4835 * descendants and excluding attribute nodes and namespace nodes; the nodes
4836 * are ordered in document order
4837 *
4838 * Returns the next element following that axis
4839 */
4840xmlNodePtr
4841xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4842 if (cur != NULL && cur->children != NULL)
4843 return cur->children ;
4844 if (cur == NULL) cur = ctxt->context->node;
4845 if (cur == NULL) return(NULL) ; /* ERROR */
4846 if (cur->next != NULL) return(cur->next) ;
4847 do {
4848 cur = cur->parent;
4849 if (cur == NULL) return(NULL);
4850 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
4851 if (cur->next != NULL) return(cur->next);
4852 } while (cur != NULL);
4853 return(cur);
4854}
4855
4856/*
4857 * xmlXPathIsAncestor:
4858 * @ancestor: the ancestor node
4859 * @node: the current node
4860 *
4861 * Check that @ancestor is a @node's ancestor
4862 *
4863 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
4864 */
4865static int
4866xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
4867 if ((ancestor == NULL) || (node == NULL)) return(0);
4868 /* nodes need to be in the same document */
4869 if (ancestor->doc != node->doc) return(0);
4870 /* avoid searching if ancestor or node is the root node */
4871 if (ancestor == (xmlNodePtr) node->doc) return(1);
4872 if (node == (xmlNodePtr) ancestor->doc) return(0);
4873 while (node->parent != NULL) {
4874 if (node->parent == ancestor)
4875 return(1);
4876 node = node->parent;
4877 }
4878 return(0);
4879}
4880
4881/**
4882 * xmlXPathNextPreceding:
4883 * @ctxt: the XPath Parser context
4884 * @cur: the current node in the traversal
4885 *
4886 * Traversal function for the "preceding" direction
4887 * the preceding axis contains all nodes in the same document as the context
4888 * node that are before the context node in document order, excluding any
4889 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4890 * ordered in reverse document order
4891 *
4892 * Returns the next element following that axis
4893 */
4894xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00004895xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
4896{
Owen Taylor3473f882001-02-23 17:55:21 +00004897 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004898 cur = ctxt->context->node;
4899 if (cur == NULL)
4900 return (NULL);
4901 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
4902 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00004903 do {
4904 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004905 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
4906 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004907 }
4908
4909 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004910 if (cur == NULL)
4911 return (NULL);
4912 if (cur == ctxt->context->doc->children)
4913 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004914 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00004915 return (cur);
4916}
4917
4918/**
4919 * xmlXPathNextPrecedingInternal:
4920 * @ctxt: the XPath Parser context
4921 * @cur: the current node in the traversal
4922 *
4923 * Traversal function for the "preceding" direction
4924 * the preceding axis contains all nodes in the same document as the context
4925 * node that are before the context node in document order, excluding any
4926 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4927 * ordered in reverse document order
4928 * This is a faster implementation but internal only since it requires a
4929 * state kept in the parser context: ctxt->ancestor.
4930 *
4931 * Returns the next element following that axis
4932 */
4933static xmlNodePtr
4934xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
4935 xmlNodePtr cur)
4936{
4937 if (cur == NULL) {
4938 cur = ctxt->context->node;
4939 if (cur == NULL)
4940 return (NULL);
4941 ctxt->ancestor = cur->parent;
4942 }
4943 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
4944 cur = cur->prev;
4945 while (cur->prev == NULL) {
4946 cur = cur->parent;
4947 if (cur == NULL)
4948 return (NULL);
4949 if (cur == ctxt->context->doc->children)
4950 return (NULL);
4951 if (cur != ctxt->ancestor)
4952 return (cur);
4953 ctxt->ancestor = cur->parent;
4954 }
4955 cur = cur->prev;
4956 while (cur->last != NULL)
4957 cur = cur->last;
4958 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004959}
4960
4961/**
4962 * xmlXPathNextNamespace:
4963 * @ctxt: the XPath Parser context
4964 * @cur: the current attribute in the traversal
4965 *
4966 * Traversal function for the "namespace" direction
4967 * the namespace axis contains the namespace nodes of the context node;
4968 * the order of nodes on this axis is implementation-defined; the axis will
4969 * be empty unless the context node is an element
4970 *
4971 * Returns the next element following that axis
4972 */
4973xmlNodePtr
4974xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00004975 xmlNodePtr ret;
4976
Owen Taylor3473f882001-02-23 17:55:21 +00004977 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00004978 if ((cur == NULL) || (ctxt->context->tmpNsList == NULL)) {
4979 if (ctxt->context->tmpNsList != NULL)
4980 xmlFree(ctxt->context->tmpNsList);
4981 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00004982 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00004983 if (ctxt->context->tmpNsList == NULL) return(NULL);
4984 ctxt->context->tmpNsNr = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004985 }
Daniel Veillard7d7e3792001-07-30 13:42:13 +00004986 ret = (xmlNodePtr)ctxt->context->tmpNsList[ctxt->context->tmpNsNr++];
4987 if (ret == NULL) {
4988 xmlFree(ctxt->context->tmpNsList);
4989 ctxt->context->tmpNsList = NULL;
4990 }
4991 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004992}
4993
4994/**
4995 * xmlXPathNextAttribute:
4996 * @ctxt: the XPath Parser context
4997 * @cur: the current attribute in the traversal
4998 *
4999 * Traversal function for the "attribute" direction
5000 * TODO: support DTD inherited default attributes
5001 *
5002 * Returns the next element following that axis
5003 */
5004xmlNodePtr
5005xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005006 if (ctxt->context->node == NULL)
5007 return(NULL);
5008 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5009 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005010 if (cur == NULL) {
5011 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5012 return(NULL);
5013 return((xmlNodePtr)ctxt->context->node->properties);
5014 }
5015 return((xmlNodePtr)cur->next);
5016}
5017
5018/************************************************************************
5019 * *
5020 * NodeTest Functions *
5021 * *
5022 ************************************************************************/
5023
Owen Taylor3473f882001-02-23 17:55:21 +00005024#define IS_FUNCTION 200
5025
Owen Taylor3473f882001-02-23 17:55:21 +00005026
5027/************************************************************************
5028 * *
5029 * Implicit tree core function library *
5030 * *
5031 ************************************************************************/
5032
5033/**
5034 * xmlXPathRoot:
5035 * @ctxt: the XPath Parser context
5036 *
5037 * Initialize the context to the root of the document
5038 */
5039void
5040xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5041 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5042 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5043}
5044
5045/************************************************************************
5046 * *
5047 * The explicit core function library *
5048 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5049 * *
5050 ************************************************************************/
5051
5052
5053/**
5054 * xmlXPathLastFunction:
5055 * @ctxt: the XPath Parser context
5056 * @nargs: the number of arguments
5057 *
5058 * Implement the last() XPath function
5059 * number last()
5060 * The last function returns the number of nodes in the context node list.
5061 */
5062void
5063xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5064 CHECK_ARITY(0);
5065 if (ctxt->context->contextSize >= 0) {
5066 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5067#ifdef DEBUG_EXPR
5068 xmlGenericError(xmlGenericErrorContext,
5069 "last() : %d\n", ctxt->context->contextSize);
5070#endif
5071 } else {
5072 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5073 }
5074}
5075
5076/**
5077 * xmlXPathPositionFunction:
5078 * @ctxt: the XPath Parser context
5079 * @nargs: the number of arguments
5080 *
5081 * Implement the position() XPath function
5082 * number position()
5083 * The position function returns the position of the context node in the
5084 * context node list. The first position is 1, and so the last positionr
5085 * will be equal to last().
5086 */
5087void
5088xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5089 CHECK_ARITY(0);
5090 if (ctxt->context->proximityPosition >= 0) {
5091 valuePush(ctxt,
5092 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5093#ifdef DEBUG_EXPR
5094 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5095 ctxt->context->proximityPosition);
5096#endif
5097 } else {
5098 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5099 }
5100}
5101
5102/**
5103 * xmlXPathCountFunction:
5104 * @ctxt: the XPath Parser context
5105 * @nargs: the number of arguments
5106 *
5107 * Implement the count() XPath function
5108 * number count(node-set)
5109 */
5110void
5111xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5112 xmlXPathObjectPtr cur;
5113
5114 CHECK_ARITY(1);
5115 if ((ctxt->value == NULL) ||
5116 ((ctxt->value->type != XPATH_NODESET) &&
5117 (ctxt->value->type != XPATH_XSLT_TREE)))
5118 XP_ERROR(XPATH_INVALID_TYPE);
5119 cur = valuePop(ctxt);
5120
Daniel Veillard911f49a2001-04-07 15:39:35 +00005121 if ((cur == NULL) || (cur->nodesetval == NULL))
5122 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00005123 else if (cur->type == XPATH_NODESET) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005124 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005125 } else {
5126 if ((cur->nodesetval->nodeNr != 1) ||
5127 (cur->nodesetval->nodeTab == NULL)) {
5128 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5129 } else {
5130 xmlNodePtr tmp;
5131 int i = 0;
5132
5133 tmp = cur->nodesetval->nodeTab[0];
5134 if (tmp != NULL) {
5135 tmp = tmp->children;
5136 while (tmp != NULL) {
5137 tmp = tmp->next;
5138 i++;
5139 }
5140 }
5141 valuePush(ctxt, xmlXPathNewFloat((double) i));
5142 }
5143 }
Owen Taylor3473f882001-02-23 17:55:21 +00005144 xmlXPathFreeObject(cur);
5145}
5146
5147/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005148 * xmlXPathGetElementsByIds:
5149 * @doc: the document
5150 * @ids: a whitespace separated list of IDs
5151 *
5152 * Selects elements by their unique ID.
5153 *
5154 * Returns a node-set of selected elements.
5155 */
5156static xmlNodeSetPtr
5157xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5158 xmlNodeSetPtr ret;
5159 const xmlChar *cur = ids;
5160 xmlChar *ID;
5161 xmlAttrPtr attr;
5162 xmlNodePtr elem = NULL;
5163
5164 ret = xmlXPathNodeSetCreate(NULL);
5165
5166 while (IS_BLANK(*cur)) cur++;
5167 while (*cur != 0) {
5168 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
5169 (*cur == '.') || (*cur == '-') ||
5170 (*cur == '_') || (*cur == ':') ||
5171 (IS_COMBINING(*cur)) ||
5172 (IS_EXTENDER(*cur)))
5173 cur++;
5174
5175 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
5176
5177 ID = xmlStrndup(ids, cur - ids);
5178 attr = xmlGetID(doc, ID);
5179 if (attr != NULL) {
5180 elem = attr->parent;
5181 xmlXPathNodeSetAdd(ret, elem);
5182 }
5183 if (ID != NULL)
5184 xmlFree(ID);
5185
5186 while (IS_BLANK(*cur)) cur++;
5187 ids = cur;
5188 }
5189 return(ret);
5190}
5191
5192/**
Owen Taylor3473f882001-02-23 17:55:21 +00005193 * xmlXPathIdFunction:
5194 * @ctxt: the XPath Parser context
5195 * @nargs: the number of arguments
5196 *
5197 * Implement the id() XPath function
5198 * node-set id(object)
5199 * The id function selects elements by their unique ID
5200 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5201 * then the result is the union of the result of applying id to the
5202 * string value of each of the nodes in the argument node-set. When the
5203 * argument to id is of any other type, the argument is converted to a
5204 * string as if by a call to the string function; the string is split
5205 * into a whitespace-separated list of tokens (whitespace is any sequence
5206 * of characters matching the production S); the result is a node-set
5207 * containing the elements in the same document as the context node that
5208 * have a unique ID equal to any of the tokens in the list.
5209 */
5210void
5211xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005212 xmlChar *tokens;
5213 xmlNodeSetPtr ret;
5214 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00005215
5216 CHECK_ARITY(1);
5217 obj = valuePop(ctxt);
5218 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
5219 if (obj->type == XPATH_NODESET) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005220 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00005221 int i;
5222
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005223 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005224
Daniel Veillard911f49a2001-04-07 15:39:35 +00005225 if (obj->nodesetval != NULL) {
5226 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005227 tokens =
5228 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
5229 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
5230 ret = xmlXPathNodeSetMerge(ret, ns);
5231 xmlXPathFreeNodeSet(ns);
5232 if (tokens != NULL)
5233 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00005234 }
Owen Taylor3473f882001-02-23 17:55:21 +00005235 }
5236
5237 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005238 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005239 return;
5240 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005241 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00005242
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005243 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
5244 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005245
Owen Taylor3473f882001-02-23 17:55:21 +00005246 xmlXPathFreeObject(obj);
5247 return;
5248}
5249
5250/**
5251 * xmlXPathLocalNameFunction:
5252 * @ctxt: the XPath Parser context
5253 * @nargs: the number of arguments
5254 *
5255 * Implement the local-name() XPath function
5256 * string local-name(node-set?)
5257 * The local-name function returns a string containing the local part
5258 * of the name of the node in the argument node-set that is first in
5259 * document order. If the node-set is empty or the first node has no
5260 * name, an empty string is returned. If the argument is omitted it
5261 * defaults to the context node.
5262 */
5263void
5264xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5265 xmlXPathObjectPtr cur;
5266
5267 if (nargs == 0) {
5268 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5269 nargs = 1;
5270 }
5271
5272 CHECK_ARITY(1);
5273 if ((ctxt->value == NULL) ||
5274 ((ctxt->value->type != XPATH_NODESET) &&
5275 (ctxt->value->type != XPATH_XSLT_TREE)))
5276 XP_ERROR(XPATH_INVALID_TYPE);
5277 cur = valuePop(ctxt);
5278
Daniel Veillard911f49a2001-04-07 15:39:35 +00005279 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005280 valuePush(ctxt, xmlXPathNewCString(""));
5281 } else {
5282 int i = 0; /* Should be first in document order !!!!! */
5283 switch (cur->nodesetval->nodeTab[i]->type) {
5284 case XML_ELEMENT_NODE:
5285 case XML_ATTRIBUTE_NODE:
5286 case XML_PI_NODE:
5287 valuePush(ctxt,
5288 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
5289 break;
5290 case XML_NAMESPACE_DECL:
5291 valuePush(ctxt, xmlXPathNewString(
5292 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
5293 break;
5294 default:
5295 valuePush(ctxt, xmlXPathNewCString(""));
5296 }
5297 }
5298 xmlXPathFreeObject(cur);
5299}
5300
5301/**
5302 * xmlXPathNamespaceURIFunction:
5303 * @ctxt: the XPath Parser context
5304 * @nargs: the number of arguments
5305 *
5306 * Implement the namespace-uri() XPath function
5307 * string namespace-uri(node-set?)
5308 * The namespace-uri function returns a string containing the
5309 * namespace URI of the expanded name of the node in the argument
5310 * node-set that is first in document order. If the node-set is empty,
5311 * the first node has no name, or the expanded name has no namespace
5312 * URI, an empty string is returned. If the argument is omitted it
5313 * defaults to the context node.
5314 */
5315void
5316xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5317 xmlXPathObjectPtr cur;
5318
5319 if (nargs == 0) {
5320 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5321 nargs = 1;
5322 }
5323 CHECK_ARITY(1);
5324 if ((ctxt->value == NULL) ||
5325 ((ctxt->value->type != XPATH_NODESET) &&
5326 (ctxt->value->type != XPATH_XSLT_TREE)))
5327 XP_ERROR(XPATH_INVALID_TYPE);
5328 cur = valuePop(ctxt);
5329
Daniel Veillard911f49a2001-04-07 15:39:35 +00005330 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005331 valuePush(ctxt, xmlXPathNewCString(""));
5332 } else {
5333 int i = 0; /* Should be first in document order !!!!! */
5334 switch (cur->nodesetval->nodeTab[i]->type) {
5335 case XML_ELEMENT_NODE:
5336 case XML_ATTRIBUTE_NODE:
5337 if (cur->nodesetval->nodeTab[i]->ns == NULL)
5338 valuePush(ctxt, xmlXPathNewCString(""));
5339 else
5340 valuePush(ctxt, xmlXPathNewString(
5341 cur->nodesetval->nodeTab[i]->ns->href));
5342 break;
5343 default:
5344 valuePush(ctxt, xmlXPathNewCString(""));
5345 }
5346 }
5347 xmlXPathFreeObject(cur);
5348}
5349
5350/**
5351 * xmlXPathNameFunction:
5352 * @ctxt: the XPath Parser context
5353 * @nargs: the number of arguments
5354 *
5355 * Implement the name() XPath function
5356 * string name(node-set?)
5357 * The name function returns a string containing a QName representing
5358 * the name of the node in the argument node-set that is first in documenti
5359 * order. The QName must represent the name with respect to the namespace
5360 * declarations in effect on the node whose name is being represented.
5361 * Typically, this will be the form in which the name occurred in the XML
5362 * source. This need not be the case if there are namespace declarations
5363 * in effect on the node that associate multiple prefixes with the same
5364 * namespace. However, an implementation may include information about
5365 * the original prefix in its representation of nodes; in this case, an
5366 * implementation can ensure that the returned string is always the same
5367 * as the QName used in the XML source. If the argument it omitted it
5368 * defaults to the context node.
5369 * Libxml keep the original prefix so the "real qualified name" used is
5370 * returned.
5371 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005372static void
Daniel Veillard04383752001-07-08 14:27:15 +00005373xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
5374{
Owen Taylor3473f882001-02-23 17:55:21 +00005375 xmlXPathObjectPtr cur;
5376
5377 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00005378 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5379 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00005380 }
5381
5382 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00005383 if ((ctxt->value == NULL) ||
5384 ((ctxt->value->type != XPATH_NODESET) &&
5385 (ctxt->value->type != XPATH_XSLT_TREE)))
5386 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00005387 cur = valuePop(ctxt);
5388
Daniel Veillard911f49a2001-04-07 15:39:35 +00005389 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00005390 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00005391 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00005392 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005393
Daniel Veillard04383752001-07-08 14:27:15 +00005394 switch (cur->nodesetval->nodeTab[i]->type) {
5395 case XML_ELEMENT_NODE:
5396 case XML_ATTRIBUTE_NODE:
5397 if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
5398 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL))
5399 valuePush(ctxt,
5400 xmlXPathNewString(cur->nodesetval->
5401 nodeTab[i]->name));
5402
5403 else {
5404 char name[2000];
5405
5406 snprintf(name, sizeof(name), "%s:%s",
5407 (char *) cur->nodesetval->nodeTab[i]->ns->
5408 prefix,
5409 (char *) cur->nodesetval->nodeTab[i]->name);
5410 name[sizeof(name) - 1] = 0;
5411 valuePush(ctxt, xmlXPathNewCString(name));
5412 }
5413 break;
5414 default:
5415 valuePush(ctxt,
5416 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
5417 xmlXPathLocalNameFunction(ctxt, 1);
5418 }
Owen Taylor3473f882001-02-23 17:55:21 +00005419 }
5420 xmlXPathFreeObject(cur);
5421}
5422
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005423
5424/**
Owen Taylor3473f882001-02-23 17:55:21 +00005425 * xmlXPathStringFunction:
5426 * @ctxt: the XPath Parser context
5427 * @nargs: the number of arguments
5428 *
5429 * Implement the string() XPath function
5430 * string string(object?)
5431 * he string function converts an object to a string as follows:
5432 * - A node-set is converted to a string by returning the value of
5433 * the node in the node-set that is first in document order.
5434 * If the node-set is empty, an empty string is returned.
5435 * - A number is converted to a string as follows
5436 * + NaN is converted to the string NaN
5437 * + positive zero is converted to the string 0
5438 * + negative zero is converted to the string 0
5439 * + positive infinity is converted to the string Infinity
5440 * + negative infinity is converted to the string -Infinity
5441 * + if the number is an integer, the number is represented in
5442 * decimal form as a Number with no decimal point and no leading
5443 * zeros, preceded by a minus sign (-) if the number is negative
5444 * + otherwise, the number is represented in decimal form as a
5445 * Number including a decimal point with at least one digit
5446 * before the decimal point and at least one digit after the
5447 * decimal point, preceded by a minus sign (-) if the number
5448 * is negative; there must be no leading zeros before the decimal
5449 * point apart possibly from the one required digit immediatelyi
5450 * before the decimal point; beyond the one required digit
5451 * after the decimal point there must be as many, but only as
5452 * many, more digits as are needed to uniquely distinguish the
5453 * number from all other IEEE 754 numeric values.
5454 * - The boolean false value is converted to the string false.
5455 * The boolean true value is converted to the string true.
5456 *
5457 * If the argument is omitted, it defaults to a node-set with the
5458 * context node as its only member.
5459 */
5460void
5461xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5462 xmlXPathObjectPtr cur;
5463
5464 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005465 valuePush(ctxt,
5466 xmlXPathWrapString(
5467 xmlXPathCastNodeToString(ctxt->context->node)));
5468 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005469 }
5470
5471 CHECK_ARITY(1);
5472 cur = valuePop(ctxt);
5473 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005474 cur = xmlXPathConvertString(cur);
5475 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005476}
5477
5478/**
5479 * xmlXPathStringLengthFunction:
5480 * @ctxt: the XPath Parser context
5481 * @nargs: the number of arguments
5482 *
5483 * Implement the string-length() XPath function
5484 * number string-length(string?)
5485 * The string-length returns the number of characters in the string
5486 * (see [3.6 Strings]). If the argument is omitted, it defaults to
5487 * the context node converted to a string, in other words the value
5488 * of the context node.
5489 */
5490void
5491xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5492 xmlXPathObjectPtr cur;
5493
5494 if (nargs == 0) {
5495 if (ctxt->context->node == NULL) {
5496 valuePush(ctxt, xmlXPathNewFloat(0));
5497 } else {
5498 xmlChar *content;
5499
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005500 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005501 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00005502 xmlFree(content);
5503 }
5504 return;
5505 }
5506 CHECK_ARITY(1);
5507 CAST_TO_STRING;
5508 CHECK_TYPE(XPATH_STRING);
5509 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005510 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00005511 xmlXPathFreeObject(cur);
5512}
5513
5514/**
5515 * xmlXPathConcatFunction:
5516 * @ctxt: the XPath Parser context
5517 * @nargs: the number of arguments
5518 *
5519 * Implement the concat() XPath function
5520 * string concat(string, string, string*)
5521 * The concat function returns the concatenation of its arguments.
5522 */
5523void
5524xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5525 xmlXPathObjectPtr cur, newobj;
5526 xmlChar *tmp;
5527
5528 if (nargs < 2) {
5529 CHECK_ARITY(2);
5530 }
5531
5532 CAST_TO_STRING;
5533 cur = valuePop(ctxt);
5534 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
5535 xmlXPathFreeObject(cur);
5536 return;
5537 }
5538 nargs--;
5539
5540 while (nargs > 0) {
5541 CAST_TO_STRING;
5542 newobj = valuePop(ctxt);
5543 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
5544 xmlXPathFreeObject(newobj);
5545 xmlXPathFreeObject(cur);
5546 XP_ERROR(XPATH_INVALID_TYPE);
5547 }
5548 tmp = xmlStrcat(newobj->stringval, cur->stringval);
5549 newobj->stringval = cur->stringval;
5550 cur->stringval = tmp;
5551
5552 xmlXPathFreeObject(newobj);
5553 nargs--;
5554 }
5555 valuePush(ctxt, cur);
5556}
5557
5558/**
5559 * xmlXPathContainsFunction:
5560 * @ctxt: the XPath Parser context
5561 * @nargs: the number of arguments
5562 *
5563 * Implement the contains() XPath function
5564 * boolean contains(string, string)
5565 * The contains function returns true if the first argument string
5566 * contains the second argument string, and otherwise returns false.
5567 */
5568void
5569xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5570 xmlXPathObjectPtr hay, needle;
5571
5572 CHECK_ARITY(2);
5573 CAST_TO_STRING;
5574 CHECK_TYPE(XPATH_STRING);
5575 needle = valuePop(ctxt);
5576 CAST_TO_STRING;
5577 hay = valuePop(ctxt);
5578 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5579 xmlXPathFreeObject(hay);
5580 xmlXPathFreeObject(needle);
5581 XP_ERROR(XPATH_INVALID_TYPE);
5582 }
5583 if (xmlStrstr(hay->stringval, needle->stringval))
5584 valuePush(ctxt, xmlXPathNewBoolean(1));
5585 else
5586 valuePush(ctxt, xmlXPathNewBoolean(0));
5587 xmlXPathFreeObject(hay);
5588 xmlXPathFreeObject(needle);
5589}
5590
5591/**
5592 * xmlXPathStartsWithFunction:
5593 * @ctxt: the XPath Parser context
5594 * @nargs: the number of arguments
5595 *
5596 * Implement the starts-with() XPath function
5597 * boolean starts-with(string, string)
5598 * The starts-with function returns true if the first argument string
5599 * starts with the second argument string, and otherwise returns false.
5600 */
5601void
5602xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5603 xmlXPathObjectPtr hay, needle;
5604 int n;
5605
5606 CHECK_ARITY(2);
5607 CAST_TO_STRING;
5608 CHECK_TYPE(XPATH_STRING);
5609 needle = valuePop(ctxt);
5610 CAST_TO_STRING;
5611 hay = valuePop(ctxt);
5612 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5613 xmlXPathFreeObject(hay);
5614 xmlXPathFreeObject(needle);
5615 XP_ERROR(XPATH_INVALID_TYPE);
5616 }
5617 n = xmlStrlen(needle->stringval);
5618 if (xmlStrncmp(hay->stringval, needle->stringval, n))
5619 valuePush(ctxt, xmlXPathNewBoolean(0));
5620 else
5621 valuePush(ctxt, xmlXPathNewBoolean(1));
5622 xmlXPathFreeObject(hay);
5623 xmlXPathFreeObject(needle);
5624}
5625
5626/**
5627 * xmlXPathSubstringFunction:
5628 * @ctxt: the XPath Parser context
5629 * @nargs: the number of arguments
5630 *
5631 * Implement the substring() XPath function
5632 * string substring(string, number, number?)
5633 * The substring function returns the substring of the first argument
5634 * starting at the position specified in the second argument with
5635 * length specified in the third argument. For example,
5636 * substring("12345",2,3) returns "234". If the third argument is not
5637 * specified, it returns the substring starting at the position specified
5638 * in the second argument and continuing to the end of the string. For
5639 * example, substring("12345",2) returns "2345". More precisely, each
5640 * character in the string (see [3.6 Strings]) is considered to have a
5641 * numeric position: the position of the first character is 1, the position
5642 * of the second character is 2 and so on. The returned substring contains
5643 * those characters for which the position of the character is greater than
5644 * or equal to the second argument and, if the third argument is specified,
5645 * less than the sum of the second and third arguments; the comparisons
5646 * and addition used for the above follow the standard IEEE 754 rules. Thus:
5647 * - substring("12345", 1.5, 2.6) returns "234"
5648 * - substring("12345", 0, 3) returns "12"
5649 * - substring("12345", 0 div 0, 3) returns ""
5650 * - substring("12345", 1, 0 div 0) returns ""
5651 * - substring("12345", -42, 1 div 0) returns "12345"
5652 * - substring("12345", -1 div 0, 1 div 0) returns ""
5653 */
5654void
5655xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5656 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005657 double le=0, in;
5658 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00005659 xmlChar *ret;
5660
Owen Taylor3473f882001-02-23 17:55:21 +00005661 if (nargs < 2) {
5662 CHECK_ARITY(2);
5663 }
5664 if (nargs > 3) {
5665 CHECK_ARITY(3);
5666 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005667 /*
5668 * take care of possible last (position) argument
5669 */
Owen Taylor3473f882001-02-23 17:55:21 +00005670 if (nargs == 3) {
5671 CAST_TO_NUMBER;
5672 CHECK_TYPE(XPATH_NUMBER);
5673 len = valuePop(ctxt);
5674 le = len->floatval;
5675 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00005676 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005677
Owen Taylor3473f882001-02-23 17:55:21 +00005678 CAST_TO_NUMBER;
5679 CHECK_TYPE(XPATH_NUMBER);
5680 start = valuePop(ctxt);
5681 in = start->floatval;
5682 xmlXPathFreeObject(start);
5683 CAST_TO_STRING;
5684 CHECK_TYPE(XPATH_STRING);
5685 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00005686 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005687
Daniel Veillard97ac1312001-05-30 19:14:17 +00005688 /*
5689 * If last pos not present, calculate last position
5690 */
5691 if (nargs != 3)
5692 le = m;
5693
5694 /*
5695 * To meet our requirements, initial index calculations
5696 * must be done before we convert to integer format
5697 *
5698 * First we normalize indices
5699 */
5700 in -= 1.0;
5701 le += in;
5702 if (in < 0.0)
5703 in = 0.0;
5704 if (le > (double)m)
5705 le = (double)m;
5706
5707 /*
5708 * Now we go to integer form, rounding up
5709 */
Owen Taylor3473f882001-02-23 17:55:21 +00005710 i = (int) in;
5711 if (((double)i) != in) i++;
5712
Owen Taylor3473f882001-02-23 17:55:21 +00005713 l = (int) le;
5714 if (((double)l) != le) l++;
5715
Daniel Veillard97ac1312001-05-30 19:14:17 +00005716 if (l > m) l=m;
Owen Taylor3473f882001-02-23 17:55:21 +00005717
5718 /* number of chars to copy */
5719 l -= i;
5720
Daniel Veillard97ac1312001-05-30 19:14:17 +00005721 ret = xmlUTF8Strsub(str->stringval, i, l);
Owen Taylor3473f882001-02-23 17:55:21 +00005722 if (ret == NULL)
5723 valuePush(ctxt, xmlXPathNewCString(""));
5724 else {
5725 valuePush(ctxt, xmlXPathNewString(ret));
5726 xmlFree(ret);
5727 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005728
Owen Taylor3473f882001-02-23 17:55:21 +00005729 xmlXPathFreeObject(str);
5730}
5731
5732/**
5733 * xmlXPathSubstringBeforeFunction:
5734 * @ctxt: the XPath Parser context
5735 * @nargs: the number of arguments
5736 *
5737 * Implement the substring-before() XPath function
5738 * string substring-before(string, string)
5739 * The substring-before function returns the substring of the first
5740 * argument string that precedes the first occurrence of the second
5741 * argument string in the first argument string, or the empty string
5742 * if the first argument string does not contain the second argument
5743 * string. For example, substring-before("1999/04/01","/") returns 1999.
5744 */
5745void
5746xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5747 xmlXPathObjectPtr str;
5748 xmlXPathObjectPtr find;
5749 xmlBufferPtr target;
5750 const xmlChar *point;
5751 int offset;
5752
5753 CHECK_ARITY(2);
5754 CAST_TO_STRING;
5755 find = valuePop(ctxt);
5756 CAST_TO_STRING;
5757 str = valuePop(ctxt);
5758
5759 target = xmlBufferCreate();
5760 if (target) {
5761 point = xmlStrstr(str->stringval, find->stringval);
5762 if (point) {
5763 offset = (int)(point - str->stringval);
5764 xmlBufferAdd(target, str->stringval, offset);
5765 }
5766 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5767 xmlBufferFree(target);
5768 }
5769
5770 xmlXPathFreeObject(str);
5771 xmlXPathFreeObject(find);
5772}
5773
5774/**
5775 * xmlXPathSubstringAfterFunction:
5776 * @ctxt: the XPath Parser context
5777 * @nargs: the number of arguments
5778 *
5779 * Implement the substring-after() XPath function
5780 * string substring-after(string, string)
5781 * The substring-after function returns the substring of the first
5782 * argument string that follows the first occurrence of the second
5783 * argument string in the first argument string, or the empty stringi
5784 * if the first argument string does not contain the second argument
5785 * string. For example, substring-after("1999/04/01","/") returns 04/01,
5786 * and substring-after("1999/04/01","19") returns 99/04/01.
5787 */
5788void
5789xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5790 xmlXPathObjectPtr str;
5791 xmlXPathObjectPtr find;
5792 xmlBufferPtr target;
5793 const xmlChar *point;
5794 int offset;
5795
5796 CHECK_ARITY(2);
5797 CAST_TO_STRING;
5798 find = valuePop(ctxt);
5799 CAST_TO_STRING;
5800 str = valuePop(ctxt);
5801
5802 target = xmlBufferCreate();
5803 if (target) {
5804 point = xmlStrstr(str->stringval, find->stringval);
5805 if (point) {
5806 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
5807 xmlBufferAdd(target, &str->stringval[offset],
5808 xmlStrlen(str->stringval) - offset);
5809 }
5810 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5811 xmlBufferFree(target);
5812 }
5813
5814 xmlXPathFreeObject(str);
5815 xmlXPathFreeObject(find);
5816}
5817
5818/**
5819 * xmlXPathNormalizeFunction:
5820 * @ctxt: the XPath Parser context
5821 * @nargs: the number of arguments
5822 *
5823 * Implement the normalize-space() XPath function
5824 * string normalize-space(string?)
5825 * The normalize-space function returns the argument string with white
5826 * space normalized by stripping leading and trailing whitespace
5827 * and replacing sequences of whitespace characters by a single
5828 * space. Whitespace characters are the same allowed by the S production
5829 * in XML. If the argument is omitted, it defaults to the context
5830 * node converted to a string, in other words the value of the context node.
5831 */
5832void
5833xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5834 xmlXPathObjectPtr obj = NULL;
5835 xmlChar *source = NULL;
5836 xmlBufferPtr target;
5837 xmlChar blank;
5838
5839 if (nargs == 0) {
5840 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005841 valuePush(ctxt,
5842 xmlXPathWrapString(
5843 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00005844 nargs = 1;
5845 }
5846
5847 CHECK_ARITY(1);
5848 CAST_TO_STRING;
5849 CHECK_TYPE(XPATH_STRING);
5850 obj = valuePop(ctxt);
5851 source = obj->stringval;
5852
5853 target = xmlBufferCreate();
5854 if (target && source) {
5855
5856 /* Skip leading whitespaces */
5857 while (IS_BLANK(*source))
5858 source++;
5859
5860 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
5861 blank = 0;
5862 while (*source) {
5863 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005864 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00005865 } else {
5866 if (blank) {
5867 xmlBufferAdd(target, &blank, 1);
5868 blank = 0;
5869 }
5870 xmlBufferAdd(target, source, 1);
5871 }
5872 source++;
5873 }
5874
5875 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5876 xmlBufferFree(target);
5877 }
5878 xmlXPathFreeObject(obj);
5879}
5880
5881/**
5882 * xmlXPathTranslateFunction:
5883 * @ctxt: the XPath Parser context
5884 * @nargs: the number of arguments
5885 *
5886 * Implement the translate() XPath function
5887 * string translate(string, string, string)
5888 * The translate function returns the first argument string with
5889 * occurrences of characters in the second argument string replaced
5890 * by the character at the corresponding position in the third argument
5891 * string. For example, translate("bar","abc","ABC") returns the string
5892 * BAr. If there is a character in the second argument string with no
5893 * character at a corresponding position in the third argument string
5894 * (because the second argument string is longer than the third argument
5895 * string), then occurrences of that character in the first argument
5896 * string are removed. For example, translate("--aaa--","abc-","ABC")
5897 * returns "AAA". If a character occurs more than once in second
5898 * argument string, then the first occurrence determines the replacement
5899 * character. If the third argument string is longer than the second
5900 * argument string, then excess characters are ignored.
5901 */
5902void
5903xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00005904 xmlXPathObjectPtr str;
5905 xmlXPathObjectPtr from;
5906 xmlXPathObjectPtr to;
5907 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005908 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00005909 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005910 xmlChar *point;
5911 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00005912
Daniel Veillarde043ee12001-04-16 14:08:07 +00005913 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00005914
Daniel Veillarde043ee12001-04-16 14:08:07 +00005915 CAST_TO_STRING;
5916 to = valuePop(ctxt);
5917 CAST_TO_STRING;
5918 from = valuePop(ctxt);
5919 CAST_TO_STRING;
5920 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005921
Daniel Veillarde043ee12001-04-16 14:08:07 +00005922 target = xmlBufferCreate();
5923 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005924 max = xmlUTF8Strlen(to->stringval);
5925 for (cptr = str->stringval; (ch=*cptr); ) {
5926 offset = xmlUTF8Strloc(from->stringval, cptr);
5927 if (offset >= 0) {
5928 if (offset < max) {
5929 point = xmlUTF8Strpos(to->stringval, offset);
5930 if (point)
5931 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
5932 }
5933 } else
5934 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
5935
5936 /* Step to next character in input */
5937 cptr++;
5938 if ( ch & 0x80 ) {
5939 /* if not simple ascii, verify proper format */
5940 if ( (ch & 0xc0) != 0xc0 ) {
5941 xmlGenericError(xmlGenericErrorContext,
5942 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5943 break;
5944 }
5945 /* then skip over remaining bytes for this char */
5946 while ( (ch <<= 1) & 0x80 )
5947 if ( (*cptr++ & 0xc0) != 0x80 ) {
5948 xmlGenericError(xmlGenericErrorContext,
5949 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5950 break;
5951 }
5952 if (ch & 0x80) /* must have had error encountered */
5953 break;
5954 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005955 }
Owen Taylor3473f882001-02-23 17:55:21 +00005956 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005957 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5958 xmlBufferFree(target);
5959 xmlXPathFreeObject(str);
5960 xmlXPathFreeObject(from);
5961 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00005962}
5963
5964/**
5965 * xmlXPathBooleanFunction:
5966 * @ctxt: the XPath Parser context
5967 * @nargs: the number of arguments
5968 *
5969 * Implement the boolean() XPath function
5970 * boolean boolean(object)
5971 * he boolean function converts its argument to a boolean as follows:
5972 * - a number is true if and only if it is neither positive or
5973 * negative zero nor NaN
5974 * - a node-set is true if and only if it is non-empty
5975 * - a string is true if and only if its length is non-zero
5976 */
5977void
5978xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5979 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00005980
5981 CHECK_ARITY(1);
5982 cur = valuePop(ctxt);
5983 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005984 cur = xmlXPathConvertBoolean(cur);
5985 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005986}
5987
5988/**
5989 * xmlXPathNotFunction:
5990 * @ctxt: the XPath Parser context
5991 * @nargs: the number of arguments
5992 *
5993 * Implement the not() XPath function
5994 * boolean not(boolean)
5995 * The not function returns true if its argument is false,
5996 * and false otherwise.
5997 */
5998void
5999xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6000 CHECK_ARITY(1);
6001 CAST_TO_BOOLEAN;
6002 CHECK_TYPE(XPATH_BOOLEAN);
6003 ctxt->value->boolval = ! ctxt->value->boolval;
6004}
6005
6006/**
6007 * xmlXPathTrueFunction:
6008 * @ctxt: the XPath Parser context
6009 * @nargs: the number of arguments
6010 *
6011 * Implement the true() XPath function
6012 * boolean true()
6013 */
6014void
6015xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6016 CHECK_ARITY(0);
6017 valuePush(ctxt, xmlXPathNewBoolean(1));
6018}
6019
6020/**
6021 * xmlXPathFalseFunction:
6022 * @ctxt: the XPath Parser context
6023 * @nargs: the number of arguments
6024 *
6025 * Implement the false() XPath function
6026 * boolean false()
6027 */
6028void
6029xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6030 CHECK_ARITY(0);
6031 valuePush(ctxt, xmlXPathNewBoolean(0));
6032}
6033
6034/**
6035 * xmlXPathLangFunction:
6036 * @ctxt: the XPath Parser context
6037 * @nargs: the number of arguments
6038 *
6039 * Implement the lang() XPath function
6040 * boolean lang(string)
6041 * The lang function returns true or false depending on whether the
6042 * language of the context node as specified by xml:lang attributes
6043 * is the same as or is a sublanguage of the language specified by
6044 * the argument string. The language of the context node is determined
6045 * by the value of the xml:lang attribute on the context node, or, if
6046 * the context node has no xml:lang attribute, by the value of the
6047 * xml:lang attribute on the nearest ancestor of the context node that
6048 * has an xml:lang attribute. If there is no such attribute, then lang
6049 * returns false. If there is such an attribute, then lang returns
6050 * true if the attribute value is equal to the argument ignoring case,
6051 * or if there is some suffix starting with - such that the attribute
6052 * value is equal to the argument ignoring that suffix of the attribute
6053 * value and ignoring case.
6054 */
6055void
6056xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6057 xmlXPathObjectPtr val;
6058 const xmlChar *theLang;
6059 const xmlChar *lang;
6060 int ret = 0;
6061 int i;
6062
6063 CHECK_ARITY(1);
6064 CAST_TO_STRING;
6065 CHECK_TYPE(XPATH_STRING);
6066 val = valuePop(ctxt);
6067 lang = val->stringval;
6068 theLang = xmlNodeGetLang(ctxt->context->node);
6069 if ((theLang != NULL) && (lang != NULL)) {
6070 for (i = 0;lang[i] != 0;i++)
6071 if (toupper(lang[i]) != toupper(theLang[i]))
6072 goto not_equal;
6073 ret = 1;
6074 }
6075not_equal:
6076 xmlXPathFreeObject(val);
6077 valuePush(ctxt, xmlXPathNewBoolean(ret));
6078}
6079
6080/**
6081 * xmlXPathNumberFunction:
6082 * @ctxt: the XPath Parser context
6083 * @nargs: the number of arguments
6084 *
6085 * Implement the number() XPath function
6086 * number number(object?)
6087 */
6088void
6089xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6090 xmlXPathObjectPtr cur;
6091 double res;
6092
6093 if (nargs == 0) {
6094 if (ctxt->context->node == NULL) {
6095 valuePush(ctxt, xmlXPathNewFloat(0.0));
6096 } else {
6097 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6098
6099 res = xmlXPathStringEvalNumber(content);
6100 valuePush(ctxt, xmlXPathNewFloat(res));
6101 xmlFree(content);
6102 }
6103 return;
6104 }
6105
6106 CHECK_ARITY(1);
6107 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006108 cur = xmlXPathConvertNumber(cur);
6109 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006110}
6111
6112/**
6113 * xmlXPathSumFunction:
6114 * @ctxt: the XPath Parser context
6115 * @nargs: the number of arguments
6116 *
6117 * Implement the sum() XPath function
6118 * number sum(node-set)
6119 * The sum function returns the sum of the values of the nodes in
6120 * the argument node-set.
6121 */
6122void
6123xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6124 xmlXPathObjectPtr cur;
6125 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006126 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006127
6128 CHECK_ARITY(1);
6129 if ((ctxt->value == NULL) ||
6130 ((ctxt->value->type != XPATH_NODESET) &&
6131 (ctxt->value->type != XPATH_XSLT_TREE)))
6132 XP_ERROR(XPATH_INVALID_TYPE);
6133 cur = valuePop(ctxt);
6134
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006135 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006136 valuePush(ctxt, xmlXPathNewFloat(0.0));
6137 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006138 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6139 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006140 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006141 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006142 }
6143 xmlXPathFreeObject(cur);
6144}
6145
6146/**
6147 * xmlXPathFloorFunction:
6148 * @ctxt: the XPath Parser context
6149 * @nargs: the number of arguments
6150 *
6151 * Implement the floor() XPath function
6152 * number floor(number)
6153 * The floor function returns the largest (closest to positive infinity)
6154 * number that is not greater than the argument and that is an integer.
6155 */
6156void
6157xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6158 CHECK_ARITY(1);
6159 CAST_TO_NUMBER;
6160 CHECK_TYPE(XPATH_NUMBER);
6161#if 0
6162 ctxt->value->floatval = floor(ctxt->value->floatval);
6163#else
6164 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
6165 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
6166#endif
6167}
6168
6169/**
6170 * xmlXPathCeilingFunction:
6171 * @ctxt: the XPath Parser context
6172 * @nargs: the number of arguments
6173 *
6174 * Implement the ceiling() XPath function
6175 * number ceiling(number)
6176 * The ceiling function returns the smallest (closest to negative infinity)
6177 * number that is not less than the argument and that is an integer.
6178 */
6179void
6180xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6181 double f;
6182
6183 CHECK_ARITY(1);
6184 CAST_TO_NUMBER;
6185 CHECK_TYPE(XPATH_NUMBER);
6186
6187#if 0
6188 ctxt->value->floatval = ceil(ctxt->value->floatval);
6189#else
6190 f = (double)((int) ctxt->value->floatval);
6191 if (f != ctxt->value->floatval)
6192 ctxt->value->floatval = f + 1;
6193#endif
6194}
6195
6196/**
6197 * xmlXPathRoundFunction:
6198 * @ctxt: the XPath Parser context
6199 * @nargs: the number of arguments
6200 *
6201 * Implement the round() XPath function
6202 * number round(number)
6203 * The round function returns the number that is closest to the
6204 * argument and that is an integer. If there are two such numbers,
6205 * then the one that is even is returned.
6206 */
6207void
6208xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6209 double f;
6210
6211 CHECK_ARITY(1);
6212 CAST_TO_NUMBER;
6213 CHECK_TYPE(XPATH_NUMBER);
6214
Daniel Veillardcda96922001-08-21 10:56:31 +00006215 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
6216 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
6217 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00006218 (ctxt->value->floatval == 0.0))
6219 return;
6220
6221#if 0
6222 f = floor(ctxt->value->floatval);
6223#else
6224 f = (double)((int) ctxt->value->floatval);
6225#endif
6226 if (ctxt->value->floatval < f + 0.5)
6227 ctxt->value->floatval = f;
6228 else
6229 ctxt->value->floatval = f + 1;
6230}
6231
6232/************************************************************************
6233 * *
6234 * The Parser *
6235 * *
6236 ************************************************************************/
6237
6238/*
6239 * a couple of forward declarations since we use a recursive call based
6240 * implementation.
6241 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006242static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006243static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006244static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006245#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006246static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
6247#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006248#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006249static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006250#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00006251static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
6252 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00006253
6254/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00006255 * xmlXPathCurrentChar:
6256 * @ctxt: the XPath parser context
6257 * @cur: pointer to the beginning of the char
6258 * @len: pointer to the length of the char read
6259 *
6260 * The current char value, if using UTF-8 this may actaully span multiple
6261 * bytes in the input buffer.
6262 *
6263 * Returns the current char value and its lenght
6264 */
6265
6266static int
6267xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
6268 unsigned char c;
6269 unsigned int val;
6270 const xmlChar *cur;
6271
6272 if (ctxt == NULL)
6273 return(0);
6274 cur = ctxt->cur;
6275
6276 /*
6277 * We are supposed to handle UTF8, check it's valid
6278 * From rfc2044: encoding of the Unicode values on UTF-8:
6279 *
6280 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
6281 * 0000 0000-0000 007F 0xxxxxxx
6282 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
6283 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
6284 *
6285 * Check for the 0x110000 limit too
6286 */
6287 c = *cur;
6288 if (c & 0x80) {
6289 if ((cur[1] & 0xc0) != 0x80)
6290 goto encoding_error;
6291 if ((c & 0xe0) == 0xe0) {
6292
6293 if ((cur[2] & 0xc0) != 0x80)
6294 goto encoding_error;
6295 if ((c & 0xf0) == 0xf0) {
6296 if (((c & 0xf8) != 0xf0) ||
6297 ((cur[3] & 0xc0) != 0x80))
6298 goto encoding_error;
6299 /* 4-byte code */
6300 *len = 4;
6301 val = (cur[0] & 0x7) << 18;
6302 val |= (cur[1] & 0x3f) << 12;
6303 val |= (cur[2] & 0x3f) << 6;
6304 val |= cur[3] & 0x3f;
6305 } else {
6306 /* 3-byte code */
6307 *len = 3;
6308 val = (cur[0] & 0xf) << 12;
6309 val |= (cur[1] & 0x3f) << 6;
6310 val |= cur[2] & 0x3f;
6311 }
6312 } else {
6313 /* 2-byte code */
6314 *len = 2;
6315 val = (cur[0] & 0x1f) << 6;
6316 val |= cur[1] & 0x3f;
6317 }
6318 if (!IS_CHAR(val)) {
6319 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
6320 }
6321 return(val);
6322 } else {
6323 /* 1-byte code */
6324 *len = 1;
6325 return((int) *cur);
6326 }
6327encoding_error:
6328 /*
6329 * If we detect an UTF8 error that probably mean that the
6330 * input encoding didn't get properly advertized in the
6331 * declaration header. Report the error and switch the encoding
6332 * to ISO-Latin-1 (if you don't like this policy, just declare the
6333 * encoding !)
6334 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00006335 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00006336 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006337}
6338
6339/**
Owen Taylor3473f882001-02-23 17:55:21 +00006340 * xmlXPathParseNCName:
6341 * @ctxt: the XPath Parser context
6342 *
6343 * parse an XML namespace non qualified name.
6344 *
6345 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
6346 *
6347 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
6348 * CombiningChar | Extender
6349 *
6350 * Returns the namespace name or NULL
6351 */
6352
6353xmlChar *
6354xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00006355 const xmlChar *in;
6356 xmlChar *ret;
6357 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006358
Daniel Veillard2156a562001-04-28 12:24:34 +00006359 /*
6360 * Accelerator for simple ASCII names
6361 */
6362 in = ctxt->cur;
6363 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6364 ((*in >= 0x41) && (*in <= 0x5A)) ||
6365 (*in == '_')) {
6366 in++;
6367 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6368 ((*in >= 0x41) && (*in <= 0x5A)) ||
6369 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00006370 (*in == '_') || (*in == '.') ||
6371 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00006372 in++;
6373 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
6374 (*in == '[') || (*in == ']') || (*in == ':') ||
6375 (*in == '@') || (*in == '*')) {
6376 count = in - ctxt->cur;
6377 if (count == 0)
6378 return(NULL);
6379 ret = xmlStrndup(ctxt->cur, count);
6380 ctxt->cur = in;
6381 return(ret);
6382 }
6383 }
6384 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00006385}
6386
Daniel Veillard2156a562001-04-28 12:24:34 +00006387
Owen Taylor3473f882001-02-23 17:55:21 +00006388/**
6389 * xmlXPathParseQName:
6390 * @ctxt: the XPath Parser context
6391 * @prefix: a xmlChar **
6392 *
6393 * parse an XML qualified name
6394 *
6395 * [NS 5] QName ::= (Prefix ':')? LocalPart
6396 *
6397 * [NS 6] Prefix ::= NCName
6398 *
6399 * [NS 7] LocalPart ::= NCName
6400 *
6401 * Returns the function returns the local part, and prefix is updated
6402 * to get the Prefix if any.
6403 */
6404
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006405static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006406xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
6407 xmlChar *ret = NULL;
6408
6409 *prefix = NULL;
6410 ret = xmlXPathParseNCName(ctxt);
6411 if (CUR == ':') {
6412 *prefix = ret;
6413 NEXT;
6414 ret = xmlXPathParseNCName(ctxt);
6415 }
6416 return(ret);
6417}
6418
6419/**
6420 * xmlXPathParseName:
6421 * @ctxt: the XPath Parser context
6422 *
6423 * parse an XML name
6424 *
6425 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6426 * CombiningChar | Extender
6427 *
6428 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6429 *
6430 * Returns the namespace name or NULL
6431 */
6432
6433xmlChar *
6434xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006435 const xmlChar *in;
6436 xmlChar *ret;
6437 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006438
Daniel Veillard61d80a22001-04-27 17:13:01 +00006439 /*
6440 * Accelerator for simple ASCII names
6441 */
6442 in = ctxt->cur;
6443 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6444 ((*in >= 0x41) && (*in <= 0x5A)) ||
6445 (*in == '_') || (*in == ':')) {
6446 in++;
6447 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6448 ((*in >= 0x41) && (*in <= 0x5A)) ||
6449 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00006450 (*in == '_') || (*in == '-') ||
6451 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00006452 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00006453 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006454 count = in - ctxt->cur;
6455 ret = xmlStrndup(ctxt->cur, count);
6456 ctxt->cur = in;
6457 return(ret);
6458 }
6459 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006460 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00006461}
6462
Daniel Veillard61d80a22001-04-27 17:13:01 +00006463static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00006464xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006465 xmlChar buf[XML_MAX_NAMELEN + 5];
6466 int len = 0, l;
6467 int c;
6468
6469 /*
6470 * Handler for more complex cases
6471 */
6472 c = CUR_CHAR(l);
6473 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00006474 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
6475 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00006476 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00006477 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006478 return(NULL);
6479 }
6480
6481 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
6482 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
6483 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006484 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006485 (IS_COMBINING(c)) ||
6486 (IS_EXTENDER(c)))) {
6487 COPY_BUF(l,buf,len,c);
6488 NEXTL(l);
6489 c = CUR_CHAR(l);
6490 if (len >= XML_MAX_NAMELEN) {
6491 /*
6492 * Okay someone managed to make a huge name, so he's ready to pay
6493 * for the processing speed.
6494 */
6495 xmlChar *buffer;
6496 int max = len * 2;
6497
6498 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
6499 if (buffer == NULL) {
6500 XP_ERROR0(XPATH_MEMORY_ERROR);
6501 }
6502 memcpy(buffer, buf, len);
6503 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
6504 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006505 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006506 (IS_COMBINING(c)) ||
6507 (IS_EXTENDER(c))) {
6508 if (len + 10 > max) {
6509 max *= 2;
6510 buffer = (xmlChar *) xmlRealloc(buffer,
6511 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00006512 if (buffer == NULL) {
6513 XP_ERROR0(XPATH_MEMORY_ERROR);
6514 }
6515 }
6516 COPY_BUF(l,buffer,len,c);
6517 NEXTL(l);
6518 c = CUR_CHAR(l);
6519 }
6520 buffer[len] = 0;
6521 return(buffer);
6522 }
6523 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006524 if (len == 0)
6525 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006526 return(xmlStrndup(buf, len));
6527}
Owen Taylor3473f882001-02-23 17:55:21 +00006528/**
6529 * xmlXPathStringEvalNumber:
6530 * @str: A string to scan
6531 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00006532 * [30a] Float ::= Number ('e' Digits?)?
6533 *
Owen Taylor3473f882001-02-23 17:55:21 +00006534 * [30] Number ::= Digits ('.' Digits?)?
6535 * | '.' Digits
6536 * [31] Digits ::= [0-9]+
6537 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006538 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00006539 * In complement of the Number expression, this function also handles
6540 * negative values : '-' Number.
6541 *
6542 * Returns the double value.
6543 */
6544double
6545xmlXPathStringEvalNumber(const xmlChar *str) {
6546 const xmlChar *cur = str;
6547 double ret = 0.0;
6548 double mult = 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006549 int ok = 0, tmp = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006550 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006551 int exponent = 0;
6552 int is_exponent_negative = 0;
6553
Owen Taylor3473f882001-02-23 17:55:21 +00006554 while (IS_BLANK(*cur)) cur++;
6555 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
6556 return(xmlXPathNAN);
6557 }
6558 if (*cur == '-') {
6559 isneg = 1;
6560 cur++;
6561 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006562 /*
6563 * tmp is a workaroudn against a gcc compiler bug
6564 */
Owen Taylor3473f882001-02-23 17:55:21 +00006565 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006566 tmp = tmp * 10 + (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00006567 ok = 1;
6568 cur++;
6569 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006570 ret = (double) tmp;
6571
Owen Taylor3473f882001-02-23 17:55:21 +00006572 if (*cur == '.') {
6573 cur++;
6574 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
6575 return(xmlXPathNAN);
6576 }
6577 while ((*cur >= '0') && (*cur <= '9')) {
6578 mult /= 10;
6579 ret = ret + (*cur - '0') * mult;
6580 cur++;
6581 }
6582 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006583 if ((*cur == 'e') || (*cur == 'E')) {
6584 cur++;
6585 if (*cur == '-') {
6586 is_exponent_negative = 1;
6587 cur++;
6588 }
6589 while ((*cur >= '0') && (*cur <= '9')) {
6590 exponent = exponent * 10 + (*cur - '0');
6591 cur++;
6592 }
6593 }
Owen Taylor3473f882001-02-23 17:55:21 +00006594 while (IS_BLANK(*cur)) cur++;
6595 if (*cur != 0) return(xmlXPathNAN);
6596 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006597 if (is_exponent_negative) exponent = -exponent;
6598 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00006599 return(ret);
6600}
6601
6602/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006603 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00006604 * @ctxt: the XPath Parser context
6605 *
6606 * [30] Number ::= Digits ('.' Digits?)?
6607 * | '.' Digits
6608 * [31] Digits ::= [0-9]+
6609 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006610 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00006611 *
6612 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006613static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006614xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
6615{
Owen Taylor3473f882001-02-23 17:55:21 +00006616 double ret = 0.0;
6617 double mult = 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006618 int ok = 0, tmp = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006619 int exponent = 0;
6620 int is_exponent_negative = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006621
6622 CHECK_ERROR;
6623 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
6624 XP_ERROR(XPATH_NUMBER_ERROR);
6625 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006626 /*
6627 * Try to work around a gcc optimizer bug
6628 */
Owen Taylor3473f882001-02-23 17:55:21 +00006629 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006630 tmp = tmp * 10 + (CUR - '0');
6631 ok = 1;
6632 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +00006633 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006634 ret = (double) tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00006635 if (CUR == '.') {
6636 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006637 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
6638 XP_ERROR(XPATH_NUMBER_ERROR);
6639 }
6640 while ((CUR >= '0') && (CUR <= '9')) {
6641 mult /= 10;
6642 ret = ret + (CUR - '0') * mult;
6643 NEXT;
6644 }
Owen Taylor3473f882001-02-23 17:55:21 +00006645 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006646 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006647 NEXT;
6648 if (CUR == '-') {
6649 is_exponent_negative = 1;
6650 NEXT;
6651 }
6652 while ((CUR >= '0') && (CUR <= '9')) {
6653 exponent = exponent * 10 + (CUR - '0');
6654 NEXT;
6655 }
6656 if (is_exponent_negative)
6657 exponent = -exponent;
6658 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006659 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006660 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006661 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006662}
6663
6664/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006665 * xmlXPathParseLiteral:
6666 * @ctxt: the XPath Parser context
6667 *
6668 * Parse a Literal
6669 *
6670 * [29] Literal ::= '"' [^"]* '"'
6671 * | "'" [^']* "'"
6672 *
6673 * Returns the value found or NULL in case of error
6674 */
6675static xmlChar *
6676xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
6677 const xmlChar *q;
6678 xmlChar *ret = NULL;
6679
6680 if (CUR == '"') {
6681 NEXT;
6682 q = CUR_PTR;
6683 while ((IS_CHAR(CUR)) && (CUR != '"'))
6684 NEXT;
6685 if (!IS_CHAR(CUR)) {
6686 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6687 } else {
6688 ret = xmlStrndup(q, CUR_PTR - q);
6689 NEXT;
6690 }
6691 } else if (CUR == '\'') {
6692 NEXT;
6693 q = CUR_PTR;
6694 while ((IS_CHAR(CUR)) && (CUR != '\''))
6695 NEXT;
6696 if (!IS_CHAR(CUR)) {
6697 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6698 } else {
6699 ret = xmlStrndup(q, CUR_PTR - q);
6700 NEXT;
6701 }
6702 } else {
6703 XP_ERROR0(XPATH_START_LITERAL_ERROR);
6704 }
6705 return(ret);
6706}
6707
6708/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006709 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00006710 * @ctxt: the XPath Parser context
6711 *
6712 * Parse a Literal and push it on the stack.
6713 *
6714 * [29] Literal ::= '"' [^"]* '"'
6715 * | "'" [^']* "'"
6716 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006717 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00006718 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006719static void
6720xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006721 const xmlChar *q;
6722 xmlChar *ret = NULL;
6723
6724 if (CUR == '"') {
6725 NEXT;
6726 q = CUR_PTR;
6727 while ((IS_CHAR(CUR)) && (CUR != '"'))
6728 NEXT;
6729 if (!IS_CHAR(CUR)) {
6730 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
6731 } else {
6732 ret = xmlStrndup(q, CUR_PTR - q);
6733 NEXT;
6734 }
6735 } else if (CUR == '\'') {
6736 NEXT;
6737 q = CUR_PTR;
6738 while ((IS_CHAR(CUR)) && (CUR != '\''))
6739 NEXT;
6740 if (!IS_CHAR(CUR)) {
6741 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
6742 } else {
6743 ret = xmlStrndup(q, CUR_PTR - q);
6744 NEXT;
6745 }
6746 } else {
6747 XP_ERROR(XPATH_START_LITERAL_ERROR);
6748 }
6749 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006750 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
6751 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006752 xmlFree(ret);
6753}
6754
6755/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006756 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00006757 * @ctxt: the XPath Parser context
6758 *
6759 * Parse a VariableReference, evaluate it and push it on the stack.
6760 *
6761 * The variable bindings consist of a mapping from variable names
6762 * to variable values. The value of a variable is an object, which
6763 * of any of the types that are possible for the value of an expression,
6764 * and may also be of additional types not specified here.
6765 *
6766 * Early evaluation is possible since:
6767 * The variable bindings [...] used to evaluate a subexpression are
6768 * always the same as those used to evaluate the containing expression.
6769 *
6770 * [36] VariableReference ::= '$' QName
6771 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006772static void
6773xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006774 xmlChar *name;
6775 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006776
6777 SKIP_BLANKS;
6778 if (CUR != '$') {
6779 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
6780 }
6781 NEXT;
6782 name = xmlXPathParseQName(ctxt, &prefix);
6783 if (name == NULL) {
6784 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
6785 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006786 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006787 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
6788 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006789 SKIP_BLANKS;
6790}
6791
6792/**
6793 * xmlXPathIsNodeType:
6794 * @ctxt: the XPath Parser context
6795 * @name: a name string
6796 *
6797 * Is the name given a NodeType one.
6798 *
6799 * [38] NodeType ::= 'comment'
6800 * | 'text'
6801 * | 'processing-instruction'
6802 * | 'node'
6803 *
6804 * Returns 1 if true 0 otherwise
6805 */
6806int
6807xmlXPathIsNodeType(const xmlChar *name) {
6808 if (name == NULL)
6809 return(0);
6810
6811 if (xmlStrEqual(name, BAD_CAST "comment"))
6812 return(1);
6813 if (xmlStrEqual(name, BAD_CAST "text"))
6814 return(1);
6815 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
6816 return(1);
6817 if (xmlStrEqual(name, BAD_CAST "node"))
6818 return(1);
6819 return(0);
6820}
6821
6822/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006823 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00006824 * @ctxt: the XPath Parser context
6825 *
6826 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
6827 * [17] Argument ::= Expr
6828 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006829 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00006830 * pushed on the stack
6831 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006832static void
6833xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006834 xmlChar *name;
6835 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006836 int nbargs = 0;
6837
6838 name = xmlXPathParseQName(ctxt, &prefix);
6839 if (name == NULL) {
6840 XP_ERROR(XPATH_EXPR_ERROR);
6841 }
6842 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006843#ifdef DEBUG_EXPR
6844 if (prefix == NULL)
6845 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
6846 name);
6847 else
6848 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
6849 prefix, name);
6850#endif
6851
Owen Taylor3473f882001-02-23 17:55:21 +00006852 if (CUR != '(') {
6853 XP_ERROR(XPATH_EXPR_ERROR);
6854 }
6855 NEXT;
6856 SKIP_BLANKS;
6857
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006858 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006859 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006860 int op1 = ctxt->comp->last;
6861 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006862 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006863 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006864 nbargs++;
6865 if (CUR == ')') break;
6866 if (CUR != ',') {
6867 XP_ERROR(XPATH_EXPR_ERROR);
6868 }
6869 NEXT;
6870 SKIP_BLANKS;
6871 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006872 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
6873 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006874 NEXT;
6875 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006876}
6877
6878/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006879 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006880 * @ctxt: the XPath Parser context
6881 *
6882 * [15] PrimaryExpr ::= VariableReference
6883 * | '(' Expr ')'
6884 * | Literal
6885 * | Number
6886 * | FunctionCall
6887 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006888 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006889 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006890static void
6891xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006892 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006893 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006894 else if (CUR == '(') {
6895 NEXT;
6896 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006897 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006898 if (CUR != ')') {
6899 XP_ERROR(XPATH_EXPR_ERROR);
6900 }
6901 NEXT;
6902 SKIP_BLANKS;
6903 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006904 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006905 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006906 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006907 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006908 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006909 }
6910 SKIP_BLANKS;
6911}
6912
6913/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006914 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006915 * @ctxt: the XPath Parser context
6916 *
6917 * [20] FilterExpr ::= PrimaryExpr
6918 * | FilterExpr Predicate
6919 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006920 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006921 * Square brackets are used to filter expressions in the same way that
6922 * they are used in location paths. It is an error if the expression to
6923 * be filtered does not evaluate to a node-set. The context node list
6924 * used for evaluating the expression in square brackets is the node-set
6925 * to be filtered listed in document order.
6926 */
6927
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006928static void
6929xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
6930 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006931 CHECK_ERROR;
6932 SKIP_BLANKS;
6933
6934 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006935 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00006936 SKIP_BLANKS;
6937 }
6938
6939
6940}
6941
6942/**
6943 * xmlXPathScanName:
6944 * @ctxt: the XPath Parser context
6945 *
6946 * Trickery: parse an XML name but without consuming the input flow
6947 * Needed to avoid insanity in the parser state.
6948 *
6949 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6950 * CombiningChar | Extender
6951 *
6952 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6953 *
6954 * [6] Names ::= Name (S Name)*
6955 *
6956 * Returns the Name parsed or NULL
6957 */
6958
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006959static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006960xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
6961 xmlChar buf[XML_MAX_NAMELEN];
6962 int len = 0;
6963
6964 SKIP_BLANKS;
6965 if (!IS_LETTER(CUR) && (CUR != '_') &&
6966 (CUR != ':')) {
6967 return(NULL);
6968 }
6969
6970 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
6971 (NXT(len) == '.') || (NXT(len) == '-') ||
6972 (NXT(len) == '_') || (NXT(len) == ':') ||
6973 (IS_COMBINING(NXT(len))) ||
6974 (IS_EXTENDER(NXT(len)))) {
6975 buf[len] = NXT(len);
6976 len++;
6977 if (len >= XML_MAX_NAMELEN) {
6978 xmlGenericError(xmlGenericErrorContext,
6979 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
6980 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
6981 (NXT(len) == '.') || (NXT(len) == '-') ||
6982 (NXT(len) == '_') || (NXT(len) == ':') ||
6983 (IS_COMBINING(NXT(len))) ||
6984 (IS_EXTENDER(NXT(len))))
6985 len++;
6986 break;
6987 }
6988 }
6989 return(xmlStrndup(buf, len));
6990}
6991
6992/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006993 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006994 * @ctxt: the XPath Parser context
6995 *
6996 * [19] PathExpr ::= LocationPath
6997 * | FilterExpr
6998 * | FilterExpr '/' RelativeLocationPath
6999 * | FilterExpr '//' RelativeLocationPath
7000 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007001 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007002 * The / operator and // operators combine an arbitrary expression
7003 * and a relative location path. It is an error if the expression
7004 * does not evaluate to a node-set.
7005 * The / operator does composition in the same way as when / is
7006 * used in a location path. As in location paths, // is short for
7007 * /descendant-or-self::node()/.
7008 */
7009
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007010static void
7011xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007012 int lc = 1; /* Should we branch to LocationPath ? */
7013 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7014
7015 SKIP_BLANKS;
7016 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
7017 (CUR == '\'') || (CUR == '"')) {
7018 lc = 0;
7019 } else if (CUR == '*') {
7020 /* relative or absolute location path */
7021 lc = 1;
7022 } else if (CUR == '/') {
7023 /* relative or absolute location path */
7024 lc = 1;
7025 } else if (CUR == '@') {
7026 /* relative abbreviated attribute location path */
7027 lc = 1;
7028 } else if (CUR == '.') {
7029 /* relative abbreviated attribute location path */
7030 lc = 1;
7031 } else {
7032 /*
7033 * Problem is finding if we have a name here whether it's:
7034 * - a nodetype
7035 * - a function call in which case it's followed by '('
7036 * - an axis in which case it's followed by ':'
7037 * - a element name
7038 * We do an a priori analysis here rather than having to
7039 * maintain parsed token content through the recursive function
7040 * calls. This looks uglier but makes the code quite easier to
7041 * read/write/debug.
7042 */
7043 SKIP_BLANKS;
7044 name = xmlXPathScanName(ctxt);
7045 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7046#ifdef DEBUG_STEP
7047 xmlGenericError(xmlGenericErrorContext,
7048 "PathExpr: Axis\n");
7049#endif
7050 lc = 1;
7051 xmlFree(name);
7052 } else if (name != NULL) {
7053 int len =xmlStrlen(name);
7054 int blank = 0;
7055
7056
7057 while (NXT(len) != 0) {
7058 if (NXT(len) == '/') {
7059 /* element name */
7060#ifdef DEBUG_STEP
7061 xmlGenericError(xmlGenericErrorContext,
7062 "PathExpr: AbbrRelLocation\n");
7063#endif
7064 lc = 1;
7065 break;
7066 } else if (IS_BLANK(NXT(len))) {
7067 /* skip to next */
7068 blank = 1;
7069 } else if (NXT(len) == ':') {
7070#ifdef DEBUG_STEP
7071 xmlGenericError(xmlGenericErrorContext,
7072 "PathExpr: AbbrRelLocation\n");
7073#endif
7074 lc = 1;
7075 break;
7076 } else if ((NXT(len) == '(')) {
7077 /* Note Type or Function */
7078 if (xmlXPathIsNodeType(name)) {
7079#ifdef DEBUG_STEP
7080 xmlGenericError(xmlGenericErrorContext,
7081 "PathExpr: Type search\n");
7082#endif
7083 lc = 1;
7084 } else {
7085#ifdef DEBUG_STEP
7086 xmlGenericError(xmlGenericErrorContext,
7087 "PathExpr: function call\n");
7088#endif
7089 lc = 0;
7090 }
7091 break;
7092 } else if ((NXT(len) == '[')) {
7093 /* element name */
7094#ifdef DEBUG_STEP
7095 xmlGenericError(xmlGenericErrorContext,
7096 "PathExpr: AbbrRelLocation\n");
7097#endif
7098 lc = 1;
7099 break;
7100 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7101 (NXT(len) == '=')) {
7102 lc = 1;
7103 break;
7104 } else {
7105 lc = 1;
7106 break;
7107 }
7108 len++;
7109 }
7110 if (NXT(len) == 0) {
7111#ifdef DEBUG_STEP
7112 xmlGenericError(xmlGenericErrorContext,
7113 "PathExpr: AbbrRelLocation\n");
7114#endif
7115 /* element name */
7116 lc = 1;
7117 }
7118 xmlFree(name);
7119 } else {
7120 /* make sure all cases are covered explicitely */
7121 XP_ERROR(XPATH_EXPR_ERROR);
7122 }
7123 }
7124
7125 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007126 if (CUR == '/') {
7127 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7128 } else {
7129 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007130 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007131 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007132 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007133 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007134 CHECK_ERROR;
7135 if ((CUR == '/') && (NXT(1) == '/')) {
7136 SKIP(2);
7137 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007138
7139 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7140 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7141 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7142
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007143 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007144 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007145 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007146 }
7147 }
7148 SKIP_BLANKS;
7149}
7150
7151/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007152 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007153 * @ctxt: the XPath Parser context
7154 *
7155 * [18] UnionExpr ::= PathExpr
7156 * | UnionExpr '|' PathExpr
7157 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007158 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007159 */
7160
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007161static void
7162xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7163 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007164 CHECK_ERROR;
7165 SKIP_BLANKS;
7166 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007167 int op1 = ctxt->comp->last;
7168 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007169
7170 NEXT;
7171 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007172 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007173
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007174 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
7175
Owen Taylor3473f882001-02-23 17:55:21 +00007176 SKIP_BLANKS;
7177 }
Owen Taylor3473f882001-02-23 17:55:21 +00007178}
7179
7180/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007181 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007182 * @ctxt: the XPath Parser context
7183 *
7184 * [27] UnaryExpr ::= UnionExpr
7185 * | '-' UnaryExpr
7186 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007187 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007188 */
7189
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007190static void
7191xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007192 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007193 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007194
7195 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00007196 while (CUR == '-') {
7197 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007198 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007199 NEXT;
7200 SKIP_BLANKS;
7201 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007202
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007203 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007204 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007205 if (found) {
7206 if (minus)
7207 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
7208 else
7209 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007210 }
7211}
7212
7213/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007214 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007215 * @ctxt: the XPath Parser context
7216 *
7217 * [26] MultiplicativeExpr ::= UnaryExpr
7218 * | MultiplicativeExpr MultiplyOperator UnaryExpr
7219 * | MultiplicativeExpr 'div' UnaryExpr
7220 * | MultiplicativeExpr 'mod' UnaryExpr
7221 * [34] MultiplyOperator ::= '*'
7222 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007223 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007224 */
7225
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007226static void
7227xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
7228 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007229 CHECK_ERROR;
7230 SKIP_BLANKS;
7231 while ((CUR == '*') ||
7232 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
7233 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
7234 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007235 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007236
7237 if (CUR == '*') {
7238 op = 0;
7239 NEXT;
7240 } else if (CUR == 'd') {
7241 op = 1;
7242 SKIP(3);
7243 } else if (CUR == 'm') {
7244 op = 2;
7245 SKIP(3);
7246 }
7247 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007248 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007249 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007250 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007251 SKIP_BLANKS;
7252 }
7253}
7254
7255/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007256 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007257 * @ctxt: the XPath Parser context
7258 *
7259 * [25] AdditiveExpr ::= MultiplicativeExpr
7260 * | AdditiveExpr '+' MultiplicativeExpr
7261 * | AdditiveExpr '-' MultiplicativeExpr
7262 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007263 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007264 */
7265
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007266static void
7267xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007268
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007269 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007270 CHECK_ERROR;
7271 SKIP_BLANKS;
7272 while ((CUR == '+') || (CUR == '-')) {
7273 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007274 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007275
7276 if (CUR == '+') plus = 1;
7277 else plus = 0;
7278 NEXT;
7279 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007280 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007281 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007282 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007283 SKIP_BLANKS;
7284 }
7285}
7286
7287/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007288 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007289 * @ctxt: the XPath Parser context
7290 *
7291 * [24] RelationalExpr ::= AdditiveExpr
7292 * | RelationalExpr '<' AdditiveExpr
7293 * | RelationalExpr '>' AdditiveExpr
7294 * | RelationalExpr '<=' AdditiveExpr
7295 * | RelationalExpr '>=' AdditiveExpr
7296 *
7297 * A <= B > C is allowed ? Answer from James, yes with
7298 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
7299 * which is basically what got implemented.
7300 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007301 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00007302 * on the stack
7303 */
7304
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007305static void
7306xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
7307 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007308 CHECK_ERROR;
7309 SKIP_BLANKS;
7310 while ((CUR == '<') ||
7311 (CUR == '>') ||
7312 ((CUR == '<') && (NXT(1) == '=')) ||
7313 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007314 int inf, strict;
7315 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007316
7317 if (CUR == '<') inf = 1;
7318 else inf = 0;
7319 if (NXT(1) == '=') strict = 0;
7320 else strict = 1;
7321 NEXT;
7322 if (!strict) NEXT;
7323 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007324 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007325 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007326 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00007327 SKIP_BLANKS;
7328 }
7329}
7330
7331/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007332 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007333 * @ctxt: the XPath Parser context
7334 *
7335 * [23] EqualityExpr ::= RelationalExpr
7336 * | EqualityExpr '=' RelationalExpr
7337 * | EqualityExpr '!=' RelationalExpr
7338 *
7339 * A != B != C is allowed ? Answer from James, yes with
7340 * (RelationalExpr = RelationalExpr) = RelationalExpr
7341 * (RelationalExpr != RelationalExpr) != RelationalExpr
7342 * which is basically what got implemented.
7343 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007344 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007345 *
7346 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007347static void
7348xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
7349 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007350 CHECK_ERROR;
7351 SKIP_BLANKS;
7352 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007353 int eq;
7354 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007355
7356 if (CUR == '=') eq = 1;
7357 else eq = 0;
7358 NEXT;
7359 if (!eq) NEXT;
7360 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007361 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007362 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007363 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007364 SKIP_BLANKS;
7365 }
7366}
7367
7368/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007369 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007370 * @ctxt: the XPath Parser context
7371 *
7372 * [22] AndExpr ::= EqualityExpr
7373 * | AndExpr 'and' EqualityExpr
7374 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007375 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007376 *
7377 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007378static void
7379xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
7380 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007381 CHECK_ERROR;
7382 SKIP_BLANKS;
7383 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007384 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007385 SKIP(3);
7386 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007387 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007388 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007389 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007390 SKIP_BLANKS;
7391 }
7392}
7393
7394/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007395 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007396 * @ctxt: the XPath Parser context
7397 *
7398 * [14] Expr ::= OrExpr
7399 * [21] OrExpr ::= AndExpr
7400 * | OrExpr 'or' AndExpr
7401 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007402 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00007403 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007404static void
7405xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
7406 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007407 CHECK_ERROR;
7408 SKIP_BLANKS;
7409 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007410 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007411 SKIP(2);
7412 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007413 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007414 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007415 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
7416 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00007417 SKIP_BLANKS;
7418 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007419 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
7420 /* more ops could be optimized too */
7421 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
7422 }
Owen Taylor3473f882001-02-23 17:55:21 +00007423}
7424
7425/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007426 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00007427 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007428 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00007429 *
7430 * [8] Predicate ::= '[' PredicateExpr ']'
7431 * [9] PredicateExpr ::= Expr
7432 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007433 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00007434 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007435static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007436xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007437 int op1 = ctxt->comp->last;
7438
7439 SKIP_BLANKS;
7440 if (CUR != '[') {
7441 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7442 }
7443 NEXT;
7444 SKIP_BLANKS;
7445
7446 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007447 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007448 CHECK_ERROR;
7449
7450 if (CUR != ']') {
7451 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7452 }
7453
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007454 if (filter)
7455 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
7456 else
7457 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007458
7459 NEXT;
7460 SKIP_BLANKS;
7461}
7462
7463/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007464 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00007465 * @ctxt: the XPath Parser context
7466 * @test: pointer to a xmlXPathTestVal
7467 * @type: pointer to a xmlXPathTypeVal
7468 * @prefix: placeholder for a possible name prefix
7469 *
7470 * [7] NodeTest ::= NameTest
7471 * | NodeType '(' ')'
7472 * | 'processing-instruction' '(' Literal ')'
7473 *
7474 * [37] NameTest ::= '*'
7475 * | NCName ':' '*'
7476 * | QName
7477 * [38] NodeType ::= 'comment'
7478 * | 'text'
7479 * | 'processing-instruction'
7480 * | 'node'
7481 *
7482 * Returns the name found and update @test, @type and @prefix appropriately
7483 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007484static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007485xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
7486 xmlXPathTypeVal *type, const xmlChar **prefix,
7487 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00007488 int blanks;
7489
7490 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
7491 STRANGE;
7492 return(NULL);
7493 }
7494 *type = 0;
7495 *test = 0;
7496 *prefix = NULL;
7497 SKIP_BLANKS;
7498
7499 if ((name == NULL) && (CUR == '*')) {
7500 /*
7501 * All elements
7502 */
7503 NEXT;
7504 *test = NODE_TEST_ALL;
7505 return(NULL);
7506 }
7507
7508 if (name == NULL)
7509 name = xmlXPathParseNCName(ctxt);
7510 if (name == NULL) {
7511 XP_ERROR0(XPATH_EXPR_ERROR);
7512 }
7513
7514 blanks = IS_BLANK(CUR);
7515 SKIP_BLANKS;
7516 if (CUR == '(') {
7517 NEXT;
7518 /*
7519 * NodeType or PI search
7520 */
7521 if (xmlStrEqual(name, BAD_CAST "comment"))
7522 *type = NODE_TYPE_COMMENT;
7523 else if (xmlStrEqual(name, BAD_CAST "node"))
7524 *type = NODE_TYPE_NODE;
7525 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
7526 *type = NODE_TYPE_PI;
7527 else if (xmlStrEqual(name, BAD_CAST "text"))
7528 *type = NODE_TYPE_TEXT;
7529 else {
7530 if (name != NULL)
7531 xmlFree(name);
7532 XP_ERROR0(XPATH_EXPR_ERROR);
7533 }
7534
7535 *test = NODE_TEST_TYPE;
7536
7537 SKIP_BLANKS;
7538 if (*type == NODE_TYPE_PI) {
7539 /*
7540 * Specific case: search a PI by name.
7541 */
Owen Taylor3473f882001-02-23 17:55:21 +00007542 if (name != NULL)
7543 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00007544 name = NULL;
7545 if (CUR != ')') {
7546 name = xmlXPathParseLiteral(ctxt);
7547 CHECK_ERROR 0;
7548 SKIP_BLANKS;
7549 }
Owen Taylor3473f882001-02-23 17:55:21 +00007550 }
7551 if (CUR != ')') {
7552 if (name != NULL)
7553 xmlFree(name);
7554 XP_ERROR0(XPATH_UNCLOSED_ERROR);
7555 }
7556 NEXT;
7557 return(name);
7558 }
7559 *test = NODE_TEST_NAME;
7560 if ((!blanks) && (CUR == ':')) {
7561 NEXT;
7562
7563 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007564 * Since currently the parser context don't have a
7565 * namespace list associated:
7566 * The namespace name for this prefix can be computed
7567 * only at evaluation time. The compilation is done
7568 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00007569 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007570#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00007571 *prefix = xmlXPathNsLookup(ctxt->context, name);
7572 if (name != NULL)
7573 xmlFree(name);
7574 if (*prefix == NULL) {
7575 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
7576 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007577#else
7578 *prefix = name;
7579#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007580
7581 if (CUR == '*') {
7582 /*
7583 * All elements
7584 */
7585 NEXT;
7586 *test = NODE_TEST_ALL;
7587 return(NULL);
7588 }
7589
7590 name = xmlXPathParseNCName(ctxt);
7591 if (name == NULL) {
7592 XP_ERROR0(XPATH_EXPR_ERROR);
7593 }
7594 }
7595 return(name);
7596}
7597
7598/**
7599 * xmlXPathIsAxisName:
7600 * @name: a preparsed name token
7601 *
7602 * [6] AxisName ::= 'ancestor'
7603 * | 'ancestor-or-self'
7604 * | 'attribute'
7605 * | 'child'
7606 * | 'descendant'
7607 * | 'descendant-or-self'
7608 * | 'following'
7609 * | 'following-sibling'
7610 * | 'namespace'
7611 * | 'parent'
7612 * | 'preceding'
7613 * | 'preceding-sibling'
7614 * | 'self'
7615 *
7616 * Returns the axis or 0
7617 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007618static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00007619xmlXPathIsAxisName(const xmlChar *name) {
7620 xmlXPathAxisVal ret = 0;
7621 switch (name[0]) {
7622 case 'a':
7623 if (xmlStrEqual(name, BAD_CAST "ancestor"))
7624 ret = AXIS_ANCESTOR;
7625 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
7626 ret = AXIS_ANCESTOR_OR_SELF;
7627 if (xmlStrEqual(name, BAD_CAST "attribute"))
7628 ret = AXIS_ATTRIBUTE;
7629 break;
7630 case 'c':
7631 if (xmlStrEqual(name, BAD_CAST "child"))
7632 ret = AXIS_CHILD;
7633 break;
7634 case 'd':
7635 if (xmlStrEqual(name, BAD_CAST "descendant"))
7636 ret = AXIS_DESCENDANT;
7637 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
7638 ret = AXIS_DESCENDANT_OR_SELF;
7639 break;
7640 case 'f':
7641 if (xmlStrEqual(name, BAD_CAST "following"))
7642 ret = AXIS_FOLLOWING;
7643 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
7644 ret = AXIS_FOLLOWING_SIBLING;
7645 break;
7646 case 'n':
7647 if (xmlStrEqual(name, BAD_CAST "namespace"))
7648 ret = AXIS_NAMESPACE;
7649 break;
7650 case 'p':
7651 if (xmlStrEqual(name, BAD_CAST "parent"))
7652 ret = AXIS_PARENT;
7653 if (xmlStrEqual(name, BAD_CAST "preceding"))
7654 ret = AXIS_PRECEDING;
7655 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
7656 ret = AXIS_PRECEDING_SIBLING;
7657 break;
7658 case 's':
7659 if (xmlStrEqual(name, BAD_CAST "self"))
7660 ret = AXIS_SELF;
7661 break;
7662 }
7663 return(ret);
7664}
7665
7666/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007667 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00007668 * @ctxt: the XPath Parser context
7669 *
7670 * [4] Step ::= AxisSpecifier NodeTest Predicate*
7671 * | AbbreviatedStep
7672 *
7673 * [12] AbbreviatedStep ::= '.' | '..'
7674 *
7675 * [5] AxisSpecifier ::= AxisName '::'
7676 * | AbbreviatedAxisSpecifier
7677 *
7678 * [13] AbbreviatedAxisSpecifier ::= '@'?
7679 *
7680 * Modified for XPtr range support as:
7681 *
7682 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
7683 * | AbbreviatedStep
7684 * | 'range-to' '(' Expr ')' Predicate*
7685 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007686 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00007687 * A location step of . is short for self::node(). This is
7688 * particularly useful in conjunction with //. For example, the
7689 * location path .//para is short for
7690 * self::node()/descendant-or-self::node()/child::para
7691 * and so will select all para descendant elements of the context
7692 * node.
7693 * Similarly, a location step of .. is short for parent::node().
7694 * For example, ../title is short for parent::node()/child::title
7695 * and so will select the title children of the parent of the context
7696 * node.
7697 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007698static void
7699xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007700#ifdef LIBXML_XPTR_ENABLED
7701 int rangeto = 0;
7702 int op2 = -1;
7703#endif
7704
Owen Taylor3473f882001-02-23 17:55:21 +00007705 SKIP_BLANKS;
7706 if ((CUR == '.') && (NXT(1) == '.')) {
7707 SKIP(2);
7708 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007709 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
7710 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007711 } else if (CUR == '.') {
7712 NEXT;
7713 SKIP_BLANKS;
7714 } else {
7715 xmlChar *name = NULL;
7716 const xmlChar *prefix = NULL;
7717 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007718 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007719 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007720 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00007721
7722 /*
7723 * The modification needed for XPointer change to the production
7724 */
7725#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007726 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00007727 name = xmlXPathParseNCName(ctxt);
7728 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007729 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007730 xmlFree(name);
7731 SKIP_BLANKS;
7732 if (CUR != '(') {
7733 XP_ERROR(XPATH_EXPR_ERROR);
7734 }
7735 NEXT;
7736 SKIP_BLANKS;
7737
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007738 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007739 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00007740 CHECK_ERROR;
7741
7742 SKIP_BLANKS;
7743 if (CUR != ')') {
7744 XP_ERROR(XPATH_EXPR_ERROR);
7745 }
7746 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007747 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007748 goto eval_predicates;
7749 }
7750 }
7751#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00007752 if (CUR == '*') {
7753 axis = AXIS_CHILD;
7754 } else {
7755 if (name == NULL)
7756 name = xmlXPathParseNCName(ctxt);
7757 if (name != NULL) {
7758 axis = xmlXPathIsAxisName(name);
7759 if (axis != 0) {
7760 SKIP_BLANKS;
7761 if ((CUR == ':') && (NXT(1) == ':')) {
7762 SKIP(2);
7763 xmlFree(name);
7764 name = NULL;
7765 } else {
7766 /* an element name can conflict with an axis one :-\ */
7767 axis = AXIS_CHILD;
7768 }
Owen Taylor3473f882001-02-23 17:55:21 +00007769 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00007770 axis = AXIS_CHILD;
7771 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007772 } else if (CUR == '@') {
7773 NEXT;
7774 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00007775 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00007776 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00007777 }
Owen Taylor3473f882001-02-23 17:55:21 +00007778 }
7779
7780 CHECK_ERROR;
7781
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007782 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00007783 if (test == 0)
7784 return;
7785
7786#ifdef DEBUG_STEP
7787 xmlGenericError(xmlGenericErrorContext,
7788 "Basis : computing new set\n");
7789#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007790
Owen Taylor3473f882001-02-23 17:55:21 +00007791#ifdef DEBUG_STEP
7792 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007793 if (ctxt->value == NULL)
7794 xmlGenericError(xmlGenericErrorContext, "no value\n");
7795 else if (ctxt->value->nodesetval == NULL)
7796 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7797 else
7798 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007799#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007800
7801eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007802 op1 = ctxt->comp->last;
7803 ctxt->comp->last = -1;
7804
Owen Taylor3473f882001-02-23 17:55:21 +00007805 SKIP_BLANKS;
7806 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007807 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007808 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007809
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007810#ifdef LIBXML_XPTR_ENABLED
7811 if (rangeto) {
7812 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
7813 } else
7814#endif
7815 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
7816 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007817
Owen Taylor3473f882001-02-23 17:55:21 +00007818 }
7819#ifdef DEBUG_STEP
7820 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007821 if (ctxt->value == NULL)
7822 xmlGenericError(xmlGenericErrorContext, "no value\n");
7823 else if (ctxt->value->nodesetval == NULL)
7824 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7825 else
7826 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
7827 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007828#endif
7829}
7830
7831/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007832 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007833 * @ctxt: the XPath Parser context
7834 *
7835 * [3] RelativeLocationPath ::= Step
7836 * | RelativeLocationPath '/' Step
7837 * | AbbreviatedRelativeLocationPath
7838 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
7839 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007840 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00007841 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007842static void
Owen Taylor3473f882001-02-23 17:55:21 +00007843#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007844xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007845#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007846xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007847#endif
7848(xmlXPathParserContextPtr ctxt) {
7849 SKIP_BLANKS;
7850 if ((CUR == '/') && (NXT(1) == '/')) {
7851 SKIP(2);
7852 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007853 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7854 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007855 } else if (CUR == '/') {
7856 NEXT;
7857 SKIP_BLANKS;
7858 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007859 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007860 SKIP_BLANKS;
7861 while (CUR == '/') {
7862 if ((CUR == '/') && (NXT(1) == '/')) {
7863 SKIP(2);
7864 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007865 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00007866 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007867 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007868 } else if (CUR == '/') {
7869 NEXT;
7870 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007871 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007872 }
7873 SKIP_BLANKS;
7874 }
7875}
7876
7877/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007878 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007879 * @ctxt: the XPath Parser context
7880 *
7881 * [1] LocationPath ::= RelativeLocationPath
7882 * | AbsoluteLocationPath
7883 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
7884 * | AbbreviatedAbsoluteLocationPath
7885 * [10] AbbreviatedAbsoluteLocationPath ::=
7886 * '//' RelativeLocationPath
7887 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007888 * Compile a location path
7889 *
Owen Taylor3473f882001-02-23 17:55:21 +00007890 * // is short for /descendant-or-self::node()/. For example,
7891 * //para is short for /descendant-or-self::node()/child::para and
7892 * so will select any para element in the document (even a para element
7893 * that is a document element will be selected by //para since the
7894 * document element node is a child of the root node); div//para is
7895 * short for div/descendant-or-self::node()/child::para and so will
7896 * select all para descendants of div children.
7897 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007898static void
7899xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007900 SKIP_BLANKS;
7901 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007902 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007903 } else {
7904 while (CUR == '/') {
7905 if ((CUR == '/') && (NXT(1) == '/')) {
7906 SKIP(2);
7907 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007908 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7909 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007910 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007911 } else if (CUR == '/') {
7912 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00007913 SKIP_BLANKS;
7914 if ((CUR != 0 ) &&
7915 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
7916 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007917 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007918 }
7919 }
7920 }
7921}
7922
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007923/************************************************************************
7924 * *
7925 * XPath precompiled expression evaluation *
7926 * *
7927 ************************************************************************/
7928
Daniel Veillardf06307e2001-07-03 10:35:50 +00007929static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007930xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
7931
7932/**
7933 * xmlXPathNodeCollectAndTest:
7934 * @ctxt: the XPath Parser context
7935 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00007936 * @first: pointer to the first element in document order
7937 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007938 *
7939 * This is the function implementing a step: based on the current list
7940 * of nodes, it builds up a new list, looking at all nodes under that
7941 * axis and selecting them it also do the predicate filtering
7942 *
7943 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00007944 *
7945 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007946 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00007947static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007948xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00007949 xmlXPathStepOpPtr op,
7950 xmlNodePtr * first, xmlNodePtr * last)
7951{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007952 xmlXPathAxisVal axis = op->value;
7953 xmlXPathTestVal test = op->value2;
7954 xmlXPathTypeVal type = op->value3;
7955 const xmlChar *prefix = op->value4;
7956 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00007957 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007958
7959#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007960 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007961#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007962 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007963 xmlNodeSetPtr ret, list;
7964 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00007965 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007966 xmlNodePtr cur = NULL;
7967 xmlXPathObjectPtr obj;
7968 xmlNodeSetPtr nodelist;
7969 xmlNodePtr tmp;
7970
Daniel Veillardf06307e2001-07-03 10:35:50 +00007971 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007972 obj = valuePop(ctxt);
7973 addNode = xmlXPathNodeSetAdd;
Daniel Veillarde043ee12001-04-16 14:08:07 +00007974 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00007975 URI = xmlXPathNsLookup(ctxt->context, prefix);
7976 if (URI == NULL)
7977 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00007978 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007979#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007980 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007981#endif
7982 switch (axis) {
7983 case AXIS_ANCESTOR:
7984#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007985 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007986#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007987 first = NULL;
7988 next = xmlXPathNextAncestor;
7989 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007990 case AXIS_ANCESTOR_OR_SELF:
7991#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007992 xmlGenericError(xmlGenericErrorContext,
7993 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007994#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007995 first = NULL;
7996 next = xmlXPathNextAncestorOrSelf;
7997 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007998 case AXIS_ATTRIBUTE:
7999#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008000 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008001#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008002 first = NULL;
8003 last = NULL;
8004 next = xmlXPathNextAttribute;
8005 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008006 case AXIS_CHILD:
8007#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008008 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008009#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008010 last = NULL;
8011 next = xmlXPathNextChild;
8012 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008013 case AXIS_DESCENDANT:
8014#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008015 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008016#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008017 last = NULL;
8018 next = xmlXPathNextDescendant;
8019 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008020 case AXIS_DESCENDANT_OR_SELF:
8021#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008022 xmlGenericError(xmlGenericErrorContext,
8023 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008024#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008025 last = NULL;
8026 next = xmlXPathNextDescendantOrSelf;
8027 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008028 case AXIS_FOLLOWING:
8029#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008030 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008031#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008032 last = NULL;
8033 next = xmlXPathNextFollowing;
8034 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008035 case AXIS_FOLLOWING_SIBLING:
8036#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008037 xmlGenericError(xmlGenericErrorContext,
8038 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008039#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008040 last = NULL;
8041 next = xmlXPathNextFollowingSibling;
8042 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008043 case AXIS_NAMESPACE:
8044#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008045 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008046#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008047 first = NULL;
8048 last = NULL;
8049 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8050 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008051 case AXIS_PARENT:
8052#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008053 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008054#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008055 first = NULL;
8056 next = xmlXPathNextParent;
8057 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008058 case AXIS_PRECEDING:
8059#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008060 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008061#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008062 first = NULL;
8063 next = xmlXPathNextPrecedingInternal;
8064 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008065 case AXIS_PRECEDING_SIBLING:
8066#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008067 xmlGenericError(xmlGenericErrorContext,
8068 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008069#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008070 first = NULL;
8071 next = xmlXPathNextPrecedingSibling;
8072 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008073 case AXIS_SELF:
8074#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008075 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008076#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008077 first = NULL;
8078 last = NULL;
8079 next = xmlXPathNextSelf;
8080 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008081 }
8082 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008083 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008084
8085 nodelist = obj->nodesetval;
8086 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008087 xmlXPathFreeObject(obj);
8088 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8089 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008090 }
8091 addNode = xmlXPathNodeSetAddUnique;
8092 ret = NULL;
8093#ifdef DEBUG_STEP
8094 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008095 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008096 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008097 case NODE_TEST_NONE:
8098 xmlGenericError(xmlGenericErrorContext,
8099 " searching for none !!!\n");
8100 break;
8101 case NODE_TEST_TYPE:
8102 xmlGenericError(xmlGenericErrorContext,
8103 " searching for type %d\n", type);
8104 break;
8105 case NODE_TEST_PI:
8106 xmlGenericError(xmlGenericErrorContext,
8107 " searching for PI !!!\n");
8108 break;
8109 case NODE_TEST_ALL:
8110 xmlGenericError(xmlGenericErrorContext,
8111 " searching for *\n");
8112 break;
8113 case NODE_TEST_NS:
8114 xmlGenericError(xmlGenericErrorContext,
8115 " searching for namespace %s\n",
8116 prefix);
8117 break;
8118 case NODE_TEST_NAME:
8119 xmlGenericError(xmlGenericErrorContext,
8120 " searching for name %s\n", name);
8121 if (prefix != NULL)
8122 xmlGenericError(xmlGenericErrorContext,
8123 " with namespace %s\n", prefix);
8124 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008125 }
8126 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8127#endif
8128 /*
8129 * 2.3 Node Tests
8130 * - For the attribute axis, the principal node type is attribute.
8131 * - For the namespace axis, the principal node type is namespace.
8132 * - For other axes, the principal node type is element.
8133 *
8134 * A node test * is true for any node of the
8135 * principal node type. For example, child::* willi
8136 * select all element children of the context node
8137 */
8138 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008139 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008140 ctxt->context->node = nodelist->nodeTab[i];
8141
Daniel Veillardf06307e2001-07-03 10:35:50 +00008142 cur = NULL;
8143 list = xmlXPathNodeSetCreate(NULL);
8144 do {
8145 cur = next(ctxt, cur);
8146 if (cur == NULL)
8147 break;
8148 if ((first != NULL) && (*first == cur))
8149 break;
8150 if (((t % 256) == 0) &&
8151 (first != NULL) && (*first != NULL) &&
8152 (xmlXPathCmpNodes(*first, cur) >= 0))
8153 break;
8154 if ((last != NULL) && (*last == cur))
8155 break;
8156 if (((t % 256) == 0) &&
8157 (last != NULL) && (*last != NULL) &&
8158 (xmlXPathCmpNodes(cur, *last) >= 0))
8159 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008160 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008161#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008162 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8163#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008164 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008165 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008166 ctxt->context->node = tmp;
8167 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008168 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008169 if ((cur->type == type) ||
8170 ((type == NODE_TYPE_NODE) &&
8171 ((cur->type == XML_DOCUMENT_NODE) ||
8172 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8173 (cur->type == XML_ELEMENT_NODE) ||
8174 (cur->type == XML_PI_NODE) ||
8175 (cur->type == XML_COMMENT_NODE) ||
8176 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00008177 (cur->type == XML_TEXT_NODE))) ||
8178 ((type == NODE_TYPE_TEXT) &&
8179 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008180#ifdef DEBUG_STEP
8181 n++;
8182#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008183 addNode(list, cur);
8184 }
8185 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008186 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008187 if (cur->type == XML_PI_NODE) {
8188 if ((name != NULL) &&
8189 (!xmlStrEqual(name, cur->name)))
8190 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008191#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008192 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008193#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008194 addNode(list, cur);
8195 }
8196 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008197 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008198 if (axis == AXIS_ATTRIBUTE) {
8199 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008200#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008201 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008202#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008203 addNode(list, cur);
8204 }
8205 } else if (axis == AXIS_NAMESPACE) {
8206 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008207#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008208 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008209#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008210 addNode(list, cur);
8211 }
8212 } else {
8213 if (cur->type == XML_ELEMENT_NODE) {
8214 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008215#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008216 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008217#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008218 addNode(list, cur);
8219 } else if ((cur->ns != NULL) &&
8220 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008221#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008222 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008223#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008224 addNode(list, cur);
8225 }
8226 }
8227 }
8228 break;
8229 case NODE_TEST_NS:{
8230 TODO;
8231 break;
8232 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008233 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008234 switch (cur->type) {
8235 case XML_ELEMENT_NODE:
8236 if (xmlStrEqual(name, cur->name)) {
8237 if (prefix == NULL) {
8238 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008239#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008240 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008241#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008242 addNode(list, cur);
8243 }
8244 } else {
8245 if ((cur->ns != NULL) &&
8246 (xmlStrEqual(URI,
8247 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008248#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008249 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008250#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008251 addNode(list, cur);
8252 }
8253 }
8254 }
8255 break;
8256 case XML_ATTRIBUTE_NODE:{
8257 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008258
Daniel Veillardf06307e2001-07-03 10:35:50 +00008259 if (xmlStrEqual(name, attr->name)) {
8260 if (prefix == NULL) {
8261 if ((attr->ns == NULL) ||
8262 (attr->ns->prefix == NULL)) {
8263#ifdef DEBUG_STEP
8264 n++;
8265#endif
8266 addNode(list,
8267 (xmlNodePtr) attr);
8268 }
8269 } else {
8270 if ((attr->ns != NULL) &&
8271 (xmlStrEqual(URI,
8272 attr->ns->
8273 href))) {
8274#ifdef DEBUG_STEP
8275 n++;
8276#endif
8277 addNode(list,
8278 (xmlNodePtr) attr);
8279 }
8280 }
8281 }
8282 break;
8283 }
8284 case XML_NAMESPACE_DECL:
8285 if (cur->type == XML_NAMESPACE_DECL) {
8286 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008287
Daniel Veillardf06307e2001-07-03 10:35:50 +00008288 if ((ns->prefix != NULL) && (name != NULL)
8289 && (xmlStrEqual(ns->prefix, name))) {
8290#ifdef DEBUG_STEP
8291 n++;
8292#endif
8293 addNode(list, cur);
8294 }
8295 }
8296 break;
8297 default:
8298 break;
8299 }
8300 break;
8301 break;
8302 }
8303 } while (cur != NULL);
8304
8305 /*
8306 * If there is some predicate filtering do it now
8307 */
8308 if (op->ch2 != -1) {
8309 xmlXPathObjectPtr obj2;
8310
8311 valuePush(ctxt, xmlXPathWrapNodeSet(list));
8312 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
8313 CHECK_TYPE0(XPATH_NODESET);
8314 obj2 = valuePop(ctxt);
8315 list = obj2->nodesetval;
8316 obj2->nodesetval = NULL;
8317 xmlXPathFreeObject(obj2);
8318 }
8319 if (ret == NULL) {
8320 ret = list;
8321 } else {
8322 ret = xmlXPathNodeSetMerge(ret, list);
8323 xmlXPathFreeNodeSet(list);
8324 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008325 }
8326 ctxt->context->node = tmp;
8327#ifdef DEBUG_STEP
8328 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008329 "\nExamined %d nodes, found %d nodes at that step\n",
8330 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008331#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008332 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00008333 if ((obj->boolval) && (obj->user != NULL)) {
8334 ctxt->value->boolval = 1;
8335 ctxt->value->user = obj->user;
8336 obj->user = NULL;
8337 obj->boolval = 0;
8338 }
8339 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008340 return(t);
8341}
8342
8343/**
8344 * xmlXPathNodeCollectAndTestNth:
8345 * @ctxt: the XPath Parser context
8346 * @op: the XPath precompiled step operation
8347 * @indx: the index to collect
8348 * @first: pointer to the first element in document order
8349 * @last: pointer to the last element in document order
8350 *
8351 * This is the function implementing a step: based on the current list
8352 * of nodes, it builds up a new list, looking at all nodes under that
8353 * axis and selecting them it also do the predicate filtering
8354 *
8355 * Pushes the new NodeSet resulting from the search.
8356 * Returns the number of node traversed
8357 */
8358static int
8359xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
8360 xmlXPathStepOpPtr op, int indx,
8361 xmlNodePtr * first, xmlNodePtr * last)
8362{
8363 xmlXPathAxisVal axis = op->value;
8364 xmlXPathTestVal test = op->value2;
8365 xmlXPathTypeVal type = op->value3;
8366 const xmlChar *prefix = op->value4;
8367 const xmlChar *name = op->value5;
8368 const xmlChar *URI = NULL;
8369 int n = 0, t = 0;
8370
8371 int i;
8372 xmlNodeSetPtr list;
8373 xmlXPathTraversalFunction next = NULL;
8374 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
8375 xmlNodePtr cur = NULL;
8376 xmlXPathObjectPtr obj;
8377 xmlNodeSetPtr nodelist;
8378 xmlNodePtr tmp;
8379
8380 CHECK_TYPE0(XPATH_NODESET);
8381 obj = valuePop(ctxt);
8382 addNode = xmlXPathNodeSetAdd;
8383 if (prefix != NULL) {
8384 URI = xmlXPathNsLookup(ctxt->context, prefix);
8385 if (URI == NULL)
8386 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8387 }
8388#ifdef DEBUG_STEP_NTH
8389 xmlGenericError(xmlGenericErrorContext, "new step : ");
8390 if (first != NULL) {
8391 if (*first != NULL)
8392 xmlGenericError(xmlGenericErrorContext, "first = %s ",
8393 (*first)->name);
8394 else
8395 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
8396 }
8397 if (last != NULL) {
8398 if (*last != NULL)
8399 xmlGenericError(xmlGenericErrorContext, "last = %s ",
8400 (*last)->name);
8401 else
8402 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
8403 }
8404#endif
8405 switch (axis) {
8406 case AXIS_ANCESTOR:
8407#ifdef DEBUG_STEP_NTH
8408 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
8409#endif
8410 first = NULL;
8411 next = xmlXPathNextAncestor;
8412 break;
8413 case AXIS_ANCESTOR_OR_SELF:
8414#ifdef DEBUG_STEP_NTH
8415 xmlGenericError(xmlGenericErrorContext,
8416 "axis 'ancestors-or-self' ");
8417#endif
8418 first = NULL;
8419 next = xmlXPathNextAncestorOrSelf;
8420 break;
8421 case AXIS_ATTRIBUTE:
8422#ifdef DEBUG_STEP_NTH
8423 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
8424#endif
8425 first = NULL;
8426 last = NULL;
8427 next = xmlXPathNextAttribute;
8428 break;
8429 case AXIS_CHILD:
8430#ifdef DEBUG_STEP_NTH
8431 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
8432#endif
8433 last = NULL;
8434 next = xmlXPathNextChild;
8435 break;
8436 case AXIS_DESCENDANT:
8437#ifdef DEBUG_STEP_NTH
8438 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
8439#endif
8440 last = NULL;
8441 next = xmlXPathNextDescendant;
8442 break;
8443 case AXIS_DESCENDANT_OR_SELF:
8444#ifdef DEBUG_STEP_NTH
8445 xmlGenericError(xmlGenericErrorContext,
8446 "axis 'descendant-or-self' ");
8447#endif
8448 last = NULL;
8449 next = xmlXPathNextDescendantOrSelf;
8450 break;
8451 case AXIS_FOLLOWING:
8452#ifdef DEBUG_STEP_NTH
8453 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
8454#endif
8455 last = NULL;
8456 next = xmlXPathNextFollowing;
8457 break;
8458 case AXIS_FOLLOWING_SIBLING:
8459#ifdef DEBUG_STEP_NTH
8460 xmlGenericError(xmlGenericErrorContext,
8461 "axis 'following-siblings' ");
8462#endif
8463 last = NULL;
8464 next = xmlXPathNextFollowingSibling;
8465 break;
8466 case AXIS_NAMESPACE:
8467#ifdef DEBUG_STEP_NTH
8468 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
8469#endif
8470 last = NULL;
8471 first = NULL;
8472 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8473 break;
8474 case AXIS_PARENT:
8475#ifdef DEBUG_STEP_NTH
8476 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
8477#endif
8478 first = NULL;
8479 next = xmlXPathNextParent;
8480 break;
8481 case AXIS_PRECEDING:
8482#ifdef DEBUG_STEP_NTH
8483 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
8484#endif
8485 first = NULL;
8486 next = xmlXPathNextPrecedingInternal;
8487 break;
8488 case AXIS_PRECEDING_SIBLING:
8489#ifdef DEBUG_STEP_NTH
8490 xmlGenericError(xmlGenericErrorContext,
8491 "axis 'preceding-sibling' ");
8492#endif
8493 first = NULL;
8494 next = xmlXPathNextPrecedingSibling;
8495 break;
8496 case AXIS_SELF:
8497#ifdef DEBUG_STEP_NTH
8498 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
8499#endif
8500 first = NULL;
8501 last = NULL;
8502 next = xmlXPathNextSelf;
8503 break;
8504 }
8505 if (next == NULL)
8506 return(0);
8507
8508 nodelist = obj->nodesetval;
8509 if (nodelist == NULL) {
8510 xmlXPathFreeObject(obj);
8511 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8512 return(0);
8513 }
8514 addNode = xmlXPathNodeSetAddUnique;
8515#ifdef DEBUG_STEP_NTH
8516 xmlGenericError(xmlGenericErrorContext,
8517 " context contains %d nodes\n", nodelist->nodeNr);
8518 switch (test) {
8519 case NODE_TEST_NONE:
8520 xmlGenericError(xmlGenericErrorContext,
8521 " searching for none !!!\n");
8522 break;
8523 case NODE_TEST_TYPE:
8524 xmlGenericError(xmlGenericErrorContext,
8525 " searching for type %d\n", type);
8526 break;
8527 case NODE_TEST_PI:
8528 xmlGenericError(xmlGenericErrorContext,
8529 " searching for PI !!!\n");
8530 break;
8531 case NODE_TEST_ALL:
8532 xmlGenericError(xmlGenericErrorContext,
8533 " searching for *\n");
8534 break;
8535 case NODE_TEST_NS:
8536 xmlGenericError(xmlGenericErrorContext,
8537 " searching for namespace %s\n",
8538 prefix);
8539 break;
8540 case NODE_TEST_NAME:
8541 xmlGenericError(xmlGenericErrorContext,
8542 " searching for name %s\n", name);
8543 if (prefix != NULL)
8544 xmlGenericError(xmlGenericErrorContext,
8545 " with namespace %s\n", prefix);
8546 break;
8547 }
8548 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8549#endif
8550 /*
8551 * 2.3 Node Tests
8552 * - For the attribute axis, the principal node type is attribute.
8553 * - For the namespace axis, the principal node type is namespace.
8554 * - For other axes, the principal node type is element.
8555 *
8556 * A node test * is true for any node of the
8557 * principal node type. For example, child::* willi
8558 * select all element children of the context node
8559 */
8560 tmp = ctxt->context->node;
8561 list = xmlXPathNodeSetCreate(NULL);
8562 for (i = 0; i < nodelist->nodeNr; i++) {
8563 ctxt->context->node = nodelist->nodeTab[i];
8564
8565 cur = NULL;
8566 n = 0;
8567 do {
8568 cur = next(ctxt, cur);
8569 if (cur == NULL)
8570 break;
8571 if ((first != NULL) && (*first == cur))
8572 break;
8573 if (((t % 256) == 0) &&
8574 (first != NULL) && (*first != NULL) &&
8575 (xmlXPathCmpNodes(*first, cur) >= 0))
8576 break;
8577 if ((last != NULL) && (*last == cur))
8578 break;
8579 if (((t % 256) == 0) &&
8580 (last != NULL) && (*last != NULL) &&
8581 (xmlXPathCmpNodes(cur, *last) >= 0))
8582 break;
8583 t++;
8584 switch (test) {
8585 case NODE_TEST_NONE:
8586 ctxt->context->node = tmp;
8587 STRANGE return(0);
8588 case NODE_TEST_TYPE:
8589 if ((cur->type == type) ||
8590 ((type == NODE_TYPE_NODE) &&
8591 ((cur->type == XML_DOCUMENT_NODE) ||
8592 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8593 (cur->type == XML_ELEMENT_NODE) ||
8594 (cur->type == XML_PI_NODE) ||
8595 (cur->type == XML_COMMENT_NODE) ||
8596 (cur->type == XML_CDATA_SECTION_NODE) ||
8597 (cur->type == XML_TEXT_NODE)))) {
8598 n++;
8599 if (n == indx)
8600 addNode(list, cur);
8601 }
8602 break;
8603 case NODE_TEST_PI:
8604 if (cur->type == XML_PI_NODE) {
8605 if ((name != NULL) &&
8606 (!xmlStrEqual(name, cur->name)))
8607 break;
8608 n++;
8609 if (n == indx)
8610 addNode(list, cur);
8611 }
8612 break;
8613 case NODE_TEST_ALL:
8614 if (axis == AXIS_ATTRIBUTE) {
8615 if (cur->type == XML_ATTRIBUTE_NODE) {
8616 n++;
8617 if (n == indx)
8618 addNode(list, cur);
8619 }
8620 } else if (axis == AXIS_NAMESPACE) {
8621 if (cur->type == XML_NAMESPACE_DECL) {
8622 n++;
8623 if (n == indx)
8624 addNode(list, cur);
8625 }
8626 } else {
8627 if (cur->type == XML_ELEMENT_NODE) {
8628 if (prefix == NULL) {
8629 n++;
8630 if (n == indx)
8631 addNode(list, cur);
8632 } else if ((cur->ns != NULL) &&
8633 (xmlStrEqual(URI, cur->ns->href))) {
8634 n++;
8635 if (n == indx)
8636 addNode(list, cur);
8637 }
8638 }
8639 }
8640 break;
8641 case NODE_TEST_NS:{
8642 TODO;
8643 break;
8644 }
8645 case NODE_TEST_NAME:
8646 switch (cur->type) {
8647 case XML_ELEMENT_NODE:
8648 if (xmlStrEqual(name, cur->name)) {
8649 if (prefix == NULL) {
8650 if (cur->ns == NULL) {
8651 n++;
8652 if (n == indx)
8653 addNode(list, cur);
8654 }
8655 } else {
8656 if ((cur->ns != NULL) &&
8657 (xmlStrEqual(URI,
8658 cur->ns->href))) {
8659 n++;
8660 if (n == indx)
8661 addNode(list, cur);
8662 }
8663 }
8664 }
8665 break;
8666 case XML_ATTRIBUTE_NODE:{
8667 xmlAttrPtr attr = (xmlAttrPtr) cur;
8668
8669 if (xmlStrEqual(name, attr->name)) {
8670 if (prefix == NULL) {
8671 if ((attr->ns == NULL) ||
8672 (attr->ns->prefix == NULL)) {
8673 n++;
8674 if (n == indx)
8675 addNode(list, cur);
8676 }
8677 } else {
8678 if ((attr->ns != NULL) &&
8679 (xmlStrEqual(URI,
8680 attr->ns->
8681 href))) {
8682 n++;
8683 if (n == indx)
8684 addNode(list, cur);
8685 }
8686 }
8687 }
8688 break;
8689 }
8690 case XML_NAMESPACE_DECL:
8691 if (cur->type == XML_NAMESPACE_DECL) {
8692 xmlNsPtr ns = (xmlNsPtr) cur;
8693
8694 if ((ns->prefix != NULL) && (name != NULL)
8695 && (xmlStrEqual(ns->prefix, name))) {
8696 n++;
8697 if (n == indx)
8698 addNode(list, cur);
8699 }
8700 }
8701 break;
8702 default:
8703 break;
8704 }
8705 break;
8706 break;
8707 }
8708 } while (n < indx);
8709 }
8710 ctxt->context->node = tmp;
8711#ifdef DEBUG_STEP_NTH
8712 xmlGenericError(xmlGenericErrorContext,
8713 "\nExamined %d nodes, found %d nodes at that step\n",
8714 t, list->nodeNr);
8715#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008716 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00008717 if ((obj->boolval) && (obj->user != NULL)) {
8718 ctxt->value->boolval = 1;
8719 ctxt->value->user = obj->user;
8720 obj->user = NULL;
8721 obj->boolval = 0;
8722 }
8723 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008724 return(t);
8725}
8726
8727/**
8728 * xmlXPathCompOpEvalFirst:
8729 * @ctxt: the XPath parser context with the compiled expression
8730 * @op: an XPath compiled operation
8731 * @first: the first elem found so far
8732 *
8733 * Evaluate the Precompiled XPath operation searching only the first
8734 * element in document order
8735 *
8736 * Returns the number of examined objects.
8737 */
8738static int
8739xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
8740 xmlXPathStepOpPtr op, xmlNodePtr * first)
8741{
8742 int total = 0, cur;
8743 xmlXPathCompExprPtr comp;
8744 xmlXPathObjectPtr arg1, arg2;
8745
8746 comp = ctxt->comp;
8747 switch (op->op) {
8748 case XPATH_OP_END:
8749 return (0);
8750 case XPATH_OP_UNION:
8751 total =
8752 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
8753 first);
8754 if ((ctxt->value != NULL)
8755 && (ctxt->value->type == XPATH_NODESET)
8756 && (ctxt->value->nodesetval != NULL)
8757 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8758 /*
8759 * limit tree traversing to first node in the result
8760 */
8761 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8762 *first = ctxt->value->nodesetval->nodeTab[0];
8763 }
8764 cur =
8765 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
8766 first);
8767 CHECK_TYPE0(XPATH_NODESET);
8768 arg2 = valuePop(ctxt);
8769
8770 CHECK_TYPE0(XPATH_NODESET);
8771 arg1 = valuePop(ctxt);
8772
8773 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8774 arg2->nodesetval);
8775 valuePush(ctxt, arg1);
8776 xmlXPathFreeObject(arg2);
8777 /* optimizer */
8778 if (total > cur)
8779 xmlXPathCompSwap(op);
8780 return (total + cur);
8781 case XPATH_OP_ROOT:
8782 xmlXPathRoot(ctxt);
8783 return (0);
8784 case XPATH_OP_NODE:
8785 if (op->ch1 != -1)
8786 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8787 if (op->ch2 != -1)
8788 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8789 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8790 return (total);
8791 case XPATH_OP_RESET:
8792 if (op->ch1 != -1)
8793 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8794 if (op->ch2 != -1)
8795 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8796 ctxt->context->node = NULL;
8797 return (total);
8798 case XPATH_OP_COLLECT:{
8799 if (op->ch1 == -1)
8800 return (total);
8801
8802 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8803
8804 /*
8805 * Optimization for [n] selection where n is a number
8806 */
8807 if ((op->ch2 != -1) &&
8808 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8809 (comp->steps[op->ch2].ch1 == -1) &&
8810 (comp->steps[op->ch2].ch2 != -1) &&
8811 (comp->steps[comp->steps[op->ch2].ch2].op ==
8812 XPATH_OP_VALUE)) {
8813 xmlXPathObjectPtr val;
8814
8815 val = comp->steps[comp->steps[op->ch2].ch2].value4;
8816 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
8817 int indx = (int) val->floatval;
8818
8819 if (val->floatval == (float) indx) {
8820 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
8821 first, NULL);
8822 return (total);
8823 }
8824 }
8825 }
8826 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
8827 return (total);
8828 }
8829 case XPATH_OP_VALUE:
8830 valuePush(ctxt,
8831 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
8832 return (0);
8833 case XPATH_OP_SORT:
8834 if (op->ch1 != -1)
8835 total +=
8836 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
8837 first);
8838 if ((ctxt->value != NULL)
8839 && (ctxt->value->type == XPATH_NODESET)
8840 && (ctxt->value->nodesetval != NULL))
8841 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8842 return (total);
8843 default:
8844 return (xmlXPathCompOpEval(ctxt, op));
8845 }
8846}
8847
8848/**
8849 * xmlXPathCompOpEvalLast:
8850 * @ctxt: the XPath parser context with the compiled expression
8851 * @op: an XPath compiled operation
8852 * @last: the last elem found so far
8853 *
8854 * Evaluate the Precompiled XPath operation searching only the last
8855 * element in document order
8856 *
8857 * Returns the number of node traversed
8858 */
8859static int
8860xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
8861 xmlNodePtr * last)
8862{
8863 int total = 0, cur;
8864 xmlXPathCompExprPtr comp;
8865 xmlXPathObjectPtr arg1, arg2;
8866
8867 comp = ctxt->comp;
8868 switch (op->op) {
8869 case XPATH_OP_END:
8870 return (0);
8871 case XPATH_OP_UNION:
8872 total =
8873 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
8874 if ((ctxt->value != NULL)
8875 && (ctxt->value->type == XPATH_NODESET)
8876 && (ctxt->value->nodesetval != NULL)
8877 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8878 /*
8879 * limit tree traversing to first node in the result
8880 */
8881 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8882 *last =
8883 ctxt->value->nodesetval->nodeTab[ctxt->value->
8884 nodesetval->nodeNr -
8885 1];
8886 }
8887 cur =
8888 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
8889 if ((ctxt->value != NULL)
8890 && (ctxt->value->type == XPATH_NODESET)
8891 && (ctxt->value->nodesetval != NULL)
8892 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8893 }
8894 CHECK_TYPE0(XPATH_NODESET);
8895 arg2 = valuePop(ctxt);
8896
8897 CHECK_TYPE0(XPATH_NODESET);
8898 arg1 = valuePop(ctxt);
8899
8900 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8901 arg2->nodesetval);
8902 valuePush(ctxt, arg1);
8903 xmlXPathFreeObject(arg2);
8904 /* optimizer */
8905 if (total > cur)
8906 xmlXPathCompSwap(op);
8907 return (total + cur);
8908 case XPATH_OP_ROOT:
8909 xmlXPathRoot(ctxt);
8910 return (0);
8911 case XPATH_OP_NODE:
8912 if (op->ch1 != -1)
8913 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8914 if (op->ch2 != -1)
8915 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8916 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8917 return (total);
8918 case XPATH_OP_RESET:
8919 if (op->ch1 != -1)
8920 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8921 if (op->ch2 != -1)
8922 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8923 ctxt->context->node = NULL;
8924 return (total);
8925 case XPATH_OP_COLLECT:{
8926 if (op->ch1 == -1)
8927 return (0);
8928
8929 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8930
8931 /*
8932 * Optimization for [n] selection where n is a number
8933 */
8934 if ((op->ch2 != -1) &&
8935 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8936 (comp->steps[op->ch2].ch1 == -1) &&
8937 (comp->steps[op->ch2].ch2 != -1) &&
8938 (comp->steps[comp->steps[op->ch2].ch2].op ==
8939 XPATH_OP_VALUE)) {
8940 xmlXPathObjectPtr val;
8941
8942 val = comp->steps[comp->steps[op->ch2].ch2].value4;
8943 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
8944 int indx = (int) val->floatval;
8945
8946 if (val->floatval == (float) indx) {
8947 total +=
8948 xmlXPathNodeCollectAndTestNth(ctxt, op,
8949 indx, NULL,
8950 last);
8951 return (total);
8952 }
8953 }
8954 }
8955 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
8956 return (total);
8957 }
8958 case XPATH_OP_VALUE:
8959 valuePush(ctxt,
8960 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
8961 return (0);
8962 case XPATH_OP_SORT:
8963 if (op->ch1 != -1)
8964 total +=
8965 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
8966 last);
8967 if ((ctxt->value != NULL)
8968 && (ctxt->value->type == XPATH_NODESET)
8969 && (ctxt->value->nodesetval != NULL))
8970 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8971 return (total);
8972 default:
8973 return (xmlXPathCompOpEval(ctxt, op));
8974 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008975}
8976
Owen Taylor3473f882001-02-23 17:55:21 +00008977/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008978 * xmlXPathCompOpEval:
8979 * @ctxt: the XPath parser context with the compiled expression
8980 * @op: an XPath compiled operation
8981 *
8982 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008983 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008984 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008985static int
8986xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
8987{
8988 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008989 int equal, ret;
8990 xmlXPathCompExprPtr comp;
8991 xmlXPathObjectPtr arg1, arg2;
8992
8993 comp = ctxt->comp;
8994 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008995 case XPATH_OP_END:
8996 return (0);
8997 case XPATH_OP_AND:
8998 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8999 xmlXPathBooleanFunction(ctxt, 1);
9000 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9001 return (total);
9002 arg2 = valuePop(ctxt);
9003 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9004 xmlXPathBooleanFunction(ctxt, 1);
9005 arg1 = valuePop(ctxt);
9006 arg1->boolval &= arg2->boolval;
9007 valuePush(ctxt, arg1);
9008 xmlXPathFreeObject(arg2);
9009 return (total);
9010 case XPATH_OP_OR:
9011 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9012 xmlXPathBooleanFunction(ctxt, 1);
9013 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9014 return (total);
9015 arg2 = valuePop(ctxt);
9016 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9017 xmlXPathBooleanFunction(ctxt, 1);
9018 arg1 = valuePop(ctxt);
9019 arg1->boolval |= arg2->boolval;
9020 valuePush(ctxt, arg1);
9021 xmlXPathFreeObject(arg2);
9022 return (total);
9023 case XPATH_OP_EQUAL:
9024 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9025 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9026 equal = xmlXPathEqualValues(ctxt);
9027 if (op->value)
9028 valuePush(ctxt, xmlXPathNewBoolean(equal));
9029 else
9030 valuePush(ctxt, xmlXPathNewBoolean(!equal));
9031 return (total);
9032 case XPATH_OP_CMP:
9033 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9034 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9035 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9036 valuePush(ctxt, xmlXPathNewBoolean(ret));
9037 return (total);
9038 case XPATH_OP_PLUS:
9039 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9040 if (op->ch2 != -1)
9041 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9042 if (op->value == 0)
9043 xmlXPathSubValues(ctxt);
9044 else if (op->value == 1)
9045 xmlXPathAddValues(ctxt);
9046 else if (op->value == 2)
9047 xmlXPathValueFlipSign(ctxt);
9048 else if (op->value == 3) {
9049 CAST_TO_NUMBER;
9050 CHECK_TYPE0(XPATH_NUMBER);
9051 }
9052 return (total);
9053 case XPATH_OP_MULT:
9054 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9055 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9056 if (op->value == 0)
9057 xmlXPathMultValues(ctxt);
9058 else if (op->value == 1)
9059 xmlXPathDivValues(ctxt);
9060 else if (op->value == 2)
9061 xmlXPathModValues(ctxt);
9062 return (total);
9063 case XPATH_OP_UNION:
9064 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9065 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9066 CHECK_TYPE0(XPATH_NODESET);
9067 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009068
Daniel Veillardf06307e2001-07-03 10:35:50 +00009069 CHECK_TYPE0(XPATH_NODESET);
9070 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009071
Daniel Veillardf06307e2001-07-03 10:35:50 +00009072 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9073 arg2->nodesetval);
9074 valuePush(ctxt, arg1);
9075 xmlXPathFreeObject(arg2);
9076 return (total);
9077 case XPATH_OP_ROOT:
9078 xmlXPathRoot(ctxt);
9079 return (total);
9080 case XPATH_OP_NODE:
9081 if (op->ch1 != -1)
9082 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9083 if (op->ch2 != -1)
9084 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9085 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9086 return (total);
9087 case XPATH_OP_RESET:
9088 if (op->ch1 != -1)
9089 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9090 if (op->ch2 != -1)
9091 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9092 ctxt->context->node = NULL;
9093 return (total);
9094 case XPATH_OP_COLLECT:{
9095 if (op->ch1 == -1)
9096 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009097
Daniel Veillardf06307e2001-07-03 10:35:50 +00009098 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009099
Daniel Veillardf06307e2001-07-03 10:35:50 +00009100 /*
9101 * Optimization for [n] selection where n is a number
9102 */
9103 if ((op->ch2 != -1) &&
9104 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9105 (comp->steps[op->ch2].ch1 == -1) &&
9106 (comp->steps[op->ch2].ch2 != -1) &&
9107 (comp->steps[comp->steps[op->ch2].ch2].op ==
9108 XPATH_OP_VALUE)) {
9109 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00009110
Daniel Veillardf06307e2001-07-03 10:35:50 +00009111 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9112 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9113 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009114
Daniel Veillardf06307e2001-07-03 10:35:50 +00009115 if (val->floatval == (float) indx) {
9116 total +=
9117 xmlXPathNodeCollectAndTestNth(ctxt, op,
9118 indx, NULL,
9119 NULL);
9120 return (total);
9121 }
9122 }
9123 }
9124 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
9125 return (total);
9126 }
9127 case XPATH_OP_VALUE:
9128 valuePush(ctxt,
9129 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9130 return (total);
9131 case XPATH_OP_VARIABLE:{
9132 if (op->ch1 != -1)
9133 total +=
9134 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9135 if (op->value5 == NULL)
9136 valuePush(ctxt,
9137 xmlXPathVariableLookup(ctxt->context,
9138 op->value4));
9139 else {
9140 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009141
Daniel Veillardf06307e2001-07-03 10:35:50 +00009142 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9143 if (URI == NULL) {
9144 xmlGenericError(xmlGenericErrorContext,
9145 "xmlXPathRunEval: variable %s bound to undefined prefix %s\n",
9146 op->value4, op->value5);
9147 return (total);
9148 }
9149 valuePush(ctxt,
9150 xmlXPathVariableLookupNS(ctxt->context,
9151 op->value4, URI));
9152 }
9153 return (total);
9154 }
9155 case XPATH_OP_FUNCTION:{
9156 xmlXPathFunction func;
9157 const xmlChar *oldFunc, *oldFuncURI;
9158
9159 if (op->ch1 != -1)
9160 total +=
9161 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9162 if (op->cache != NULL)
9163 func = (xmlXPathFunction) op->cache;
9164 else {
9165 const xmlChar *URI = NULL;
9166
9167 if (op->value5 == NULL)
9168 func =
9169 xmlXPathFunctionLookup(ctxt->context,
9170 op->value4);
9171 else {
9172 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9173 if (URI == NULL) {
9174 xmlGenericError(xmlGenericErrorContext,
9175 "xmlXPathRunEval: function %s bound to undefined prefix %s\n",
9176 op->value4, op->value5);
9177 return (total);
9178 }
9179 func = xmlXPathFunctionLookupNS(ctxt->context,
9180 op->value4, URI);
9181 }
9182 if (func == NULL) {
9183 xmlGenericError(xmlGenericErrorContext,
9184 "xmlXPathRunEval: function %s not found\n",
9185 op->value4);
9186 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
9187 return (total);
9188 }
9189 op->cache = (void *) func;
9190 op->cacheURI = (void *) URI;
9191 }
9192 oldFunc = ctxt->context->function;
9193 oldFuncURI = ctxt->context->functionURI;
9194 ctxt->context->function = op->value4;
9195 ctxt->context->functionURI = op->cacheURI;
9196 func(ctxt, op->value);
9197 ctxt->context->function = oldFunc;
9198 ctxt->context->functionURI = oldFuncURI;
9199 return (total);
9200 }
9201 case XPATH_OP_ARG:
9202 if (op->ch1 != -1)
9203 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9204 if (op->ch2 != -1)
9205 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9206 return (total);
9207 case XPATH_OP_PREDICATE:
9208 case XPATH_OP_FILTER:{
9209 xmlXPathObjectPtr res;
9210 xmlXPathObjectPtr obj, tmp;
9211 xmlNodeSetPtr newset = NULL;
9212 xmlNodeSetPtr oldset;
9213 xmlNodePtr oldnode;
9214 int i;
9215
9216 /*
9217 * Optimization for ()[1] selection i.e. the first elem
9218 */
9219 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9220 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9221 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
9222 xmlXPathObjectPtr val;
9223
9224 val = comp->steps[op->ch2].value4;
9225 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
9226 (val->floatval == 1.0)) {
9227 xmlNodePtr first = NULL;
9228
9229 total +=
9230 xmlXPathCompOpEvalFirst(ctxt,
9231 &comp->steps[op->ch1],
9232 &first);
9233 /*
9234 * The nodeset should be in document order,
9235 * Keep only the first value
9236 */
9237 if ((ctxt->value != NULL) &&
9238 (ctxt->value->type == XPATH_NODESET) &&
9239 (ctxt->value->nodesetval != NULL) &&
9240 (ctxt->value->nodesetval->nodeNr > 1))
9241 ctxt->value->nodesetval->nodeNr = 1;
9242 return (total);
9243 }
9244 }
9245 /*
9246 * Optimization for ()[last()] selection i.e. the last elem
9247 */
9248 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9249 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9250 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
9251 int f = comp->steps[op->ch2].ch1;
9252
9253 if ((f != -1) &&
9254 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
9255 (comp->steps[f].value5 == NULL) &&
9256 (comp->steps[f].value == 0) &&
9257 (comp->steps[f].value4 != NULL) &&
9258 (xmlStrEqual
9259 (comp->steps[f].value4, BAD_CAST "last"))) {
9260 xmlNodePtr last = NULL;
9261
9262 total +=
9263 xmlXPathCompOpEvalLast(ctxt,
9264 &comp->steps[op->ch1],
9265 &last);
9266 /*
9267 * The nodeset should be in document order,
9268 * Keep only the last value
9269 */
9270 if ((ctxt->value != NULL) &&
9271 (ctxt->value->type == XPATH_NODESET) &&
9272 (ctxt->value->nodesetval != NULL) &&
9273 (ctxt->value->nodesetval->nodeTab != NULL) &&
9274 (ctxt->value->nodesetval->nodeNr > 1)) {
9275 ctxt->value->nodesetval->nodeTab[0] =
9276 ctxt->value->nodesetval->nodeTab[ctxt->
9277 value->
9278 nodesetval->
9279 nodeNr -
9280 1];
9281 ctxt->value->nodesetval->nodeNr = 1;
9282 }
9283 return (total);
9284 }
9285 }
9286
9287 if (op->ch1 != -1)
9288 total +=
9289 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9290 if (op->ch2 == -1)
9291 return (total);
9292 if (ctxt->value == NULL)
9293 return (total);
9294
9295 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009296
9297#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009298 /*
9299 * Hum are we filtering the result of an XPointer expression
9300 */
9301 if (ctxt->value->type == XPATH_LOCATIONSET) {
9302 xmlLocationSetPtr newlocset = NULL;
9303 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009304
Daniel Veillardf06307e2001-07-03 10:35:50 +00009305 /*
9306 * Extract the old locset, and then evaluate the result of the
9307 * expression for all the element in the locset. use it to grow
9308 * up a new locset.
9309 */
9310 CHECK_TYPE0(XPATH_LOCATIONSET);
9311 obj = valuePop(ctxt);
9312 oldlocset = obj->user;
9313 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009314
Daniel Veillardf06307e2001-07-03 10:35:50 +00009315 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
9316 ctxt->context->contextSize = 0;
9317 ctxt->context->proximityPosition = 0;
9318 if (op->ch2 != -1)
9319 total +=
9320 xmlXPathCompOpEval(ctxt,
9321 &comp->steps[op->ch2]);
9322 res = valuePop(ctxt);
9323 if (res != NULL)
9324 xmlXPathFreeObject(res);
9325 valuePush(ctxt, obj);
9326 CHECK_ERROR0;
9327 return (total);
9328 }
9329 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009330
Daniel Veillardf06307e2001-07-03 10:35:50 +00009331 for (i = 0; i < oldlocset->locNr; i++) {
9332 /*
9333 * Run the evaluation with a node list made of a
9334 * single item in the nodelocset.
9335 */
9336 ctxt->context->node = oldlocset->locTab[i]->user;
9337 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9338 valuePush(ctxt, tmp);
9339 ctxt->context->contextSize = oldlocset->locNr;
9340 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009341
Daniel Veillardf06307e2001-07-03 10:35:50 +00009342 if (op->ch2 != -1)
9343 total +=
9344 xmlXPathCompOpEval(ctxt,
9345 &comp->steps[op->ch2]);
9346 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009347
Daniel Veillardf06307e2001-07-03 10:35:50 +00009348 /*
9349 * The result of the evaluation need to be tested to
9350 * decided whether the filter succeeded or not
9351 */
9352 res = valuePop(ctxt);
9353 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9354 xmlXPtrLocationSetAdd(newlocset,
9355 xmlXPathObjectCopy
9356 (oldlocset->locTab[i]));
9357 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009358
Daniel Veillardf06307e2001-07-03 10:35:50 +00009359 /*
9360 * Cleanup
9361 */
9362 if (res != NULL)
9363 xmlXPathFreeObject(res);
9364 if (ctxt->value == tmp) {
9365 res = valuePop(ctxt);
9366 xmlXPathFreeObject(res);
9367 }
9368
9369 ctxt->context->node = NULL;
9370 }
9371
9372 /*
9373 * The result is used as the new evaluation locset.
9374 */
9375 xmlXPathFreeObject(obj);
9376 ctxt->context->node = NULL;
9377 ctxt->context->contextSize = -1;
9378 ctxt->context->proximityPosition = -1;
9379 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
9380 ctxt->context->node = oldnode;
9381 return (total);
9382 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009383#endif /* LIBXML_XPTR_ENABLED */
9384
Daniel Veillardf06307e2001-07-03 10:35:50 +00009385 /*
9386 * Extract the old set, and then evaluate the result of the
9387 * expression for all the element in the set. use it to grow
9388 * up a new set.
9389 */
9390 CHECK_TYPE0(XPATH_NODESET);
9391 obj = valuePop(ctxt);
9392 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00009393
Daniel Veillardf06307e2001-07-03 10:35:50 +00009394 oldnode = ctxt->context->node;
9395 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009396
Daniel Veillardf06307e2001-07-03 10:35:50 +00009397 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
9398 ctxt->context->contextSize = 0;
9399 ctxt->context->proximityPosition = 0;
9400 if (op->ch2 != -1)
9401 total +=
9402 xmlXPathCompOpEval(ctxt,
9403 &comp->steps[op->ch2]);
9404 res = valuePop(ctxt);
9405 if (res != NULL)
9406 xmlXPathFreeObject(res);
9407 valuePush(ctxt, obj);
9408 ctxt->context->node = oldnode;
9409 CHECK_ERROR0;
9410 } else {
9411 /*
9412 * Initialize the new set.
9413 */
9414 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009415
Daniel Veillardf06307e2001-07-03 10:35:50 +00009416 for (i = 0; i < oldset->nodeNr; i++) {
9417 /*
9418 * Run the evaluation with a node list made of
9419 * a single item in the nodeset.
9420 */
9421 ctxt->context->node = oldset->nodeTab[i];
9422 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9423 valuePush(ctxt, tmp);
9424 ctxt->context->contextSize = oldset->nodeNr;
9425 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009426
Daniel Veillardf06307e2001-07-03 10:35:50 +00009427 if (op->ch2 != -1)
9428 total +=
9429 xmlXPathCompOpEval(ctxt,
9430 &comp->steps[op->ch2]);
9431 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009432
Daniel Veillardf06307e2001-07-03 10:35:50 +00009433 /*
9434 * The result of the evaluation need to be tested to
9435 * decided whether the filter succeeded or not
9436 */
9437 res = valuePop(ctxt);
9438 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9439 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
9440 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009441
Daniel Veillardf06307e2001-07-03 10:35:50 +00009442 /*
9443 * Cleanup
9444 */
9445 if (res != NULL)
9446 xmlXPathFreeObject(res);
9447 if (ctxt->value == tmp) {
9448 res = valuePop(ctxt);
9449 xmlXPathFreeObject(res);
9450 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009451
Daniel Veillardf06307e2001-07-03 10:35:50 +00009452 ctxt->context->node = NULL;
9453 }
9454
9455 /*
9456 * The result is used as the new evaluation set.
9457 */
9458 xmlXPathFreeObject(obj);
9459 ctxt->context->node = NULL;
9460 ctxt->context->contextSize = -1;
9461 ctxt->context->proximityPosition = -1;
9462 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
9463 }
9464 ctxt->context->node = oldnode;
9465 return (total);
9466 }
9467 case XPATH_OP_SORT:
9468 if (op->ch1 != -1)
9469 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9470 if ((ctxt->value != NULL) &&
9471 (ctxt->value->type == XPATH_NODESET) &&
9472 (ctxt->value->nodesetval != NULL))
9473 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9474 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009475#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009476 case XPATH_OP_RANGETO:{
9477 xmlXPathObjectPtr range;
9478 xmlXPathObjectPtr res, obj;
9479 xmlXPathObjectPtr tmp;
9480 xmlLocationSetPtr newset = NULL;
9481 xmlNodeSetPtr oldset;
9482 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009483
Daniel Veillardf06307e2001-07-03 10:35:50 +00009484 if (op->ch1 != -1)
9485 total +=
9486 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9487 if (op->ch2 == -1)
9488 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009489
Daniel Veillardf06307e2001-07-03 10:35:50 +00009490 CHECK_TYPE0(XPATH_NODESET);
9491 obj = valuePop(ctxt);
9492 oldset = obj->nodesetval;
9493 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009494
Daniel Veillardf06307e2001-07-03 10:35:50 +00009495 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009496
Daniel Veillardf06307e2001-07-03 10:35:50 +00009497 if (oldset != NULL) {
9498 for (i = 0; i < oldset->nodeNr; i++) {
9499 /*
9500 * Run the evaluation with a node list made of a single item
9501 * in the nodeset.
9502 */
9503 ctxt->context->node = oldset->nodeTab[i];
9504 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9505 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009506
Daniel Veillardf06307e2001-07-03 10:35:50 +00009507 if (op->ch2 != -1)
9508 total +=
9509 xmlXPathCompOpEval(ctxt,
9510 &comp->steps[op->ch2]);
9511 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009512
Daniel Veillardf06307e2001-07-03 10:35:50 +00009513 /*
9514 * The result of the evaluation need to be tested to
9515 * decided whether the filter succeeded or not
9516 */
9517 res = valuePop(ctxt);
9518 range =
9519 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
9520 res);
9521 if (range != NULL) {
9522 xmlXPtrLocationSetAdd(newset, range);
9523 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009524
Daniel Veillardf06307e2001-07-03 10:35:50 +00009525 /*
9526 * Cleanup
9527 */
9528 if (res != NULL)
9529 xmlXPathFreeObject(res);
9530 if (ctxt->value == tmp) {
9531 res = valuePop(ctxt);
9532 xmlXPathFreeObject(res);
9533 }
9534
9535 ctxt->context->node = NULL;
9536 }
9537 }
9538
9539 /*
9540 * The result is used as the new evaluation set.
9541 */
9542 xmlXPathFreeObject(obj);
9543 ctxt->context->node = NULL;
9544 ctxt->context->contextSize = -1;
9545 ctxt->context->proximityPosition = -1;
9546 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
9547 return (total);
9548 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009549#endif /* LIBXML_XPTR_ENABLED */
9550 }
9551 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009552 "XPath: unknown precompiled operation %d\n", op->op);
9553 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009554}
9555
9556/**
9557 * xmlXPathRunEval:
9558 * @ctxt: the XPath parser context with the compiled expression
9559 *
9560 * Evaluate the Precompiled XPath expression in the given context.
9561 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009562static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009563xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
9564 xmlXPathCompExprPtr comp;
9565
9566 if ((ctxt == NULL) || (ctxt->comp == NULL))
9567 return;
9568
9569 if (ctxt->valueTab == NULL) {
9570 /* Allocate the value stack */
9571 ctxt->valueTab = (xmlXPathObjectPtr *)
9572 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
9573 if (ctxt->valueTab == NULL) {
9574 xmlFree(ctxt);
9575 xmlGenericError(xmlGenericErrorContext,
9576 "xmlXPathRunEval: out of memory\n");
9577 return;
9578 }
9579 ctxt->valueNr = 0;
9580 ctxt->valueMax = 10;
9581 ctxt->value = NULL;
9582 }
9583 comp = ctxt->comp;
9584 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
9585}
9586
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009587/************************************************************************
9588 * *
9589 * Public interfaces *
9590 * *
9591 ************************************************************************/
9592
9593/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009594 * xmlXPathEvalPredicate:
9595 * @ctxt: the XPath context
9596 * @res: the Predicate Expression evaluation result
9597 *
9598 * Evaluate a predicate result for the current node.
9599 * A PredicateExpr is evaluated by evaluating the Expr and converting
9600 * the result to a boolean. If the result is a number, the result will
9601 * be converted to true if the number is equal to the position of the
9602 * context node in the context node list (as returned by the position
9603 * function) and will be converted to false otherwise; if the result
9604 * is not a number, then the result will be converted as if by a call
9605 * to the boolean function.
9606 *
9607 * Return 1 if predicate is true, 0 otherwise
9608 */
9609int
9610xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
9611 if (res == NULL) return(0);
9612 switch (res->type) {
9613 case XPATH_BOOLEAN:
9614 return(res->boolval);
9615 case XPATH_NUMBER:
9616 return(res->floatval == ctxt->proximityPosition);
9617 case XPATH_NODESET:
9618 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009619 if (res->nodesetval == NULL)
9620 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009621 return(res->nodesetval->nodeNr != 0);
9622 case XPATH_STRING:
9623 return((res->stringval != NULL) &&
9624 (xmlStrlen(res->stringval) != 0));
9625 default:
9626 STRANGE
9627 }
9628 return(0);
9629}
9630
9631/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009632 * xmlXPathEvaluatePredicateResult:
9633 * @ctxt: the XPath Parser context
9634 * @res: the Predicate Expression evaluation result
9635 *
9636 * Evaluate a predicate result for the current node.
9637 * A PredicateExpr is evaluated by evaluating the Expr and converting
9638 * the result to a boolean. If the result is a number, the result will
9639 * be converted to true if the number is equal to the position of the
9640 * context node in the context node list (as returned by the position
9641 * function) and will be converted to false otherwise; if the result
9642 * is not a number, then the result will be converted as if by a call
9643 * to the boolean function.
9644 *
9645 * Return 1 if predicate is true, 0 otherwise
9646 */
9647int
9648xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
9649 xmlXPathObjectPtr res) {
9650 if (res == NULL) return(0);
9651 switch (res->type) {
9652 case XPATH_BOOLEAN:
9653 return(res->boolval);
9654 case XPATH_NUMBER:
9655 return(res->floatval == ctxt->context->proximityPosition);
9656 case XPATH_NODESET:
9657 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +00009658 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +00009659 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009660 return(res->nodesetval->nodeNr != 0);
9661 case XPATH_STRING:
9662 return((res->stringval != NULL) &&
9663 (xmlStrlen(res->stringval) != 0));
9664 default:
9665 STRANGE
9666 }
9667 return(0);
9668}
9669
9670/**
9671 * xmlXPathCompile:
9672 * @str: the XPath expression
9673 *
9674 * Compile an XPath expression
9675 *
9676 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9677 * the caller has to free the object.
9678 */
9679xmlXPathCompExprPtr
9680xmlXPathCompile(const xmlChar *str) {
9681 xmlXPathParserContextPtr ctxt;
9682 xmlXPathCompExprPtr comp;
9683
9684 xmlXPathInit();
9685
9686 ctxt = xmlXPathNewParserContext(str, NULL);
9687 xmlXPathCompileExpr(ctxt);
9688
Daniel Veillard40af6492001-04-22 08:50:55 +00009689 if (*ctxt->cur != 0) {
9690 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9691 comp = NULL;
9692 } else {
9693 comp = ctxt->comp;
9694 ctxt->comp = NULL;
9695 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009696 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009697#ifdef DEBUG_EVAL_COUNTS
9698 if (comp != NULL) {
9699 comp->string = xmlStrdup(str);
9700 comp->nb = 0;
9701 }
9702#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009703 return(comp);
9704}
9705
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009706/**
9707 * xmlXPathCompiledEval:
9708 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +00009709 * @ctx: the XPath context
9710 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009711 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +00009712 *
9713 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9714 * the caller has to free the object.
9715 */
9716xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009717xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +00009718 xmlXPathParserContextPtr ctxt;
9719 xmlXPathObjectPtr res, tmp, init = NULL;
9720 int stack = 0;
9721
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009722 if ((comp == NULL) || (ctx == NULL))
9723 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00009724 xmlXPathInit();
9725
9726 CHECK_CONTEXT(ctx)
9727
Daniel Veillardf06307e2001-07-03 10:35:50 +00009728#ifdef DEBUG_EVAL_COUNTS
9729 comp->nb++;
9730 if ((comp->string != NULL) && (comp->nb > 100)) {
9731 fprintf(stderr, "100 x %s\n", comp->string);
9732 comp->nb = 0;
9733 }
9734#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009735 ctxt = xmlXPathCompParserContext(comp, ctx);
9736 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009737
9738 if (ctxt->value == NULL) {
9739 xmlGenericError(xmlGenericErrorContext,
9740 "xmlXPathEval: evaluation failed\n");
9741 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009742 } else {
9743 res = valuePop(ctxt);
9744 }
9745
Daniel Veillardf06307e2001-07-03 10:35:50 +00009746
Owen Taylor3473f882001-02-23 17:55:21 +00009747 do {
9748 tmp = valuePop(ctxt);
9749 if (tmp != NULL) {
9750 if (tmp != init)
9751 stack++;
9752 xmlXPathFreeObject(tmp);
9753 }
9754 } while (tmp != NULL);
9755 if ((stack != 0) && (res != NULL)) {
9756 xmlGenericError(xmlGenericErrorContext,
9757 "xmlXPathEval: %d object left on the stack\n",
9758 stack);
9759 }
9760 if (ctxt->error != XPATH_EXPRESSION_OK) {
9761 xmlXPathFreeObject(res);
9762 res = NULL;
9763 }
9764
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009765
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009766 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009767 xmlXPathFreeParserContext(ctxt);
9768 return(res);
9769}
9770
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009771/**
9772 * xmlXPathEvalExpr:
9773 * @ctxt: the XPath Parser context
9774 *
9775 * Parse and evaluate an XPath expression in the given context,
9776 * then push the result on the context stack
9777 */
9778void
9779xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
9780 xmlXPathCompileExpr(ctxt);
9781 xmlXPathRunEval(ctxt);
9782}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009783
9784/**
9785 * xmlXPathEval:
9786 * @str: the XPath expression
9787 * @ctx: the XPath context
9788 *
9789 * Evaluate the XPath Location Path in the given context.
9790 *
9791 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9792 * the caller has to free the object.
9793 */
9794xmlXPathObjectPtr
9795xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
9796 xmlXPathParserContextPtr ctxt;
9797 xmlXPathObjectPtr res, tmp, init = NULL;
9798 int stack = 0;
9799
9800 xmlXPathInit();
9801
9802 CHECK_CONTEXT(ctx)
9803
9804 ctxt = xmlXPathNewParserContext(str, ctx);
9805 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009806
9807 if (ctxt->value == NULL) {
9808 xmlGenericError(xmlGenericErrorContext,
9809 "xmlXPathEval: evaluation failed\n");
9810 res = NULL;
9811 } else if (*ctxt->cur != 0) {
9812 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9813 res = NULL;
9814 } else {
9815 res = valuePop(ctxt);
9816 }
9817
9818 do {
9819 tmp = valuePop(ctxt);
9820 if (tmp != NULL) {
9821 if (tmp != init)
9822 stack++;
9823 xmlXPathFreeObject(tmp);
9824 }
9825 } while (tmp != NULL);
9826 if ((stack != 0) && (res != NULL)) {
9827 xmlGenericError(xmlGenericErrorContext,
9828 "xmlXPathEval: %d object left on the stack\n",
9829 stack);
9830 }
9831 if (ctxt->error != XPATH_EXPRESSION_OK) {
9832 xmlXPathFreeObject(res);
9833 res = NULL;
9834 }
9835
Owen Taylor3473f882001-02-23 17:55:21 +00009836 xmlXPathFreeParserContext(ctxt);
9837 return(res);
9838}
9839
9840/**
9841 * xmlXPathEvalExpression:
9842 * @str: the XPath expression
9843 * @ctxt: the XPath context
9844 *
9845 * Evaluate the XPath expression in the given context.
9846 *
9847 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
9848 * the caller has to free the object.
9849 */
9850xmlXPathObjectPtr
9851xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
9852 xmlXPathParserContextPtr pctxt;
9853 xmlXPathObjectPtr res, tmp;
9854 int stack = 0;
9855
9856 xmlXPathInit();
9857
9858 CHECK_CONTEXT(ctxt)
9859
9860 pctxt = xmlXPathNewParserContext(str, ctxt);
9861 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009862
9863 if (*pctxt->cur != 0) {
9864 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9865 res = NULL;
9866 } else {
9867 res = valuePop(pctxt);
9868 }
9869 do {
9870 tmp = valuePop(pctxt);
9871 if (tmp != NULL) {
9872 xmlXPathFreeObject(tmp);
9873 stack++;
9874 }
9875 } while (tmp != NULL);
9876 if ((stack != 0) && (res != NULL)) {
9877 xmlGenericError(xmlGenericErrorContext,
9878 "xmlXPathEvalExpression: %d object left on the stack\n",
9879 stack);
9880 }
9881 xmlXPathFreeParserContext(pctxt);
9882 return(res);
9883}
9884
9885/**
9886 * xmlXPathRegisterAllFunctions:
9887 * @ctxt: the XPath context
9888 *
9889 * Registers all default XPath functions in this context
9890 */
9891void
9892xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
9893{
9894 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
9895 xmlXPathBooleanFunction);
9896 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
9897 xmlXPathCeilingFunction);
9898 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
9899 xmlXPathCountFunction);
9900 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
9901 xmlXPathConcatFunction);
9902 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
9903 xmlXPathContainsFunction);
9904 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
9905 xmlXPathIdFunction);
9906 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
9907 xmlXPathFalseFunction);
9908 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
9909 xmlXPathFloorFunction);
9910 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
9911 xmlXPathLastFunction);
9912 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
9913 xmlXPathLangFunction);
9914 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
9915 xmlXPathLocalNameFunction);
9916 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
9917 xmlXPathNotFunction);
9918 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
9919 xmlXPathNameFunction);
9920 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
9921 xmlXPathNamespaceURIFunction);
9922 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
9923 xmlXPathNormalizeFunction);
9924 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
9925 xmlXPathNumberFunction);
9926 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
9927 xmlXPathPositionFunction);
9928 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
9929 xmlXPathRoundFunction);
9930 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
9931 xmlXPathStringFunction);
9932 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
9933 xmlXPathStringLengthFunction);
9934 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
9935 xmlXPathStartsWithFunction);
9936 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
9937 xmlXPathSubstringFunction);
9938 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
9939 xmlXPathSubstringBeforeFunction);
9940 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
9941 xmlXPathSubstringAfterFunction);
9942 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
9943 xmlXPathSumFunction);
9944 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
9945 xmlXPathTrueFunction);
9946 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
9947 xmlXPathTranslateFunction);
9948}
9949
9950#endif /* LIBXML_XPATH_ENABLED */