blob: b716fa612eb80da6d317b21d26949b3fce6e573f [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;
4425 ctxt->value->floatval = arg1 % arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00004426}
4427
4428/************************************************************************
4429 * *
4430 * The traversal functions *
4431 * *
4432 ************************************************************************/
4433
Owen Taylor3473f882001-02-23 17:55:21 +00004434/*
4435 * A traversal function enumerates nodes along an axis.
4436 * Initially it must be called with NULL, and it indicates
4437 * termination on the axis by returning NULL.
4438 */
4439typedef xmlNodePtr (*xmlXPathTraversalFunction)
4440 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
4441
4442/**
4443 * xmlXPathNextSelf:
4444 * @ctxt: the XPath Parser context
4445 * @cur: the current node in the traversal
4446 *
4447 * Traversal function for the "self" direction
4448 * The self axis contains just the context node itself
4449 *
4450 * Returns the next element following that axis
4451 */
4452xmlNodePtr
4453xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4454 if (cur == NULL)
4455 return(ctxt->context->node);
4456 return(NULL);
4457}
4458
4459/**
4460 * xmlXPathNextChild:
4461 * @ctxt: the XPath Parser context
4462 * @cur: the current node in the traversal
4463 *
4464 * Traversal function for the "child" direction
4465 * The child axis contains the children of the context node in document order.
4466 *
4467 * Returns the next element following that axis
4468 */
4469xmlNodePtr
4470xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4471 if (cur == NULL) {
4472 if (ctxt->context->node == NULL) return(NULL);
4473 switch (ctxt->context->node->type) {
4474 case XML_ELEMENT_NODE:
4475 case XML_TEXT_NODE:
4476 case XML_CDATA_SECTION_NODE:
4477 case XML_ENTITY_REF_NODE:
4478 case XML_ENTITY_NODE:
4479 case XML_PI_NODE:
4480 case XML_COMMENT_NODE:
4481 case XML_NOTATION_NODE:
4482 case XML_DTD_NODE:
4483 return(ctxt->context->node->children);
4484 case XML_DOCUMENT_NODE:
4485 case XML_DOCUMENT_TYPE_NODE:
4486 case XML_DOCUMENT_FRAG_NODE:
4487 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004488#ifdef LIBXML_DOCB_ENABLED
4489 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004490#endif
4491 return(((xmlDocPtr) ctxt->context->node)->children);
4492 case XML_ELEMENT_DECL:
4493 case XML_ATTRIBUTE_DECL:
4494 case XML_ENTITY_DECL:
4495 case XML_ATTRIBUTE_NODE:
4496 case XML_NAMESPACE_DECL:
4497 case XML_XINCLUDE_START:
4498 case XML_XINCLUDE_END:
4499 return(NULL);
4500 }
4501 return(NULL);
4502 }
4503 if ((cur->type == XML_DOCUMENT_NODE) ||
4504 (cur->type == XML_HTML_DOCUMENT_NODE))
4505 return(NULL);
4506 return(cur->next);
4507}
4508
4509/**
4510 * xmlXPathNextDescendant:
4511 * @ctxt: the XPath Parser context
4512 * @cur: the current node in the traversal
4513 *
4514 * Traversal function for the "descendant" direction
4515 * the descendant axis contains the descendants of the context node in document
4516 * order; a descendant is a child or a child of a child and so on.
4517 *
4518 * Returns the next element following that axis
4519 */
4520xmlNodePtr
4521xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4522 if (cur == NULL) {
4523 if (ctxt->context->node == NULL)
4524 return(NULL);
4525 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4526 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4527 return(NULL);
4528
4529 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
4530 return(ctxt->context->doc->children);
4531 return(ctxt->context->node->children);
4532 }
4533
Daniel Veillard567e1b42001-08-01 15:53:47 +00004534 if (cur->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004535 if (cur->children->type != XML_ENTITY_DECL)
Daniel Veillard567e1b42001-08-01 15:53:47 +00004536 return(cur->children);
4537 }
4538
4539 if (cur == ctxt->context->node) return(NULL);
4540
Owen Taylor3473f882001-02-23 17:55:21 +00004541 if (cur->next != NULL) return(cur->next);
4542
4543 do {
4544 cur = cur->parent;
4545 if (cur == NULL) return(NULL);
4546 if (cur == ctxt->context->node) return(NULL);
4547 if (cur->next != NULL) {
4548 cur = cur->next;
4549 return(cur);
4550 }
4551 } while (cur != NULL);
4552 return(cur);
4553}
4554
4555/**
4556 * xmlXPathNextDescendantOrSelf:
4557 * @ctxt: the XPath Parser context
4558 * @cur: the current node in the traversal
4559 *
4560 * Traversal function for the "descendant-or-self" direction
4561 * the descendant-or-self axis contains the context node and the descendants
4562 * of the context node in document order; thus the context node is the first
4563 * node on the axis, and the first child of the context node is the second node
4564 * on the axis
4565 *
4566 * Returns the next element following that axis
4567 */
4568xmlNodePtr
4569xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4570 if (cur == NULL) {
4571 if (ctxt->context->node == NULL)
4572 return(NULL);
4573 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4574 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4575 return(NULL);
4576 return(ctxt->context->node);
4577 }
4578
4579 return(xmlXPathNextDescendant(ctxt, cur));
4580}
4581
4582/**
4583 * xmlXPathNextParent:
4584 * @ctxt: the XPath Parser context
4585 * @cur: the current node in the traversal
4586 *
4587 * Traversal function for the "parent" direction
4588 * The parent axis contains the parent of the context node, if there is one.
4589 *
4590 * Returns the next element following that axis
4591 */
4592xmlNodePtr
4593xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4594 /*
4595 * the parent of an attribute or namespace node is the element
4596 * to which the attribute or namespace node is attached
4597 * Namespace handling !!!
4598 */
4599 if (cur == NULL) {
4600 if (ctxt->context->node == NULL) return(NULL);
4601 switch (ctxt->context->node->type) {
4602 case XML_ELEMENT_NODE:
4603 case XML_TEXT_NODE:
4604 case XML_CDATA_SECTION_NODE:
4605 case XML_ENTITY_REF_NODE:
4606 case XML_ENTITY_NODE:
4607 case XML_PI_NODE:
4608 case XML_COMMENT_NODE:
4609 case XML_NOTATION_NODE:
4610 case XML_DTD_NODE:
4611 case XML_ELEMENT_DECL:
4612 case XML_ATTRIBUTE_DECL:
4613 case XML_XINCLUDE_START:
4614 case XML_XINCLUDE_END:
4615 case XML_ENTITY_DECL:
4616 if (ctxt->context->node->parent == NULL)
4617 return((xmlNodePtr) ctxt->context->doc);
4618 return(ctxt->context->node->parent);
4619 case XML_ATTRIBUTE_NODE: {
4620 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4621
4622 return(att->parent);
4623 }
4624 case XML_DOCUMENT_NODE:
4625 case XML_DOCUMENT_TYPE_NODE:
4626 case XML_DOCUMENT_FRAG_NODE:
4627 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004628#ifdef LIBXML_DOCB_ENABLED
4629 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004630#endif
4631 return(NULL);
4632 case XML_NAMESPACE_DECL:
4633 /*
4634 * TODO !!! may require extending struct _xmlNs with
4635 * parent field
4636 * C.f. Infoset case...
4637 */
4638 return(NULL);
4639 }
4640 }
4641 return(NULL);
4642}
4643
4644/**
4645 * xmlXPathNextAncestor:
4646 * @ctxt: the XPath Parser context
4647 * @cur: the current node in the traversal
4648 *
4649 * Traversal function for the "ancestor" direction
4650 * the ancestor axis contains the ancestors of the context node; the ancestors
4651 * of the context node consist of the parent of context node and the parent's
4652 * parent and so on; the nodes are ordered in reverse document order; thus the
4653 * parent is the first node on the axis, and the parent's parent is the second
4654 * node on the axis
4655 *
4656 * Returns the next element following that axis
4657 */
4658xmlNodePtr
4659xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4660 /*
4661 * the parent of an attribute or namespace node is the element
4662 * to which the attribute or namespace node is attached
4663 * !!!!!!!!!!!!!
4664 */
4665 if (cur == NULL) {
4666 if (ctxt->context->node == NULL) return(NULL);
4667 switch (ctxt->context->node->type) {
4668 case XML_ELEMENT_NODE:
4669 case XML_TEXT_NODE:
4670 case XML_CDATA_SECTION_NODE:
4671 case XML_ENTITY_REF_NODE:
4672 case XML_ENTITY_NODE:
4673 case XML_PI_NODE:
4674 case XML_COMMENT_NODE:
4675 case XML_DTD_NODE:
4676 case XML_ELEMENT_DECL:
4677 case XML_ATTRIBUTE_DECL:
4678 case XML_ENTITY_DECL:
4679 case XML_NOTATION_NODE:
4680 case XML_XINCLUDE_START:
4681 case XML_XINCLUDE_END:
4682 if (ctxt->context->node->parent == NULL)
4683 return((xmlNodePtr) ctxt->context->doc);
4684 return(ctxt->context->node->parent);
4685 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004686 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00004687
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004688 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00004689 }
4690 case XML_DOCUMENT_NODE:
4691 case XML_DOCUMENT_TYPE_NODE:
4692 case XML_DOCUMENT_FRAG_NODE:
4693 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004694#ifdef LIBXML_DOCB_ENABLED
4695 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004696#endif
4697 return(NULL);
4698 case XML_NAMESPACE_DECL:
4699 /*
4700 * TODO !!! may require extending struct _xmlNs with
4701 * parent field
4702 * C.f. Infoset case...
4703 */
4704 return(NULL);
4705 }
4706 return(NULL);
4707 }
4708 if (cur == ctxt->context->doc->children)
4709 return((xmlNodePtr) ctxt->context->doc);
4710 if (cur == (xmlNodePtr) ctxt->context->doc)
4711 return(NULL);
4712 switch (cur->type) {
4713 case XML_ELEMENT_NODE:
4714 case XML_TEXT_NODE:
4715 case XML_CDATA_SECTION_NODE:
4716 case XML_ENTITY_REF_NODE:
4717 case XML_ENTITY_NODE:
4718 case XML_PI_NODE:
4719 case XML_COMMENT_NODE:
4720 case XML_NOTATION_NODE:
4721 case XML_DTD_NODE:
4722 case XML_ELEMENT_DECL:
4723 case XML_ATTRIBUTE_DECL:
4724 case XML_ENTITY_DECL:
4725 case XML_XINCLUDE_START:
4726 case XML_XINCLUDE_END:
4727 return(cur->parent);
4728 case XML_ATTRIBUTE_NODE: {
4729 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4730
4731 return(att->parent);
4732 }
4733 case XML_DOCUMENT_NODE:
4734 case XML_DOCUMENT_TYPE_NODE:
4735 case XML_DOCUMENT_FRAG_NODE:
4736 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004737#ifdef LIBXML_DOCB_ENABLED
4738 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004739#endif
4740 return(NULL);
4741 case XML_NAMESPACE_DECL:
4742 /*
4743 * TODO !!! may require extending struct _xmlNs with
4744 * parent field
4745 * C.f. Infoset case...
4746 */
4747 return(NULL);
4748 }
4749 return(NULL);
4750}
4751
4752/**
4753 * xmlXPathNextAncestorOrSelf:
4754 * @ctxt: the XPath Parser context
4755 * @cur: the current node in the traversal
4756 *
4757 * Traversal function for the "ancestor-or-self" direction
4758 * he ancestor-or-self axis contains the context node and ancestors of
4759 * the context node in reverse document order; thus the context node is
4760 * the first node on the axis, and the context node's parent the second;
4761 * parent here is defined the same as with the parent axis.
4762 *
4763 * Returns the next element following that axis
4764 */
4765xmlNodePtr
4766xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4767 if (cur == NULL)
4768 return(ctxt->context->node);
4769 return(xmlXPathNextAncestor(ctxt, cur));
4770}
4771
4772/**
4773 * xmlXPathNextFollowingSibling:
4774 * @ctxt: the XPath Parser context
4775 * @cur: the current node in the traversal
4776 *
4777 * Traversal function for the "following-sibling" direction
4778 * The following-sibling axis contains the following siblings of the context
4779 * node in document order.
4780 *
4781 * Returns the next element following that axis
4782 */
4783xmlNodePtr
4784xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4785 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4786 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4787 return(NULL);
4788 if (cur == (xmlNodePtr) ctxt->context->doc)
4789 return(NULL);
4790 if (cur == NULL)
4791 return(ctxt->context->node->next);
4792 return(cur->next);
4793}
4794
4795/**
4796 * xmlXPathNextPrecedingSibling:
4797 * @ctxt: the XPath Parser context
4798 * @cur: the current node in the traversal
4799 *
4800 * Traversal function for the "preceding-sibling" direction
4801 * The preceding-sibling axis contains the preceding siblings of the context
4802 * node in reverse document order; the first preceding sibling is first on the
4803 * axis; the sibling preceding that node is the second on the axis and so on.
4804 *
4805 * Returns the next element following that axis
4806 */
4807xmlNodePtr
4808xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4809 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4810 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4811 return(NULL);
4812 if (cur == (xmlNodePtr) ctxt->context->doc)
4813 return(NULL);
4814 if (cur == NULL)
4815 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004816 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
4817 cur = cur->prev;
4818 if (cur == NULL)
4819 return(ctxt->context->node->prev);
4820 }
Owen Taylor3473f882001-02-23 17:55:21 +00004821 return(cur->prev);
4822}
4823
4824/**
4825 * xmlXPathNextFollowing:
4826 * @ctxt: the XPath Parser context
4827 * @cur: the current node in the traversal
4828 *
4829 * Traversal function for the "following" direction
4830 * The following axis contains all nodes in the same document as the context
4831 * node that are after the context node in document order, excluding any
4832 * descendants and excluding attribute nodes and namespace nodes; the nodes
4833 * are ordered in document order
4834 *
4835 * Returns the next element following that axis
4836 */
4837xmlNodePtr
4838xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4839 if (cur != NULL && cur->children != NULL)
4840 return cur->children ;
4841 if (cur == NULL) cur = ctxt->context->node;
4842 if (cur == NULL) return(NULL) ; /* ERROR */
4843 if (cur->next != NULL) return(cur->next) ;
4844 do {
4845 cur = cur->parent;
4846 if (cur == NULL) return(NULL);
4847 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
4848 if (cur->next != NULL) return(cur->next);
4849 } while (cur != NULL);
4850 return(cur);
4851}
4852
4853/*
4854 * xmlXPathIsAncestor:
4855 * @ancestor: the ancestor node
4856 * @node: the current node
4857 *
4858 * Check that @ancestor is a @node's ancestor
4859 *
4860 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
4861 */
4862static int
4863xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
4864 if ((ancestor == NULL) || (node == NULL)) return(0);
4865 /* nodes need to be in the same document */
4866 if (ancestor->doc != node->doc) return(0);
4867 /* avoid searching if ancestor or node is the root node */
4868 if (ancestor == (xmlNodePtr) node->doc) return(1);
4869 if (node == (xmlNodePtr) ancestor->doc) return(0);
4870 while (node->parent != NULL) {
4871 if (node->parent == ancestor)
4872 return(1);
4873 node = node->parent;
4874 }
4875 return(0);
4876}
4877
4878/**
4879 * xmlXPathNextPreceding:
4880 * @ctxt: the XPath Parser context
4881 * @cur: the current node in the traversal
4882 *
4883 * Traversal function for the "preceding" direction
4884 * the preceding axis contains all nodes in the same document as the context
4885 * node that are before the context node in document order, excluding any
4886 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4887 * ordered in reverse document order
4888 *
4889 * Returns the next element following that axis
4890 */
4891xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00004892xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
4893{
Owen Taylor3473f882001-02-23 17:55:21 +00004894 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004895 cur = ctxt->context->node;
4896 if (cur == NULL)
4897 return (NULL);
4898 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
4899 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00004900 do {
4901 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004902 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
4903 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004904 }
4905
4906 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004907 if (cur == NULL)
4908 return (NULL);
4909 if (cur == ctxt->context->doc->children)
4910 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004911 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00004912 return (cur);
4913}
4914
4915/**
4916 * xmlXPathNextPrecedingInternal:
4917 * @ctxt: the XPath Parser context
4918 * @cur: the current node in the traversal
4919 *
4920 * Traversal function for the "preceding" direction
4921 * the preceding axis contains all nodes in the same document as the context
4922 * node that are before the context node in document order, excluding any
4923 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4924 * ordered in reverse document order
4925 * This is a faster implementation but internal only since it requires a
4926 * state kept in the parser context: ctxt->ancestor.
4927 *
4928 * Returns the next element following that axis
4929 */
4930static xmlNodePtr
4931xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
4932 xmlNodePtr cur)
4933{
4934 if (cur == NULL) {
4935 cur = ctxt->context->node;
4936 if (cur == NULL)
4937 return (NULL);
4938 ctxt->ancestor = cur->parent;
4939 }
4940 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
4941 cur = cur->prev;
4942 while (cur->prev == NULL) {
4943 cur = cur->parent;
4944 if (cur == NULL)
4945 return (NULL);
4946 if (cur == ctxt->context->doc->children)
4947 return (NULL);
4948 if (cur != ctxt->ancestor)
4949 return (cur);
4950 ctxt->ancestor = cur->parent;
4951 }
4952 cur = cur->prev;
4953 while (cur->last != NULL)
4954 cur = cur->last;
4955 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004956}
4957
4958/**
4959 * xmlXPathNextNamespace:
4960 * @ctxt: the XPath Parser context
4961 * @cur: the current attribute in the traversal
4962 *
4963 * Traversal function for the "namespace" direction
4964 * the namespace axis contains the namespace nodes of the context node;
4965 * the order of nodes on this axis is implementation-defined; the axis will
4966 * be empty unless the context node is an element
4967 *
4968 * Returns the next element following that axis
4969 */
4970xmlNodePtr
4971xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00004972 xmlNodePtr ret;
4973
Owen Taylor3473f882001-02-23 17:55:21 +00004974 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00004975 if ((cur == NULL) || (ctxt->context->tmpNsList == NULL)) {
4976 if (ctxt->context->tmpNsList != NULL)
4977 xmlFree(ctxt->context->tmpNsList);
4978 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00004979 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00004980 if (ctxt->context->tmpNsList == NULL) return(NULL);
4981 ctxt->context->tmpNsNr = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004982 }
Daniel Veillard7d7e3792001-07-30 13:42:13 +00004983 ret = (xmlNodePtr)ctxt->context->tmpNsList[ctxt->context->tmpNsNr++];
4984 if (ret == NULL) {
4985 xmlFree(ctxt->context->tmpNsList);
4986 ctxt->context->tmpNsList = NULL;
4987 }
4988 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004989}
4990
4991/**
4992 * xmlXPathNextAttribute:
4993 * @ctxt: the XPath Parser context
4994 * @cur: the current attribute in the traversal
4995 *
4996 * Traversal function for the "attribute" direction
4997 * TODO: support DTD inherited default attributes
4998 *
4999 * Returns the next element following that axis
5000 */
5001xmlNodePtr
5002xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005003 if (ctxt->context->node == NULL)
5004 return(NULL);
5005 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5006 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005007 if (cur == NULL) {
5008 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5009 return(NULL);
5010 return((xmlNodePtr)ctxt->context->node->properties);
5011 }
5012 return((xmlNodePtr)cur->next);
5013}
5014
5015/************************************************************************
5016 * *
5017 * NodeTest Functions *
5018 * *
5019 ************************************************************************/
5020
Owen Taylor3473f882001-02-23 17:55:21 +00005021#define IS_FUNCTION 200
5022
Owen Taylor3473f882001-02-23 17:55:21 +00005023
5024/************************************************************************
5025 * *
5026 * Implicit tree core function library *
5027 * *
5028 ************************************************************************/
5029
5030/**
5031 * xmlXPathRoot:
5032 * @ctxt: the XPath Parser context
5033 *
5034 * Initialize the context to the root of the document
5035 */
5036void
5037xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5038 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5039 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5040}
5041
5042/************************************************************************
5043 * *
5044 * The explicit core function library *
5045 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5046 * *
5047 ************************************************************************/
5048
5049
5050/**
5051 * xmlXPathLastFunction:
5052 * @ctxt: the XPath Parser context
5053 * @nargs: the number of arguments
5054 *
5055 * Implement the last() XPath function
5056 * number last()
5057 * The last function returns the number of nodes in the context node list.
5058 */
5059void
5060xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5061 CHECK_ARITY(0);
5062 if (ctxt->context->contextSize >= 0) {
5063 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5064#ifdef DEBUG_EXPR
5065 xmlGenericError(xmlGenericErrorContext,
5066 "last() : %d\n", ctxt->context->contextSize);
5067#endif
5068 } else {
5069 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5070 }
5071}
5072
5073/**
5074 * xmlXPathPositionFunction:
5075 * @ctxt: the XPath Parser context
5076 * @nargs: the number of arguments
5077 *
5078 * Implement the position() XPath function
5079 * number position()
5080 * The position function returns the position of the context node in the
5081 * context node list. The first position is 1, and so the last positionr
5082 * will be equal to last().
5083 */
5084void
5085xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5086 CHECK_ARITY(0);
5087 if (ctxt->context->proximityPosition >= 0) {
5088 valuePush(ctxt,
5089 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5090#ifdef DEBUG_EXPR
5091 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5092 ctxt->context->proximityPosition);
5093#endif
5094 } else {
5095 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5096 }
5097}
5098
5099/**
5100 * xmlXPathCountFunction:
5101 * @ctxt: the XPath Parser context
5102 * @nargs: the number of arguments
5103 *
5104 * Implement the count() XPath function
5105 * number count(node-set)
5106 */
5107void
5108xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5109 xmlXPathObjectPtr cur;
5110
5111 CHECK_ARITY(1);
5112 if ((ctxt->value == NULL) ||
5113 ((ctxt->value->type != XPATH_NODESET) &&
5114 (ctxt->value->type != XPATH_XSLT_TREE)))
5115 XP_ERROR(XPATH_INVALID_TYPE);
5116 cur = valuePop(ctxt);
5117
Daniel Veillard911f49a2001-04-07 15:39:35 +00005118 if ((cur == NULL) || (cur->nodesetval == NULL))
5119 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00005120 else if (cur->type == XPATH_NODESET) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005121 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005122 } else {
5123 if ((cur->nodesetval->nodeNr != 1) ||
5124 (cur->nodesetval->nodeTab == NULL)) {
5125 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5126 } else {
5127 xmlNodePtr tmp;
5128 int i = 0;
5129
5130 tmp = cur->nodesetval->nodeTab[0];
5131 if (tmp != NULL) {
5132 tmp = tmp->children;
5133 while (tmp != NULL) {
5134 tmp = tmp->next;
5135 i++;
5136 }
5137 }
5138 valuePush(ctxt, xmlXPathNewFloat((double) i));
5139 }
5140 }
Owen Taylor3473f882001-02-23 17:55:21 +00005141 xmlXPathFreeObject(cur);
5142}
5143
5144/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005145 * xmlXPathGetElementsByIds:
5146 * @doc: the document
5147 * @ids: a whitespace separated list of IDs
5148 *
5149 * Selects elements by their unique ID.
5150 *
5151 * Returns a node-set of selected elements.
5152 */
5153static xmlNodeSetPtr
5154xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5155 xmlNodeSetPtr ret;
5156 const xmlChar *cur = ids;
5157 xmlChar *ID;
5158 xmlAttrPtr attr;
5159 xmlNodePtr elem = NULL;
5160
5161 ret = xmlXPathNodeSetCreate(NULL);
5162
5163 while (IS_BLANK(*cur)) cur++;
5164 while (*cur != 0) {
5165 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
5166 (*cur == '.') || (*cur == '-') ||
5167 (*cur == '_') || (*cur == ':') ||
5168 (IS_COMBINING(*cur)) ||
5169 (IS_EXTENDER(*cur)))
5170 cur++;
5171
5172 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
5173
5174 ID = xmlStrndup(ids, cur - ids);
5175 attr = xmlGetID(doc, ID);
5176 if (attr != NULL) {
5177 elem = attr->parent;
5178 xmlXPathNodeSetAdd(ret, elem);
5179 }
5180 if (ID != NULL)
5181 xmlFree(ID);
5182
5183 while (IS_BLANK(*cur)) cur++;
5184 ids = cur;
5185 }
5186 return(ret);
5187}
5188
5189/**
Owen Taylor3473f882001-02-23 17:55:21 +00005190 * xmlXPathIdFunction:
5191 * @ctxt: the XPath Parser context
5192 * @nargs: the number of arguments
5193 *
5194 * Implement the id() XPath function
5195 * node-set id(object)
5196 * The id function selects elements by their unique ID
5197 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5198 * then the result is the union of the result of applying id to the
5199 * string value of each of the nodes in the argument node-set. When the
5200 * argument to id is of any other type, the argument is converted to a
5201 * string as if by a call to the string function; the string is split
5202 * into a whitespace-separated list of tokens (whitespace is any sequence
5203 * of characters matching the production S); the result is a node-set
5204 * containing the elements in the same document as the context node that
5205 * have a unique ID equal to any of the tokens in the list.
5206 */
5207void
5208xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005209 xmlChar *tokens;
5210 xmlNodeSetPtr ret;
5211 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00005212
5213 CHECK_ARITY(1);
5214 obj = valuePop(ctxt);
5215 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
5216 if (obj->type == XPATH_NODESET) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005217 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00005218 int i;
5219
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005220 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005221
Daniel Veillard911f49a2001-04-07 15:39:35 +00005222 if (obj->nodesetval != NULL) {
5223 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005224 tokens =
5225 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
5226 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
5227 ret = xmlXPathNodeSetMerge(ret, ns);
5228 xmlXPathFreeNodeSet(ns);
5229 if (tokens != NULL)
5230 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00005231 }
Owen Taylor3473f882001-02-23 17:55:21 +00005232 }
5233
5234 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005235 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005236 return;
5237 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005238 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00005239
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005240 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
5241 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00005242
Owen Taylor3473f882001-02-23 17:55:21 +00005243 xmlXPathFreeObject(obj);
5244 return;
5245}
5246
5247/**
5248 * xmlXPathLocalNameFunction:
5249 * @ctxt: the XPath Parser context
5250 * @nargs: the number of arguments
5251 *
5252 * Implement the local-name() XPath function
5253 * string local-name(node-set?)
5254 * The local-name function returns a string containing the local part
5255 * of the name of the node in the argument node-set that is first in
5256 * document order. If the node-set is empty or the first node has no
5257 * name, an empty string is returned. If the argument is omitted it
5258 * defaults to the context node.
5259 */
5260void
5261xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5262 xmlXPathObjectPtr cur;
5263
5264 if (nargs == 0) {
5265 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5266 nargs = 1;
5267 }
5268
5269 CHECK_ARITY(1);
5270 if ((ctxt->value == NULL) ||
5271 ((ctxt->value->type != XPATH_NODESET) &&
5272 (ctxt->value->type != XPATH_XSLT_TREE)))
5273 XP_ERROR(XPATH_INVALID_TYPE);
5274 cur = valuePop(ctxt);
5275
Daniel Veillard911f49a2001-04-07 15:39:35 +00005276 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005277 valuePush(ctxt, xmlXPathNewCString(""));
5278 } else {
5279 int i = 0; /* Should be first in document order !!!!! */
5280 switch (cur->nodesetval->nodeTab[i]->type) {
5281 case XML_ELEMENT_NODE:
5282 case XML_ATTRIBUTE_NODE:
5283 case XML_PI_NODE:
5284 valuePush(ctxt,
5285 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
5286 break;
5287 case XML_NAMESPACE_DECL:
5288 valuePush(ctxt, xmlXPathNewString(
5289 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
5290 break;
5291 default:
5292 valuePush(ctxt, xmlXPathNewCString(""));
5293 }
5294 }
5295 xmlXPathFreeObject(cur);
5296}
5297
5298/**
5299 * xmlXPathNamespaceURIFunction:
5300 * @ctxt: the XPath Parser context
5301 * @nargs: the number of arguments
5302 *
5303 * Implement the namespace-uri() XPath function
5304 * string namespace-uri(node-set?)
5305 * The namespace-uri function returns a string containing the
5306 * namespace URI of the expanded name of the node in the argument
5307 * node-set that is first in document order. If the node-set is empty,
5308 * the first node has no name, or the expanded name has no namespace
5309 * URI, an empty string is returned. If the argument is omitted it
5310 * defaults to the context node.
5311 */
5312void
5313xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5314 xmlXPathObjectPtr cur;
5315
5316 if (nargs == 0) {
5317 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5318 nargs = 1;
5319 }
5320 CHECK_ARITY(1);
5321 if ((ctxt->value == NULL) ||
5322 ((ctxt->value->type != XPATH_NODESET) &&
5323 (ctxt->value->type != XPATH_XSLT_TREE)))
5324 XP_ERROR(XPATH_INVALID_TYPE);
5325 cur = valuePop(ctxt);
5326
Daniel Veillard911f49a2001-04-07 15:39:35 +00005327 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005328 valuePush(ctxt, xmlXPathNewCString(""));
5329 } else {
5330 int i = 0; /* Should be first in document order !!!!! */
5331 switch (cur->nodesetval->nodeTab[i]->type) {
5332 case XML_ELEMENT_NODE:
5333 case XML_ATTRIBUTE_NODE:
5334 if (cur->nodesetval->nodeTab[i]->ns == NULL)
5335 valuePush(ctxt, xmlXPathNewCString(""));
5336 else
5337 valuePush(ctxt, xmlXPathNewString(
5338 cur->nodesetval->nodeTab[i]->ns->href));
5339 break;
5340 default:
5341 valuePush(ctxt, xmlXPathNewCString(""));
5342 }
5343 }
5344 xmlXPathFreeObject(cur);
5345}
5346
5347/**
5348 * xmlXPathNameFunction:
5349 * @ctxt: the XPath Parser context
5350 * @nargs: the number of arguments
5351 *
5352 * Implement the name() XPath function
5353 * string name(node-set?)
5354 * The name function returns a string containing a QName representing
5355 * the name of the node in the argument node-set that is first in documenti
5356 * order. The QName must represent the name with respect to the namespace
5357 * declarations in effect on the node whose name is being represented.
5358 * Typically, this will be the form in which the name occurred in the XML
5359 * source. This need not be the case if there are namespace declarations
5360 * in effect on the node that associate multiple prefixes with the same
5361 * namespace. However, an implementation may include information about
5362 * the original prefix in its representation of nodes; in this case, an
5363 * implementation can ensure that the returned string is always the same
5364 * as the QName used in the XML source. If the argument it omitted it
5365 * defaults to the context node.
5366 * Libxml keep the original prefix so the "real qualified name" used is
5367 * returned.
5368 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005369static void
Daniel Veillard04383752001-07-08 14:27:15 +00005370xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
5371{
Owen Taylor3473f882001-02-23 17:55:21 +00005372 xmlXPathObjectPtr cur;
5373
5374 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00005375 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5376 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00005377 }
5378
5379 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00005380 if ((ctxt->value == NULL) ||
5381 ((ctxt->value->type != XPATH_NODESET) &&
5382 (ctxt->value->type != XPATH_XSLT_TREE)))
5383 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00005384 cur = valuePop(ctxt);
5385
Daniel Veillard911f49a2001-04-07 15:39:35 +00005386 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00005387 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00005388 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00005389 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005390
Daniel Veillard04383752001-07-08 14:27:15 +00005391 switch (cur->nodesetval->nodeTab[i]->type) {
5392 case XML_ELEMENT_NODE:
5393 case XML_ATTRIBUTE_NODE:
5394 if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
5395 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL))
5396 valuePush(ctxt,
5397 xmlXPathNewString(cur->nodesetval->
5398 nodeTab[i]->name));
5399
5400 else {
5401 char name[2000];
5402
5403 snprintf(name, sizeof(name), "%s:%s",
5404 (char *) cur->nodesetval->nodeTab[i]->ns->
5405 prefix,
5406 (char *) cur->nodesetval->nodeTab[i]->name);
5407 name[sizeof(name) - 1] = 0;
5408 valuePush(ctxt, xmlXPathNewCString(name));
5409 }
5410 break;
5411 default:
5412 valuePush(ctxt,
5413 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
5414 xmlXPathLocalNameFunction(ctxt, 1);
5415 }
Owen Taylor3473f882001-02-23 17:55:21 +00005416 }
5417 xmlXPathFreeObject(cur);
5418}
5419
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005420
5421/**
Owen Taylor3473f882001-02-23 17:55:21 +00005422 * xmlXPathStringFunction:
5423 * @ctxt: the XPath Parser context
5424 * @nargs: the number of arguments
5425 *
5426 * Implement the string() XPath function
5427 * string string(object?)
5428 * he string function converts an object to a string as follows:
5429 * - A node-set is converted to a string by returning the value of
5430 * the node in the node-set that is first in document order.
5431 * If the node-set is empty, an empty string is returned.
5432 * - A number is converted to a string as follows
5433 * + NaN is converted to the string NaN
5434 * + positive zero is converted to the string 0
5435 * + negative zero is converted to the string 0
5436 * + positive infinity is converted to the string Infinity
5437 * + negative infinity is converted to the string -Infinity
5438 * + if the number is an integer, the number is represented in
5439 * decimal form as a Number with no decimal point and no leading
5440 * zeros, preceded by a minus sign (-) if the number is negative
5441 * + otherwise, the number is represented in decimal form as a
5442 * Number including a decimal point with at least one digit
5443 * before the decimal point and at least one digit after the
5444 * decimal point, preceded by a minus sign (-) if the number
5445 * is negative; there must be no leading zeros before the decimal
5446 * point apart possibly from the one required digit immediatelyi
5447 * before the decimal point; beyond the one required digit
5448 * after the decimal point there must be as many, but only as
5449 * many, more digits as are needed to uniquely distinguish the
5450 * number from all other IEEE 754 numeric values.
5451 * - The boolean false value is converted to the string false.
5452 * The boolean true value is converted to the string true.
5453 *
5454 * If the argument is omitted, it defaults to a node-set with the
5455 * context node as its only member.
5456 */
5457void
5458xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5459 xmlXPathObjectPtr cur;
5460
5461 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005462 valuePush(ctxt,
5463 xmlXPathWrapString(
5464 xmlXPathCastNodeToString(ctxt->context->node)));
5465 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005466 }
5467
5468 CHECK_ARITY(1);
5469 cur = valuePop(ctxt);
5470 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005471 cur = xmlXPathConvertString(cur);
5472 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005473}
5474
5475/**
5476 * xmlXPathStringLengthFunction:
5477 * @ctxt: the XPath Parser context
5478 * @nargs: the number of arguments
5479 *
5480 * Implement the string-length() XPath function
5481 * number string-length(string?)
5482 * The string-length returns the number of characters in the string
5483 * (see [3.6 Strings]). If the argument is omitted, it defaults to
5484 * the context node converted to a string, in other words the value
5485 * of the context node.
5486 */
5487void
5488xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5489 xmlXPathObjectPtr cur;
5490
5491 if (nargs == 0) {
5492 if (ctxt->context->node == NULL) {
5493 valuePush(ctxt, xmlXPathNewFloat(0));
5494 } else {
5495 xmlChar *content;
5496
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005497 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005498 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00005499 xmlFree(content);
5500 }
5501 return;
5502 }
5503 CHECK_ARITY(1);
5504 CAST_TO_STRING;
5505 CHECK_TYPE(XPATH_STRING);
5506 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00005507 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00005508 xmlXPathFreeObject(cur);
5509}
5510
5511/**
5512 * xmlXPathConcatFunction:
5513 * @ctxt: the XPath Parser context
5514 * @nargs: the number of arguments
5515 *
5516 * Implement the concat() XPath function
5517 * string concat(string, string, string*)
5518 * The concat function returns the concatenation of its arguments.
5519 */
5520void
5521xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5522 xmlXPathObjectPtr cur, newobj;
5523 xmlChar *tmp;
5524
5525 if (nargs < 2) {
5526 CHECK_ARITY(2);
5527 }
5528
5529 CAST_TO_STRING;
5530 cur = valuePop(ctxt);
5531 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
5532 xmlXPathFreeObject(cur);
5533 return;
5534 }
5535 nargs--;
5536
5537 while (nargs > 0) {
5538 CAST_TO_STRING;
5539 newobj = valuePop(ctxt);
5540 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
5541 xmlXPathFreeObject(newobj);
5542 xmlXPathFreeObject(cur);
5543 XP_ERROR(XPATH_INVALID_TYPE);
5544 }
5545 tmp = xmlStrcat(newobj->stringval, cur->stringval);
5546 newobj->stringval = cur->stringval;
5547 cur->stringval = tmp;
5548
5549 xmlXPathFreeObject(newobj);
5550 nargs--;
5551 }
5552 valuePush(ctxt, cur);
5553}
5554
5555/**
5556 * xmlXPathContainsFunction:
5557 * @ctxt: the XPath Parser context
5558 * @nargs: the number of arguments
5559 *
5560 * Implement the contains() XPath function
5561 * boolean contains(string, string)
5562 * The contains function returns true if the first argument string
5563 * contains the second argument string, and otherwise returns false.
5564 */
5565void
5566xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5567 xmlXPathObjectPtr hay, needle;
5568
5569 CHECK_ARITY(2);
5570 CAST_TO_STRING;
5571 CHECK_TYPE(XPATH_STRING);
5572 needle = valuePop(ctxt);
5573 CAST_TO_STRING;
5574 hay = valuePop(ctxt);
5575 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5576 xmlXPathFreeObject(hay);
5577 xmlXPathFreeObject(needle);
5578 XP_ERROR(XPATH_INVALID_TYPE);
5579 }
5580 if (xmlStrstr(hay->stringval, needle->stringval))
5581 valuePush(ctxt, xmlXPathNewBoolean(1));
5582 else
5583 valuePush(ctxt, xmlXPathNewBoolean(0));
5584 xmlXPathFreeObject(hay);
5585 xmlXPathFreeObject(needle);
5586}
5587
5588/**
5589 * xmlXPathStartsWithFunction:
5590 * @ctxt: the XPath Parser context
5591 * @nargs: the number of arguments
5592 *
5593 * Implement the starts-with() XPath function
5594 * boolean starts-with(string, string)
5595 * The starts-with function returns true if the first argument string
5596 * starts with the second argument string, and otherwise returns false.
5597 */
5598void
5599xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5600 xmlXPathObjectPtr hay, needle;
5601 int n;
5602
5603 CHECK_ARITY(2);
5604 CAST_TO_STRING;
5605 CHECK_TYPE(XPATH_STRING);
5606 needle = valuePop(ctxt);
5607 CAST_TO_STRING;
5608 hay = valuePop(ctxt);
5609 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
5610 xmlXPathFreeObject(hay);
5611 xmlXPathFreeObject(needle);
5612 XP_ERROR(XPATH_INVALID_TYPE);
5613 }
5614 n = xmlStrlen(needle->stringval);
5615 if (xmlStrncmp(hay->stringval, needle->stringval, n))
5616 valuePush(ctxt, xmlXPathNewBoolean(0));
5617 else
5618 valuePush(ctxt, xmlXPathNewBoolean(1));
5619 xmlXPathFreeObject(hay);
5620 xmlXPathFreeObject(needle);
5621}
5622
5623/**
5624 * xmlXPathSubstringFunction:
5625 * @ctxt: the XPath Parser context
5626 * @nargs: the number of arguments
5627 *
5628 * Implement the substring() XPath function
5629 * string substring(string, number, number?)
5630 * The substring function returns the substring of the first argument
5631 * starting at the position specified in the second argument with
5632 * length specified in the third argument. For example,
5633 * substring("12345",2,3) returns "234". If the third argument is not
5634 * specified, it returns the substring starting at the position specified
5635 * in the second argument and continuing to the end of the string. For
5636 * example, substring("12345",2) returns "2345". More precisely, each
5637 * character in the string (see [3.6 Strings]) is considered to have a
5638 * numeric position: the position of the first character is 1, the position
5639 * of the second character is 2 and so on. The returned substring contains
5640 * those characters for which the position of the character is greater than
5641 * or equal to the second argument and, if the third argument is specified,
5642 * less than the sum of the second and third arguments; the comparisons
5643 * and addition used for the above follow the standard IEEE 754 rules. Thus:
5644 * - substring("12345", 1.5, 2.6) returns "234"
5645 * - substring("12345", 0, 3) returns "12"
5646 * - substring("12345", 0 div 0, 3) returns ""
5647 * - substring("12345", 1, 0 div 0) returns ""
5648 * - substring("12345", -42, 1 div 0) returns "12345"
5649 * - substring("12345", -1 div 0, 1 div 0) returns ""
5650 */
5651void
5652xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5653 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005654 double le=0, in;
5655 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00005656 xmlChar *ret;
5657
Owen Taylor3473f882001-02-23 17:55:21 +00005658 if (nargs < 2) {
5659 CHECK_ARITY(2);
5660 }
5661 if (nargs > 3) {
5662 CHECK_ARITY(3);
5663 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005664 /*
5665 * take care of possible last (position) argument
5666 */
Owen Taylor3473f882001-02-23 17:55:21 +00005667 if (nargs == 3) {
5668 CAST_TO_NUMBER;
5669 CHECK_TYPE(XPATH_NUMBER);
5670 len = valuePop(ctxt);
5671 le = len->floatval;
5672 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00005673 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005674
Owen Taylor3473f882001-02-23 17:55:21 +00005675 CAST_TO_NUMBER;
5676 CHECK_TYPE(XPATH_NUMBER);
5677 start = valuePop(ctxt);
5678 in = start->floatval;
5679 xmlXPathFreeObject(start);
5680 CAST_TO_STRING;
5681 CHECK_TYPE(XPATH_STRING);
5682 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00005683 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005684
Daniel Veillard97ac1312001-05-30 19:14:17 +00005685 /*
5686 * If last pos not present, calculate last position
5687 */
5688 if (nargs != 3)
5689 le = m;
5690
5691 /*
5692 * To meet our requirements, initial index calculations
5693 * must be done before we convert to integer format
5694 *
5695 * First we normalize indices
5696 */
5697 in -= 1.0;
5698 le += in;
5699 if (in < 0.0)
5700 in = 0.0;
5701 if (le > (double)m)
5702 le = (double)m;
5703
5704 /*
5705 * Now we go to integer form, rounding up
5706 */
Owen Taylor3473f882001-02-23 17:55:21 +00005707 i = (int) in;
5708 if (((double)i) != in) i++;
5709
Owen Taylor3473f882001-02-23 17:55:21 +00005710 l = (int) le;
5711 if (((double)l) != le) l++;
5712
Daniel Veillard97ac1312001-05-30 19:14:17 +00005713 if (l > m) l=m;
Owen Taylor3473f882001-02-23 17:55:21 +00005714
5715 /* number of chars to copy */
5716 l -= i;
5717
Daniel Veillard97ac1312001-05-30 19:14:17 +00005718 ret = xmlUTF8Strsub(str->stringval, i, l);
Owen Taylor3473f882001-02-23 17:55:21 +00005719 if (ret == NULL)
5720 valuePush(ctxt, xmlXPathNewCString(""));
5721 else {
5722 valuePush(ctxt, xmlXPathNewString(ret));
5723 xmlFree(ret);
5724 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00005725
Owen Taylor3473f882001-02-23 17:55:21 +00005726 xmlXPathFreeObject(str);
5727}
5728
5729/**
5730 * xmlXPathSubstringBeforeFunction:
5731 * @ctxt: the XPath Parser context
5732 * @nargs: the number of arguments
5733 *
5734 * Implement the substring-before() XPath function
5735 * string substring-before(string, string)
5736 * The substring-before function returns the substring of the first
5737 * argument string that precedes the first occurrence of the second
5738 * argument string in the first argument string, or the empty string
5739 * if the first argument string does not contain the second argument
5740 * string. For example, substring-before("1999/04/01","/") returns 1999.
5741 */
5742void
5743xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5744 xmlXPathObjectPtr str;
5745 xmlXPathObjectPtr find;
5746 xmlBufferPtr target;
5747 const xmlChar *point;
5748 int offset;
5749
5750 CHECK_ARITY(2);
5751 CAST_TO_STRING;
5752 find = valuePop(ctxt);
5753 CAST_TO_STRING;
5754 str = valuePop(ctxt);
5755
5756 target = xmlBufferCreate();
5757 if (target) {
5758 point = xmlStrstr(str->stringval, find->stringval);
5759 if (point) {
5760 offset = (int)(point - str->stringval);
5761 xmlBufferAdd(target, str->stringval, offset);
5762 }
5763 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5764 xmlBufferFree(target);
5765 }
5766
5767 xmlXPathFreeObject(str);
5768 xmlXPathFreeObject(find);
5769}
5770
5771/**
5772 * xmlXPathSubstringAfterFunction:
5773 * @ctxt: the XPath Parser context
5774 * @nargs: the number of arguments
5775 *
5776 * Implement the substring-after() XPath function
5777 * string substring-after(string, string)
5778 * The substring-after function returns the substring of the first
5779 * argument string that follows the first occurrence of the second
5780 * argument string in the first argument string, or the empty stringi
5781 * if the first argument string does not contain the second argument
5782 * string. For example, substring-after("1999/04/01","/") returns 04/01,
5783 * and substring-after("1999/04/01","19") returns 99/04/01.
5784 */
5785void
5786xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5787 xmlXPathObjectPtr str;
5788 xmlXPathObjectPtr find;
5789 xmlBufferPtr target;
5790 const xmlChar *point;
5791 int offset;
5792
5793 CHECK_ARITY(2);
5794 CAST_TO_STRING;
5795 find = valuePop(ctxt);
5796 CAST_TO_STRING;
5797 str = valuePop(ctxt);
5798
5799 target = xmlBufferCreate();
5800 if (target) {
5801 point = xmlStrstr(str->stringval, find->stringval);
5802 if (point) {
5803 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
5804 xmlBufferAdd(target, &str->stringval[offset],
5805 xmlStrlen(str->stringval) - offset);
5806 }
5807 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5808 xmlBufferFree(target);
5809 }
5810
5811 xmlXPathFreeObject(str);
5812 xmlXPathFreeObject(find);
5813}
5814
5815/**
5816 * xmlXPathNormalizeFunction:
5817 * @ctxt: the XPath Parser context
5818 * @nargs: the number of arguments
5819 *
5820 * Implement the normalize-space() XPath function
5821 * string normalize-space(string?)
5822 * The normalize-space function returns the argument string with white
5823 * space normalized by stripping leading and trailing whitespace
5824 * and replacing sequences of whitespace characters by a single
5825 * space. Whitespace characters are the same allowed by the S production
5826 * in XML. If the argument is omitted, it defaults to the context
5827 * node converted to a string, in other words the value of the context node.
5828 */
5829void
5830xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5831 xmlXPathObjectPtr obj = NULL;
5832 xmlChar *source = NULL;
5833 xmlBufferPtr target;
5834 xmlChar blank;
5835
5836 if (nargs == 0) {
5837 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005838 valuePush(ctxt,
5839 xmlXPathWrapString(
5840 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00005841 nargs = 1;
5842 }
5843
5844 CHECK_ARITY(1);
5845 CAST_TO_STRING;
5846 CHECK_TYPE(XPATH_STRING);
5847 obj = valuePop(ctxt);
5848 source = obj->stringval;
5849
5850 target = xmlBufferCreate();
5851 if (target && source) {
5852
5853 /* Skip leading whitespaces */
5854 while (IS_BLANK(*source))
5855 source++;
5856
5857 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
5858 blank = 0;
5859 while (*source) {
5860 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005861 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00005862 } else {
5863 if (blank) {
5864 xmlBufferAdd(target, &blank, 1);
5865 blank = 0;
5866 }
5867 xmlBufferAdd(target, source, 1);
5868 }
5869 source++;
5870 }
5871
5872 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5873 xmlBufferFree(target);
5874 }
5875 xmlXPathFreeObject(obj);
5876}
5877
5878/**
5879 * xmlXPathTranslateFunction:
5880 * @ctxt: the XPath Parser context
5881 * @nargs: the number of arguments
5882 *
5883 * Implement the translate() XPath function
5884 * string translate(string, string, string)
5885 * The translate function returns the first argument string with
5886 * occurrences of characters in the second argument string replaced
5887 * by the character at the corresponding position in the third argument
5888 * string. For example, translate("bar","abc","ABC") returns the string
5889 * BAr. If there is a character in the second argument string with no
5890 * character at a corresponding position in the third argument string
5891 * (because the second argument string is longer than the third argument
5892 * string), then occurrences of that character in the first argument
5893 * string are removed. For example, translate("--aaa--","abc-","ABC")
5894 * returns "AAA". If a character occurs more than once in second
5895 * argument string, then the first occurrence determines the replacement
5896 * character. If the third argument string is longer than the second
5897 * argument string, then excess characters are ignored.
5898 */
5899void
5900xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00005901 xmlXPathObjectPtr str;
5902 xmlXPathObjectPtr from;
5903 xmlXPathObjectPtr to;
5904 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005905 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00005906 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00005907 xmlChar *point;
5908 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00005909
Daniel Veillarde043ee12001-04-16 14:08:07 +00005910 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00005911
Daniel Veillarde043ee12001-04-16 14:08:07 +00005912 CAST_TO_STRING;
5913 to = valuePop(ctxt);
5914 CAST_TO_STRING;
5915 from = valuePop(ctxt);
5916 CAST_TO_STRING;
5917 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005918
Daniel Veillarde043ee12001-04-16 14:08:07 +00005919 target = xmlBufferCreate();
5920 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00005921 max = xmlUTF8Strlen(to->stringval);
5922 for (cptr = str->stringval; (ch=*cptr); ) {
5923 offset = xmlUTF8Strloc(from->stringval, cptr);
5924 if (offset >= 0) {
5925 if (offset < max) {
5926 point = xmlUTF8Strpos(to->stringval, offset);
5927 if (point)
5928 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
5929 }
5930 } else
5931 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
5932
5933 /* Step to next character in input */
5934 cptr++;
5935 if ( ch & 0x80 ) {
5936 /* if not simple ascii, verify proper format */
5937 if ( (ch & 0xc0) != 0xc0 ) {
5938 xmlGenericError(xmlGenericErrorContext,
5939 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5940 break;
5941 }
5942 /* then skip over remaining bytes for this char */
5943 while ( (ch <<= 1) & 0x80 )
5944 if ( (*cptr++ & 0xc0) != 0x80 ) {
5945 xmlGenericError(xmlGenericErrorContext,
5946 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
5947 break;
5948 }
5949 if (ch & 0x80) /* must have had error encountered */
5950 break;
5951 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005952 }
Owen Taylor3473f882001-02-23 17:55:21 +00005953 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005954 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5955 xmlBufferFree(target);
5956 xmlXPathFreeObject(str);
5957 xmlXPathFreeObject(from);
5958 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00005959}
5960
5961/**
5962 * xmlXPathBooleanFunction:
5963 * @ctxt: the XPath Parser context
5964 * @nargs: the number of arguments
5965 *
5966 * Implement the boolean() XPath function
5967 * boolean boolean(object)
5968 * he boolean function converts its argument to a boolean as follows:
5969 * - a number is true if and only if it is neither positive or
5970 * negative zero nor NaN
5971 * - a node-set is true if and only if it is non-empty
5972 * - a string is true if and only if its length is non-zero
5973 */
5974void
5975xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5976 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00005977
5978 CHECK_ARITY(1);
5979 cur = valuePop(ctxt);
5980 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005981 cur = xmlXPathConvertBoolean(cur);
5982 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005983}
5984
5985/**
5986 * xmlXPathNotFunction:
5987 * @ctxt: the XPath Parser context
5988 * @nargs: the number of arguments
5989 *
5990 * Implement the not() XPath function
5991 * boolean not(boolean)
5992 * The not function returns true if its argument is false,
5993 * and false otherwise.
5994 */
5995void
5996xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5997 CHECK_ARITY(1);
5998 CAST_TO_BOOLEAN;
5999 CHECK_TYPE(XPATH_BOOLEAN);
6000 ctxt->value->boolval = ! ctxt->value->boolval;
6001}
6002
6003/**
6004 * xmlXPathTrueFunction:
6005 * @ctxt: the XPath Parser context
6006 * @nargs: the number of arguments
6007 *
6008 * Implement the true() XPath function
6009 * boolean true()
6010 */
6011void
6012xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6013 CHECK_ARITY(0);
6014 valuePush(ctxt, xmlXPathNewBoolean(1));
6015}
6016
6017/**
6018 * xmlXPathFalseFunction:
6019 * @ctxt: the XPath Parser context
6020 * @nargs: the number of arguments
6021 *
6022 * Implement the false() XPath function
6023 * boolean false()
6024 */
6025void
6026xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6027 CHECK_ARITY(0);
6028 valuePush(ctxt, xmlXPathNewBoolean(0));
6029}
6030
6031/**
6032 * xmlXPathLangFunction:
6033 * @ctxt: the XPath Parser context
6034 * @nargs: the number of arguments
6035 *
6036 * Implement the lang() XPath function
6037 * boolean lang(string)
6038 * The lang function returns true or false depending on whether the
6039 * language of the context node as specified by xml:lang attributes
6040 * is the same as or is a sublanguage of the language specified by
6041 * the argument string. The language of the context node is determined
6042 * by the value of the xml:lang attribute on the context node, or, if
6043 * the context node has no xml:lang attribute, by the value of the
6044 * xml:lang attribute on the nearest ancestor of the context node that
6045 * has an xml:lang attribute. If there is no such attribute, then lang
6046 * returns false. If there is such an attribute, then lang returns
6047 * true if the attribute value is equal to the argument ignoring case,
6048 * or if there is some suffix starting with - such that the attribute
6049 * value is equal to the argument ignoring that suffix of the attribute
6050 * value and ignoring case.
6051 */
6052void
6053xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6054 xmlXPathObjectPtr val;
6055 const xmlChar *theLang;
6056 const xmlChar *lang;
6057 int ret = 0;
6058 int i;
6059
6060 CHECK_ARITY(1);
6061 CAST_TO_STRING;
6062 CHECK_TYPE(XPATH_STRING);
6063 val = valuePop(ctxt);
6064 lang = val->stringval;
6065 theLang = xmlNodeGetLang(ctxt->context->node);
6066 if ((theLang != NULL) && (lang != NULL)) {
6067 for (i = 0;lang[i] != 0;i++)
6068 if (toupper(lang[i]) != toupper(theLang[i]))
6069 goto not_equal;
6070 ret = 1;
6071 }
6072not_equal:
6073 xmlXPathFreeObject(val);
6074 valuePush(ctxt, xmlXPathNewBoolean(ret));
6075}
6076
6077/**
6078 * xmlXPathNumberFunction:
6079 * @ctxt: the XPath Parser context
6080 * @nargs: the number of arguments
6081 *
6082 * Implement the number() XPath function
6083 * number number(object?)
6084 */
6085void
6086xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6087 xmlXPathObjectPtr cur;
6088 double res;
6089
6090 if (nargs == 0) {
6091 if (ctxt->context->node == NULL) {
6092 valuePush(ctxt, xmlXPathNewFloat(0.0));
6093 } else {
6094 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6095
6096 res = xmlXPathStringEvalNumber(content);
6097 valuePush(ctxt, xmlXPathNewFloat(res));
6098 xmlFree(content);
6099 }
6100 return;
6101 }
6102
6103 CHECK_ARITY(1);
6104 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006105 cur = xmlXPathConvertNumber(cur);
6106 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006107}
6108
6109/**
6110 * xmlXPathSumFunction:
6111 * @ctxt: the XPath Parser context
6112 * @nargs: the number of arguments
6113 *
6114 * Implement the sum() XPath function
6115 * number sum(node-set)
6116 * The sum function returns the sum of the values of the nodes in
6117 * the argument node-set.
6118 */
6119void
6120xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6121 xmlXPathObjectPtr cur;
6122 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006123 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006124
6125 CHECK_ARITY(1);
6126 if ((ctxt->value == NULL) ||
6127 ((ctxt->value->type != XPATH_NODESET) &&
6128 (ctxt->value->type != XPATH_XSLT_TREE)))
6129 XP_ERROR(XPATH_INVALID_TYPE);
6130 cur = valuePop(ctxt);
6131
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006132 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006133 valuePush(ctxt, xmlXPathNewFloat(0.0));
6134 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006135 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6136 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006137 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006138 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00006139 }
6140 xmlXPathFreeObject(cur);
6141}
6142
6143/**
6144 * xmlXPathFloorFunction:
6145 * @ctxt: the XPath Parser context
6146 * @nargs: the number of arguments
6147 *
6148 * Implement the floor() XPath function
6149 * number floor(number)
6150 * The floor function returns the largest (closest to positive infinity)
6151 * number that is not greater than the argument and that is an integer.
6152 */
6153void
6154xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6155 CHECK_ARITY(1);
6156 CAST_TO_NUMBER;
6157 CHECK_TYPE(XPATH_NUMBER);
6158#if 0
6159 ctxt->value->floatval = floor(ctxt->value->floatval);
6160#else
6161 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
6162 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
6163#endif
6164}
6165
6166/**
6167 * xmlXPathCeilingFunction:
6168 * @ctxt: the XPath Parser context
6169 * @nargs: the number of arguments
6170 *
6171 * Implement the ceiling() XPath function
6172 * number ceiling(number)
6173 * The ceiling function returns the smallest (closest to negative infinity)
6174 * number that is not less than the argument and that is an integer.
6175 */
6176void
6177xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6178 double f;
6179
6180 CHECK_ARITY(1);
6181 CAST_TO_NUMBER;
6182 CHECK_TYPE(XPATH_NUMBER);
6183
6184#if 0
6185 ctxt->value->floatval = ceil(ctxt->value->floatval);
6186#else
6187 f = (double)((int) ctxt->value->floatval);
6188 if (f != ctxt->value->floatval)
6189 ctxt->value->floatval = f + 1;
6190#endif
6191}
6192
6193/**
6194 * xmlXPathRoundFunction:
6195 * @ctxt: the XPath Parser context
6196 * @nargs: the number of arguments
6197 *
6198 * Implement the round() XPath function
6199 * number round(number)
6200 * The round function returns the number that is closest to the
6201 * argument and that is an integer. If there are two such numbers,
6202 * then the one that is even is returned.
6203 */
6204void
6205xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6206 double f;
6207
6208 CHECK_ARITY(1);
6209 CAST_TO_NUMBER;
6210 CHECK_TYPE(XPATH_NUMBER);
6211
Daniel Veillardcda96922001-08-21 10:56:31 +00006212 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
6213 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
6214 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00006215 (ctxt->value->floatval == 0.0))
6216 return;
6217
6218#if 0
6219 f = floor(ctxt->value->floatval);
6220#else
6221 f = (double)((int) ctxt->value->floatval);
6222#endif
6223 if (ctxt->value->floatval < f + 0.5)
6224 ctxt->value->floatval = f;
6225 else
6226 ctxt->value->floatval = f + 1;
6227}
6228
6229/************************************************************************
6230 * *
6231 * The Parser *
6232 * *
6233 ************************************************************************/
6234
6235/*
6236 * a couple of forward declarations since we use a recursive call based
6237 * implementation.
6238 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006239static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006240static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006241static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006242#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006243static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
6244#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006245#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006246static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006247#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00006248static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
6249 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00006250
6251/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00006252 * xmlXPathCurrentChar:
6253 * @ctxt: the XPath parser context
6254 * @cur: pointer to the beginning of the char
6255 * @len: pointer to the length of the char read
6256 *
6257 * The current char value, if using UTF-8 this may actaully span multiple
6258 * bytes in the input buffer.
6259 *
6260 * Returns the current char value and its lenght
6261 */
6262
6263static int
6264xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
6265 unsigned char c;
6266 unsigned int val;
6267 const xmlChar *cur;
6268
6269 if (ctxt == NULL)
6270 return(0);
6271 cur = ctxt->cur;
6272
6273 /*
6274 * We are supposed to handle UTF8, check it's valid
6275 * From rfc2044: encoding of the Unicode values on UTF-8:
6276 *
6277 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
6278 * 0000 0000-0000 007F 0xxxxxxx
6279 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
6280 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
6281 *
6282 * Check for the 0x110000 limit too
6283 */
6284 c = *cur;
6285 if (c & 0x80) {
6286 if ((cur[1] & 0xc0) != 0x80)
6287 goto encoding_error;
6288 if ((c & 0xe0) == 0xe0) {
6289
6290 if ((cur[2] & 0xc0) != 0x80)
6291 goto encoding_error;
6292 if ((c & 0xf0) == 0xf0) {
6293 if (((c & 0xf8) != 0xf0) ||
6294 ((cur[3] & 0xc0) != 0x80))
6295 goto encoding_error;
6296 /* 4-byte code */
6297 *len = 4;
6298 val = (cur[0] & 0x7) << 18;
6299 val |= (cur[1] & 0x3f) << 12;
6300 val |= (cur[2] & 0x3f) << 6;
6301 val |= cur[3] & 0x3f;
6302 } else {
6303 /* 3-byte code */
6304 *len = 3;
6305 val = (cur[0] & 0xf) << 12;
6306 val |= (cur[1] & 0x3f) << 6;
6307 val |= cur[2] & 0x3f;
6308 }
6309 } else {
6310 /* 2-byte code */
6311 *len = 2;
6312 val = (cur[0] & 0x1f) << 6;
6313 val |= cur[1] & 0x3f;
6314 }
6315 if (!IS_CHAR(val)) {
6316 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
6317 }
6318 return(val);
6319 } else {
6320 /* 1-byte code */
6321 *len = 1;
6322 return((int) *cur);
6323 }
6324encoding_error:
6325 /*
6326 * If we detect an UTF8 error that probably mean that the
6327 * input encoding didn't get properly advertized in the
6328 * declaration header. Report the error and switch the encoding
6329 * to ISO-Latin-1 (if you don't like this policy, just declare the
6330 * encoding !)
6331 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00006332 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00006333 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006334}
6335
6336/**
Owen Taylor3473f882001-02-23 17:55:21 +00006337 * xmlXPathParseNCName:
6338 * @ctxt: the XPath Parser context
6339 *
6340 * parse an XML namespace non qualified name.
6341 *
6342 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
6343 *
6344 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
6345 * CombiningChar | Extender
6346 *
6347 * Returns the namespace name or NULL
6348 */
6349
6350xmlChar *
6351xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00006352 const xmlChar *in;
6353 xmlChar *ret;
6354 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006355
Daniel Veillard2156a562001-04-28 12:24:34 +00006356 /*
6357 * Accelerator for simple ASCII names
6358 */
6359 in = ctxt->cur;
6360 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6361 ((*in >= 0x41) && (*in <= 0x5A)) ||
6362 (*in == '_')) {
6363 in++;
6364 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6365 ((*in >= 0x41) && (*in <= 0x5A)) ||
6366 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00006367 (*in == '_') || (*in == '.') ||
6368 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00006369 in++;
6370 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
6371 (*in == '[') || (*in == ']') || (*in == ':') ||
6372 (*in == '@') || (*in == '*')) {
6373 count = in - ctxt->cur;
6374 if (count == 0)
6375 return(NULL);
6376 ret = xmlStrndup(ctxt->cur, count);
6377 ctxt->cur = in;
6378 return(ret);
6379 }
6380 }
6381 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00006382}
6383
Daniel Veillard2156a562001-04-28 12:24:34 +00006384
Owen Taylor3473f882001-02-23 17:55:21 +00006385/**
6386 * xmlXPathParseQName:
6387 * @ctxt: the XPath Parser context
6388 * @prefix: a xmlChar **
6389 *
6390 * parse an XML qualified name
6391 *
6392 * [NS 5] QName ::= (Prefix ':')? LocalPart
6393 *
6394 * [NS 6] Prefix ::= NCName
6395 *
6396 * [NS 7] LocalPart ::= NCName
6397 *
6398 * Returns the function returns the local part, and prefix is updated
6399 * to get the Prefix if any.
6400 */
6401
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006402static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006403xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
6404 xmlChar *ret = NULL;
6405
6406 *prefix = NULL;
6407 ret = xmlXPathParseNCName(ctxt);
6408 if (CUR == ':') {
6409 *prefix = ret;
6410 NEXT;
6411 ret = xmlXPathParseNCName(ctxt);
6412 }
6413 return(ret);
6414}
6415
6416/**
6417 * xmlXPathParseName:
6418 * @ctxt: the XPath Parser context
6419 *
6420 * parse an XML name
6421 *
6422 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6423 * CombiningChar | Extender
6424 *
6425 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6426 *
6427 * Returns the namespace name or NULL
6428 */
6429
6430xmlChar *
6431xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006432 const xmlChar *in;
6433 xmlChar *ret;
6434 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006435
Daniel Veillard61d80a22001-04-27 17:13:01 +00006436 /*
6437 * Accelerator for simple ASCII names
6438 */
6439 in = ctxt->cur;
6440 if (((*in >= 0x61) && (*in <= 0x7A)) ||
6441 ((*in >= 0x41) && (*in <= 0x5A)) ||
6442 (*in == '_') || (*in == ':')) {
6443 in++;
6444 while (((*in >= 0x61) && (*in <= 0x7A)) ||
6445 ((*in >= 0x41) && (*in <= 0x5A)) ||
6446 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00006447 (*in == '_') || (*in == '-') ||
6448 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00006449 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00006450 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006451 count = in - ctxt->cur;
6452 ret = xmlStrndup(ctxt->cur, count);
6453 ctxt->cur = in;
6454 return(ret);
6455 }
6456 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006457 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00006458}
6459
Daniel Veillard61d80a22001-04-27 17:13:01 +00006460static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00006461xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006462 xmlChar buf[XML_MAX_NAMELEN + 5];
6463 int len = 0, l;
6464 int c;
6465
6466 /*
6467 * Handler for more complex cases
6468 */
6469 c = CUR_CHAR(l);
6470 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00006471 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
6472 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00006473 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00006474 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00006475 return(NULL);
6476 }
6477
6478 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
6479 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
6480 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006481 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006482 (IS_COMBINING(c)) ||
6483 (IS_EXTENDER(c)))) {
6484 COPY_BUF(l,buf,len,c);
6485 NEXTL(l);
6486 c = CUR_CHAR(l);
6487 if (len >= XML_MAX_NAMELEN) {
6488 /*
6489 * Okay someone managed to make a huge name, so he's ready to pay
6490 * for the processing speed.
6491 */
6492 xmlChar *buffer;
6493 int max = len * 2;
6494
6495 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
6496 if (buffer == NULL) {
6497 XP_ERROR0(XPATH_MEMORY_ERROR);
6498 }
6499 memcpy(buffer, buf, len);
6500 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
6501 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00006502 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00006503 (IS_COMBINING(c)) ||
6504 (IS_EXTENDER(c))) {
6505 if (len + 10 > max) {
6506 max *= 2;
6507 buffer = (xmlChar *) xmlRealloc(buffer,
6508 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00006509 if (buffer == NULL) {
6510 XP_ERROR0(XPATH_MEMORY_ERROR);
6511 }
6512 }
6513 COPY_BUF(l,buffer,len,c);
6514 NEXTL(l);
6515 c = CUR_CHAR(l);
6516 }
6517 buffer[len] = 0;
6518 return(buffer);
6519 }
6520 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006521 if (len == 0)
6522 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00006523 return(xmlStrndup(buf, len));
6524}
Owen Taylor3473f882001-02-23 17:55:21 +00006525/**
6526 * xmlXPathStringEvalNumber:
6527 * @str: A string to scan
6528 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00006529 * [30a] Float ::= Number ('e' Digits?)?
6530 *
Owen Taylor3473f882001-02-23 17:55:21 +00006531 * [30] Number ::= Digits ('.' Digits?)?
6532 * | '.' Digits
6533 * [31] Digits ::= [0-9]+
6534 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006535 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00006536 * In complement of the Number expression, this function also handles
6537 * negative values : '-' Number.
6538 *
6539 * Returns the double value.
6540 */
6541double
6542xmlXPathStringEvalNumber(const xmlChar *str) {
6543 const xmlChar *cur = str;
6544 double ret = 0.0;
6545 double mult = 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006546 int ok = 0, tmp = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006547 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006548 int exponent = 0;
6549 int is_exponent_negative = 0;
6550
Owen Taylor3473f882001-02-23 17:55:21 +00006551 while (IS_BLANK(*cur)) cur++;
6552 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
6553 return(xmlXPathNAN);
6554 }
6555 if (*cur == '-') {
6556 isneg = 1;
6557 cur++;
6558 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006559 /*
6560 * tmp is a workaroudn against a gcc compiler bug
6561 */
Owen Taylor3473f882001-02-23 17:55:21 +00006562 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006563 tmp = tmp * 10 + (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00006564 ok = 1;
6565 cur++;
6566 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006567 ret = (double) tmp;
6568
Owen Taylor3473f882001-02-23 17:55:21 +00006569 if (*cur == '.') {
6570 cur++;
6571 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
6572 return(xmlXPathNAN);
6573 }
6574 while ((*cur >= '0') && (*cur <= '9')) {
6575 mult /= 10;
6576 ret = ret + (*cur - '0') * mult;
6577 cur++;
6578 }
6579 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006580 if ((*cur == 'e') || (*cur == 'E')) {
6581 cur++;
6582 if (*cur == '-') {
6583 is_exponent_negative = 1;
6584 cur++;
6585 }
6586 while ((*cur >= '0') && (*cur <= '9')) {
6587 exponent = exponent * 10 + (*cur - '0');
6588 cur++;
6589 }
6590 }
Owen Taylor3473f882001-02-23 17:55:21 +00006591 while (IS_BLANK(*cur)) cur++;
6592 if (*cur != 0) return(xmlXPathNAN);
6593 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006594 if (is_exponent_negative) exponent = -exponent;
6595 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00006596 return(ret);
6597}
6598
6599/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006600 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00006601 * @ctxt: the XPath Parser context
6602 *
6603 * [30] Number ::= Digits ('.' Digits?)?
6604 * | '.' Digits
6605 * [31] Digits ::= [0-9]+
6606 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006607 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00006608 *
6609 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006610static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006611xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
6612{
Owen Taylor3473f882001-02-23 17:55:21 +00006613 double ret = 0.0;
6614 double mult = 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006615 int ok = 0, tmp = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00006616 int exponent = 0;
6617 int is_exponent_negative = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006618
6619 CHECK_ERROR;
6620 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
6621 XP_ERROR(XPATH_NUMBER_ERROR);
6622 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006623 /*
6624 * Try to work around a gcc optimizer bug
6625 */
Owen Taylor3473f882001-02-23 17:55:21 +00006626 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006627 tmp = tmp * 10 + (CUR - '0');
6628 ok = 1;
6629 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +00006630 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006631 ret = (double) tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00006632 if (CUR == '.') {
6633 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006634 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
6635 XP_ERROR(XPATH_NUMBER_ERROR);
6636 }
6637 while ((CUR >= '0') && (CUR <= '9')) {
6638 mult /= 10;
6639 ret = ret + (CUR - '0') * mult;
6640 NEXT;
6641 }
Owen Taylor3473f882001-02-23 17:55:21 +00006642 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00006643 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006644 NEXT;
6645 if (CUR == '-') {
6646 is_exponent_negative = 1;
6647 NEXT;
6648 }
6649 while ((CUR >= '0') && (CUR <= '9')) {
6650 exponent = exponent * 10 + (CUR - '0');
6651 NEXT;
6652 }
6653 if (is_exponent_negative)
6654 exponent = -exponent;
6655 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006656 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006657 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006658 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006659}
6660
6661/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006662 * xmlXPathParseLiteral:
6663 * @ctxt: the XPath Parser context
6664 *
6665 * Parse a Literal
6666 *
6667 * [29] Literal ::= '"' [^"]* '"'
6668 * | "'" [^']* "'"
6669 *
6670 * Returns the value found or NULL in case of error
6671 */
6672static xmlChar *
6673xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
6674 const xmlChar *q;
6675 xmlChar *ret = NULL;
6676
6677 if (CUR == '"') {
6678 NEXT;
6679 q = CUR_PTR;
6680 while ((IS_CHAR(CUR)) && (CUR != '"'))
6681 NEXT;
6682 if (!IS_CHAR(CUR)) {
6683 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6684 } else {
6685 ret = xmlStrndup(q, CUR_PTR - q);
6686 NEXT;
6687 }
6688 } else if (CUR == '\'') {
6689 NEXT;
6690 q = CUR_PTR;
6691 while ((IS_CHAR(CUR)) && (CUR != '\''))
6692 NEXT;
6693 if (!IS_CHAR(CUR)) {
6694 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
6695 } else {
6696 ret = xmlStrndup(q, CUR_PTR - q);
6697 NEXT;
6698 }
6699 } else {
6700 XP_ERROR0(XPATH_START_LITERAL_ERROR);
6701 }
6702 return(ret);
6703}
6704
6705/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006706 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00006707 * @ctxt: the XPath Parser context
6708 *
6709 * Parse a Literal and push it on the stack.
6710 *
6711 * [29] Literal ::= '"' [^"]* '"'
6712 * | "'" [^']* "'"
6713 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006714 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00006715 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006716static void
6717xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006718 const xmlChar *q;
6719 xmlChar *ret = NULL;
6720
6721 if (CUR == '"') {
6722 NEXT;
6723 q = CUR_PTR;
6724 while ((IS_CHAR(CUR)) && (CUR != '"'))
6725 NEXT;
6726 if (!IS_CHAR(CUR)) {
6727 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
6728 } else {
6729 ret = xmlStrndup(q, CUR_PTR - q);
6730 NEXT;
6731 }
6732 } else if (CUR == '\'') {
6733 NEXT;
6734 q = CUR_PTR;
6735 while ((IS_CHAR(CUR)) && (CUR != '\''))
6736 NEXT;
6737 if (!IS_CHAR(CUR)) {
6738 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
6739 } else {
6740 ret = xmlStrndup(q, CUR_PTR - q);
6741 NEXT;
6742 }
6743 } else {
6744 XP_ERROR(XPATH_START_LITERAL_ERROR);
6745 }
6746 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006747 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
6748 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006749 xmlFree(ret);
6750}
6751
6752/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006753 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00006754 * @ctxt: the XPath Parser context
6755 *
6756 * Parse a VariableReference, evaluate it and push it on the stack.
6757 *
6758 * The variable bindings consist of a mapping from variable names
6759 * to variable values. The value of a variable is an object, which
6760 * of any of the types that are possible for the value of an expression,
6761 * and may also be of additional types not specified here.
6762 *
6763 * Early evaluation is possible since:
6764 * The variable bindings [...] used to evaluate a subexpression are
6765 * always the same as those used to evaluate the containing expression.
6766 *
6767 * [36] VariableReference ::= '$' QName
6768 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006769static void
6770xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006771 xmlChar *name;
6772 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006773
6774 SKIP_BLANKS;
6775 if (CUR != '$') {
6776 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
6777 }
6778 NEXT;
6779 name = xmlXPathParseQName(ctxt, &prefix);
6780 if (name == NULL) {
6781 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
6782 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006783 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006784 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
6785 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006786 SKIP_BLANKS;
6787}
6788
6789/**
6790 * xmlXPathIsNodeType:
6791 * @ctxt: the XPath Parser context
6792 * @name: a name string
6793 *
6794 * Is the name given a NodeType one.
6795 *
6796 * [38] NodeType ::= 'comment'
6797 * | 'text'
6798 * | 'processing-instruction'
6799 * | 'node'
6800 *
6801 * Returns 1 if true 0 otherwise
6802 */
6803int
6804xmlXPathIsNodeType(const xmlChar *name) {
6805 if (name == NULL)
6806 return(0);
6807
6808 if (xmlStrEqual(name, BAD_CAST "comment"))
6809 return(1);
6810 if (xmlStrEqual(name, BAD_CAST "text"))
6811 return(1);
6812 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
6813 return(1);
6814 if (xmlStrEqual(name, BAD_CAST "node"))
6815 return(1);
6816 return(0);
6817}
6818
6819/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006820 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00006821 * @ctxt: the XPath Parser context
6822 *
6823 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
6824 * [17] Argument ::= Expr
6825 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006826 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00006827 * pushed on the stack
6828 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006829static void
6830xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006831 xmlChar *name;
6832 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00006833 int nbargs = 0;
6834
6835 name = xmlXPathParseQName(ctxt, &prefix);
6836 if (name == NULL) {
6837 XP_ERROR(XPATH_EXPR_ERROR);
6838 }
6839 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006840#ifdef DEBUG_EXPR
6841 if (prefix == NULL)
6842 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
6843 name);
6844 else
6845 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
6846 prefix, name);
6847#endif
6848
Owen Taylor3473f882001-02-23 17:55:21 +00006849 if (CUR != '(') {
6850 XP_ERROR(XPATH_EXPR_ERROR);
6851 }
6852 NEXT;
6853 SKIP_BLANKS;
6854
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006855 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006856 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006857 int op1 = ctxt->comp->last;
6858 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006859 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006860 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006861 nbargs++;
6862 if (CUR == ')') break;
6863 if (CUR != ',') {
6864 XP_ERROR(XPATH_EXPR_ERROR);
6865 }
6866 NEXT;
6867 SKIP_BLANKS;
6868 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006869 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
6870 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006871 NEXT;
6872 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006873}
6874
6875/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006876 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006877 * @ctxt: the XPath Parser context
6878 *
6879 * [15] PrimaryExpr ::= VariableReference
6880 * | '(' Expr ')'
6881 * | Literal
6882 * | Number
6883 * | FunctionCall
6884 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006885 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006886 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006887static void
6888xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006889 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006890 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006891 else if (CUR == '(') {
6892 NEXT;
6893 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006894 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006895 if (CUR != ')') {
6896 XP_ERROR(XPATH_EXPR_ERROR);
6897 }
6898 NEXT;
6899 SKIP_BLANKS;
6900 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006901 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006902 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006903 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006904 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006905 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006906 }
6907 SKIP_BLANKS;
6908}
6909
6910/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006911 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006912 * @ctxt: the XPath Parser context
6913 *
6914 * [20] FilterExpr ::= PrimaryExpr
6915 * | FilterExpr Predicate
6916 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006917 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006918 * Square brackets are used to filter expressions in the same way that
6919 * they are used in location paths. It is an error if the expression to
6920 * be filtered does not evaluate to a node-set. The context node list
6921 * used for evaluating the expression in square brackets is the node-set
6922 * to be filtered listed in document order.
6923 */
6924
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006925static void
6926xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
6927 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006928 CHECK_ERROR;
6929 SKIP_BLANKS;
6930
6931 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006932 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00006933 SKIP_BLANKS;
6934 }
6935
6936
6937}
6938
6939/**
6940 * xmlXPathScanName:
6941 * @ctxt: the XPath Parser context
6942 *
6943 * Trickery: parse an XML name but without consuming the input flow
6944 * Needed to avoid insanity in the parser state.
6945 *
6946 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6947 * CombiningChar | Extender
6948 *
6949 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6950 *
6951 * [6] Names ::= Name (S Name)*
6952 *
6953 * Returns the Name parsed or NULL
6954 */
6955
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006956static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006957xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
6958 xmlChar buf[XML_MAX_NAMELEN];
6959 int len = 0;
6960
6961 SKIP_BLANKS;
6962 if (!IS_LETTER(CUR) && (CUR != '_') &&
6963 (CUR != ':')) {
6964 return(NULL);
6965 }
6966
6967 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
6968 (NXT(len) == '.') || (NXT(len) == '-') ||
6969 (NXT(len) == '_') || (NXT(len) == ':') ||
6970 (IS_COMBINING(NXT(len))) ||
6971 (IS_EXTENDER(NXT(len)))) {
6972 buf[len] = NXT(len);
6973 len++;
6974 if (len >= XML_MAX_NAMELEN) {
6975 xmlGenericError(xmlGenericErrorContext,
6976 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
6977 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
6978 (NXT(len) == '.') || (NXT(len) == '-') ||
6979 (NXT(len) == '_') || (NXT(len) == ':') ||
6980 (IS_COMBINING(NXT(len))) ||
6981 (IS_EXTENDER(NXT(len))))
6982 len++;
6983 break;
6984 }
6985 }
6986 return(xmlStrndup(buf, len));
6987}
6988
6989/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006990 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006991 * @ctxt: the XPath Parser context
6992 *
6993 * [19] PathExpr ::= LocationPath
6994 * | FilterExpr
6995 * | FilterExpr '/' RelativeLocationPath
6996 * | FilterExpr '//' RelativeLocationPath
6997 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006998 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006999 * The / operator and // operators combine an arbitrary expression
7000 * and a relative location path. It is an error if the expression
7001 * does not evaluate to a node-set.
7002 * The / operator does composition in the same way as when / is
7003 * used in a location path. As in location paths, // is short for
7004 * /descendant-or-self::node()/.
7005 */
7006
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007007static void
7008xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007009 int lc = 1; /* Should we branch to LocationPath ? */
7010 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7011
7012 SKIP_BLANKS;
7013 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
7014 (CUR == '\'') || (CUR == '"')) {
7015 lc = 0;
7016 } else if (CUR == '*') {
7017 /* relative or absolute location path */
7018 lc = 1;
7019 } else if (CUR == '/') {
7020 /* relative or absolute location path */
7021 lc = 1;
7022 } else if (CUR == '@') {
7023 /* relative abbreviated attribute location path */
7024 lc = 1;
7025 } else if (CUR == '.') {
7026 /* relative abbreviated attribute location path */
7027 lc = 1;
7028 } else {
7029 /*
7030 * Problem is finding if we have a name here whether it's:
7031 * - a nodetype
7032 * - a function call in which case it's followed by '('
7033 * - an axis in which case it's followed by ':'
7034 * - a element name
7035 * We do an a priori analysis here rather than having to
7036 * maintain parsed token content through the recursive function
7037 * calls. This looks uglier but makes the code quite easier to
7038 * read/write/debug.
7039 */
7040 SKIP_BLANKS;
7041 name = xmlXPathScanName(ctxt);
7042 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7043#ifdef DEBUG_STEP
7044 xmlGenericError(xmlGenericErrorContext,
7045 "PathExpr: Axis\n");
7046#endif
7047 lc = 1;
7048 xmlFree(name);
7049 } else if (name != NULL) {
7050 int len =xmlStrlen(name);
7051 int blank = 0;
7052
7053
7054 while (NXT(len) != 0) {
7055 if (NXT(len) == '/') {
7056 /* element name */
7057#ifdef DEBUG_STEP
7058 xmlGenericError(xmlGenericErrorContext,
7059 "PathExpr: AbbrRelLocation\n");
7060#endif
7061 lc = 1;
7062 break;
7063 } else if (IS_BLANK(NXT(len))) {
7064 /* skip to next */
7065 blank = 1;
7066 } else if (NXT(len) == ':') {
7067#ifdef DEBUG_STEP
7068 xmlGenericError(xmlGenericErrorContext,
7069 "PathExpr: AbbrRelLocation\n");
7070#endif
7071 lc = 1;
7072 break;
7073 } else if ((NXT(len) == '(')) {
7074 /* Note Type or Function */
7075 if (xmlXPathIsNodeType(name)) {
7076#ifdef DEBUG_STEP
7077 xmlGenericError(xmlGenericErrorContext,
7078 "PathExpr: Type search\n");
7079#endif
7080 lc = 1;
7081 } else {
7082#ifdef DEBUG_STEP
7083 xmlGenericError(xmlGenericErrorContext,
7084 "PathExpr: function call\n");
7085#endif
7086 lc = 0;
7087 }
7088 break;
7089 } else if ((NXT(len) == '[')) {
7090 /* element name */
7091#ifdef DEBUG_STEP
7092 xmlGenericError(xmlGenericErrorContext,
7093 "PathExpr: AbbrRelLocation\n");
7094#endif
7095 lc = 1;
7096 break;
7097 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7098 (NXT(len) == '=')) {
7099 lc = 1;
7100 break;
7101 } else {
7102 lc = 1;
7103 break;
7104 }
7105 len++;
7106 }
7107 if (NXT(len) == 0) {
7108#ifdef DEBUG_STEP
7109 xmlGenericError(xmlGenericErrorContext,
7110 "PathExpr: AbbrRelLocation\n");
7111#endif
7112 /* element name */
7113 lc = 1;
7114 }
7115 xmlFree(name);
7116 } else {
7117 /* make sure all cases are covered explicitely */
7118 XP_ERROR(XPATH_EXPR_ERROR);
7119 }
7120 }
7121
7122 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007123 if (CUR == '/') {
7124 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
7125 } else {
7126 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007127 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007128 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007129 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007130 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007131 CHECK_ERROR;
7132 if ((CUR == '/') && (NXT(1) == '/')) {
7133 SKIP(2);
7134 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007135
7136 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7137 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
7138 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
7139
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007140 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007141 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007142 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007143 }
7144 }
7145 SKIP_BLANKS;
7146}
7147
7148/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007149 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007150 * @ctxt: the XPath Parser context
7151 *
7152 * [18] UnionExpr ::= PathExpr
7153 * | UnionExpr '|' PathExpr
7154 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007155 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007156 */
7157
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007158static void
7159xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
7160 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007161 CHECK_ERROR;
7162 SKIP_BLANKS;
7163 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007164 int op1 = ctxt->comp->last;
7165 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007166
7167 NEXT;
7168 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007169 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007170
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007171 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
7172
Owen Taylor3473f882001-02-23 17:55:21 +00007173 SKIP_BLANKS;
7174 }
Owen Taylor3473f882001-02-23 17:55:21 +00007175}
7176
7177/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007178 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007179 * @ctxt: the XPath Parser context
7180 *
7181 * [27] UnaryExpr ::= UnionExpr
7182 * | '-' UnaryExpr
7183 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007184 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007185 */
7186
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007187static void
7188xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007189 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007190 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007191
7192 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00007193 while (CUR == '-') {
7194 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007195 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007196 NEXT;
7197 SKIP_BLANKS;
7198 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007199
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007200 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007201 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007202 if (found) {
7203 if (minus)
7204 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
7205 else
7206 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007207 }
7208}
7209
7210/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007211 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007212 * @ctxt: the XPath Parser context
7213 *
7214 * [26] MultiplicativeExpr ::= UnaryExpr
7215 * | MultiplicativeExpr MultiplyOperator UnaryExpr
7216 * | MultiplicativeExpr 'div' UnaryExpr
7217 * | MultiplicativeExpr 'mod' UnaryExpr
7218 * [34] MultiplyOperator ::= '*'
7219 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007220 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007221 */
7222
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007223static void
7224xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
7225 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007226 CHECK_ERROR;
7227 SKIP_BLANKS;
7228 while ((CUR == '*') ||
7229 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
7230 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
7231 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007232 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007233
7234 if (CUR == '*') {
7235 op = 0;
7236 NEXT;
7237 } else if (CUR == 'd') {
7238 op = 1;
7239 SKIP(3);
7240 } else if (CUR == 'm') {
7241 op = 2;
7242 SKIP(3);
7243 }
7244 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007245 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007246 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007247 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007248 SKIP_BLANKS;
7249 }
7250}
7251
7252/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007253 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007254 * @ctxt: the XPath Parser context
7255 *
7256 * [25] AdditiveExpr ::= MultiplicativeExpr
7257 * | AdditiveExpr '+' MultiplicativeExpr
7258 * | AdditiveExpr '-' MultiplicativeExpr
7259 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007260 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007261 */
7262
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007263static void
7264xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007265
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007266 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007267 CHECK_ERROR;
7268 SKIP_BLANKS;
7269 while ((CUR == '+') || (CUR == '-')) {
7270 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007271 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007272
7273 if (CUR == '+') plus = 1;
7274 else plus = 0;
7275 NEXT;
7276 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007277 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007278 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007279 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007280 SKIP_BLANKS;
7281 }
7282}
7283
7284/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007285 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007286 * @ctxt: the XPath Parser context
7287 *
7288 * [24] RelationalExpr ::= AdditiveExpr
7289 * | RelationalExpr '<' AdditiveExpr
7290 * | RelationalExpr '>' AdditiveExpr
7291 * | RelationalExpr '<=' AdditiveExpr
7292 * | RelationalExpr '>=' AdditiveExpr
7293 *
7294 * A <= B > C is allowed ? Answer from James, yes with
7295 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
7296 * which is basically what got implemented.
7297 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007298 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00007299 * on the stack
7300 */
7301
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007302static void
7303xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
7304 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007305 CHECK_ERROR;
7306 SKIP_BLANKS;
7307 while ((CUR == '<') ||
7308 (CUR == '>') ||
7309 ((CUR == '<') && (NXT(1) == '=')) ||
7310 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007311 int inf, strict;
7312 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007313
7314 if (CUR == '<') inf = 1;
7315 else inf = 0;
7316 if (NXT(1) == '=') strict = 0;
7317 else strict = 1;
7318 NEXT;
7319 if (!strict) NEXT;
7320 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007321 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007322 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007323 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00007324 SKIP_BLANKS;
7325 }
7326}
7327
7328/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007329 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007330 * @ctxt: the XPath Parser context
7331 *
7332 * [23] EqualityExpr ::= RelationalExpr
7333 * | EqualityExpr '=' RelationalExpr
7334 * | EqualityExpr '!=' RelationalExpr
7335 *
7336 * A != B != C is allowed ? Answer from James, yes with
7337 * (RelationalExpr = RelationalExpr) = RelationalExpr
7338 * (RelationalExpr != RelationalExpr) != RelationalExpr
7339 * which is basically what got implemented.
7340 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007341 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007342 *
7343 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007344static void
7345xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
7346 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007347 CHECK_ERROR;
7348 SKIP_BLANKS;
7349 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007350 int eq;
7351 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007352
7353 if (CUR == '=') eq = 1;
7354 else eq = 0;
7355 NEXT;
7356 if (!eq) NEXT;
7357 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007358 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007359 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007360 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007361 SKIP_BLANKS;
7362 }
7363}
7364
7365/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007366 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007367 * @ctxt: the XPath Parser context
7368 *
7369 * [22] AndExpr ::= EqualityExpr
7370 * | AndExpr 'and' EqualityExpr
7371 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007372 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007373 *
7374 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007375static void
7376xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
7377 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007378 CHECK_ERROR;
7379 SKIP_BLANKS;
7380 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007381 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007382 SKIP(3);
7383 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007384 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007385 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007386 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007387 SKIP_BLANKS;
7388 }
7389}
7390
7391/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007392 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007393 * @ctxt: the XPath Parser context
7394 *
7395 * [14] Expr ::= OrExpr
7396 * [21] OrExpr ::= AndExpr
7397 * | OrExpr 'or' AndExpr
7398 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007399 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00007400 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007401static void
7402xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
7403 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007404 CHECK_ERROR;
7405 SKIP_BLANKS;
7406 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007407 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007408 SKIP(2);
7409 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007410 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007411 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007412 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
7413 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00007414 SKIP_BLANKS;
7415 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007416 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
7417 /* more ops could be optimized too */
7418 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
7419 }
Owen Taylor3473f882001-02-23 17:55:21 +00007420}
7421
7422/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007423 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00007424 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007425 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00007426 *
7427 * [8] Predicate ::= '[' PredicateExpr ']'
7428 * [9] PredicateExpr ::= Expr
7429 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007430 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00007431 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007432static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007433xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007434 int op1 = ctxt->comp->last;
7435
7436 SKIP_BLANKS;
7437 if (CUR != '[') {
7438 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7439 }
7440 NEXT;
7441 SKIP_BLANKS;
7442
7443 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007444 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007445 CHECK_ERROR;
7446
7447 if (CUR != ']') {
7448 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
7449 }
7450
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007451 if (filter)
7452 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
7453 else
7454 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007455
7456 NEXT;
7457 SKIP_BLANKS;
7458}
7459
7460/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007461 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00007462 * @ctxt: the XPath Parser context
7463 * @test: pointer to a xmlXPathTestVal
7464 * @type: pointer to a xmlXPathTypeVal
7465 * @prefix: placeholder for a possible name prefix
7466 *
7467 * [7] NodeTest ::= NameTest
7468 * | NodeType '(' ')'
7469 * | 'processing-instruction' '(' Literal ')'
7470 *
7471 * [37] NameTest ::= '*'
7472 * | NCName ':' '*'
7473 * | QName
7474 * [38] NodeType ::= 'comment'
7475 * | 'text'
7476 * | 'processing-instruction'
7477 * | 'node'
7478 *
7479 * Returns the name found and update @test, @type and @prefix appropriately
7480 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007481static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007482xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
7483 xmlXPathTypeVal *type, const xmlChar **prefix,
7484 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00007485 int blanks;
7486
7487 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
7488 STRANGE;
7489 return(NULL);
7490 }
7491 *type = 0;
7492 *test = 0;
7493 *prefix = NULL;
7494 SKIP_BLANKS;
7495
7496 if ((name == NULL) && (CUR == '*')) {
7497 /*
7498 * All elements
7499 */
7500 NEXT;
7501 *test = NODE_TEST_ALL;
7502 return(NULL);
7503 }
7504
7505 if (name == NULL)
7506 name = xmlXPathParseNCName(ctxt);
7507 if (name == NULL) {
7508 XP_ERROR0(XPATH_EXPR_ERROR);
7509 }
7510
7511 blanks = IS_BLANK(CUR);
7512 SKIP_BLANKS;
7513 if (CUR == '(') {
7514 NEXT;
7515 /*
7516 * NodeType or PI search
7517 */
7518 if (xmlStrEqual(name, BAD_CAST "comment"))
7519 *type = NODE_TYPE_COMMENT;
7520 else if (xmlStrEqual(name, BAD_CAST "node"))
7521 *type = NODE_TYPE_NODE;
7522 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
7523 *type = NODE_TYPE_PI;
7524 else if (xmlStrEqual(name, BAD_CAST "text"))
7525 *type = NODE_TYPE_TEXT;
7526 else {
7527 if (name != NULL)
7528 xmlFree(name);
7529 XP_ERROR0(XPATH_EXPR_ERROR);
7530 }
7531
7532 *test = NODE_TEST_TYPE;
7533
7534 SKIP_BLANKS;
7535 if (*type == NODE_TYPE_PI) {
7536 /*
7537 * Specific case: search a PI by name.
7538 */
Owen Taylor3473f882001-02-23 17:55:21 +00007539 if (name != NULL)
7540 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00007541 name = NULL;
7542 if (CUR != ')') {
7543 name = xmlXPathParseLiteral(ctxt);
7544 CHECK_ERROR 0;
7545 SKIP_BLANKS;
7546 }
Owen Taylor3473f882001-02-23 17:55:21 +00007547 }
7548 if (CUR != ')') {
7549 if (name != NULL)
7550 xmlFree(name);
7551 XP_ERROR0(XPATH_UNCLOSED_ERROR);
7552 }
7553 NEXT;
7554 return(name);
7555 }
7556 *test = NODE_TEST_NAME;
7557 if ((!blanks) && (CUR == ':')) {
7558 NEXT;
7559
7560 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007561 * Since currently the parser context don't have a
7562 * namespace list associated:
7563 * The namespace name for this prefix can be computed
7564 * only at evaluation time. The compilation is done
7565 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00007566 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007567#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00007568 *prefix = xmlXPathNsLookup(ctxt->context, name);
7569 if (name != NULL)
7570 xmlFree(name);
7571 if (*prefix == NULL) {
7572 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
7573 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007574#else
7575 *prefix = name;
7576#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007577
7578 if (CUR == '*') {
7579 /*
7580 * All elements
7581 */
7582 NEXT;
7583 *test = NODE_TEST_ALL;
7584 return(NULL);
7585 }
7586
7587 name = xmlXPathParseNCName(ctxt);
7588 if (name == NULL) {
7589 XP_ERROR0(XPATH_EXPR_ERROR);
7590 }
7591 }
7592 return(name);
7593}
7594
7595/**
7596 * xmlXPathIsAxisName:
7597 * @name: a preparsed name token
7598 *
7599 * [6] AxisName ::= 'ancestor'
7600 * | 'ancestor-or-self'
7601 * | 'attribute'
7602 * | 'child'
7603 * | 'descendant'
7604 * | 'descendant-or-self'
7605 * | 'following'
7606 * | 'following-sibling'
7607 * | 'namespace'
7608 * | 'parent'
7609 * | 'preceding'
7610 * | 'preceding-sibling'
7611 * | 'self'
7612 *
7613 * Returns the axis or 0
7614 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007615static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00007616xmlXPathIsAxisName(const xmlChar *name) {
7617 xmlXPathAxisVal ret = 0;
7618 switch (name[0]) {
7619 case 'a':
7620 if (xmlStrEqual(name, BAD_CAST "ancestor"))
7621 ret = AXIS_ANCESTOR;
7622 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
7623 ret = AXIS_ANCESTOR_OR_SELF;
7624 if (xmlStrEqual(name, BAD_CAST "attribute"))
7625 ret = AXIS_ATTRIBUTE;
7626 break;
7627 case 'c':
7628 if (xmlStrEqual(name, BAD_CAST "child"))
7629 ret = AXIS_CHILD;
7630 break;
7631 case 'd':
7632 if (xmlStrEqual(name, BAD_CAST "descendant"))
7633 ret = AXIS_DESCENDANT;
7634 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
7635 ret = AXIS_DESCENDANT_OR_SELF;
7636 break;
7637 case 'f':
7638 if (xmlStrEqual(name, BAD_CAST "following"))
7639 ret = AXIS_FOLLOWING;
7640 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
7641 ret = AXIS_FOLLOWING_SIBLING;
7642 break;
7643 case 'n':
7644 if (xmlStrEqual(name, BAD_CAST "namespace"))
7645 ret = AXIS_NAMESPACE;
7646 break;
7647 case 'p':
7648 if (xmlStrEqual(name, BAD_CAST "parent"))
7649 ret = AXIS_PARENT;
7650 if (xmlStrEqual(name, BAD_CAST "preceding"))
7651 ret = AXIS_PRECEDING;
7652 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
7653 ret = AXIS_PRECEDING_SIBLING;
7654 break;
7655 case 's':
7656 if (xmlStrEqual(name, BAD_CAST "self"))
7657 ret = AXIS_SELF;
7658 break;
7659 }
7660 return(ret);
7661}
7662
7663/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007664 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00007665 * @ctxt: the XPath Parser context
7666 *
7667 * [4] Step ::= AxisSpecifier NodeTest Predicate*
7668 * | AbbreviatedStep
7669 *
7670 * [12] AbbreviatedStep ::= '.' | '..'
7671 *
7672 * [5] AxisSpecifier ::= AxisName '::'
7673 * | AbbreviatedAxisSpecifier
7674 *
7675 * [13] AbbreviatedAxisSpecifier ::= '@'?
7676 *
7677 * Modified for XPtr range support as:
7678 *
7679 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
7680 * | AbbreviatedStep
7681 * | 'range-to' '(' Expr ')' Predicate*
7682 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007683 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00007684 * A location step of . is short for self::node(). This is
7685 * particularly useful in conjunction with //. For example, the
7686 * location path .//para is short for
7687 * self::node()/descendant-or-self::node()/child::para
7688 * and so will select all para descendant elements of the context
7689 * node.
7690 * Similarly, a location step of .. is short for parent::node().
7691 * For example, ../title is short for parent::node()/child::title
7692 * and so will select the title children of the parent of the context
7693 * node.
7694 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007695static void
7696xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007697#ifdef LIBXML_XPTR_ENABLED
7698 int rangeto = 0;
7699 int op2 = -1;
7700#endif
7701
Owen Taylor3473f882001-02-23 17:55:21 +00007702 SKIP_BLANKS;
7703 if ((CUR == '.') && (NXT(1) == '.')) {
7704 SKIP(2);
7705 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007706 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
7707 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007708 } else if (CUR == '.') {
7709 NEXT;
7710 SKIP_BLANKS;
7711 } else {
7712 xmlChar *name = NULL;
7713 const xmlChar *prefix = NULL;
7714 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007715 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007716 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007717 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00007718
7719 /*
7720 * The modification needed for XPointer change to the production
7721 */
7722#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007723 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00007724 name = xmlXPathParseNCName(ctxt);
7725 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007726 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00007727 xmlFree(name);
7728 SKIP_BLANKS;
7729 if (CUR != '(') {
7730 XP_ERROR(XPATH_EXPR_ERROR);
7731 }
7732 NEXT;
7733 SKIP_BLANKS;
7734
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007735 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007736 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00007737 CHECK_ERROR;
7738
7739 SKIP_BLANKS;
7740 if (CUR != ')') {
7741 XP_ERROR(XPATH_EXPR_ERROR);
7742 }
7743 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007744 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007745 goto eval_predicates;
7746 }
7747 }
7748#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00007749 if (CUR == '*') {
7750 axis = AXIS_CHILD;
7751 } else {
7752 if (name == NULL)
7753 name = xmlXPathParseNCName(ctxt);
7754 if (name != NULL) {
7755 axis = xmlXPathIsAxisName(name);
7756 if (axis != 0) {
7757 SKIP_BLANKS;
7758 if ((CUR == ':') && (NXT(1) == ':')) {
7759 SKIP(2);
7760 xmlFree(name);
7761 name = NULL;
7762 } else {
7763 /* an element name can conflict with an axis one :-\ */
7764 axis = AXIS_CHILD;
7765 }
Owen Taylor3473f882001-02-23 17:55:21 +00007766 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00007767 axis = AXIS_CHILD;
7768 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007769 } else if (CUR == '@') {
7770 NEXT;
7771 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00007772 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00007773 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00007774 }
Owen Taylor3473f882001-02-23 17:55:21 +00007775 }
7776
7777 CHECK_ERROR;
7778
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007779 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00007780 if (test == 0)
7781 return;
7782
7783#ifdef DEBUG_STEP
7784 xmlGenericError(xmlGenericErrorContext,
7785 "Basis : computing new set\n");
7786#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007787
Owen Taylor3473f882001-02-23 17:55:21 +00007788#ifdef DEBUG_STEP
7789 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007790 if (ctxt->value == NULL)
7791 xmlGenericError(xmlGenericErrorContext, "no value\n");
7792 else if (ctxt->value->nodesetval == NULL)
7793 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7794 else
7795 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007796#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007797
7798eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007799 op1 = ctxt->comp->last;
7800 ctxt->comp->last = -1;
7801
Owen Taylor3473f882001-02-23 17:55:21 +00007802 SKIP_BLANKS;
7803 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007804 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007805 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007806
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007807#ifdef LIBXML_XPTR_ENABLED
7808 if (rangeto) {
7809 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
7810 } else
7811#endif
7812 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
7813 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007814
Owen Taylor3473f882001-02-23 17:55:21 +00007815 }
7816#ifdef DEBUG_STEP
7817 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00007818 if (ctxt->value == NULL)
7819 xmlGenericError(xmlGenericErrorContext, "no value\n");
7820 else if (ctxt->value->nodesetval == NULL)
7821 xmlGenericError(xmlGenericErrorContext, "Empty\n");
7822 else
7823 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
7824 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00007825#endif
7826}
7827
7828/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007829 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007830 * @ctxt: the XPath Parser context
7831 *
7832 * [3] RelativeLocationPath ::= Step
7833 * | RelativeLocationPath '/' Step
7834 * | AbbreviatedRelativeLocationPath
7835 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
7836 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007837 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00007838 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007839static void
Owen Taylor3473f882001-02-23 17:55:21 +00007840#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007841xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007842#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007843xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00007844#endif
7845(xmlXPathParserContextPtr ctxt) {
7846 SKIP_BLANKS;
7847 if ((CUR == '/') && (NXT(1) == '/')) {
7848 SKIP(2);
7849 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007850 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7851 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007852 } else if (CUR == '/') {
7853 NEXT;
7854 SKIP_BLANKS;
7855 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007856 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007857 SKIP_BLANKS;
7858 while (CUR == '/') {
7859 if ((CUR == '/') && (NXT(1) == '/')) {
7860 SKIP(2);
7861 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007862 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00007863 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007864 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007865 } else if (CUR == '/') {
7866 NEXT;
7867 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007868 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007869 }
7870 SKIP_BLANKS;
7871 }
7872}
7873
7874/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007875 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007876 * @ctxt: the XPath Parser context
7877 *
7878 * [1] LocationPath ::= RelativeLocationPath
7879 * | AbsoluteLocationPath
7880 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
7881 * | AbbreviatedAbsoluteLocationPath
7882 * [10] AbbreviatedAbsoluteLocationPath ::=
7883 * '//' RelativeLocationPath
7884 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007885 * Compile a location path
7886 *
Owen Taylor3473f882001-02-23 17:55:21 +00007887 * // is short for /descendant-or-self::node()/. For example,
7888 * //para is short for /descendant-or-self::node()/child::para and
7889 * so will select any para element in the document (even a para element
7890 * that is a document element will be selected by //para since the
7891 * document element node is a child of the root node); div//para is
7892 * short for div/descendant-or-self::node()/child::para and so will
7893 * select all para descendants of div children.
7894 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007895static void
7896xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007897 SKIP_BLANKS;
7898 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007899 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007900 } else {
7901 while (CUR == '/') {
7902 if ((CUR == '/') && (NXT(1) == '/')) {
7903 SKIP(2);
7904 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007905 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7906 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007907 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007908 } else if (CUR == '/') {
7909 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00007910 SKIP_BLANKS;
7911 if ((CUR != 0 ) &&
7912 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
7913 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007914 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007915 }
7916 }
7917 }
7918}
7919
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007920/************************************************************************
7921 * *
7922 * XPath precompiled expression evaluation *
7923 * *
7924 ************************************************************************/
7925
Daniel Veillardf06307e2001-07-03 10:35:50 +00007926static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007927xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
7928
7929/**
7930 * xmlXPathNodeCollectAndTest:
7931 * @ctxt: the XPath Parser context
7932 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00007933 * @first: pointer to the first element in document order
7934 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007935 *
7936 * This is the function implementing a step: based on the current list
7937 * of nodes, it builds up a new list, looking at all nodes under that
7938 * axis and selecting them it also do the predicate filtering
7939 *
7940 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00007941 *
7942 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007943 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00007944static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007945xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00007946 xmlXPathStepOpPtr op,
7947 xmlNodePtr * first, xmlNodePtr * last)
7948{
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007949 xmlXPathAxisVal axis = op->value;
7950 xmlXPathTestVal test = op->value2;
7951 xmlXPathTypeVal type = op->value3;
7952 const xmlChar *prefix = op->value4;
7953 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00007954 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007955
7956#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007957 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007958#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007959 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007960 xmlNodeSetPtr ret, list;
7961 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00007962 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007963 xmlNodePtr cur = NULL;
7964 xmlXPathObjectPtr obj;
7965 xmlNodeSetPtr nodelist;
7966 xmlNodePtr tmp;
7967
Daniel Veillardf06307e2001-07-03 10:35:50 +00007968 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007969 obj = valuePop(ctxt);
7970 addNode = xmlXPathNodeSetAdd;
Daniel Veillarde043ee12001-04-16 14:08:07 +00007971 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00007972 URI = xmlXPathNsLookup(ctxt->context, prefix);
7973 if (URI == NULL)
7974 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00007975 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007976#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007977 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007978#endif
7979 switch (axis) {
7980 case AXIS_ANCESTOR:
7981#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007982 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007983#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007984 first = NULL;
7985 next = xmlXPathNextAncestor;
7986 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007987 case AXIS_ANCESTOR_OR_SELF:
7988#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007989 xmlGenericError(xmlGenericErrorContext,
7990 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007991#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007992 first = NULL;
7993 next = xmlXPathNextAncestorOrSelf;
7994 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007995 case AXIS_ATTRIBUTE:
7996#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00007997 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007998#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00007999 first = NULL;
8000 last = NULL;
8001 next = xmlXPathNextAttribute;
8002 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008003 case AXIS_CHILD:
8004#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008005 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008006#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008007 last = NULL;
8008 next = xmlXPathNextChild;
8009 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008010 case AXIS_DESCENDANT:
8011#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008012 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008013#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008014 last = NULL;
8015 next = xmlXPathNextDescendant;
8016 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008017 case AXIS_DESCENDANT_OR_SELF:
8018#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008019 xmlGenericError(xmlGenericErrorContext,
8020 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008021#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008022 last = NULL;
8023 next = xmlXPathNextDescendantOrSelf;
8024 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008025 case AXIS_FOLLOWING:
8026#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008027 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008028#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008029 last = NULL;
8030 next = xmlXPathNextFollowing;
8031 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008032 case AXIS_FOLLOWING_SIBLING:
8033#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008034 xmlGenericError(xmlGenericErrorContext,
8035 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008036#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008037 last = NULL;
8038 next = xmlXPathNextFollowingSibling;
8039 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008040 case AXIS_NAMESPACE:
8041#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008042 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008043#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008044 first = NULL;
8045 last = NULL;
8046 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8047 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008048 case AXIS_PARENT:
8049#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008050 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008051#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008052 first = NULL;
8053 next = xmlXPathNextParent;
8054 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008055 case AXIS_PRECEDING:
8056#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008057 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008058#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008059 first = NULL;
8060 next = xmlXPathNextPrecedingInternal;
8061 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008062 case AXIS_PRECEDING_SIBLING:
8063#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008064 xmlGenericError(xmlGenericErrorContext,
8065 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008066#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008067 first = NULL;
8068 next = xmlXPathNextPrecedingSibling;
8069 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008070 case AXIS_SELF:
8071#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008072 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008073#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008074 first = NULL;
8075 last = NULL;
8076 next = xmlXPathNextSelf;
8077 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008078 }
8079 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008080 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008081
8082 nodelist = obj->nodesetval;
8083 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008084 xmlXPathFreeObject(obj);
8085 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8086 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008087 }
8088 addNode = xmlXPathNodeSetAddUnique;
8089 ret = NULL;
8090#ifdef DEBUG_STEP
8091 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008092 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008093 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008094 case NODE_TEST_NONE:
8095 xmlGenericError(xmlGenericErrorContext,
8096 " searching for none !!!\n");
8097 break;
8098 case NODE_TEST_TYPE:
8099 xmlGenericError(xmlGenericErrorContext,
8100 " searching for type %d\n", type);
8101 break;
8102 case NODE_TEST_PI:
8103 xmlGenericError(xmlGenericErrorContext,
8104 " searching for PI !!!\n");
8105 break;
8106 case NODE_TEST_ALL:
8107 xmlGenericError(xmlGenericErrorContext,
8108 " searching for *\n");
8109 break;
8110 case NODE_TEST_NS:
8111 xmlGenericError(xmlGenericErrorContext,
8112 " searching for namespace %s\n",
8113 prefix);
8114 break;
8115 case NODE_TEST_NAME:
8116 xmlGenericError(xmlGenericErrorContext,
8117 " searching for name %s\n", name);
8118 if (prefix != NULL)
8119 xmlGenericError(xmlGenericErrorContext,
8120 " with namespace %s\n", prefix);
8121 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008122 }
8123 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8124#endif
8125 /*
8126 * 2.3 Node Tests
8127 * - For the attribute axis, the principal node type is attribute.
8128 * - For the namespace axis, the principal node type is namespace.
8129 * - For other axes, the principal node type is element.
8130 *
8131 * A node test * is true for any node of the
8132 * principal node type. For example, child::* willi
8133 * select all element children of the context node
8134 */
8135 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008136 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008137 ctxt->context->node = nodelist->nodeTab[i];
8138
Daniel Veillardf06307e2001-07-03 10:35:50 +00008139 cur = NULL;
8140 list = xmlXPathNodeSetCreate(NULL);
8141 do {
8142 cur = next(ctxt, cur);
8143 if (cur == NULL)
8144 break;
8145 if ((first != NULL) && (*first == cur))
8146 break;
8147 if (((t % 256) == 0) &&
8148 (first != NULL) && (*first != NULL) &&
8149 (xmlXPathCmpNodes(*first, cur) >= 0))
8150 break;
8151 if ((last != NULL) && (*last == cur))
8152 break;
8153 if (((t % 256) == 0) &&
8154 (last != NULL) && (*last != NULL) &&
8155 (xmlXPathCmpNodes(cur, *last) >= 0))
8156 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008157 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008158#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008159 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
8160#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008161 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008162 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008163 ctxt->context->node = tmp;
8164 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008165 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008166 if ((cur->type == type) ||
8167 ((type == NODE_TYPE_NODE) &&
8168 ((cur->type == XML_DOCUMENT_NODE) ||
8169 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8170 (cur->type == XML_ELEMENT_NODE) ||
8171 (cur->type == XML_PI_NODE) ||
8172 (cur->type == XML_COMMENT_NODE) ||
8173 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00008174 (cur->type == XML_TEXT_NODE))) ||
8175 ((type == NODE_TYPE_TEXT) &&
8176 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008177#ifdef DEBUG_STEP
8178 n++;
8179#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008180 addNode(list, cur);
8181 }
8182 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008183 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008184 if (cur->type == XML_PI_NODE) {
8185 if ((name != NULL) &&
8186 (!xmlStrEqual(name, cur->name)))
8187 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008188#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008189 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008190#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008191 addNode(list, cur);
8192 }
8193 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008194 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008195 if (axis == AXIS_ATTRIBUTE) {
8196 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008197#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008198 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008199#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008200 addNode(list, cur);
8201 }
8202 } else if (axis == AXIS_NAMESPACE) {
8203 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008204#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008205 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008206#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008207 addNode(list, cur);
8208 }
8209 } else {
8210 if (cur->type == XML_ELEMENT_NODE) {
8211 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008212#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008213 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008214#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008215 addNode(list, cur);
8216 } else if ((cur->ns != NULL) &&
8217 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008218#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008219 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008220#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008221 addNode(list, cur);
8222 }
8223 }
8224 }
8225 break;
8226 case NODE_TEST_NS:{
8227 TODO;
8228 break;
8229 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008230 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00008231 switch (cur->type) {
8232 case XML_ELEMENT_NODE:
8233 if (xmlStrEqual(name, cur->name)) {
8234 if (prefix == NULL) {
8235 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008236#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008237 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008238#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008239 addNode(list, cur);
8240 }
8241 } else {
8242 if ((cur->ns != NULL) &&
8243 (xmlStrEqual(URI,
8244 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008245#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008246 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008247#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008248 addNode(list, cur);
8249 }
8250 }
8251 }
8252 break;
8253 case XML_ATTRIBUTE_NODE:{
8254 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008255
Daniel Veillardf06307e2001-07-03 10:35:50 +00008256 if (xmlStrEqual(name, attr->name)) {
8257 if (prefix == NULL) {
8258 if ((attr->ns == NULL) ||
8259 (attr->ns->prefix == NULL)) {
8260#ifdef DEBUG_STEP
8261 n++;
8262#endif
8263 addNode(list,
8264 (xmlNodePtr) attr);
8265 }
8266 } else {
8267 if ((attr->ns != NULL) &&
8268 (xmlStrEqual(URI,
8269 attr->ns->
8270 href))) {
8271#ifdef DEBUG_STEP
8272 n++;
8273#endif
8274 addNode(list,
8275 (xmlNodePtr) attr);
8276 }
8277 }
8278 }
8279 break;
8280 }
8281 case XML_NAMESPACE_DECL:
8282 if (cur->type == XML_NAMESPACE_DECL) {
8283 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008284
Daniel Veillardf06307e2001-07-03 10:35:50 +00008285 if ((ns->prefix != NULL) && (name != NULL)
8286 && (xmlStrEqual(ns->prefix, name))) {
8287#ifdef DEBUG_STEP
8288 n++;
8289#endif
8290 addNode(list, cur);
8291 }
8292 }
8293 break;
8294 default:
8295 break;
8296 }
8297 break;
8298 break;
8299 }
8300 } while (cur != NULL);
8301
8302 /*
8303 * If there is some predicate filtering do it now
8304 */
8305 if (op->ch2 != -1) {
8306 xmlXPathObjectPtr obj2;
8307
8308 valuePush(ctxt, xmlXPathWrapNodeSet(list));
8309 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
8310 CHECK_TYPE0(XPATH_NODESET);
8311 obj2 = valuePop(ctxt);
8312 list = obj2->nodesetval;
8313 obj2->nodesetval = NULL;
8314 xmlXPathFreeObject(obj2);
8315 }
8316 if (ret == NULL) {
8317 ret = list;
8318 } else {
8319 ret = xmlXPathNodeSetMerge(ret, list);
8320 xmlXPathFreeNodeSet(list);
8321 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008322 }
8323 ctxt->context->node = tmp;
8324#ifdef DEBUG_STEP
8325 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008326 "\nExamined %d nodes, found %d nodes at that step\n",
8327 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008328#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008329 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00008330 if ((obj->boolval) && (obj->user != NULL)) {
8331 ctxt->value->boolval = 1;
8332 ctxt->value->user = obj->user;
8333 obj->user = NULL;
8334 obj->boolval = 0;
8335 }
8336 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008337 return(t);
8338}
8339
8340/**
8341 * xmlXPathNodeCollectAndTestNth:
8342 * @ctxt: the XPath Parser context
8343 * @op: the XPath precompiled step operation
8344 * @indx: the index to collect
8345 * @first: pointer to the first element in document order
8346 * @last: pointer to the last element in document order
8347 *
8348 * This is the function implementing a step: based on the current list
8349 * of nodes, it builds up a new list, looking at all nodes under that
8350 * axis and selecting them it also do the predicate filtering
8351 *
8352 * Pushes the new NodeSet resulting from the search.
8353 * Returns the number of node traversed
8354 */
8355static int
8356xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
8357 xmlXPathStepOpPtr op, int indx,
8358 xmlNodePtr * first, xmlNodePtr * last)
8359{
8360 xmlXPathAxisVal axis = op->value;
8361 xmlXPathTestVal test = op->value2;
8362 xmlXPathTypeVal type = op->value3;
8363 const xmlChar *prefix = op->value4;
8364 const xmlChar *name = op->value5;
8365 const xmlChar *URI = NULL;
8366 int n = 0, t = 0;
8367
8368 int i;
8369 xmlNodeSetPtr list;
8370 xmlXPathTraversalFunction next = NULL;
8371 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
8372 xmlNodePtr cur = NULL;
8373 xmlXPathObjectPtr obj;
8374 xmlNodeSetPtr nodelist;
8375 xmlNodePtr tmp;
8376
8377 CHECK_TYPE0(XPATH_NODESET);
8378 obj = valuePop(ctxt);
8379 addNode = xmlXPathNodeSetAdd;
8380 if (prefix != NULL) {
8381 URI = xmlXPathNsLookup(ctxt->context, prefix);
8382 if (URI == NULL)
8383 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8384 }
8385#ifdef DEBUG_STEP_NTH
8386 xmlGenericError(xmlGenericErrorContext, "new step : ");
8387 if (first != NULL) {
8388 if (*first != NULL)
8389 xmlGenericError(xmlGenericErrorContext, "first = %s ",
8390 (*first)->name);
8391 else
8392 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
8393 }
8394 if (last != NULL) {
8395 if (*last != NULL)
8396 xmlGenericError(xmlGenericErrorContext, "last = %s ",
8397 (*last)->name);
8398 else
8399 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
8400 }
8401#endif
8402 switch (axis) {
8403 case AXIS_ANCESTOR:
8404#ifdef DEBUG_STEP_NTH
8405 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
8406#endif
8407 first = NULL;
8408 next = xmlXPathNextAncestor;
8409 break;
8410 case AXIS_ANCESTOR_OR_SELF:
8411#ifdef DEBUG_STEP_NTH
8412 xmlGenericError(xmlGenericErrorContext,
8413 "axis 'ancestors-or-self' ");
8414#endif
8415 first = NULL;
8416 next = xmlXPathNextAncestorOrSelf;
8417 break;
8418 case AXIS_ATTRIBUTE:
8419#ifdef DEBUG_STEP_NTH
8420 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
8421#endif
8422 first = NULL;
8423 last = NULL;
8424 next = xmlXPathNextAttribute;
8425 break;
8426 case AXIS_CHILD:
8427#ifdef DEBUG_STEP_NTH
8428 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
8429#endif
8430 last = NULL;
8431 next = xmlXPathNextChild;
8432 break;
8433 case AXIS_DESCENDANT:
8434#ifdef DEBUG_STEP_NTH
8435 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
8436#endif
8437 last = NULL;
8438 next = xmlXPathNextDescendant;
8439 break;
8440 case AXIS_DESCENDANT_OR_SELF:
8441#ifdef DEBUG_STEP_NTH
8442 xmlGenericError(xmlGenericErrorContext,
8443 "axis 'descendant-or-self' ");
8444#endif
8445 last = NULL;
8446 next = xmlXPathNextDescendantOrSelf;
8447 break;
8448 case AXIS_FOLLOWING:
8449#ifdef DEBUG_STEP_NTH
8450 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
8451#endif
8452 last = NULL;
8453 next = xmlXPathNextFollowing;
8454 break;
8455 case AXIS_FOLLOWING_SIBLING:
8456#ifdef DEBUG_STEP_NTH
8457 xmlGenericError(xmlGenericErrorContext,
8458 "axis 'following-siblings' ");
8459#endif
8460 last = NULL;
8461 next = xmlXPathNextFollowingSibling;
8462 break;
8463 case AXIS_NAMESPACE:
8464#ifdef DEBUG_STEP_NTH
8465 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
8466#endif
8467 last = NULL;
8468 first = NULL;
8469 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8470 break;
8471 case AXIS_PARENT:
8472#ifdef DEBUG_STEP_NTH
8473 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
8474#endif
8475 first = NULL;
8476 next = xmlXPathNextParent;
8477 break;
8478 case AXIS_PRECEDING:
8479#ifdef DEBUG_STEP_NTH
8480 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
8481#endif
8482 first = NULL;
8483 next = xmlXPathNextPrecedingInternal;
8484 break;
8485 case AXIS_PRECEDING_SIBLING:
8486#ifdef DEBUG_STEP_NTH
8487 xmlGenericError(xmlGenericErrorContext,
8488 "axis 'preceding-sibling' ");
8489#endif
8490 first = NULL;
8491 next = xmlXPathNextPrecedingSibling;
8492 break;
8493 case AXIS_SELF:
8494#ifdef DEBUG_STEP_NTH
8495 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
8496#endif
8497 first = NULL;
8498 last = NULL;
8499 next = xmlXPathNextSelf;
8500 break;
8501 }
8502 if (next == NULL)
8503 return(0);
8504
8505 nodelist = obj->nodesetval;
8506 if (nodelist == NULL) {
8507 xmlXPathFreeObject(obj);
8508 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8509 return(0);
8510 }
8511 addNode = xmlXPathNodeSetAddUnique;
8512#ifdef DEBUG_STEP_NTH
8513 xmlGenericError(xmlGenericErrorContext,
8514 " context contains %d nodes\n", nodelist->nodeNr);
8515 switch (test) {
8516 case NODE_TEST_NONE:
8517 xmlGenericError(xmlGenericErrorContext,
8518 " searching for none !!!\n");
8519 break;
8520 case NODE_TEST_TYPE:
8521 xmlGenericError(xmlGenericErrorContext,
8522 " searching for type %d\n", type);
8523 break;
8524 case NODE_TEST_PI:
8525 xmlGenericError(xmlGenericErrorContext,
8526 " searching for PI !!!\n");
8527 break;
8528 case NODE_TEST_ALL:
8529 xmlGenericError(xmlGenericErrorContext,
8530 " searching for *\n");
8531 break;
8532 case NODE_TEST_NS:
8533 xmlGenericError(xmlGenericErrorContext,
8534 " searching for namespace %s\n",
8535 prefix);
8536 break;
8537 case NODE_TEST_NAME:
8538 xmlGenericError(xmlGenericErrorContext,
8539 " searching for name %s\n", name);
8540 if (prefix != NULL)
8541 xmlGenericError(xmlGenericErrorContext,
8542 " with namespace %s\n", prefix);
8543 break;
8544 }
8545 xmlGenericError(xmlGenericErrorContext, "Testing : ");
8546#endif
8547 /*
8548 * 2.3 Node Tests
8549 * - For the attribute axis, the principal node type is attribute.
8550 * - For the namespace axis, the principal node type is namespace.
8551 * - For other axes, the principal node type is element.
8552 *
8553 * A node test * is true for any node of the
8554 * principal node type. For example, child::* willi
8555 * select all element children of the context node
8556 */
8557 tmp = ctxt->context->node;
8558 list = xmlXPathNodeSetCreate(NULL);
8559 for (i = 0; i < nodelist->nodeNr; i++) {
8560 ctxt->context->node = nodelist->nodeTab[i];
8561
8562 cur = NULL;
8563 n = 0;
8564 do {
8565 cur = next(ctxt, cur);
8566 if (cur == NULL)
8567 break;
8568 if ((first != NULL) && (*first == cur))
8569 break;
8570 if (((t % 256) == 0) &&
8571 (first != NULL) && (*first != NULL) &&
8572 (xmlXPathCmpNodes(*first, cur) >= 0))
8573 break;
8574 if ((last != NULL) && (*last == cur))
8575 break;
8576 if (((t % 256) == 0) &&
8577 (last != NULL) && (*last != NULL) &&
8578 (xmlXPathCmpNodes(cur, *last) >= 0))
8579 break;
8580 t++;
8581 switch (test) {
8582 case NODE_TEST_NONE:
8583 ctxt->context->node = tmp;
8584 STRANGE return(0);
8585 case NODE_TEST_TYPE:
8586 if ((cur->type == type) ||
8587 ((type == NODE_TYPE_NODE) &&
8588 ((cur->type == XML_DOCUMENT_NODE) ||
8589 (cur->type == XML_HTML_DOCUMENT_NODE) ||
8590 (cur->type == XML_ELEMENT_NODE) ||
8591 (cur->type == XML_PI_NODE) ||
8592 (cur->type == XML_COMMENT_NODE) ||
8593 (cur->type == XML_CDATA_SECTION_NODE) ||
8594 (cur->type == XML_TEXT_NODE)))) {
8595 n++;
8596 if (n == indx)
8597 addNode(list, cur);
8598 }
8599 break;
8600 case NODE_TEST_PI:
8601 if (cur->type == XML_PI_NODE) {
8602 if ((name != NULL) &&
8603 (!xmlStrEqual(name, cur->name)))
8604 break;
8605 n++;
8606 if (n == indx)
8607 addNode(list, cur);
8608 }
8609 break;
8610 case NODE_TEST_ALL:
8611 if (axis == AXIS_ATTRIBUTE) {
8612 if (cur->type == XML_ATTRIBUTE_NODE) {
8613 n++;
8614 if (n == indx)
8615 addNode(list, cur);
8616 }
8617 } else if (axis == AXIS_NAMESPACE) {
8618 if (cur->type == XML_NAMESPACE_DECL) {
8619 n++;
8620 if (n == indx)
8621 addNode(list, cur);
8622 }
8623 } else {
8624 if (cur->type == XML_ELEMENT_NODE) {
8625 if (prefix == NULL) {
8626 n++;
8627 if (n == indx)
8628 addNode(list, cur);
8629 } else if ((cur->ns != NULL) &&
8630 (xmlStrEqual(URI, cur->ns->href))) {
8631 n++;
8632 if (n == indx)
8633 addNode(list, cur);
8634 }
8635 }
8636 }
8637 break;
8638 case NODE_TEST_NS:{
8639 TODO;
8640 break;
8641 }
8642 case NODE_TEST_NAME:
8643 switch (cur->type) {
8644 case XML_ELEMENT_NODE:
8645 if (xmlStrEqual(name, cur->name)) {
8646 if (prefix == NULL) {
8647 if (cur->ns == NULL) {
8648 n++;
8649 if (n == indx)
8650 addNode(list, cur);
8651 }
8652 } else {
8653 if ((cur->ns != NULL) &&
8654 (xmlStrEqual(URI,
8655 cur->ns->href))) {
8656 n++;
8657 if (n == indx)
8658 addNode(list, cur);
8659 }
8660 }
8661 }
8662 break;
8663 case XML_ATTRIBUTE_NODE:{
8664 xmlAttrPtr attr = (xmlAttrPtr) cur;
8665
8666 if (xmlStrEqual(name, attr->name)) {
8667 if (prefix == NULL) {
8668 if ((attr->ns == NULL) ||
8669 (attr->ns->prefix == NULL)) {
8670 n++;
8671 if (n == indx)
8672 addNode(list, cur);
8673 }
8674 } else {
8675 if ((attr->ns != NULL) &&
8676 (xmlStrEqual(URI,
8677 attr->ns->
8678 href))) {
8679 n++;
8680 if (n == indx)
8681 addNode(list, cur);
8682 }
8683 }
8684 }
8685 break;
8686 }
8687 case XML_NAMESPACE_DECL:
8688 if (cur->type == XML_NAMESPACE_DECL) {
8689 xmlNsPtr ns = (xmlNsPtr) cur;
8690
8691 if ((ns->prefix != NULL) && (name != NULL)
8692 && (xmlStrEqual(ns->prefix, name))) {
8693 n++;
8694 if (n == indx)
8695 addNode(list, cur);
8696 }
8697 }
8698 break;
8699 default:
8700 break;
8701 }
8702 break;
8703 break;
8704 }
8705 } while (n < indx);
8706 }
8707 ctxt->context->node = tmp;
8708#ifdef DEBUG_STEP_NTH
8709 xmlGenericError(xmlGenericErrorContext,
8710 "\nExamined %d nodes, found %d nodes at that step\n",
8711 t, list->nodeNr);
8712#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008713 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00008714 if ((obj->boolval) && (obj->user != NULL)) {
8715 ctxt->value->boolval = 1;
8716 ctxt->value->user = obj->user;
8717 obj->user = NULL;
8718 obj->boolval = 0;
8719 }
8720 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008721 return(t);
8722}
8723
8724/**
8725 * xmlXPathCompOpEvalFirst:
8726 * @ctxt: the XPath parser context with the compiled expression
8727 * @op: an XPath compiled operation
8728 * @first: the first elem found so far
8729 *
8730 * Evaluate the Precompiled XPath operation searching only the first
8731 * element in document order
8732 *
8733 * Returns the number of examined objects.
8734 */
8735static int
8736xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
8737 xmlXPathStepOpPtr op, xmlNodePtr * first)
8738{
8739 int total = 0, cur;
8740 xmlXPathCompExprPtr comp;
8741 xmlXPathObjectPtr arg1, arg2;
8742
8743 comp = ctxt->comp;
8744 switch (op->op) {
8745 case XPATH_OP_END:
8746 return (0);
8747 case XPATH_OP_UNION:
8748 total =
8749 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
8750 first);
8751 if ((ctxt->value != NULL)
8752 && (ctxt->value->type == XPATH_NODESET)
8753 && (ctxt->value->nodesetval != NULL)
8754 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8755 /*
8756 * limit tree traversing to first node in the result
8757 */
8758 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8759 *first = ctxt->value->nodesetval->nodeTab[0];
8760 }
8761 cur =
8762 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
8763 first);
8764 CHECK_TYPE0(XPATH_NODESET);
8765 arg2 = valuePop(ctxt);
8766
8767 CHECK_TYPE0(XPATH_NODESET);
8768 arg1 = valuePop(ctxt);
8769
8770 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8771 arg2->nodesetval);
8772 valuePush(ctxt, arg1);
8773 xmlXPathFreeObject(arg2);
8774 /* optimizer */
8775 if (total > cur)
8776 xmlXPathCompSwap(op);
8777 return (total + cur);
8778 case XPATH_OP_ROOT:
8779 xmlXPathRoot(ctxt);
8780 return (0);
8781 case XPATH_OP_NODE:
8782 if (op->ch1 != -1)
8783 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8784 if (op->ch2 != -1)
8785 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8786 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8787 return (total);
8788 case XPATH_OP_RESET:
8789 if (op->ch1 != -1)
8790 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8791 if (op->ch2 != -1)
8792 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8793 ctxt->context->node = NULL;
8794 return (total);
8795 case XPATH_OP_COLLECT:{
8796 if (op->ch1 == -1)
8797 return (total);
8798
8799 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8800
8801 /*
8802 * Optimization for [n] selection where n is a number
8803 */
8804 if ((op->ch2 != -1) &&
8805 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8806 (comp->steps[op->ch2].ch1 == -1) &&
8807 (comp->steps[op->ch2].ch2 != -1) &&
8808 (comp->steps[comp->steps[op->ch2].ch2].op ==
8809 XPATH_OP_VALUE)) {
8810 xmlXPathObjectPtr val;
8811
8812 val = comp->steps[comp->steps[op->ch2].ch2].value4;
8813 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
8814 int indx = (int) val->floatval;
8815
8816 if (val->floatval == (float) indx) {
8817 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
8818 first, NULL);
8819 return (total);
8820 }
8821 }
8822 }
8823 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
8824 return (total);
8825 }
8826 case XPATH_OP_VALUE:
8827 valuePush(ctxt,
8828 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
8829 return (0);
8830 case XPATH_OP_SORT:
8831 if (op->ch1 != -1)
8832 total +=
8833 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
8834 first);
8835 if ((ctxt->value != NULL)
8836 && (ctxt->value->type == XPATH_NODESET)
8837 && (ctxt->value->nodesetval != NULL))
8838 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8839 return (total);
8840 default:
8841 return (xmlXPathCompOpEval(ctxt, op));
8842 }
8843}
8844
8845/**
8846 * xmlXPathCompOpEvalLast:
8847 * @ctxt: the XPath parser context with the compiled expression
8848 * @op: an XPath compiled operation
8849 * @last: the last elem found so far
8850 *
8851 * Evaluate the Precompiled XPath operation searching only the last
8852 * element in document order
8853 *
8854 * Returns the number of node traversed
8855 */
8856static int
8857xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
8858 xmlNodePtr * last)
8859{
8860 int total = 0, cur;
8861 xmlXPathCompExprPtr comp;
8862 xmlXPathObjectPtr arg1, arg2;
8863
8864 comp = ctxt->comp;
8865 switch (op->op) {
8866 case XPATH_OP_END:
8867 return (0);
8868 case XPATH_OP_UNION:
8869 total =
8870 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
8871 if ((ctxt->value != NULL)
8872 && (ctxt->value->type == XPATH_NODESET)
8873 && (ctxt->value->nodesetval != NULL)
8874 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8875 /*
8876 * limit tree traversing to first node in the result
8877 */
8878 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8879 *last =
8880 ctxt->value->nodesetval->nodeTab[ctxt->value->
8881 nodesetval->nodeNr -
8882 1];
8883 }
8884 cur =
8885 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
8886 if ((ctxt->value != NULL)
8887 && (ctxt->value->type == XPATH_NODESET)
8888 && (ctxt->value->nodesetval != NULL)
8889 && (ctxt->value->nodesetval->nodeNr >= 1)) {
8890 }
8891 CHECK_TYPE0(XPATH_NODESET);
8892 arg2 = valuePop(ctxt);
8893
8894 CHECK_TYPE0(XPATH_NODESET);
8895 arg1 = valuePop(ctxt);
8896
8897 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
8898 arg2->nodesetval);
8899 valuePush(ctxt, arg1);
8900 xmlXPathFreeObject(arg2);
8901 /* optimizer */
8902 if (total > cur)
8903 xmlXPathCompSwap(op);
8904 return (total + cur);
8905 case XPATH_OP_ROOT:
8906 xmlXPathRoot(ctxt);
8907 return (0);
8908 case XPATH_OP_NODE:
8909 if (op->ch1 != -1)
8910 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8911 if (op->ch2 != -1)
8912 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8913 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
8914 return (total);
8915 case XPATH_OP_RESET:
8916 if (op->ch1 != -1)
8917 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8918 if (op->ch2 != -1)
8919 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
8920 ctxt->context->node = NULL;
8921 return (total);
8922 case XPATH_OP_COLLECT:{
8923 if (op->ch1 == -1)
8924 return (0);
8925
8926 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8927
8928 /*
8929 * Optimization for [n] selection where n is a number
8930 */
8931 if ((op->ch2 != -1) &&
8932 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
8933 (comp->steps[op->ch2].ch1 == -1) &&
8934 (comp->steps[op->ch2].ch2 != -1) &&
8935 (comp->steps[comp->steps[op->ch2].ch2].op ==
8936 XPATH_OP_VALUE)) {
8937 xmlXPathObjectPtr val;
8938
8939 val = comp->steps[comp->steps[op->ch2].ch2].value4;
8940 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
8941 int indx = (int) val->floatval;
8942
8943 if (val->floatval == (float) indx) {
8944 total +=
8945 xmlXPathNodeCollectAndTestNth(ctxt, op,
8946 indx, NULL,
8947 last);
8948 return (total);
8949 }
8950 }
8951 }
8952 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
8953 return (total);
8954 }
8955 case XPATH_OP_VALUE:
8956 valuePush(ctxt,
8957 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
8958 return (0);
8959 case XPATH_OP_SORT:
8960 if (op->ch1 != -1)
8961 total +=
8962 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
8963 last);
8964 if ((ctxt->value != NULL)
8965 && (ctxt->value->type == XPATH_NODESET)
8966 && (ctxt->value->nodesetval != NULL))
8967 xmlXPathNodeSetSort(ctxt->value->nodesetval);
8968 return (total);
8969 default:
8970 return (xmlXPathCompOpEval(ctxt, op));
8971 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008972}
8973
Owen Taylor3473f882001-02-23 17:55:21 +00008974/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008975 * xmlXPathCompOpEval:
8976 * @ctxt: the XPath parser context with the compiled expression
8977 * @op: an XPath compiled operation
8978 *
8979 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008980 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008981 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008982static int
8983xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
8984{
8985 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008986 int equal, ret;
8987 xmlXPathCompExprPtr comp;
8988 xmlXPathObjectPtr arg1, arg2;
8989
8990 comp = ctxt->comp;
8991 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008992 case XPATH_OP_END:
8993 return (0);
8994 case XPATH_OP_AND:
8995 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
8996 xmlXPathBooleanFunction(ctxt, 1);
8997 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
8998 return (total);
8999 arg2 = valuePop(ctxt);
9000 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9001 xmlXPathBooleanFunction(ctxt, 1);
9002 arg1 = valuePop(ctxt);
9003 arg1->boolval &= arg2->boolval;
9004 valuePush(ctxt, arg1);
9005 xmlXPathFreeObject(arg2);
9006 return (total);
9007 case XPATH_OP_OR:
9008 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9009 xmlXPathBooleanFunction(ctxt, 1);
9010 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9011 return (total);
9012 arg2 = valuePop(ctxt);
9013 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9014 xmlXPathBooleanFunction(ctxt, 1);
9015 arg1 = valuePop(ctxt);
9016 arg1->boolval |= arg2->boolval;
9017 valuePush(ctxt, arg1);
9018 xmlXPathFreeObject(arg2);
9019 return (total);
9020 case XPATH_OP_EQUAL:
9021 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9022 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9023 equal = xmlXPathEqualValues(ctxt);
9024 if (op->value)
9025 valuePush(ctxt, xmlXPathNewBoolean(equal));
9026 else
9027 valuePush(ctxt, xmlXPathNewBoolean(!equal));
9028 return (total);
9029 case XPATH_OP_CMP:
9030 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9031 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9032 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
9033 valuePush(ctxt, xmlXPathNewBoolean(ret));
9034 return (total);
9035 case XPATH_OP_PLUS:
9036 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9037 if (op->ch2 != -1)
9038 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9039 if (op->value == 0)
9040 xmlXPathSubValues(ctxt);
9041 else if (op->value == 1)
9042 xmlXPathAddValues(ctxt);
9043 else if (op->value == 2)
9044 xmlXPathValueFlipSign(ctxt);
9045 else if (op->value == 3) {
9046 CAST_TO_NUMBER;
9047 CHECK_TYPE0(XPATH_NUMBER);
9048 }
9049 return (total);
9050 case XPATH_OP_MULT:
9051 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9052 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9053 if (op->value == 0)
9054 xmlXPathMultValues(ctxt);
9055 else if (op->value == 1)
9056 xmlXPathDivValues(ctxt);
9057 else if (op->value == 2)
9058 xmlXPathModValues(ctxt);
9059 return (total);
9060 case XPATH_OP_UNION:
9061 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9062 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9063 CHECK_TYPE0(XPATH_NODESET);
9064 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009065
Daniel Veillardf06307e2001-07-03 10:35:50 +00009066 CHECK_TYPE0(XPATH_NODESET);
9067 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009068
Daniel Veillardf06307e2001-07-03 10:35:50 +00009069 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9070 arg2->nodesetval);
9071 valuePush(ctxt, arg1);
9072 xmlXPathFreeObject(arg2);
9073 return (total);
9074 case XPATH_OP_ROOT:
9075 xmlXPathRoot(ctxt);
9076 return (total);
9077 case XPATH_OP_NODE:
9078 if (op->ch1 != -1)
9079 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9080 if (op->ch2 != -1)
9081 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9082 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9083 return (total);
9084 case XPATH_OP_RESET:
9085 if (op->ch1 != -1)
9086 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9087 if (op->ch2 != -1)
9088 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9089 ctxt->context->node = NULL;
9090 return (total);
9091 case XPATH_OP_COLLECT:{
9092 if (op->ch1 == -1)
9093 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009094
Daniel Veillardf06307e2001-07-03 10:35:50 +00009095 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009096
Daniel Veillardf06307e2001-07-03 10:35:50 +00009097 /*
9098 * Optimization for [n] selection where n is a number
9099 */
9100 if ((op->ch2 != -1) &&
9101 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9102 (comp->steps[op->ch2].ch1 == -1) &&
9103 (comp->steps[op->ch2].ch2 != -1) &&
9104 (comp->steps[comp->steps[op->ch2].ch2].op ==
9105 XPATH_OP_VALUE)) {
9106 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +00009107
Daniel Veillardf06307e2001-07-03 10:35:50 +00009108 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9109 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9110 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009111
Daniel Veillardf06307e2001-07-03 10:35:50 +00009112 if (val->floatval == (float) indx) {
9113 total +=
9114 xmlXPathNodeCollectAndTestNth(ctxt, op,
9115 indx, NULL,
9116 NULL);
9117 return (total);
9118 }
9119 }
9120 }
9121 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
9122 return (total);
9123 }
9124 case XPATH_OP_VALUE:
9125 valuePush(ctxt,
9126 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9127 return (total);
9128 case XPATH_OP_VARIABLE:{
9129 if (op->ch1 != -1)
9130 total +=
9131 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9132 if (op->value5 == NULL)
9133 valuePush(ctxt,
9134 xmlXPathVariableLookup(ctxt->context,
9135 op->value4));
9136 else {
9137 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009138
Daniel Veillardf06307e2001-07-03 10:35:50 +00009139 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9140 if (URI == NULL) {
9141 xmlGenericError(xmlGenericErrorContext,
9142 "xmlXPathRunEval: variable %s bound to undefined prefix %s\n",
9143 op->value4, op->value5);
9144 return (total);
9145 }
9146 valuePush(ctxt,
9147 xmlXPathVariableLookupNS(ctxt->context,
9148 op->value4, URI));
9149 }
9150 return (total);
9151 }
9152 case XPATH_OP_FUNCTION:{
9153 xmlXPathFunction func;
9154 const xmlChar *oldFunc, *oldFuncURI;
9155
9156 if (op->ch1 != -1)
9157 total +=
9158 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9159 if (op->cache != NULL)
9160 func = (xmlXPathFunction) op->cache;
9161 else {
9162 const xmlChar *URI = NULL;
9163
9164 if (op->value5 == NULL)
9165 func =
9166 xmlXPathFunctionLookup(ctxt->context,
9167 op->value4);
9168 else {
9169 URI = xmlXPathNsLookup(ctxt->context, op->value5);
9170 if (URI == NULL) {
9171 xmlGenericError(xmlGenericErrorContext,
9172 "xmlXPathRunEval: function %s bound to undefined prefix %s\n",
9173 op->value4, op->value5);
9174 return (total);
9175 }
9176 func = xmlXPathFunctionLookupNS(ctxt->context,
9177 op->value4, URI);
9178 }
9179 if (func == NULL) {
9180 xmlGenericError(xmlGenericErrorContext,
9181 "xmlXPathRunEval: function %s not found\n",
9182 op->value4);
9183 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
9184 return (total);
9185 }
9186 op->cache = (void *) func;
9187 op->cacheURI = (void *) URI;
9188 }
9189 oldFunc = ctxt->context->function;
9190 oldFuncURI = ctxt->context->functionURI;
9191 ctxt->context->function = op->value4;
9192 ctxt->context->functionURI = op->cacheURI;
9193 func(ctxt, op->value);
9194 ctxt->context->function = oldFunc;
9195 ctxt->context->functionURI = oldFuncURI;
9196 return (total);
9197 }
9198 case XPATH_OP_ARG:
9199 if (op->ch1 != -1)
9200 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9201 if (op->ch2 != -1)
9202 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9203 return (total);
9204 case XPATH_OP_PREDICATE:
9205 case XPATH_OP_FILTER:{
9206 xmlXPathObjectPtr res;
9207 xmlXPathObjectPtr obj, tmp;
9208 xmlNodeSetPtr newset = NULL;
9209 xmlNodeSetPtr oldset;
9210 xmlNodePtr oldnode;
9211 int i;
9212
9213 /*
9214 * Optimization for ()[1] selection i.e. the first elem
9215 */
9216 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9217 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9218 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
9219 xmlXPathObjectPtr val;
9220
9221 val = comp->steps[op->ch2].value4;
9222 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
9223 (val->floatval == 1.0)) {
9224 xmlNodePtr first = NULL;
9225
9226 total +=
9227 xmlXPathCompOpEvalFirst(ctxt,
9228 &comp->steps[op->ch1],
9229 &first);
9230 /*
9231 * The nodeset should be in document order,
9232 * Keep only the first value
9233 */
9234 if ((ctxt->value != NULL) &&
9235 (ctxt->value->type == XPATH_NODESET) &&
9236 (ctxt->value->nodesetval != NULL) &&
9237 (ctxt->value->nodesetval->nodeNr > 1))
9238 ctxt->value->nodesetval->nodeNr = 1;
9239 return (total);
9240 }
9241 }
9242 /*
9243 * Optimization for ()[last()] selection i.e. the last elem
9244 */
9245 if ((op->ch1 != -1) && (op->ch2 != -1) &&
9246 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
9247 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
9248 int f = comp->steps[op->ch2].ch1;
9249
9250 if ((f != -1) &&
9251 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
9252 (comp->steps[f].value5 == NULL) &&
9253 (comp->steps[f].value == 0) &&
9254 (comp->steps[f].value4 != NULL) &&
9255 (xmlStrEqual
9256 (comp->steps[f].value4, BAD_CAST "last"))) {
9257 xmlNodePtr last = NULL;
9258
9259 total +=
9260 xmlXPathCompOpEvalLast(ctxt,
9261 &comp->steps[op->ch1],
9262 &last);
9263 /*
9264 * The nodeset should be in document order,
9265 * Keep only the last value
9266 */
9267 if ((ctxt->value != NULL) &&
9268 (ctxt->value->type == XPATH_NODESET) &&
9269 (ctxt->value->nodesetval != NULL) &&
9270 (ctxt->value->nodesetval->nodeTab != NULL) &&
9271 (ctxt->value->nodesetval->nodeNr > 1)) {
9272 ctxt->value->nodesetval->nodeTab[0] =
9273 ctxt->value->nodesetval->nodeTab[ctxt->
9274 value->
9275 nodesetval->
9276 nodeNr -
9277 1];
9278 ctxt->value->nodesetval->nodeNr = 1;
9279 }
9280 return (total);
9281 }
9282 }
9283
9284 if (op->ch1 != -1)
9285 total +=
9286 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9287 if (op->ch2 == -1)
9288 return (total);
9289 if (ctxt->value == NULL)
9290 return (total);
9291
9292 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009293
9294#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009295 /*
9296 * Hum are we filtering the result of an XPointer expression
9297 */
9298 if (ctxt->value->type == XPATH_LOCATIONSET) {
9299 xmlLocationSetPtr newlocset = NULL;
9300 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009301
Daniel Veillardf06307e2001-07-03 10:35:50 +00009302 /*
9303 * Extract the old locset, and then evaluate the result of the
9304 * expression for all the element in the locset. use it to grow
9305 * up a new locset.
9306 */
9307 CHECK_TYPE0(XPATH_LOCATIONSET);
9308 obj = valuePop(ctxt);
9309 oldlocset = obj->user;
9310 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009311
Daniel Veillardf06307e2001-07-03 10:35:50 +00009312 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
9313 ctxt->context->contextSize = 0;
9314 ctxt->context->proximityPosition = 0;
9315 if (op->ch2 != -1)
9316 total +=
9317 xmlXPathCompOpEval(ctxt,
9318 &comp->steps[op->ch2]);
9319 res = valuePop(ctxt);
9320 if (res != NULL)
9321 xmlXPathFreeObject(res);
9322 valuePush(ctxt, obj);
9323 CHECK_ERROR0;
9324 return (total);
9325 }
9326 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009327
Daniel Veillardf06307e2001-07-03 10:35:50 +00009328 for (i = 0; i < oldlocset->locNr; i++) {
9329 /*
9330 * Run the evaluation with a node list made of a
9331 * single item in the nodelocset.
9332 */
9333 ctxt->context->node = oldlocset->locTab[i]->user;
9334 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9335 valuePush(ctxt, tmp);
9336 ctxt->context->contextSize = oldlocset->locNr;
9337 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009338
Daniel Veillardf06307e2001-07-03 10:35:50 +00009339 if (op->ch2 != -1)
9340 total +=
9341 xmlXPathCompOpEval(ctxt,
9342 &comp->steps[op->ch2]);
9343 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009344
Daniel Veillardf06307e2001-07-03 10:35:50 +00009345 /*
9346 * The result of the evaluation need to be tested to
9347 * decided whether the filter succeeded or not
9348 */
9349 res = valuePop(ctxt);
9350 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9351 xmlXPtrLocationSetAdd(newlocset,
9352 xmlXPathObjectCopy
9353 (oldlocset->locTab[i]));
9354 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009355
Daniel Veillardf06307e2001-07-03 10:35:50 +00009356 /*
9357 * Cleanup
9358 */
9359 if (res != NULL)
9360 xmlXPathFreeObject(res);
9361 if (ctxt->value == tmp) {
9362 res = valuePop(ctxt);
9363 xmlXPathFreeObject(res);
9364 }
9365
9366 ctxt->context->node = NULL;
9367 }
9368
9369 /*
9370 * The result is used as the new evaluation locset.
9371 */
9372 xmlXPathFreeObject(obj);
9373 ctxt->context->node = NULL;
9374 ctxt->context->contextSize = -1;
9375 ctxt->context->proximityPosition = -1;
9376 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
9377 ctxt->context->node = oldnode;
9378 return (total);
9379 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009380#endif /* LIBXML_XPTR_ENABLED */
9381
Daniel Veillardf06307e2001-07-03 10:35:50 +00009382 /*
9383 * Extract the old set, and then evaluate the result of the
9384 * expression for all the element in the set. use it to grow
9385 * up a new set.
9386 */
9387 CHECK_TYPE0(XPATH_NODESET);
9388 obj = valuePop(ctxt);
9389 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00009390
Daniel Veillardf06307e2001-07-03 10:35:50 +00009391 oldnode = ctxt->context->node;
9392 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009393
Daniel Veillardf06307e2001-07-03 10:35:50 +00009394 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
9395 ctxt->context->contextSize = 0;
9396 ctxt->context->proximityPosition = 0;
9397 if (op->ch2 != -1)
9398 total +=
9399 xmlXPathCompOpEval(ctxt,
9400 &comp->steps[op->ch2]);
9401 res = valuePop(ctxt);
9402 if (res != NULL)
9403 xmlXPathFreeObject(res);
9404 valuePush(ctxt, obj);
9405 ctxt->context->node = oldnode;
9406 CHECK_ERROR0;
9407 } else {
9408 /*
9409 * Initialize the new set.
9410 */
9411 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009412
Daniel Veillardf06307e2001-07-03 10:35:50 +00009413 for (i = 0; i < oldset->nodeNr; i++) {
9414 /*
9415 * Run the evaluation with a node list made of
9416 * a single item in the nodeset.
9417 */
9418 ctxt->context->node = oldset->nodeTab[i];
9419 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9420 valuePush(ctxt, tmp);
9421 ctxt->context->contextSize = oldset->nodeNr;
9422 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009423
Daniel Veillardf06307e2001-07-03 10:35:50 +00009424 if (op->ch2 != -1)
9425 total +=
9426 xmlXPathCompOpEval(ctxt,
9427 &comp->steps[op->ch2]);
9428 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009429
Daniel Veillardf06307e2001-07-03 10:35:50 +00009430 /*
9431 * The result of the evaluation need to be tested to
9432 * decided whether the filter succeeded or not
9433 */
9434 res = valuePop(ctxt);
9435 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
9436 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
9437 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009438
Daniel Veillardf06307e2001-07-03 10:35:50 +00009439 /*
9440 * Cleanup
9441 */
9442 if (res != NULL)
9443 xmlXPathFreeObject(res);
9444 if (ctxt->value == tmp) {
9445 res = valuePop(ctxt);
9446 xmlXPathFreeObject(res);
9447 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009448
Daniel Veillardf06307e2001-07-03 10:35:50 +00009449 ctxt->context->node = NULL;
9450 }
9451
9452 /*
9453 * The result is used as the new evaluation set.
9454 */
9455 xmlXPathFreeObject(obj);
9456 ctxt->context->node = NULL;
9457 ctxt->context->contextSize = -1;
9458 ctxt->context->proximityPosition = -1;
9459 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
9460 }
9461 ctxt->context->node = oldnode;
9462 return (total);
9463 }
9464 case XPATH_OP_SORT:
9465 if (op->ch1 != -1)
9466 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9467 if ((ctxt->value != NULL) &&
9468 (ctxt->value->type == XPATH_NODESET) &&
9469 (ctxt->value->nodesetval != NULL))
9470 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9471 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009472#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +00009473 case XPATH_OP_RANGETO:{
9474 xmlXPathObjectPtr range;
9475 xmlXPathObjectPtr res, obj;
9476 xmlXPathObjectPtr tmp;
9477 xmlLocationSetPtr newset = NULL;
9478 xmlNodeSetPtr oldset;
9479 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009480
Daniel Veillardf06307e2001-07-03 10:35:50 +00009481 if (op->ch1 != -1)
9482 total +=
9483 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9484 if (op->ch2 == -1)
9485 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009486
Daniel Veillardf06307e2001-07-03 10:35:50 +00009487 CHECK_TYPE0(XPATH_NODESET);
9488 obj = valuePop(ctxt);
9489 oldset = obj->nodesetval;
9490 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009491
Daniel Veillardf06307e2001-07-03 10:35:50 +00009492 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009493
Daniel Veillardf06307e2001-07-03 10:35:50 +00009494 if (oldset != NULL) {
9495 for (i = 0; i < oldset->nodeNr; i++) {
9496 /*
9497 * Run the evaluation with a node list made of a single item
9498 * in the nodeset.
9499 */
9500 ctxt->context->node = oldset->nodeTab[i];
9501 tmp = xmlXPathNewNodeSet(ctxt->context->node);
9502 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009503
Daniel Veillardf06307e2001-07-03 10:35:50 +00009504 if (op->ch2 != -1)
9505 total +=
9506 xmlXPathCompOpEval(ctxt,
9507 &comp->steps[op->ch2]);
9508 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009509
Daniel Veillardf06307e2001-07-03 10:35:50 +00009510 /*
9511 * The result of the evaluation need to be tested to
9512 * decided whether the filter succeeded or not
9513 */
9514 res = valuePop(ctxt);
9515 range =
9516 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
9517 res);
9518 if (range != NULL) {
9519 xmlXPtrLocationSetAdd(newset, range);
9520 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009521
Daniel Veillardf06307e2001-07-03 10:35:50 +00009522 /*
9523 * Cleanup
9524 */
9525 if (res != NULL)
9526 xmlXPathFreeObject(res);
9527 if (ctxt->value == tmp) {
9528 res = valuePop(ctxt);
9529 xmlXPathFreeObject(res);
9530 }
9531
9532 ctxt->context->node = NULL;
9533 }
9534 }
9535
9536 /*
9537 * The result is used as the new evaluation set.
9538 */
9539 xmlXPathFreeObject(obj);
9540 ctxt->context->node = NULL;
9541 ctxt->context->contextSize = -1;
9542 ctxt->context->proximityPosition = -1;
9543 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
9544 return (total);
9545 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009546#endif /* LIBXML_XPTR_ENABLED */
9547 }
9548 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009549 "XPath: unknown precompiled operation %d\n", op->op);
9550 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009551}
9552
9553/**
9554 * xmlXPathRunEval:
9555 * @ctxt: the XPath parser context with the compiled expression
9556 *
9557 * Evaluate the Precompiled XPath expression in the given context.
9558 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009559static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009560xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
9561 xmlXPathCompExprPtr comp;
9562
9563 if ((ctxt == NULL) || (ctxt->comp == NULL))
9564 return;
9565
9566 if (ctxt->valueTab == NULL) {
9567 /* Allocate the value stack */
9568 ctxt->valueTab = (xmlXPathObjectPtr *)
9569 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
9570 if (ctxt->valueTab == NULL) {
9571 xmlFree(ctxt);
9572 xmlGenericError(xmlGenericErrorContext,
9573 "xmlXPathRunEval: out of memory\n");
9574 return;
9575 }
9576 ctxt->valueNr = 0;
9577 ctxt->valueMax = 10;
9578 ctxt->value = NULL;
9579 }
9580 comp = ctxt->comp;
9581 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
9582}
9583
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009584/************************************************************************
9585 * *
9586 * Public interfaces *
9587 * *
9588 ************************************************************************/
9589
9590/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009591 * xmlXPathEvalPredicate:
9592 * @ctxt: the XPath context
9593 * @res: the Predicate Expression evaluation result
9594 *
9595 * Evaluate a predicate result for the current node.
9596 * A PredicateExpr is evaluated by evaluating the Expr and converting
9597 * the result to a boolean. If the result is a number, the result will
9598 * be converted to true if the number is equal to the position of the
9599 * context node in the context node list (as returned by the position
9600 * function) and will be converted to false otherwise; if the result
9601 * is not a number, then the result will be converted as if by a call
9602 * to the boolean function.
9603 *
9604 * Return 1 if predicate is true, 0 otherwise
9605 */
9606int
9607xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
9608 if (res == NULL) return(0);
9609 switch (res->type) {
9610 case XPATH_BOOLEAN:
9611 return(res->boolval);
9612 case XPATH_NUMBER:
9613 return(res->floatval == ctxt->proximityPosition);
9614 case XPATH_NODESET:
9615 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009616 if (res->nodesetval == NULL)
9617 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009618 return(res->nodesetval->nodeNr != 0);
9619 case XPATH_STRING:
9620 return((res->stringval != NULL) &&
9621 (xmlStrlen(res->stringval) != 0));
9622 default:
9623 STRANGE
9624 }
9625 return(0);
9626}
9627
9628/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009629 * xmlXPathEvaluatePredicateResult:
9630 * @ctxt: the XPath Parser context
9631 * @res: the Predicate Expression evaluation result
9632 *
9633 * Evaluate a predicate result for the current node.
9634 * A PredicateExpr is evaluated by evaluating the Expr and converting
9635 * the result to a boolean. If the result is a number, the result will
9636 * be converted to true if the number is equal to the position of the
9637 * context node in the context node list (as returned by the position
9638 * function) and will be converted to false otherwise; if the result
9639 * is not a number, then the result will be converted as if by a call
9640 * to the boolean function.
9641 *
9642 * Return 1 if predicate is true, 0 otherwise
9643 */
9644int
9645xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
9646 xmlXPathObjectPtr res) {
9647 if (res == NULL) return(0);
9648 switch (res->type) {
9649 case XPATH_BOOLEAN:
9650 return(res->boolval);
9651 case XPATH_NUMBER:
9652 return(res->floatval == ctxt->context->proximityPosition);
9653 case XPATH_NODESET:
9654 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +00009655 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +00009656 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009657 return(res->nodesetval->nodeNr != 0);
9658 case XPATH_STRING:
9659 return((res->stringval != NULL) &&
9660 (xmlStrlen(res->stringval) != 0));
9661 default:
9662 STRANGE
9663 }
9664 return(0);
9665}
9666
9667/**
9668 * xmlXPathCompile:
9669 * @str: the XPath expression
9670 *
9671 * Compile an XPath expression
9672 *
9673 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9674 * the caller has to free the object.
9675 */
9676xmlXPathCompExprPtr
9677xmlXPathCompile(const xmlChar *str) {
9678 xmlXPathParserContextPtr ctxt;
9679 xmlXPathCompExprPtr comp;
9680
9681 xmlXPathInit();
9682
9683 ctxt = xmlXPathNewParserContext(str, NULL);
9684 xmlXPathCompileExpr(ctxt);
9685
Daniel Veillard40af6492001-04-22 08:50:55 +00009686 if (*ctxt->cur != 0) {
9687 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9688 comp = NULL;
9689 } else {
9690 comp = ctxt->comp;
9691 ctxt->comp = NULL;
9692 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009693 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009694#ifdef DEBUG_EVAL_COUNTS
9695 if (comp != NULL) {
9696 comp->string = xmlStrdup(str);
9697 comp->nb = 0;
9698 }
9699#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009700 return(comp);
9701}
9702
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009703/**
9704 * xmlXPathCompiledEval:
9705 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +00009706 * @ctx: the XPath context
9707 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009708 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +00009709 *
9710 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9711 * the caller has to free the object.
9712 */
9713xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009714xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +00009715 xmlXPathParserContextPtr ctxt;
9716 xmlXPathObjectPtr res, tmp, init = NULL;
9717 int stack = 0;
9718
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009719 if ((comp == NULL) || (ctx == NULL))
9720 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00009721 xmlXPathInit();
9722
9723 CHECK_CONTEXT(ctx)
9724
Daniel Veillardf06307e2001-07-03 10:35:50 +00009725#ifdef DEBUG_EVAL_COUNTS
9726 comp->nb++;
9727 if ((comp->string != NULL) && (comp->nb > 100)) {
9728 fprintf(stderr, "100 x %s\n", comp->string);
9729 comp->nb = 0;
9730 }
9731#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009732 ctxt = xmlXPathCompParserContext(comp, ctx);
9733 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009734
9735 if (ctxt->value == NULL) {
9736 xmlGenericError(xmlGenericErrorContext,
9737 "xmlXPathEval: evaluation failed\n");
9738 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009739 } else {
9740 res = valuePop(ctxt);
9741 }
9742
Daniel Veillardf06307e2001-07-03 10:35:50 +00009743
Owen Taylor3473f882001-02-23 17:55:21 +00009744 do {
9745 tmp = valuePop(ctxt);
9746 if (tmp != NULL) {
9747 if (tmp != init)
9748 stack++;
9749 xmlXPathFreeObject(tmp);
9750 }
9751 } while (tmp != NULL);
9752 if ((stack != 0) && (res != NULL)) {
9753 xmlGenericError(xmlGenericErrorContext,
9754 "xmlXPathEval: %d object left on the stack\n",
9755 stack);
9756 }
9757 if (ctxt->error != XPATH_EXPRESSION_OK) {
9758 xmlXPathFreeObject(res);
9759 res = NULL;
9760 }
9761
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009762
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009763 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009764 xmlXPathFreeParserContext(ctxt);
9765 return(res);
9766}
9767
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009768/**
9769 * xmlXPathEvalExpr:
9770 * @ctxt: the XPath Parser context
9771 *
9772 * Parse and evaluate an XPath expression in the given context,
9773 * then push the result on the context stack
9774 */
9775void
9776xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
9777 xmlXPathCompileExpr(ctxt);
9778 xmlXPathRunEval(ctxt);
9779}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009780
9781/**
9782 * xmlXPathEval:
9783 * @str: the XPath expression
9784 * @ctx: the XPath context
9785 *
9786 * Evaluate the XPath Location Path in the given context.
9787 *
9788 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
9789 * the caller has to free the object.
9790 */
9791xmlXPathObjectPtr
9792xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
9793 xmlXPathParserContextPtr ctxt;
9794 xmlXPathObjectPtr res, tmp, init = NULL;
9795 int stack = 0;
9796
9797 xmlXPathInit();
9798
9799 CHECK_CONTEXT(ctx)
9800
9801 ctxt = xmlXPathNewParserContext(str, ctx);
9802 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009803
9804 if (ctxt->value == NULL) {
9805 xmlGenericError(xmlGenericErrorContext,
9806 "xmlXPathEval: evaluation failed\n");
9807 res = NULL;
9808 } else if (*ctxt->cur != 0) {
9809 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9810 res = NULL;
9811 } else {
9812 res = valuePop(ctxt);
9813 }
9814
9815 do {
9816 tmp = valuePop(ctxt);
9817 if (tmp != NULL) {
9818 if (tmp != init)
9819 stack++;
9820 xmlXPathFreeObject(tmp);
9821 }
9822 } while (tmp != NULL);
9823 if ((stack != 0) && (res != NULL)) {
9824 xmlGenericError(xmlGenericErrorContext,
9825 "xmlXPathEval: %d object left on the stack\n",
9826 stack);
9827 }
9828 if (ctxt->error != XPATH_EXPRESSION_OK) {
9829 xmlXPathFreeObject(res);
9830 res = NULL;
9831 }
9832
Owen Taylor3473f882001-02-23 17:55:21 +00009833 xmlXPathFreeParserContext(ctxt);
9834 return(res);
9835}
9836
9837/**
9838 * xmlXPathEvalExpression:
9839 * @str: the XPath expression
9840 * @ctxt: the XPath context
9841 *
9842 * Evaluate the XPath expression in the given context.
9843 *
9844 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
9845 * the caller has to free the object.
9846 */
9847xmlXPathObjectPtr
9848xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
9849 xmlXPathParserContextPtr pctxt;
9850 xmlXPathObjectPtr res, tmp;
9851 int stack = 0;
9852
9853 xmlXPathInit();
9854
9855 CHECK_CONTEXT(ctxt)
9856
9857 pctxt = xmlXPathNewParserContext(str, ctxt);
9858 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009859
9860 if (*pctxt->cur != 0) {
9861 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
9862 res = NULL;
9863 } else {
9864 res = valuePop(pctxt);
9865 }
9866 do {
9867 tmp = valuePop(pctxt);
9868 if (tmp != NULL) {
9869 xmlXPathFreeObject(tmp);
9870 stack++;
9871 }
9872 } while (tmp != NULL);
9873 if ((stack != 0) && (res != NULL)) {
9874 xmlGenericError(xmlGenericErrorContext,
9875 "xmlXPathEvalExpression: %d object left on the stack\n",
9876 stack);
9877 }
9878 xmlXPathFreeParserContext(pctxt);
9879 return(res);
9880}
9881
9882/**
9883 * xmlXPathRegisterAllFunctions:
9884 * @ctxt: the XPath context
9885 *
9886 * Registers all default XPath functions in this context
9887 */
9888void
9889xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
9890{
9891 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
9892 xmlXPathBooleanFunction);
9893 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
9894 xmlXPathCeilingFunction);
9895 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
9896 xmlXPathCountFunction);
9897 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
9898 xmlXPathConcatFunction);
9899 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
9900 xmlXPathContainsFunction);
9901 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
9902 xmlXPathIdFunction);
9903 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
9904 xmlXPathFalseFunction);
9905 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
9906 xmlXPathFloorFunction);
9907 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
9908 xmlXPathLastFunction);
9909 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
9910 xmlXPathLangFunction);
9911 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
9912 xmlXPathLocalNameFunction);
9913 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
9914 xmlXPathNotFunction);
9915 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
9916 xmlXPathNameFunction);
9917 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
9918 xmlXPathNamespaceURIFunction);
9919 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
9920 xmlXPathNormalizeFunction);
9921 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
9922 xmlXPathNumberFunction);
9923 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
9924 xmlXPathPositionFunction);
9925 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
9926 xmlXPathRoundFunction);
9927 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
9928 xmlXPathStringFunction);
9929 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
9930 xmlXPathStringLengthFunction);
9931 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
9932 xmlXPathStartsWithFunction);
9933 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
9934 xmlXPathSubstringFunction);
9935 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
9936 xmlXPathSubstringBeforeFunction);
9937 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
9938 xmlXPathSubstringAfterFunction);
9939 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
9940 xmlXPathSumFunction);
9941 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
9942 xmlXPathTrueFunction);
9943 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
9944 xmlXPathTranslateFunction);
9945}
9946
9947#endif /* LIBXML_XPATH_ENABLED */