[LIBXML2] Update to version 2.9.8. CORE-15280
[reactos.git] / sdk / lib / 3rdparty / libxml2 / xpath.c
1 /*
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 *f
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 *
13 * Author: daniel@veillard.com
14 *
15 */
16
17 /* To avoid EBCDIC trouble when parsing on zOS */
18 #if defined(__MVS__)
19 #pragma convert("ISO8859-1")
20 #endif
21
22 #define IN_LIBXML
23 #include "libxml.h"
24
25 #include <limits.h>
26 #include <string.h>
27 #include <stddef.h>
28
29 #ifdef HAVE_SYS_TYPES_H
30 #include <sys/types.h>
31 #endif
32 #ifdef HAVE_MATH_H
33 #include <math.h>
34 #endif
35 #ifdef HAVE_FLOAT_H
36 #include <float.h>
37 #endif
38 #ifdef HAVE_CTYPE_H
39 #include <ctype.h>
40 #endif
41 #ifdef HAVE_SIGNAL_H
42 #include <signal.h>
43 #endif
44
45 #include <libxml/xmlmemory.h>
46 #include <libxml/tree.h>
47 #include <libxml/valid.h>
48 #include <libxml/xpath.h>
49 #include <libxml/xpathInternals.h>
50 #include <libxml/parserInternals.h>
51 #include <libxml/hash.h>
52 #ifdef LIBXML_XPTR_ENABLED
53 #include <libxml/xpointer.h>
54 #endif
55 #ifdef LIBXML_DEBUG_ENABLED
56 #include <libxml/debugXML.h>
57 #endif
58 #include <libxml/xmlerror.h>
59 #include <libxml/threads.h>
60 #include <libxml/globals.h>
61 #ifdef LIBXML_PATTERN_ENABLED
62 #include <libxml/pattern.h>
63 #endif
64
65 #include "buf.h"
66
67 #ifdef LIBXML_PATTERN_ENABLED
68 #define XPATH_STREAMING
69 #endif
70
71 #define TODO \
72 xmlGenericError(xmlGenericErrorContext, \
73 "Unimplemented block at %s:%d\n", \
74 __FILE__, __LINE__);
75
76 /**
77 * WITH_TIM_SORT:
78 *
79 * Use the Timsort algorithm provided in timsort.h to sort
80 * nodeset as this is a great improvement over the old Shell sort
81 * used in xmlXPathNodeSetSort()
82 */
83 #define WITH_TIM_SORT
84
85 /*
86 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
87 * If defined, this will use xmlXPathCmpNodesExt() instead of
88 * xmlXPathCmpNodes(). The new function is optimized comparison of
89 * non-element nodes; actually it will speed up comparison only if
90 * xmlXPathOrderDocElems() was called in order to index the elements of
91 * a tree in document order; Libxslt does such an indexing, thus it will
92 * benefit from this optimization.
93 */
94 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
95
96 /*
97 * XP_OPTIMIZED_FILTER_FIRST:
98 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
99 * in a way, that it stop evaluation at the first node.
100 */
101 #define XP_OPTIMIZED_FILTER_FIRST
102
103 /*
104 * XP_DEBUG_OBJ_USAGE:
105 * Internal flag to enable tracking of how much XPath objects have been
106 * created.
107 */
108 /* #define XP_DEBUG_OBJ_USAGE */
109
110 /*
111 * XPATH_MAX_STEPS:
112 * when compiling an XPath expression we arbitrary limit the maximum
113 * number of step operation in the compiled expression. 1000000 is
114 * an insanely large value which should never be reached under normal
115 * circumstances
116 */
117 #define XPATH_MAX_STEPS 1000000
118
119 /*
120 * XPATH_MAX_STACK_DEPTH:
121 * when evaluating an XPath expression we arbitrary limit the maximum
122 * number of object allowed to be pushed on the stack. 1000000 is
123 * an insanely large value which should never be reached under normal
124 * circumstances
125 */
126 #define XPATH_MAX_STACK_DEPTH 1000000
127
128 /*
129 * XPATH_MAX_NODESET_LENGTH:
130 * when evaluating an XPath expression nodesets are created and we
131 * arbitrary limit the maximum length of those node set. 10000000 is
132 * an insanely large value which should never be reached under normal
133 * circumstances, one would first need to construct an in memory tree
134 * with more than 10 millions nodes.
135 */
136 #define XPATH_MAX_NODESET_LENGTH 10000000
137
138 /*
139 * TODO:
140 * There are a few spots where some tests are done which depend upon ascii
141 * data. These should be enhanced for full UTF8 support (see particularly
142 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
143 */
144
145 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
146 /**
147 * xmlXPathCmpNodesExt:
148 * @node1: the first node
149 * @node2: the second node
150 *
151 * Compare two nodes w.r.t document order.
152 * This one is optimized for handling of non-element nodes.
153 *
154 * Returns -2 in case of error 1 if first point < second point, 0 if
155 * it's the same node, -1 otherwise
156 */
157 static int
158 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
159 int depth1, depth2;
160 int misc = 0, precedence1 = 0, precedence2 = 0;
161 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
162 xmlNodePtr cur, root;
163 ptrdiff_t l1, l2;
164
165 if ((node1 == NULL) || (node2 == NULL))
166 return(-2);
167
168 if (node1 == node2)
169 return(0);
170
171 /*
172 * a couple of optimizations which will avoid computations in most cases
173 */
174 switch (node1->type) {
175 case XML_ELEMENT_NODE:
176 if (node2->type == XML_ELEMENT_NODE) {
177 if ((0 > (ptrdiff_t) node1->content) &&
178 (0 > (ptrdiff_t) node2->content) &&
179 (node1->doc == node2->doc))
180 {
181 l1 = -((ptrdiff_t) node1->content);
182 l2 = -((ptrdiff_t) node2->content);
183 if (l1 < l2)
184 return(1);
185 if (l1 > l2)
186 return(-1);
187 } else
188 goto turtle_comparison;
189 }
190 break;
191 case XML_ATTRIBUTE_NODE:
192 precedence1 = 1; /* element is owner */
193 miscNode1 = node1;
194 node1 = node1->parent;
195 misc = 1;
196 break;
197 case XML_TEXT_NODE:
198 case XML_CDATA_SECTION_NODE:
199 case XML_COMMENT_NODE:
200 case XML_PI_NODE: {
201 miscNode1 = node1;
202 /*
203 * Find nearest element node.
204 */
205 if (node1->prev != NULL) {
206 do {
207 node1 = node1->prev;
208 if (node1->type == XML_ELEMENT_NODE) {
209 precedence1 = 3; /* element in prev-sibl axis */
210 break;
211 }
212 if (node1->prev == NULL) {
213 precedence1 = 2; /* element is parent */
214 /*
215 * URGENT TODO: Are there any cases, where the
216 * parent of such a node is not an element node?
217 */
218 node1 = node1->parent;
219 break;
220 }
221 } while (1);
222 } else {
223 precedence1 = 2; /* element is parent */
224 node1 = node1->parent;
225 }
226 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
227 (0 <= (ptrdiff_t) node1->content)) {
228 /*
229 * Fallback for whatever case.
230 */
231 node1 = miscNode1;
232 precedence1 = 0;
233 } else
234 misc = 1;
235 }
236 break;
237 case XML_NAMESPACE_DECL:
238 /*
239 * TODO: why do we return 1 for namespace nodes?
240 */
241 return(1);
242 default:
243 break;
244 }
245 switch (node2->type) {
246 case XML_ELEMENT_NODE:
247 break;
248 case XML_ATTRIBUTE_NODE:
249 precedence2 = 1; /* element is owner */
250 miscNode2 = node2;
251 node2 = node2->parent;
252 misc = 1;
253 break;
254 case XML_TEXT_NODE:
255 case XML_CDATA_SECTION_NODE:
256 case XML_COMMENT_NODE:
257 case XML_PI_NODE: {
258 miscNode2 = node2;
259 if (node2->prev != NULL) {
260 do {
261 node2 = node2->prev;
262 if (node2->type == XML_ELEMENT_NODE) {
263 precedence2 = 3; /* element in prev-sibl axis */
264 break;
265 }
266 if (node2->prev == NULL) {
267 precedence2 = 2; /* element is parent */
268 node2 = node2->parent;
269 break;
270 }
271 } while (1);
272 } else {
273 precedence2 = 2; /* element is parent */
274 node2 = node2->parent;
275 }
276 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
277 (0 <= (ptrdiff_t) node2->content))
278 {
279 node2 = miscNode2;
280 precedence2 = 0;
281 } else
282 misc = 1;
283 }
284 break;
285 case XML_NAMESPACE_DECL:
286 return(1);
287 default:
288 break;
289 }
290 if (misc) {
291 if (node1 == node2) {
292 if (precedence1 == precedence2) {
293 /*
294 * The ugly case; but normally there aren't many
295 * adjacent non-element nodes around.
296 */
297 cur = miscNode2->prev;
298 while (cur != NULL) {
299 if (cur == miscNode1)
300 return(1);
301 if (cur->type == XML_ELEMENT_NODE)
302 return(-1);
303 cur = cur->prev;
304 }
305 return (-1);
306 } else {
307 /*
308 * Evaluate based on higher precedence wrt to the element.
309 * TODO: This assumes attributes are sorted before content.
310 * Is this 100% correct?
311 */
312 if (precedence1 < precedence2)
313 return(1);
314 else
315 return(-1);
316 }
317 }
318 /*
319 * Special case: One of the helper-elements is contained by the other.
320 * <foo>
321 * <node2>
322 * <node1>Text-1(precedence1 == 2)</node1>
323 * </node2>
324 * Text-6(precedence2 == 3)
325 * </foo>
326 */
327 if ((precedence2 == 3) && (precedence1 > 1)) {
328 cur = node1->parent;
329 while (cur) {
330 if (cur == node2)
331 return(1);
332 cur = cur->parent;
333 }
334 }
335 if ((precedence1 == 3) && (precedence2 > 1)) {
336 cur = node2->parent;
337 while (cur) {
338 if (cur == node1)
339 return(-1);
340 cur = cur->parent;
341 }
342 }
343 }
344
345 /*
346 * Speedup using document order if availble.
347 */
348 if ((node1->type == XML_ELEMENT_NODE) &&
349 (node2->type == XML_ELEMENT_NODE) &&
350 (0 > (ptrdiff_t) node1->content) &&
351 (0 > (ptrdiff_t) node2->content) &&
352 (node1->doc == node2->doc)) {
353
354 l1 = -((ptrdiff_t) node1->content);
355 l2 = -((ptrdiff_t) node2->content);
356 if (l1 < l2)
357 return(1);
358 if (l1 > l2)
359 return(-1);
360 }
361
362 turtle_comparison:
363
364 if (node1 == node2->prev)
365 return(1);
366 if (node1 == node2->next)
367 return(-1);
368 /*
369 * compute depth to root
370 */
371 for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
372 if (cur->parent == node1)
373 return(1);
374 depth2++;
375 }
376 root = cur;
377 for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
378 if (cur->parent == node2)
379 return(-1);
380 depth1++;
381 }
382 /*
383 * Distinct document (or distinct entities :-( ) case.
384 */
385 if (root != cur) {
386 return(-2);
387 }
388 /*
389 * get the nearest common ancestor.
390 */
391 while (depth1 > depth2) {
392 depth1--;
393 node1 = node1->parent;
394 }
395 while (depth2 > depth1) {
396 depth2--;
397 node2 = node2->parent;
398 }
399 while (node1->parent != node2->parent) {
400 node1 = node1->parent;
401 node2 = node2->parent;
402 /* should not happen but just in case ... */
403 if ((node1 == NULL) || (node2 == NULL))
404 return(-2);
405 }
406 /*
407 * Find who's first.
408 */
409 if (node1 == node2->prev)
410 return(1);
411 if (node1 == node2->next)
412 return(-1);
413 /*
414 * Speedup using document order if availble.
415 */
416 if ((node1->type == XML_ELEMENT_NODE) &&
417 (node2->type == XML_ELEMENT_NODE) &&
418 (0 > (ptrdiff_t) node1->content) &&
419 (0 > (ptrdiff_t) node2->content) &&
420 (node1->doc == node2->doc)) {
421
422 l1 = -((ptrdiff_t) node1->content);
423 l2 = -((ptrdiff_t) node2->content);
424 if (l1 < l2)
425 return(1);
426 if (l1 > l2)
427 return(-1);
428 }
429
430 for (cur = node1->next;cur != NULL;cur = cur->next)
431 if (cur == node2)
432 return(1);
433 return(-1); /* assume there is no sibling list corruption */
434 }
435 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
436
437 /*
438 * Wrapper for the Timsort argorithm from timsort.h
439 */
440 #ifdef WITH_TIM_SORT
441 #define SORT_NAME libxml_domnode
442 #define SORT_TYPE xmlNodePtr
443 /**
444 * wrap_cmp:
445 * @x: a node
446 * @y: another node
447 *
448 * Comparison function for the Timsort implementation
449 *
450 * Returns -2 in case of error -1 if first point < second point, 0 if
451 * it's the same node, +1 otherwise
452 */
453 static
454 int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
455 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
456 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
457 {
458 int res = xmlXPathCmpNodesExt(x, y);
459 return res == -2 ? res : -res;
460 }
461 #else
462 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
463 {
464 int res = xmlXPathCmpNodes(x, y);
465 return res == -2 ? res : -res;
466 }
467 #endif
468 #define SORT_CMP(x, y) (wrap_cmp(x, y))
469 #include "timsort.h"
470 #endif /* WITH_TIM_SORT */
471
472 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
473
474 /************************************************************************
475 * *
476 * Floating point stuff *
477 * *
478 ************************************************************************/
479
480 #ifndef NAN
481 #define NAN (0.0 / 0.0)
482 #endif
483
484 #ifndef INFINITY
485 #define INFINITY HUGE_VAL
486 #endif
487
488 double xmlXPathNAN = NAN;
489 double xmlXPathPINF = INFINITY;
490 double xmlXPathNINF = -INFINITY;
491
492 /**
493 * xmlXPathInit:
494 *
495 * Initialize the XPath environment
496 *
497 * Does nothing but must be kept as public function.
498 */
499 void
500 xmlXPathInit(void) {
501 }
502
503 /**
504 * xmlXPathIsNaN:
505 * @val: a double value
506 *
507 * Returns 1 if the value is a NaN, 0 otherwise
508 */
509 int
510 xmlXPathIsNaN(double val) {
511 #ifdef isnan
512 return isnan(val);
513 #else
514 return !(val == val);
515 #endif
516 }
517
518 /**
519 * xmlXPathIsInf:
520 * @val: a double value
521 *
522 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
523 */
524 int
525 xmlXPathIsInf(double val) {
526 #ifdef isinf
527 return isinf(val) ? (val > 0 ? 1 : -1) : 0;
528 #else
529 if (val >= HUGE_VAL)
530 return 1;
531 if (val <= -HUGE_VAL)
532 return -1;
533 return 0;
534 #endif
535 }
536
537 #endif /* SCHEMAS or XPATH */
538
539 #ifdef LIBXML_XPATH_ENABLED
540
541 /*
542 * TODO: when compatibility allows remove all "fake node libxslt" strings
543 * the test should just be name[0] = ' '
544 */
545 #ifdef DEBUG_XPATH_EXPRESSION
546 #define DEBUG_STEP
547 #define DEBUG_EXPR
548 #define DEBUG_EVAL_COUNTS
549 #endif
550
551 static xmlNs xmlXPathXMLNamespaceStruct = {
552 NULL,
553 XML_NAMESPACE_DECL,
554 XML_XML_NAMESPACE,
555 BAD_CAST "xml",
556 NULL,
557 NULL
558 };
559 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
560 #ifndef LIBXML_THREAD_ENABLED
561 /*
562 * Optimizer is disabled only when threaded apps are detected while
563 * the library ain't compiled for thread safety.
564 */
565 static int xmlXPathDisableOptimizer = 0;
566 #endif
567
568 /************************************************************************
569 * *
570 * Error handling routines *
571 * *
572 ************************************************************************/
573
574 /**
575 * XP_ERRORNULL:
576 * @X: the error code
577 *
578 * Macro to raise an XPath error and return NULL.
579 */
580 #define XP_ERRORNULL(X) \
581 { xmlXPathErr(ctxt, X); return(NULL); }
582
583 /*
584 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
585 */
586 static const char *xmlXPathErrorMessages[] = {
587 "Ok\n",
588 "Number encoding\n",
589 "Unfinished literal\n",
590 "Start of literal\n",
591 "Expected $ for variable reference\n",
592 "Undefined variable\n",
593 "Invalid predicate\n",
594 "Invalid expression\n",
595 "Missing closing curly brace\n",
596 "Unregistered function\n",
597 "Invalid operand\n",
598 "Invalid type\n",
599 "Invalid number of arguments\n",
600 "Invalid context size\n",
601 "Invalid context position\n",
602 "Memory allocation error\n",
603 "Syntax error\n",
604 "Resource error\n",
605 "Sub resource error\n",
606 "Undefined namespace prefix\n",
607 "Encoding error\n",
608 "Char out of XML range\n",
609 "Invalid or incomplete context\n",
610 "Stack usage error\n",
611 "Forbidden variable\n",
612 "?? Unknown error ??\n" /* Must be last in the list! */
613 };
614 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
615 sizeof(xmlXPathErrorMessages[0])) - 1)
616 /**
617 * xmlXPathErrMemory:
618 * @ctxt: an XPath context
619 * @extra: extra informations
620 *
621 * Handle a redefinition of attribute error
622 */
623 static void
624 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
625 {
626 if (ctxt != NULL) {
627 if (extra) {
628 xmlChar buf[200];
629
630 xmlStrPrintf(buf, 200,
631 "Memory allocation failed : %s\n",
632 extra);
633 ctxt->lastError.message = (char *) xmlStrdup(buf);
634 } else {
635 ctxt->lastError.message = (char *)
636 xmlStrdup(BAD_CAST "Memory allocation failed\n");
637 }
638 ctxt->lastError.domain = XML_FROM_XPATH;
639 ctxt->lastError.code = XML_ERR_NO_MEMORY;
640 if (ctxt->error != NULL)
641 ctxt->error(ctxt->userData, &ctxt->lastError);
642 } else {
643 if (extra)
644 __xmlRaiseError(NULL, NULL, NULL,
645 NULL, NULL, XML_FROM_XPATH,
646 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
647 extra, NULL, NULL, 0, 0,
648 "Memory allocation failed : %s\n", extra);
649 else
650 __xmlRaiseError(NULL, NULL, NULL,
651 NULL, NULL, XML_FROM_XPATH,
652 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
653 NULL, NULL, NULL, 0, 0,
654 "Memory allocation failed\n");
655 }
656 }
657
658 /**
659 * xmlXPathPErrMemory:
660 * @ctxt: an XPath parser context
661 * @extra: extra informations
662 *
663 * Handle a redefinition of attribute error
664 */
665 static void
666 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
667 {
668 if (ctxt == NULL)
669 xmlXPathErrMemory(NULL, extra);
670 else {
671 ctxt->error = XPATH_MEMORY_ERROR;
672 xmlXPathErrMemory(ctxt->context, extra);
673 }
674 }
675
676 /**
677 * xmlXPathErr:
678 * @ctxt: a XPath parser context
679 * @error: the error code
680 *
681 * Handle an XPath error
682 */
683 void
684 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
685 {
686 if ((error < 0) || (error > MAXERRNO))
687 error = MAXERRNO;
688 if (ctxt == NULL) {
689 __xmlRaiseError(NULL, NULL, NULL,
690 NULL, NULL, XML_FROM_XPATH,
691 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
692 XML_ERR_ERROR, NULL, 0,
693 NULL, NULL, NULL, 0, 0,
694 "%s", xmlXPathErrorMessages[error]);
695 return;
696 }
697 ctxt->error = error;
698 if (ctxt->context == NULL) {
699 __xmlRaiseError(NULL, NULL, NULL,
700 NULL, NULL, XML_FROM_XPATH,
701 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
702 XML_ERR_ERROR, NULL, 0,
703 (const char *) ctxt->base, NULL, NULL,
704 ctxt->cur - ctxt->base, 0,
705 "%s", xmlXPathErrorMessages[error]);
706 return;
707 }
708
709 /* cleanup current last error */
710 xmlResetError(&ctxt->context->lastError);
711
712 ctxt->context->lastError.domain = XML_FROM_XPATH;
713 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
714 XPATH_EXPRESSION_OK;
715 ctxt->context->lastError.level = XML_ERR_ERROR;
716 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
717 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
718 ctxt->context->lastError.node = ctxt->context->debugNode;
719 if (ctxt->context->error != NULL) {
720 ctxt->context->error(ctxt->context->userData,
721 &ctxt->context->lastError);
722 } else {
723 __xmlRaiseError(NULL, NULL, NULL,
724 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
725 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
726 XML_ERR_ERROR, NULL, 0,
727 (const char *) ctxt->base, NULL, NULL,
728 ctxt->cur - ctxt->base, 0,
729 "%s", xmlXPathErrorMessages[error]);
730 }
731
732 }
733
734 /**
735 * xmlXPatherror:
736 * @ctxt: the XPath Parser context
737 * @file: the file name
738 * @line: the line number
739 * @no: the error number
740 *
741 * Formats an error message.
742 */
743 void
744 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
745 int line ATTRIBUTE_UNUSED, int no) {
746 xmlXPathErr(ctxt, no);
747 }
748
749 /************************************************************************
750 * *
751 * Utilities *
752 * *
753 ************************************************************************/
754
755 /**
756 * xsltPointerList:
757 *
758 * Pointer-list for various purposes.
759 */
760 typedef struct _xmlPointerList xmlPointerList;
761 typedef xmlPointerList *xmlPointerListPtr;
762 struct _xmlPointerList {
763 void **items;
764 int number;
765 int size;
766 };
767 /*
768 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
769 * and here, we should make the functions public.
770 */
771 static int
772 xmlPointerListAddSize(xmlPointerListPtr list,
773 void *item,
774 int initialSize)
775 {
776 if (list->items == NULL) {
777 if (initialSize <= 0)
778 initialSize = 1;
779 list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
780 if (list->items == NULL) {
781 xmlXPathErrMemory(NULL,
782 "xmlPointerListCreate: allocating item\n");
783 return(-1);
784 }
785 list->number = 0;
786 list->size = initialSize;
787 } else if (list->size <= list->number) {
788 if (list->size > 50000000) {
789 xmlXPathErrMemory(NULL,
790 "xmlPointerListAddSize: re-allocating item\n");
791 return(-1);
792 }
793 list->size *= 2;
794 list->items = (void **) xmlRealloc(list->items,
795 list->size * sizeof(void *));
796 if (list->items == NULL) {
797 xmlXPathErrMemory(NULL,
798 "xmlPointerListAddSize: re-allocating item\n");
799 list->size = 0;
800 return(-1);
801 }
802 }
803 list->items[list->number++] = item;
804 return(0);
805 }
806
807 /**
808 * xsltPointerListCreate:
809 *
810 * Creates an xsltPointerList structure.
811 *
812 * Returns a xsltPointerList structure or NULL in case of an error.
813 */
814 static xmlPointerListPtr
815 xmlPointerListCreate(int initialSize)
816 {
817 xmlPointerListPtr ret;
818
819 ret = xmlMalloc(sizeof(xmlPointerList));
820 if (ret == NULL) {
821 xmlXPathErrMemory(NULL,
822 "xmlPointerListCreate: allocating item\n");
823 return (NULL);
824 }
825 memset(ret, 0, sizeof(xmlPointerList));
826 if (initialSize > 0) {
827 xmlPointerListAddSize(ret, NULL, initialSize);
828 ret->number = 0;
829 }
830 return (ret);
831 }
832
833 /**
834 * xsltPointerListFree:
835 *
836 * Frees the xsltPointerList structure. This does not free
837 * the content of the list.
838 */
839 static void
840 xmlPointerListFree(xmlPointerListPtr list)
841 {
842 if (list == NULL)
843 return;
844 if (list->items != NULL)
845 xmlFree(list->items);
846 xmlFree(list);
847 }
848
849 /************************************************************************
850 * *
851 * Parser Types *
852 * *
853 ************************************************************************/
854
855 /*
856 * Types are private:
857 */
858
859 typedef enum {
860 XPATH_OP_END=0,
861 XPATH_OP_AND,
862 XPATH_OP_OR,
863 XPATH_OP_EQUAL,
864 XPATH_OP_CMP,
865 XPATH_OP_PLUS,
866 XPATH_OP_MULT,
867 XPATH_OP_UNION,
868 XPATH_OP_ROOT,
869 XPATH_OP_NODE,
870 XPATH_OP_RESET, /* 10 */
871 XPATH_OP_COLLECT,
872 XPATH_OP_VALUE, /* 12 */
873 XPATH_OP_VARIABLE,
874 XPATH_OP_FUNCTION,
875 XPATH_OP_ARG,
876 XPATH_OP_PREDICATE,
877 XPATH_OP_FILTER, /* 17 */
878 XPATH_OP_SORT /* 18 */
879 #ifdef LIBXML_XPTR_ENABLED
880 ,XPATH_OP_RANGETO
881 #endif
882 } xmlXPathOp;
883
884 typedef enum {
885 AXIS_ANCESTOR = 1,
886 AXIS_ANCESTOR_OR_SELF,
887 AXIS_ATTRIBUTE,
888 AXIS_CHILD,
889 AXIS_DESCENDANT,
890 AXIS_DESCENDANT_OR_SELF,
891 AXIS_FOLLOWING,
892 AXIS_FOLLOWING_SIBLING,
893 AXIS_NAMESPACE,
894 AXIS_PARENT,
895 AXIS_PRECEDING,
896 AXIS_PRECEDING_SIBLING,
897 AXIS_SELF
898 } xmlXPathAxisVal;
899
900 typedef enum {
901 NODE_TEST_NONE = 0,
902 NODE_TEST_TYPE = 1,
903 NODE_TEST_PI = 2,
904 NODE_TEST_ALL = 3,
905 NODE_TEST_NS = 4,
906 NODE_TEST_NAME = 5
907 } xmlXPathTestVal;
908
909 typedef enum {
910 NODE_TYPE_NODE = 0,
911 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
912 NODE_TYPE_TEXT = XML_TEXT_NODE,
913 NODE_TYPE_PI = XML_PI_NODE
914 } xmlXPathTypeVal;
915
916 typedef struct _xmlXPathStepOp xmlXPathStepOp;
917 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
918 struct _xmlXPathStepOp {
919 xmlXPathOp op; /* The identifier of the operation */
920 int ch1; /* First child */
921 int ch2; /* Second child */
922 int value;
923 int value2;
924 int value3;
925 void *value4;
926 void *value5;
927 xmlXPathFunction cache;
928 void *cacheURI;
929 };
930
931 struct _xmlXPathCompExpr {
932 int nbStep; /* Number of steps in this expression */
933 int maxStep; /* Maximum number of steps allocated */
934 xmlXPathStepOp *steps; /* ops for computation of this expression */
935 int last; /* index of last step in expression */
936 xmlChar *expr; /* the expression being computed */
937 xmlDictPtr dict; /* the dictionary to use if any */
938 #ifdef DEBUG_EVAL_COUNTS
939 int nb;
940 xmlChar *string;
941 #endif
942 #ifdef XPATH_STREAMING
943 xmlPatternPtr stream;
944 #endif
945 };
946
947 /************************************************************************
948 * *
949 * Forward declarations *
950 * *
951 ************************************************************************/
952 static void
953 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
954 static void
955 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
956 static int
957 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
958 xmlXPathStepOpPtr op, xmlNodePtr *first);
959 static int
960 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
961 xmlXPathStepOpPtr op,
962 int isPredicate);
963 static void
964 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
965
966 /************************************************************************
967 * *
968 * Parser Type functions *
969 * *
970 ************************************************************************/
971
972 /**
973 * xmlXPathNewCompExpr:
974 *
975 * Create a new Xpath component
976 *
977 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
978 */
979 static xmlXPathCompExprPtr
980 xmlXPathNewCompExpr(void) {
981 xmlXPathCompExprPtr cur;
982
983 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
984 if (cur == NULL) {
985 xmlXPathErrMemory(NULL, "allocating component\n");
986 return(NULL);
987 }
988 memset(cur, 0, sizeof(xmlXPathCompExpr));
989 cur->maxStep = 10;
990 cur->nbStep = 0;
991 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
992 sizeof(xmlXPathStepOp));
993 if (cur->steps == NULL) {
994 xmlXPathErrMemory(NULL, "allocating steps\n");
995 xmlFree(cur);
996 return(NULL);
997 }
998 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
999 cur->last = -1;
1000 #ifdef DEBUG_EVAL_COUNTS
1001 cur->nb = 0;
1002 #endif
1003 return(cur);
1004 }
1005
1006 /**
1007 * xmlXPathFreeCompExpr:
1008 * @comp: an XPATH comp
1009 *
1010 * Free up the memory allocated by @comp
1011 */
1012 void
1013 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1014 {
1015 xmlXPathStepOpPtr op;
1016 int i;
1017
1018 if (comp == NULL)
1019 return;
1020 if (comp->dict == NULL) {
1021 for (i = 0; i < comp->nbStep; i++) {
1022 op = &comp->steps[i];
1023 if (op->value4 != NULL) {
1024 if (op->op == XPATH_OP_VALUE)
1025 xmlXPathFreeObject(op->value4);
1026 else
1027 xmlFree(op->value4);
1028 }
1029 if (op->value5 != NULL)
1030 xmlFree(op->value5);
1031 }
1032 } else {
1033 for (i = 0; i < comp->nbStep; i++) {
1034 op = &comp->steps[i];
1035 if (op->value4 != NULL) {
1036 if (op->op == XPATH_OP_VALUE)
1037 xmlXPathFreeObject(op->value4);
1038 }
1039 }
1040 xmlDictFree(comp->dict);
1041 }
1042 if (comp->steps != NULL) {
1043 xmlFree(comp->steps);
1044 }
1045 #ifdef DEBUG_EVAL_COUNTS
1046 if (comp->string != NULL) {
1047 xmlFree(comp->string);
1048 }
1049 #endif
1050 #ifdef XPATH_STREAMING
1051 if (comp->stream != NULL) {
1052 xmlFreePatternList(comp->stream);
1053 }
1054 #endif
1055 if (comp->expr != NULL) {
1056 xmlFree(comp->expr);
1057 }
1058
1059 xmlFree(comp);
1060 }
1061
1062 /**
1063 * xmlXPathCompExprAdd:
1064 * @comp: the compiled expression
1065 * @ch1: first child index
1066 * @ch2: second child index
1067 * @op: an op
1068 * @value: the first int value
1069 * @value2: the second int value
1070 * @value3: the third int value
1071 * @value4: the first string value
1072 * @value5: the second string value
1073 *
1074 * Add a step to an XPath Compiled Expression
1075 *
1076 * Returns -1 in case of failure, the index otherwise
1077 */
1078 static int
1079 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
1080 xmlXPathOp op, int value,
1081 int value2, int value3, void *value4, void *value5) {
1082 if (comp->nbStep >= comp->maxStep) {
1083 xmlXPathStepOp *real;
1084
1085 if (comp->maxStep >= XPATH_MAX_STEPS) {
1086 xmlXPathErrMemory(NULL, "adding step\n");
1087 return(-1);
1088 }
1089 comp->maxStep *= 2;
1090 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1091 comp->maxStep * sizeof(xmlXPathStepOp));
1092 if (real == NULL) {
1093 comp->maxStep /= 2;
1094 xmlXPathErrMemory(NULL, "adding step\n");
1095 return(-1);
1096 }
1097 comp->steps = real;
1098 }
1099 comp->last = comp->nbStep;
1100 comp->steps[comp->nbStep].ch1 = ch1;
1101 comp->steps[comp->nbStep].ch2 = ch2;
1102 comp->steps[comp->nbStep].op = op;
1103 comp->steps[comp->nbStep].value = value;
1104 comp->steps[comp->nbStep].value2 = value2;
1105 comp->steps[comp->nbStep].value3 = value3;
1106 if ((comp->dict != NULL) &&
1107 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1108 (op == XPATH_OP_COLLECT))) {
1109 if (value4 != NULL) {
1110 comp->steps[comp->nbStep].value4 = (xmlChar *)
1111 (void *)xmlDictLookup(comp->dict, value4, -1);
1112 xmlFree(value4);
1113 } else
1114 comp->steps[comp->nbStep].value4 = NULL;
1115 if (value5 != NULL) {
1116 comp->steps[comp->nbStep].value5 = (xmlChar *)
1117 (void *)xmlDictLookup(comp->dict, value5, -1);
1118 xmlFree(value5);
1119 } else
1120 comp->steps[comp->nbStep].value5 = NULL;
1121 } else {
1122 comp->steps[comp->nbStep].value4 = value4;
1123 comp->steps[comp->nbStep].value5 = value5;
1124 }
1125 comp->steps[comp->nbStep].cache = NULL;
1126 return(comp->nbStep++);
1127 }
1128
1129 /**
1130 * xmlXPathCompSwap:
1131 * @comp: the compiled expression
1132 * @op: operation index
1133 *
1134 * Swaps 2 operations in the compiled expression
1135 */
1136 static void
1137 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1138 int tmp;
1139
1140 #ifndef LIBXML_THREAD_ENABLED
1141 /*
1142 * Since this manipulates possibly shared variables, this is
1143 * disabled if one detects that the library is used in a multithreaded
1144 * application
1145 */
1146 if (xmlXPathDisableOptimizer)
1147 return;
1148 #endif
1149
1150 tmp = op->ch1;
1151 op->ch1 = op->ch2;
1152 op->ch2 = tmp;
1153 }
1154
1155 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1156 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
1157 (op), (val), (val2), (val3), (val4), (val5))
1158 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
1159 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
1160 (op), (val), (val2), (val3), (val4), (val5))
1161
1162 #define PUSH_LEAVE_EXPR(op, val, val2) \
1163 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1164
1165 #define PUSH_UNARY_EXPR(op, ch, val, val2) \
1166 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1167
1168 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
1169 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
1170 (val), (val2), 0 ,NULL ,NULL)
1171
1172 /************************************************************************
1173 * *
1174 * XPath object cache structures *
1175 * *
1176 ************************************************************************/
1177
1178 /* #define XP_DEFAULT_CACHE_ON */
1179
1180 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1181
1182 typedef struct _xmlXPathContextCache xmlXPathContextCache;
1183 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1184 struct _xmlXPathContextCache {
1185 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
1186 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
1187 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
1188 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
1189 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
1190 int maxNodeset;
1191 int maxString;
1192 int maxBoolean;
1193 int maxNumber;
1194 int maxMisc;
1195 #ifdef XP_DEBUG_OBJ_USAGE
1196 int dbgCachedAll;
1197 int dbgCachedNodeset;
1198 int dbgCachedString;
1199 int dbgCachedBool;
1200 int dbgCachedNumber;
1201 int dbgCachedPoint;
1202 int dbgCachedRange;
1203 int dbgCachedLocset;
1204 int dbgCachedUsers;
1205 int dbgCachedXSLTTree;
1206 int dbgCachedUndefined;
1207
1208
1209 int dbgReusedAll;
1210 int dbgReusedNodeset;
1211 int dbgReusedString;
1212 int dbgReusedBool;
1213 int dbgReusedNumber;
1214 int dbgReusedPoint;
1215 int dbgReusedRange;
1216 int dbgReusedLocset;
1217 int dbgReusedUsers;
1218 int dbgReusedXSLTTree;
1219 int dbgReusedUndefined;
1220
1221 #endif
1222 };
1223
1224 /************************************************************************
1225 * *
1226 * Debugging related functions *
1227 * *
1228 ************************************************************************/
1229
1230 #define STRANGE \
1231 xmlGenericError(xmlGenericErrorContext, \
1232 "Internal error at %s:%d\n", \
1233 __FILE__, __LINE__);
1234
1235 #ifdef LIBXML_DEBUG_ENABLED
1236 static void
1237 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1238 int i;
1239 char shift[100];
1240
1241 for (i = 0;((i < depth) && (i < 25));i++)
1242 shift[2 * i] = shift[2 * i + 1] = ' ';
1243 shift[2 * i] = shift[2 * i + 1] = 0;
1244 if (cur == NULL) {
1245 fprintf(output, "%s", shift);
1246 fprintf(output, "Node is NULL !\n");
1247 return;
1248
1249 }
1250
1251 if ((cur->type == XML_DOCUMENT_NODE) ||
1252 (cur->type == XML_HTML_DOCUMENT_NODE)) {
1253 fprintf(output, "%s", shift);
1254 fprintf(output, " /\n");
1255 } else if (cur->type == XML_ATTRIBUTE_NODE)
1256 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1257 else
1258 xmlDebugDumpOneNode(output, cur, depth);
1259 }
1260 static void
1261 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1262 xmlNodePtr tmp;
1263 int i;
1264 char shift[100];
1265
1266 for (i = 0;((i < depth) && (i < 25));i++)
1267 shift[2 * i] = shift[2 * i + 1] = ' ';
1268 shift[2 * i] = shift[2 * i + 1] = 0;
1269 if (cur == NULL) {
1270 fprintf(output, "%s", shift);
1271 fprintf(output, "Node is NULL !\n");
1272 return;
1273
1274 }
1275
1276 while (cur != NULL) {
1277 tmp = cur;
1278 cur = cur->next;
1279 xmlDebugDumpOneNode(output, tmp, depth);
1280 }
1281 }
1282
1283 static void
1284 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1285 int i;
1286 char shift[100];
1287
1288 for (i = 0;((i < depth) && (i < 25));i++)
1289 shift[2 * i] = shift[2 * i + 1] = ' ';
1290 shift[2 * i] = shift[2 * i + 1] = 0;
1291
1292 if (cur == NULL) {
1293 fprintf(output, "%s", shift);
1294 fprintf(output, "NodeSet is NULL !\n");
1295 return;
1296
1297 }
1298
1299 if (cur != NULL) {
1300 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1301 for (i = 0;i < cur->nodeNr;i++) {
1302 fprintf(output, "%s", shift);
1303 fprintf(output, "%d", i + 1);
1304 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1305 }
1306 }
1307 }
1308
1309 static void
1310 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1311 int i;
1312 char shift[100];
1313
1314 for (i = 0;((i < depth) && (i < 25));i++)
1315 shift[2 * i] = shift[2 * i + 1] = ' ';
1316 shift[2 * i] = shift[2 * i + 1] = 0;
1317
1318 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1319 fprintf(output, "%s", shift);
1320 fprintf(output, "Value Tree is NULL !\n");
1321 return;
1322
1323 }
1324
1325 fprintf(output, "%s", shift);
1326 fprintf(output, "%d", i + 1);
1327 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1328 }
1329 #if defined(LIBXML_XPTR_ENABLED)
1330 static void
1331 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1332 int i;
1333 char shift[100];
1334
1335 for (i = 0;((i < depth) && (i < 25));i++)
1336 shift[2 * i] = shift[2 * i + 1] = ' ';
1337 shift[2 * i] = shift[2 * i + 1] = 0;
1338
1339 if (cur == NULL) {
1340 fprintf(output, "%s", shift);
1341 fprintf(output, "LocationSet is NULL !\n");
1342 return;
1343
1344 }
1345
1346 for (i = 0;i < cur->locNr;i++) {
1347 fprintf(output, "%s", shift);
1348 fprintf(output, "%d : ", i + 1);
1349 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1350 }
1351 }
1352 #endif /* LIBXML_XPTR_ENABLED */
1353
1354 /**
1355 * xmlXPathDebugDumpObject:
1356 * @output: the FILE * to dump the output
1357 * @cur: the object to inspect
1358 * @depth: indentation level
1359 *
1360 * Dump the content of the object for debugging purposes
1361 */
1362 void
1363 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1364 int i;
1365 char shift[100];
1366
1367 if (output == NULL) return;
1368
1369 for (i = 0;((i < depth) && (i < 25));i++)
1370 shift[2 * i] = shift[2 * i + 1] = ' ';
1371 shift[2 * i] = shift[2 * i + 1] = 0;
1372
1373
1374 fprintf(output, "%s", shift);
1375
1376 if (cur == NULL) {
1377 fprintf(output, "Object is empty (NULL)\n");
1378 return;
1379 }
1380 switch(cur->type) {
1381 case XPATH_UNDEFINED:
1382 fprintf(output, "Object is uninitialized\n");
1383 break;
1384 case XPATH_NODESET:
1385 fprintf(output, "Object is a Node Set :\n");
1386 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1387 break;
1388 case XPATH_XSLT_TREE:
1389 fprintf(output, "Object is an XSLT value tree :\n");
1390 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1391 break;
1392 case XPATH_BOOLEAN:
1393 fprintf(output, "Object is a Boolean : ");
1394 if (cur->boolval) fprintf(output, "true\n");
1395 else fprintf(output, "false\n");
1396 break;
1397 case XPATH_NUMBER:
1398 switch (xmlXPathIsInf(cur->floatval)) {
1399 case 1:
1400 fprintf(output, "Object is a number : Infinity\n");
1401 break;
1402 case -1:
1403 fprintf(output, "Object is a number : -Infinity\n");
1404 break;
1405 default:
1406 if (xmlXPathIsNaN(cur->floatval)) {
1407 fprintf(output, "Object is a number : NaN\n");
1408 } else if (cur->floatval == 0) {
1409 /* Omit sign for negative zero. */
1410 fprintf(output, "Object is a number : 0\n");
1411 } else {
1412 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1413 }
1414 }
1415 break;
1416 case XPATH_STRING:
1417 fprintf(output, "Object is a string : ");
1418 xmlDebugDumpString(output, cur->stringval);
1419 fprintf(output, "\n");
1420 break;
1421 case XPATH_POINT:
1422 fprintf(output, "Object is a point : index %d in node", cur->index);
1423 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1424 fprintf(output, "\n");
1425 break;
1426 case XPATH_RANGE:
1427 if ((cur->user2 == NULL) ||
1428 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1429 fprintf(output, "Object is a collapsed range :\n");
1430 fprintf(output, "%s", shift);
1431 if (cur->index >= 0)
1432 fprintf(output, "index %d in ", cur->index);
1433 fprintf(output, "node\n");
1434 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1435 depth + 1);
1436 } else {
1437 fprintf(output, "Object is a range :\n");
1438 fprintf(output, "%s", shift);
1439 fprintf(output, "From ");
1440 if (cur->index >= 0)
1441 fprintf(output, "index %d in ", cur->index);
1442 fprintf(output, "node\n");
1443 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1444 depth + 1);
1445 fprintf(output, "%s", shift);
1446 fprintf(output, "To ");
1447 if (cur->index2 >= 0)
1448 fprintf(output, "index %d in ", cur->index2);
1449 fprintf(output, "node\n");
1450 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1451 depth + 1);
1452 fprintf(output, "\n");
1453 }
1454 break;
1455 case XPATH_LOCATIONSET:
1456 #if defined(LIBXML_XPTR_ENABLED)
1457 fprintf(output, "Object is a Location Set:\n");
1458 xmlXPathDebugDumpLocationSet(output,
1459 (xmlLocationSetPtr) cur->user, depth);
1460 #endif
1461 break;
1462 case XPATH_USERS:
1463 fprintf(output, "Object is user defined\n");
1464 break;
1465 }
1466 }
1467
1468 static void
1469 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1470 xmlXPathStepOpPtr op, int depth) {
1471 int i;
1472 char shift[100];
1473
1474 for (i = 0;((i < depth) && (i < 25));i++)
1475 shift[2 * i] = shift[2 * i + 1] = ' ';
1476 shift[2 * i] = shift[2 * i + 1] = 0;
1477
1478 fprintf(output, "%s", shift);
1479 if (op == NULL) {
1480 fprintf(output, "Step is NULL\n");
1481 return;
1482 }
1483 switch (op->op) {
1484 case XPATH_OP_END:
1485 fprintf(output, "END"); break;
1486 case XPATH_OP_AND:
1487 fprintf(output, "AND"); break;
1488 case XPATH_OP_OR:
1489 fprintf(output, "OR"); break;
1490 case XPATH_OP_EQUAL:
1491 if (op->value)
1492 fprintf(output, "EQUAL =");
1493 else
1494 fprintf(output, "EQUAL !=");
1495 break;
1496 case XPATH_OP_CMP:
1497 if (op->value)
1498 fprintf(output, "CMP <");
1499 else
1500 fprintf(output, "CMP >");
1501 if (!op->value2)
1502 fprintf(output, "=");
1503 break;
1504 case XPATH_OP_PLUS:
1505 if (op->value == 0)
1506 fprintf(output, "PLUS -");
1507 else if (op->value == 1)
1508 fprintf(output, "PLUS +");
1509 else if (op->value == 2)
1510 fprintf(output, "PLUS unary -");
1511 else if (op->value == 3)
1512 fprintf(output, "PLUS unary - -");
1513 break;
1514 case XPATH_OP_MULT:
1515 if (op->value == 0)
1516 fprintf(output, "MULT *");
1517 else if (op->value == 1)
1518 fprintf(output, "MULT div");
1519 else
1520 fprintf(output, "MULT mod");
1521 break;
1522 case XPATH_OP_UNION:
1523 fprintf(output, "UNION"); break;
1524 case XPATH_OP_ROOT:
1525 fprintf(output, "ROOT"); break;
1526 case XPATH_OP_NODE:
1527 fprintf(output, "NODE"); break;
1528 case XPATH_OP_RESET:
1529 fprintf(output, "RESET"); break;
1530 case XPATH_OP_SORT:
1531 fprintf(output, "SORT"); break;
1532 case XPATH_OP_COLLECT: {
1533 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1534 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1535 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1536 const xmlChar *prefix = op->value4;
1537 const xmlChar *name = op->value5;
1538
1539 fprintf(output, "COLLECT ");
1540 switch (axis) {
1541 case AXIS_ANCESTOR:
1542 fprintf(output, " 'ancestors' "); break;
1543 case AXIS_ANCESTOR_OR_SELF:
1544 fprintf(output, " 'ancestors-or-self' "); break;
1545 case AXIS_ATTRIBUTE:
1546 fprintf(output, " 'attributes' "); break;
1547 case AXIS_CHILD:
1548 fprintf(output, " 'child' "); break;
1549 case AXIS_DESCENDANT:
1550 fprintf(output, " 'descendant' "); break;
1551 case AXIS_DESCENDANT_OR_SELF:
1552 fprintf(output, " 'descendant-or-self' "); break;
1553 case AXIS_FOLLOWING:
1554 fprintf(output, " 'following' "); break;
1555 case AXIS_FOLLOWING_SIBLING:
1556 fprintf(output, " 'following-siblings' "); break;
1557 case AXIS_NAMESPACE:
1558 fprintf(output, " 'namespace' "); break;
1559 case AXIS_PARENT:
1560 fprintf(output, " 'parent' "); break;
1561 case AXIS_PRECEDING:
1562 fprintf(output, " 'preceding' "); break;
1563 case AXIS_PRECEDING_SIBLING:
1564 fprintf(output, " 'preceding-sibling' "); break;
1565 case AXIS_SELF:
1566 fprintf(output, " 'self' "); break;
1567 }
1568 switch (test) {
1569 case NODE_TEST_NONE:
1570 fprintf(output, "'none' "); break;
1571 case NODE_TEST_TYPE:
1572 fprintf(output, "'type' "); break;
1573 case NODE_TEST_PI:
1574 fprintf(output, "'PI' "); break;
1575 case NODE_TEST_ALL:
1576 fprintf(output, "'all' "); break;
1577 case NODE_TEST_NS:
1578 fprintf(output, "'namespace' "); break;
1579 case NODE_TEST_NAME:
1580 fprintf(output, "'name' "); break;
1581 }
1582 switch (type) {
1583 case NODE_TYPE_NODE:
1584 fprintf(output, "'node' "); break;
1585 case NODE_TYPE_COMMENT:
1586 fprintf(output, "'comment' "); break;
1587 case NODE_TYPE_TEXT:
1588 fprintf(output, "'text' "); break;
1589 case NODE_TYPE_PI:
1590 fprintf(output, "'PI' "); break;
1591 }
1592 if (prefix != NULL)
1593 fprintf(output, "%s:", prefix);
1594 if (name != NULL)
1595 fprintf(output, "%s", (const char *) name);
1596 break;
1597
1598 }
1599 case XPATH_OP_VALUE: {
1600 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1601
1602 fprintf(output, "ELEM ");
1603 xmlXPathDebugDumpObject(output, object, 0);
1604 goto finish;
1605 }
1606 case XPATH_OP_VARIABLE: {
1607 const xmlChar *prefix = op->value5;
1608 const xmlChar *name = op->value4;
1609
1610 if (prefix != NULL)
1611 fprintf(output, "VARIABLE %s:%s", prefix, name);
1612 else
1613 fprintf(output, "VARIABLE %s", name);
1614 break;
1615 }
1616 case XPATH_OP_FUNCTION: {
1617 int nbargs = op->value;
1618 const xmlChar *prefix = op->value5;
1619 const xmlChar *name = op->value4;
1620
1621 if (prefix != NULL)
1622 fprintf(output, "FUNCTION %s:%s(%d args)",
1623 prefix, name, nbargs);
1624 else
1625 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1626 break;
1627 }
1628 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1629 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1630 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1631 #ifdef LIBXML_XPTR_ENABLED
1632 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1633 #endif
1634 default:
1635 fprintf(output, "UNKNOWN %d\n", op->op); return;
1636 }
1637 fprintf(output, "\n");
1638 finish:
1639 if (op->ch1 >= 0)
1640 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1641 if (op->ch2 >= 0)
1642 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1643 }
1644
1645 /**
1646 * xmlXPathDebugDumpCompExpr:
1647 * @output: the FILE * for the output
1648 * @comp: the precompiled XPath expression
1649 * @depth: the indentation level.
1650 *
1651 * Dumps the tree of the compiled XPath expression.
1652 */
1653 void
1654 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1655 int depth) {
1656 int i;
1657 char shift[100];
1658
1659 if ((output == NULL) || (comp == NULL)) return;
1660
1661 for (i = 0;((i < depth) && (i < 25));i++)
1662 shift[2 * i] = shift[2 * i + 1] = ' ';
1663 shift[2 * i] = shift[2 * i + 1] = 0;
1664
1665 fprintf(output, "%s", shift);
1666
1667 #ifdef XPATH_STREAMING
1668 if (comp->stream) {
1669 fprintf(output, "Streaming Expression\n");
1670 } else
1671 #endif
1672 {
1673 fprintf(output, "Compiled Expression : %d elements\n",
1674 comp->nbStep);
1675 i = comp->last;
1676 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1677 }
1678 }
1679
1680 #ifdef XP_DEBUG_OBJ_USAGE
1681
1682 /*
1683 * XPath object usage related debugging variables.
1684 */
1685 static int xmlXPathDebugObjCounterUndefined = 0;
1686 static int xmlXPathDebugObjCounterNodeset = 0;
1687 static int xmlXPathDebugObjCounterBool = 0;
1688 static int xmlXPathDebugObjCounterNumber = 0;
1689 static int xmlXPathDebugObjCounterString = 0;
1690 static int xmlXPathDebugObjCounterPoint = 0;
1691 static int xmlXPathDebugObjCounterRange = 0;
1692 static int xmlXPathDebugObjCounterLocset = 0;
1693 static int xmlXPathDebugObjCounterUsers = 0;
1694 static int xmlXPathDebugObjCounterXSLTTree = 0;
1695 static int xmlXPathDebugObjCounterAll = 0;
1696
1697 static int xmlXPathDebugObjTotalUndefined = 0;
1698 static int xmlXPathDebugObjTotalNodeset = 0;
1699 static int xmlXPathDebugObjTotalBool = 0;
1700 static int xmlXPathDebugObjTotalNumber = 0;
1701 static int xmlXPathDebugObjTotalString = 0;
1702 static int xmlXPathDebugObjTotalPoint = 0;
1703 static int xmlXPathDebugObjTotalRange = 0;
1704 static int xmlXPathDebugObjTotalLocset = 0;
1705 static int xmlXPathDebugObjTotalUsers = 0;
1706 static int xmlXPathDebugObjTotalXSLTTree = 0;
1707 static int xmlXPathDebugObjTotalAll = 0;
1708
1709 static int xmlXPathDebugObjMaxUndefined = 0;
1710 static int xmlXPathDebugObjMaxNodeset = 0;
1711 static int xmlXPathDebugObjMaxBool = 0;
1712 static int xmlXPathDebugObjMaxNumber = 0;
1713 static int xmlXPathDebugObjMaxString = 0;
1714 static int xmlXPathDebugObjMaxPoint = 0;
1715 static int xmlXPathDebugObjMaxRange = 0;
1716 static int xmlXPathDebugObjMaxLocset = 0;
1717 static int xmlXPathDebugObjMaxUsers = 0;
1718 static int xmlXPathDebugObjMaxXSLTTree = 0;
1719 static int xmlXPathDebugObjMaxAll = 0;
1720
1721 /* REVISIT TODO: Make this static when committing */
1722 static void
1723 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1724 {
1725 if (ctxt != NULL) {
1726 if (ctxt->cache != NULL) {
1727 xmlXPathContextCachePtr cache =
1728 (xmlXPathContextCachePtr) ctxt->cache;
1729
1730 cache->dbgCachedAll = 0;
1731 cache->dbgCachedNodeset = 0;
1732 cache->dbgCachedString = 0;
1733 cache->dbgCachedBool = 0;
1734 cache->dbgCachedNumber = 0;
1735 cache->dbgCachedPoint = 0;
1736 cache->dbgCachedRange = 0;
1737 cache->dbgCachedLocset = 0;
1738 cache->dbgCachedUsers = 0;
1739 cache->dbgCachedXSLTTree = 0;
1740 cache->dbgCachedUndefined = 0;
1741
1742 cache->dbgReusedAll = 0;
1743 cache->dbgReusedNodeset = 0;
1744 cache->dbgReusedString = 0;
1745 cache->dbgReusedBool = 0;
1746 cache->dbgReusedNumber = 0;
1747 cache->dbgReusedPoint = 0;
1748 cache->dbgReusedRange = 0;
1749 cache->dbgReusedLocset = 0;
1750 cache->dbgReusedUsers = 0;
1751 cache->dbgReusedXSLTTree = 0;
1752 cache->dbgReusedUndefined = 0;
1753 }
1754 }
1755
1756 xmlXPathDebugObjCounterUndefined = 0;
1757 xmlXPathDebugObjCounterNodeset = 0;
1758 xmlXPathDebugObjCounterBool = 0;
1759 xmlXPathDebugObjCounterNumber = 0;
1760 xmlXPathDebugObjCounterString = 0;
1761 xmlXPathDebugObjCounterPoint = 0;
1762 xmlXPathDebugObjCounterRange = 0;
1763 xmlXPathDebugObjCounterLocset = 0;
1764 xmlXPathDebugObjCounterUsers = 0;
1765 xmlXPathDebugObjCounterXSLTTree = 0;
1766 xmlXPathDebugObjCounterAll = 0;
1767
1768 xmlXPathDebugObjTotalUndefined = 0;
1769 xmlXPathDebugObjTotalNodeset = 0;
1770 xmlXPathDebugObjTotalBool = 0;
1771 xmlXPathDebugObjTotalNumber = 0;
1772 xmlXPathDebugObjTotalString = 0;
1773 xmlXPathDebugObjTotalPoint = 0;
1774 xmlXPathDebugObjTotalRange = 0;
1775 xmlXPathDebugObjTotalLocset = 0;
1776 xmlXPathDebugObjTotalUsers = 0;
1777 xmlXPathDebugObjTotalXSLTTree = 0;
1778 xmlXPathDebugObjTotalAll = 0;
1779
1780 xmlXPathDebugObjMaxUndefined = 0;
1781 xmlXPathDebugObjMaxNodeset = 0;
1782 xmlXPathDebugObjMaxBool = 0;
1783 xmlXPathDebugObjMaxNumber = 0;
1784 xmlXPathDebugObjMaxString = 0;
1785 xmlXPathDebugObjMaxPoint = 0;
1786 xmlXPathDebugObjMaxRange = 0;
1787 xmlXPathDebugObjMaxLocset = 0;
1788 xmlXPathDebugObjMaxUsers = 0;
1789 xmlXPathDebugObjMaxXSLTTree = 0;
1790 xmlXPathDebugObjMaxAll = 0;
1791
1792 }
1793
1794 static void
1795 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1796 xmlXPathObjectType objType)
1797 {
1798 int isCached = 0;
1799
1800 if (ctxt != NULL) {
1801 if (ctxt->cache != NULL) {
1802 xmlXPathContextCachePtr cache =
1803 (xmlXPathContextCachePtr) ctxt->cache;
1804
1805 isCached = 1;
1806
1807 cache->dbgReusedAll++;
1808 switch (objType) {
1809 case XPATH_UNDEFINED:
1810 cache->dbgReusedUndefined++;
1811 break;
1812 case XPATH_NODESET:
1813 cache->dbgReusedNodeset++;
1814 break;
1815 case XPATH_BOOLEAN:
1816 cache->dbgReusedBool++;
1817 break;
1818 case XPATH_NUMBER:
1819 cache->dbgReusedNumber++;
1820 break;
1821 case XPATH_STRING:
1822 cache->dbgReusedString++;
1823 break;
1824 case XPATH_POINT:
1825 cache->dbgReusedPoint++;
1826 break;
1827 case XPATH_RANGE:
1828 cache->dbgReusedRange++;
1829 break;
1830 case XPATH_LOCATIONSET:
1831 cache->dbgReusedLocset++;
1832 break;
1833 case XPATH_USERS:
1834 cache->dbgReusedUsers++;
1835 break;
1836 case XPATH_XSLT_TREE:
1837 cache->dbgReusedXSLTTree++;
1838 break;
1839 default:
1840 break;
1841 }
1842 }
1843 }
1844
1845 switch (objType) {
1846 case XPATH_UNDEFINED:
1847 if (! isCached)
1848 xmlXPathDebugObjTotalUndefined++;
1849 xmlXPathDebugObjCounterUndefined++;
1850 if (xmlXPathDebugObjCounterUndefined >
1851 xmlXPathDebugObjMaxUndefined)
1852 xmlXPathDebugObjMaxUndefined =
1853 xmlXPathDebugObjCounterUndefined;
1854 break;
1855 case XPATH_NODESET:
1856 if (! isCached)
1857 xmlXPathDebugObjTotalNodeset++;
1858 xmlXPathDebugObjCounterNodeset++;
1859 if (xmlXPathDebugObjCounterNodeset >
1860 xmlXPathDebugObjMaxNodeset)
1861 xmlXPathDebugObjMaxNodeset =
1862 xmlXPathDebugObjCounterNodeset;
1863 break;
1864 case XPATH_BOOLEAN:
1865 if (! isCached)
1866 xmlXPathDebugObjTotalBool++;
1867 xmlXPathDebugObjCounterBool++;
1868 if (xmlXPathDebugObjCounterBool >
1869 xmlXPathDebugObjMaxBool)
1870 xmlXPathDebugObjMaxBool =
1871 xmlXPathDebugObjCounterBool;
1872 break;
1873 case XPATH_NUMBER:
1874 if (! isCached)
1875 xmlXPathDebugObjTotalNumber++;
1876 xmlXPathDebugObjCounterNumber++;
1877 if (xmlXPathDebugObjCounterNumber >
1878 xmlXPathDebugObjMaxNumber)
1879 xmlXPathDebugObjMaxNumber =
1880 xmlXPathDebugObjCounterNumber;
1881 break;
1882 case XPATH_STRING:
1883 if (! isCached)
1884 xmlXPathDebugObjTotalString++;
1885 xmlXPathDebugObjCounterString++;
1886 if (xmlXPathDebugObjCounterString >
1887 xmlXPathDebugObjMaxString)
1888 xmlXPathDebugObjMaxString =
1889 xmlXPathDebugObjCounterString;
1890 break;
1891 case XPATH_POINT:
1892 if (! isCached)
1893 xmlXPathDebugObjTotalPoint++;
1894 xmlXPathDebugObjCounterPoint++;
1895 if (xmlXPathDebugObjCounterPoint >
1896 xmlXPathDebugObjMaxPoint)
1897 xmlXPathDebugObjMaxPoint =
1898 xmlXPathDebugObjCounterPoint;
1899 break;
1900 case XPATH_RANGE:
1901 if (! isCached)
1902 xmlXPathDebugObjTotalRange++;
1903 xmlXPathDebugObjCounterRange++;
1904 if (xmlXPathDebugObjCounterRange >
1905 xmlXPathDebugObjMaxRange)
1906 xmlXPathDebugObjMaxRange =
1907 xmlXPathDebugObjCounterRange;
1908 break;
1909 case XPATH_LOCATIONSET:
1910 if (! isCached)
1911 xmlXPathDebugObjTotalLocset++;
1912 xmlXPathDebugObjCounterLocset++;
1913 if (xmlXPathDebugObjCounterLocset >
1914 xmlXPathDebugObjMaxLocset)
1915 xmlXPathDebugObjMaxLocset =
1916 xmlXPathDebugObjCounterLocset;
1917 break;
1918 case XPATH_USERS:
1919 if (! isCached)
1920 xmlXPathDebugObjTotalUsers++;
1921 xmlXPathDebugObjCounterUsers++;
1922 if (xmlXPathDebugObjCounterUsers >
1923 xmlXPathDebugObjMaxUsers)
1924 xmlXPathDebugObjMaxUsers =
1925 xmlXPathDebugObjCounterUsers;
1926 break;
1927 case XPATH_XSLT_TREE:
1928 if (! isCached)
1929 xmlXPathDebugObjTotalXSLTTree++;
1930 xmlXPathDebugObjCounterXSLTTree++;
1931 if (xmlXPathDebugObjCounterXSLTTree >
1932 xmlXPathDebugObjMaxXSLTTree)
1933 xmlXPathDebugObjMaxXSLTTree =
1934 xmlXPathDebugObjCounterXSLTTree;
1935 break;
1936 default:
1937 break;
1938 }
1939 if (! isCached)
1940 xmlXPathDebugObjTotalAll++;
1941 xmlXPathDebugObjCounterAll++;
1942 if (xmlXPathDebugObjCounterAll >
1943 xmlXPathDebugObjMaxAll)
1944 xmlXPathDebugObjMaxAll =
1945 xmlXPathDebugObjCounterAll;
1946 }
1947
1948 static void
1949 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1950 xmlXPathObjectType objType)
1951 {
1952 int isCached = 0;
1953
1954 if (ctxt != NULL) {
1955 if (ctxt->cache != NULL) {
1956 xmlXPathContextCachePtr cache =
1957 (xmlXPathContextCachePtr) ctxt->cache;
1958
1959 isCached = 1;
1960
1961 cache->dbgCachedAll++;
1962 switch (objType) {
1963 case XPATH_UNDEFINED:
1964 cache->dbgCachedUndefined++;
1965 break;
1966 case XPATH_NODESET:
1967 cache->dbgCachedNodeset++;
1968 break;
1969 case XPATH_BOOLEAN:
1970 cache->dbgCachedBool++;
1971 break;
1972 case XPATH_NUMBER:
1973 cache->dbgCachedNumber++;
1974 break;
1975 case XPATH_STRING:
1976 cache->dbgCachedString++;
1977 break;
1978 case XPATH_POINT:
1979 cache->dbgCachedPoint++;
1980 break;
1981 case XPATH_RANGE:
1982 cache->dbgCachedRange++;
1983 break;
1984 case XPATH_LOCATIONSET:
1985 cache->dbgCachedLocset++;
1986 break;
1987 case XPATH_USERS:
1988 cache->dbgCachedUsers++;
1989 break;
1990 case XPATH_XSLT_TREE:
1991 cache->dbgCachedXSLTTree++;
1992 break;
1993 default:
1994 break;
1995 }
1996
1997 }
1998 }
1999 switch (objType) {
2000 case XPATH_UNDEFINED:
2001 xmlXPathDebugObjCounterUndefined--;
2002 break;
2003 case XPATH_NODESET:
2004 xmlXPathDebugObjCounterNodeset--;
2005 break;
2006 case XPATH_BOOLEAN:
2007 xmlXPathDebugObjCounterBool--;
2008 break;
2009 case XPATH_NUMBER:
2010 xmlXPathDebugObjCounterNumber--;
2011 break;
2012 case XPATH_STRING:
2013 xmlXPathDebugObjCounterString--;
2014 break;
2015 case XPATH_POINT:
2016 xmlXPathDebugObjCounterPoint--;
2017 break;
2018 case XPATH_RANGE:
2019 xmlXPathDebugObjCounterRange--;
2020 break;
2021 case XPATH_LOCATIONSET:
2022 xmlXPathDebugObjCounterLocset--;
2023 break;
2024 case XPATH_USERS:
2025 xmlXPathDebugObjCounterUsers--;
2026 break;
2027 case XPATH_XSLT_TREE:
2028 xmlXPathDebugObjCounterXSLTTree--;
2029 break;
2030 default:
2031 break;
2032 }
2033 xmlXPathDebugObjCounterAll--;
2034 }
2035
2036 /* REVISIT TODO: Make this static when committing */
2037 static void
2038 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2039 {
2040 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2041 reqXSLTTree, reqUndefined;
2042 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2043 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2044 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2045 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2046 int leftObjs = xmlXPathDebugObjCounterAll;
2047
2048 reqAll = xmlXPathDebugObjTotalAll;
2049 reqNodeset = xmlXPathDebugObjTotalNodeset;
2050 reqString = xmlXPathDebugObjTotalString;
2051 reqBool = xmlXPathDebugObjTotalBool;
2052 reqNumber = xmlXPathDebugObjTotalNumber;
2053 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2054 reqUndefined = xmlXPathDebugObjTotalUndefined;
2055
2056 printf("# XPath object usage:\n");
2057
2058 if (ctxt != NULL) {
2059 if (ctxt->cache != NULL) {
2060 xmlXPathContextCachePtr cache =
2061 (xmlXPathContextCachePtr) ctxt->cache;
2062
2063 reAll = cache->dbgReusedAll;
2064 reqAll += reAll;
2065 reNodeset = cache->dbgReusedNodeset;
2066 reqNodeset += reNodeset;
2067 reString = cache->dbgReusedString;
2068 reqString += reString;
2069 reBool = cache->dbgReusedBool;
2070 reqBool += reBool;
2071 reNumber = cache->dbgReusedNumber;
2072 reqNumber += reNumber;
2073 reXSLTTree = cache->dbgReusedXSLTTree;
2074 reqXSLTTree += reXSLTTree;
2075 reUndefined = cache->dbgReusedUndefined;
2076 reqUndefined += reUndefined;
2077
2078 caAll = cache->dbgCachedAll;
2079 caBool = cache->dbgCachedBool;
2080 caNodeset = cache->dbgCachedNodeset;
2081 caString = cache->dbgCachedString;
2082 caNumber = cache->dbgCachedNumber;
2083 caXSLTTree = cache->dbgCachedXSLTTree;
2084 caUndefined = cache->dbgCachedUndefined;
2085
2086 if (cache->nodesetObjs)
2087 leftObjs -= cache->nodesetObjs->number;
2088 if (cache->stringObjs)
2089 leftObjs -= cache->stringObjs->number;
2090 if (cache->booleanObjs)
2091 leftObjs -= cache->booleanObjs->number;
2092 if (cache->numberObjs)
2093 leftObjs -= cache->numberObjs->number;
2094 if (cache->miscObjs)
2095 leftObjs -= cache->miscObjs->number;
2096 }
2097 }
2098
2099 printf("# all\n");
2100 printf("# total : %d\n", reqAll);
2101 printf("# left : %d\n", leftObjs);
2102 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
2103 printf("# reused : %d\n", reAll);
2104 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
2105
2106 printf("# node-sets\n");
2107 printf("# total : %d\n", reqNodeset);
2108 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
2109 printf("# reused : %d\n", reNodeset);
2110 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
2111
2112 printf("# strings\n");
2113 printf("# total : %d\n", reqString);
2114 printf("# created: %d\n", xmlXPathDebugObjTotalString);
2115 printf("# reused : %d\n", reString);
2116 printf("# max : %d\n", xmlXPathDebugObjMaxString);
2117
2118 printf("# booleans\n");
2119 printf("# total : %d\n", reqBool);
2120 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
2121 printf("# reused : %d\n", reBool);
2122 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
2123
2124 printf("# numbers\n");
2125 printf("# total : %d\n", reqNumber);
2126 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
2127 printf("# reused : %d\n", reNumber);
2128 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
2129
2130 printf("# XSLT result tree fragments\n");
2131 printf("# total : %d\n", reqXSLTTree);
2132 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2133 printf("# reused : %d\n", reXSLTTree);
2134 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
2135
2136 printf("# undefined\n");
2137 printf("# total : %d\n", reqUndefined);
2138 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
2139 printf("# reused : %d\n", reUndefined);
2140 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
2141
2142 }
2143
2144 #endif /* XP_DEBUG_OBJ_USAGE */
2145
2146 #endif /* LIBXML_DEBUG_ENABLED */
2147
2148 /************************************************************************
2149 * *
2150 * XPath object caching *
2151 * *
2152 ************************************************************************/
2153
2154 /**
2155 * xmlXPathNewCache:
2156 *
2157 * Create a new object cache
2158 *
2159 * Returns the xmlXPathCache just allocated.
2160 */
2161 static xmlXPathContextCachePtr
2162 xmlXPathNewCache(void)
2163 {
2164 xmlXPathContextCachePtr ret;
2165
2166 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2167 if (ret == NULL) {
2168 xmlXPathErrMemory(NULL, "creating object cache\n");
2169 return(NULL);
2170 }
2171 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
2172 ret->maxNodeset = 100;
2173 ret->maxString = 100;
2174 ret->maxBoolean = 100;
2175 ret->maxNumber = 100;
2176 ret->maxMisc = 100;
2177 return(ret);
2178 }
2179
2180 static void
2181 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2182 {
2183 int i;
2184 xmlXPathObjectPtr obj;
2185
2186 if (list == NULL)
2187 return;
2188
2189 for (i = 0; i < list->number; i++) {
2190 obj = list->items[i];
2191 /*
2192 * Note that it is already assured that we don't need to
2193 * look out for namespace nodes in the node-set.
2194 */
2195 if (obj->nodesetval != NULL) {
2196 if (obj->nodesetval->nodeTab != NULL)
2197 xmlFree(obj->nodesetval->nodeTab);
2198 xmlFree(obj->nodesetval);
2199 }
2200 xmlFree(obj);
2201 #ifdef XP_DEBUG_OBJ_USAGE
2202 xmlXPathDebugObjCounterAll--;
2203 #endif
2204 }
2205 xmlPointerListFree(list);
2206 }
2207
2208 static void
2209 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2210 {
2211 if (cache == NULL)
2212 return;
2213 if (cache->nodesetObjs)
2214 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2215 if (cache->stringObjs)
2216 xmlXPathCacheFreeObjectList(cache->stringObjs);
2217 if (cache->booleanObjs)
2218 xmlXPathCacheFreeObjectList(cache->booleanObjs);
2219 if (cache->numberObjs)
2220 xmlXPathCacheFreeObjectList(cache->numberObjs);
2221 if (cache->miscObjs)
2222 xmlXPathCacheFreeObjectList(cache->miscObjs);
2223 xmlFree(cache);
2224 }
2225
2226 /**
2227 * xmlXPathContextSetCache:
2228 *
2229 * @ctxt: the XPath context
2230 * @active: enables/disables (creates/frees) the cache
2231 * @value: a value with semantics dependant on @options
2232 * @options: options (currently only the value 0 is used)
2233 *
2234 * Creates/frees an object cache on the XPath context.
2235 * If activates XPath objects (xmlXPathObject) will be cached internally
2236 * to be reused.
2237 * @options:
2238 * 0: This will set the XPath object caching:
2239 * @value:
2240 * This will set the maximum number of XPath objects
2241 * to be cached per slot
2242 * There are 5 slots for: node-set, string, number, boolean, and
2243 * misc objects. Use <0 for the default number (100).
2244 * Other values for @options have currently no effect.
2245 *
2246 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2247 */
2248 int
2249 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2250 int active,
2251 int value,
2252 int options)
2253 {
2254 if (ctxt == NULL)
2255 return(-1);
2256 if (active) {
2257 xmlXPathContextCachePtr cache;
2258
2259 if (ctxt->cache == NULL) {
2260 ctxt->cache = xmlXPathNewCache();
2261 if (ctxt->cache == NULL)
2262 return(-1);
2263 }
2264 cache = (xmlXPathContextCachePtr) ctxt->cache;
2265 if (options == 0) {
2266 if (value < 0)
2267 value = 100;
2268 cache->maxNodeset = value;
2269 cache->maxString = value;
2270 cache->maxNumber = value;
2271 cache->maxBoolean = value;
2272 cache->maxMisc = value;
2273 }
2274 } else if (ctxt->cache != NULL) {
2275 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2276 ctxt->cache = NULL;
2277 }
2278 return(0);
2279 }
2280
2281 /**
2282 * xmlXPathCacheWrapNodeSet:
2283 * @ctxt: the XPath context
2284 * @val: the NodePtr value
2285 *
2286 * This is the cached version of xmlXPathWrapNodeSet().
2287 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2288 *
2289 * Returns the created or reused object.
2290 */
2291 static xmlXPathObjectPtr
2292 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2293 {
2294 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2295 xmlXPathContextCachePtr cache =
2296 (xmlXPathContextCachePtr) ctxt->cache;
2297
2298 if ((cache->miscObjs != NULL) &&
2299 (cache->miscObjs->number != 0))
2300 {
2301 xmlXPathObjectPtr ret;
2302
2303 ret = (xmlXPathObjectPtr)
2304 cache->miscObjs->items[--cache->miscObjs->number];
2305 ret->type = XPATH_NODESET;
2306 ret->nodesetval = val;
2307 #ifdef XP_DEBUG_OBJ_USAGE
2308 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2309 #endif
2310 return(ret);
2311 }
2312 }
2313
2314 return(xmlXPathWrapNodeSet(val));
2315
2316 }
2317
2318 /**
2319 * xmlXPathCacheWrapString:
2320 * @ctxt: the XPath context
2321 * @val: the xmlChar * value
2322 *
2323 * This is the cached version of xmlXPathWrapString().
2324 * Wraps the @val string into an XPath object.
2325 *
2326 * Returns the created or reused object.
2327 */
2328 static xmlXPathObjectPtr
2329 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2330 {
2331 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2332 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2333
2334 if ((cache->stringObjs != NULL) &&
2335 (cache->stringObjs->number != 0))
2336 {
2337
2338 xmlXPathObjectPtr ret;
2339
2340 ret = (xmlXPathObjectPtr)
2341 cache->stringObjs->items[--cache->stringObjs->number];
2342 ret->type = XPATH_STRING;
2343 ret->stringval = val;
2344 #ifdef XP_DEBUG_OBJ_USAGE
2345 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2346 #endif
2347 return(ret);
2348 } else if ((cache->miscObjs != NULL) &&
2349 (cache->miscObjs->number != 0))
2350 {
2351 xmlXPathObjectPtr ret;
2352 /*
2353 * Fallback to misc-cache.
2354 */
2355 ret = (xmlXPathObjectPtr)
2356 cache->miscObjs->items[--cache->miscObjs->number];
2357
2358 ret->type = XPATH_STRING;
2359 ret->stringval = val;
2360 #ifdef XP_DEBUG_OBJ_USAGE
2361 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2362 #endif
2363 return(ret);
2364 }
2365 }
2366 return(xmlXPathWrapString(val));
2367 }
2368
2369 /**
2370 * xmlXPathCacheNewNodeSet:
2371 * @ctxt: the XPath context
2372 * @val: the NodePtr value
2373 *
2374 * This is the cached version of xmlXPathNewNodeSet().
2375 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2376 * it with the single Node @val
2377 *
2378 * Returns the created or reused object.
2379 */
2380 static xmlXPathObjectPtr
2381 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2382 {
2383 if ((ctxt != NULL) && (ctxt->cache)) {
2384 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2385
2386 if ((cache->nodesetObjs != NULL) &&
2387 (cache->nodesetObjs->number != 0))
2388 {
2389 xmlXPathObjectPtr ret;
2390 /*
2391 * Use the nodset-cache.
2392 */
2393 ret = (xmlXPathObjectPtr)
2394 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2395 ret->type = XPATH_NODESET;
2396 ret->boolval = 0;
2397 if (val) {
2398 if ((ret->nodesetval->nodeMax == 0) ||
2399 (val->type == XML_NAMESPACE_DECL))
2400 {
2401 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2402 } else {
2403 ret->nodesetval->nodeTab[0] = val;
2404 ret->nodesetval->nodeNr = 1;
2405 }
2406 }
2407 #ifdef XP_DEBUG_OBJ_USAGE
2408 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2409 #endif
2410 return(ret);
2411 } else if ((cache->miscObjs != NULL) &&
2412 (cache->miscObjs->number != 0))
2413 {
2414 xmlXPathObjectPtr ret;
2415 /*
2416 * Fallback to misc-cache.
2417 */
2418
2419 ret = (xmlXPathObjectPtr)
2420 cache->miscObjs->items[--cache->miscObjs->number];
2421
2422 ret->type = XPATH_NODESET;
2423 ret->boolval = 0;
2424 ret->nodesetval = xmlXPathNodeSetCreate(val);
2425 if (ret->nodesetval == NULL) {
2426 ctxt->lastError.domain = XML_FROM_XPATH;
2427 ctxt->lastError.code = XML_ERR_NO_MEMORY;
2428 return(NULL);
2429 }
2430 #ifdef XP_DEBUG_OBJ_USAGE
2431 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2432 #endif
2433 return(ret);
2434 }
2435 }
2436 return(xmlXPathNewNodeSet(val));
2437 }
2438
2439 /**
2440 * xmlXPathCacheNewCString:
2441 * @ctxt: the XPath context
2442 * @val: the char * value
2443 *
2444 * This is the cached version of xmlXPathNewCString().
2445 * Acquire an xmlXPathObjectPtr of type string and of value @val
2446 *
2447 * Returns the created or reused object.
2448 */
2449 static xmlXPathObjectPtr
2450 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2451 {
2452 if ((ctxt != NULL) && (ctxt->cache)) {
2453 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2454
2455 if ((cache->stringObjs != NULL) &&
2456 (cache->stringObjs->number != 0))
2457 {
2458 xmlXPathObjectPtr ret;
2459
2460 ret = (xmlXPathObjectPtr)
2461 cache->stringObjs->items[--cache->stringObjs->number];
2462
2463 ret->type = XPATH_STRING;
2464 ret->stringval = xmlStrdup(BAD_CAST val);
2465 #ifdef XP_DEBUG_OBJ_USAGE
2466 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2467 #endif
2468 return(ret);
2469 } else if ((cache->miscObjs != NULL) &&
2470 (cache->miscObjs->number != 0))
2471 {
2472 xmlXPathObjectPtr ret;
2473
2474 ret = (xmlXPathObjectPtr)
2475 cache->miscObjs->items[--cache->miscObjs->number];
2476
2477 ret->type = XPATH_STRING;
2478 ret->stringval = xmlStrdup(BAD_CAST val);
2479 #ifdef XP_DEBUG_OBJ_USAGE
2480 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2481 #endif
2482 return(ret);
2483 }
2484 }
2485 return(xmlXPathNewCString(val));
2486 }
2487
2488 /**
2489 * xmlXPathCacheNewString:
2490 * @ctxt: the XPath context
2491 * @val: the xmlChar * value
2492 *
2493 * This is the cached version of xmlXPathNewString().
2494 * Acquire an xmlXPathObjectPtr of type string and of value @val
2495 *
2496 * Returns the created or reused object.
2497 */
2498 static xmlXPathObjectPtr
2499 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2500 {
2501 if ((ctxt != NULL) && (ctxt->cache)) {
2502 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2503
2504 if ((cache->stringObjs != NULL) &&
2505 (cache->stringObjs->number != 0))
2506 {
2507 xmlXPathObjectPtr ret;
2508
2509 ret = (xmlXPathObjectPtr)
2510 cache->stringObjs->items[--cache->stringObjs->number];
2511 ret->type = XPATH_STRING;
2512 if (val != NULL)
2513 ret->stringval = xmlStrdup(val);
2514 else
2515 ret->stringval = xmlStrdup((const xmlChar *)"");
2516 #ifdef XP_DEBUG_OBJ_USAGE
2517 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2518 #endif
2519 return(ret);
2520 } else if ((cache->miscObjs != NULL) &&
2521 (cache->miscObjs->number != 0))
2522 {
2523 xmlXPathObjectPtr ret;
2524
2525 ret = (xmlXPathObjectPtr)
2526 cache->miscObjs->items[--cache->miscObjs->number];
2527
2528 ret->type = XPATH_STRING;
2529 if (val != NULL)
2530 ret->stringval = xmlStrdup(val);
2531 else
2532 ret->stringval = xmlStrdup((const xmlChar *)"");
2533 #ifdef XP_DEBUG_OBJ_USAGE
2534 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2535 #endif
2536 return(ret);
2537 }
2538 }
2539 return(xmlXPathNewString(val));
2540 }
2541
2542 /**
2543 * xmlXPathCacheNewBoolean:
2544 * @ctxt: the XPath context
2545 * @val: the boolean value
2546 *
2547 * This is the cached version of xmlXPathNewBoolean().
2548 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2549 *
2550 * Returns the created or reused object.
2551 */
2552 static xmlXPathObjectPtr
2553 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2554 {
2555 if ((ctxt != NULL) && (ctxt->cache)) {
2556 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2557
2558 if ((cache->booleanObjs != NULL) &&
2559 (cache->booleanObjs->number != 0))
2560 {
2561 xmlXPathObjectPtr ret;
2562
2563 ret = (xmlXPathObjectPtr)
2564 cache->booleanObjs->items[--cache->booleanObjs->number];
2565 ret->type = XPATH_BOOLEAN;
2566 ret->boolval = (val != 0);
2567 #ifdef XP_DEBUG_OBJ_USAGE
2568 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2569 #endif
2570 return(ret);
2571 } else if ((cache->miscObjs != NULL) &&
2572 (cache->miscObjs->number != 0))
2573 {
2574 xmlXPathObjectPtr ret;
2575
2576 ret = (xmlXPathObjectPtr)
2577 cache->miscObjs->items[--cache->miscObjs->number];
2578
2579 ret->type = XPATH_BOOLEAN;
2580 ret->boolval = (val != 0);
2581 #ifdef XP_DEBUG_OBJ_USAGE
2582 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2583 #endif
2584 return(ret);
2585 }
2586 }
2587 return(xmlXPathNewBoolean(val));
2588 }
2589
2590 /**
2591 * xmlXPathCacheNewFloat:
2592 * @ctxt: the XPath context
2593 * @val: the double value
2594 *
2595 * This is the cached version of xmlXPathNewFloat().
2596 * Acquires an xmlXPathObjectPtr of type double and of value @val
2597 *
2598 * Returns the created or reused object.
2599 */
2600 static xmlXPathObjectPtr
2601 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2602 {
2603 if ((ctxt != NULL) && (ctxt->cache)) {
2604 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2605
2606 if ((cache->numberObjs != NULL) &&
2607 (cache->numberObjs->number != 0))
2608 {
2609 xmlXPathObjectPtr ret;
2610
2611 ret = (xmlXPathObjectPtr)
2612 cache->numberObjs->items[--cache->numberObjs->number];
2613 ret->type = XPATH_NUMBER;
2614 ret->floatval = val;
2615 #ifdef XP_DEBUG_OBJ_USAGE
2616 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2617 #endif
2618 return(ret);
2619 } else if ((cache->miscObjs != NULL) &&
2620 (cache->miscObjs->number != 0))
2621 {
2622 xmlXPathObjectPtr ret;
2623
2624 ret = (xmlXPathObjectPtr)
2625 cache->miscObjs->items[--cache->miscObjs->number];
2626
2627 ret->type = XPATH_NUMBER;
2628 ret->floatval = val;
2629 #ifdef XP_DEBUG_OBJ_USAGE
2630 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2631 #endif
2632 return(ret);
2633 }
2634 }
2635 return(xmlXPathNewFloat(val));
2636 }
2637
2638 /**
2639 * xmlXPathCacheConvertString:
2640 * @ctxt: the XPath context
2641 * @val: an XPath object
2642 *
2643 * This is the cached version of xmlXPathConvertString().
2644 * Converts an existing object to its string() equivalent
2645 *
2646 * Returns a created or reused object, the old one is freed (cached)
2647 * (or the operation is done directly on @val)
2648 */
2649
2650 static xmlXPathObjectPtr
2651 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2652 xmlChar *res = NULL;
2653
2654 if (val == NULL)
2655 return(xmlXPathCacheNewCString(ctxt, ""));
2656
2657 switch (val->type) {
2658 case XPATH_UNDEFINED:
2659 #ifdef DEBUG_EXPR
2660 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2661 #endif
2662 break;
2663 case XPATH_NODESET:
2664 case XPATH_XSLT_TREE:
2665 res = xmlXPathCastNodeSetToString(val->nodesetval);
2666 break;
2667 case XPATH_STRING:
2668 return(val);
2669 case XPATH_BOOLEAN:
2670 res = xmlXPathCastBooleanToString(val->boolval);
2671 break;
2672 case XPATH_NUMBER:
2673 res = xmlXPathCastNumberToString(val->floatval);
2674 break;
2675 case XPATH_USERS:
2676 case XPATH_POINT:
2677 case XPATH_RANGE:
2678 case XPATH_LOCATIONSET:
2679 TODO;
2680 break;
2681 }
2682 xmlXPathReleaseObject(ctxt, val);
2683 if (res == NULL)
2684 return(xmlXPathCacheNewCString(ctxt, ""));
2685 return(xmlXPathCacheWrapString(ctxt, res));
2686 }
2687
2688 /**
2689 * xmlXPathCacheObjectCopy:
2690 * @ctxt: the XPath context
2691 * @val: the original object
2692 *
2693 * This is the cached version of xmlXPathObjectCopy().
2694 * Acquire a copy of a given object
2695 *
2696 * Returns a created or reused created object.
2697 */
2698 static xmlXPathObjectPtr
2699 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2700 {
2701 if (val == NULL)
2702 return(NULL);
2703
2704 if (XP_HAS_CACHE(ctxt)) {
2705 switch (val->type) {
2706 case XPATH_NODESET:
2707 return(xmlXPathCacheWrapNodeSet(ctxt,
2708 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2709 case XPATH_STRING:
2710 return(xmlXPathCacheNewString(ctxt, val->stringval));
2711 case XPATH_BOOLEAN:
2712 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2713 case XPATH_NUMBER:
2714 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2715 default:
2716 break;
2717 }
2718 }
2719 return(xmlXPathObjectCopy(val));
2720 }
2721
2722 /**
2723 * xmlXPathCacheConvertBoolean:
2724 * @ctxt: the XPath context
2725 * @val: an XPath object
2726 *
2727 * This is the cached version of xmlXPathConvertBoolean().
2728 * Converts an existing object to its boolean() equivalent
2729 *
2730 * Returns a created or reused object, the old one is freed (or the operation
2731 * is done directly on @val)
2732 */
2733 static xmlXPathObjectPtr
2734 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2735 xmlXPathObjectPtr ret;
2736
2737 if (val == NULL)
2738 return(xmlXPathCacheNewBoolean(ctxt, 0));
2739 if (val->type == XPATH_BOOLEAN)
2740 return(val);
2741 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2742 xmlXPathReleaseObject(ctxt, val);
2743 return(ret);
2744 }
2745
2746 /**
2747 * xmlXPathCacheConvertNumber:
2748 * @ctxt: the XPath context
2749 * @val: an XPath object
2750 *
2751 * This is the cached version of xmlXPathConvertNumber().
2752 * Converts an existing object to its number() equivalent
2753 *
2754 * Returns a created or reused object, the old one is freed (or the operation
2755 * is done directly on @val)
2756 */
2757 static xmlXPathObjectPtr
2758 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2759 xmlXPathObjectPtr ret;
2760
2761 if (val == NULL)
2762 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2763 if (val->type == XPATH_NUMBER)
2764 return(val);
2765 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2766 xmlXPathReleaseObject(ctxt, val);
2767 return(ret);
2768 }
2769
2770 /************************************************************************
2771 * *
2772 * Parser stacks related functions and macros *
2773 * *
2774 ************************************************************************/
2775
2776 /**
2777 * xmlXPathSetFrame:
2778 * @ctxt: an XPath parser context
2779 *
2780 * Set the callee evaluation frame
2781 *
2782 * Returns the previous frame value to be restored once done
2783 */
2784 static int
2785 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2786 int ret;
2787
2788 if (ctxt == NULL)
2789 return(0);
2790 ret = ctxt->valueFrame;
2791 ctxt->valueFrame = ctxt->valueNr;
2792 return(ret);
2793 }
2794
2795 /**
2796 * xmlXPathPopFrame:
2797 * @ctxt: an XPath parser context
2798 * @frame: the previous frame value
2799 *
2800 * Remove the callee evaluation frame
2801 */
2802 static void
2803 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2804 if (ctxt == NULL)
2805 return;
2806 if (ctxt->valueNr < ctxt->valueFrame) {
2807 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2808 }
2809 ctxt->valueFrame = frame;
2810 }
2811
2812 /**
2813 * valuePop:
2814 * @ctxt: an XPath evaluation context
2815 *
2816 * Pops the top XPath object from the value stack
2817 *
2818 * Returns the XPath object just removed
2819 */
2820 xmlXPathObjectPtr
2821 valuePop(xmlXPathParserContextPtr ctxt)
2822 {
2823 xmlXPathObjectPtr ret;
2824
2825 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2826 return (NULL);
2827
2828 if (ctxt->valueNr <= ctxt->valueFrame) {
2829 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2830 return (NULL);
2831 }
2832
2833 ctxt->valueNr--;
2834 if (ctxt->valueNr > 0)
2835 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2836 else
2837 ctxt->value = NULL;
2838 ret = ctxt->valueTab[ctxt->valueNr];
2839 ctxt->valueTab[ctxt->valueNr] = NULL;
2840 return (ret);
2841 }
2842 /**
2843 * valuePush:
2844 * @ctxt: an XPath evaluation context
2845 * @value: the XPath object
2846 *
2847 * Pushes a new XPath object on top of the value stack
2848 *
2849 * returns the number of items on the value stack
2850 */
2851 int
2852 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2853 {
2854 if ((ctxt == NULL) || (value == NULL)) return(-1);
2855 if (ctxt->valueNr >= ctxt->valueMax) {
2856 xmlXPathObjectPtr *tmp;
2857
2858 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2859 xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
2860 ctxt->error = XPATH_MEMORY_ERROR;
2861 return (0);
2862 }
2863 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2864 2 * ctxt->valueMax *
2865 sizeof(ctxt->valueTab[0]));
2866 if (tmp == NULL) {
2867 xmlXPathErrMemory(NULL, "pushing value\n");
2868 ctxt->error = XPATH_MEMORY_ERROR;
2869 return (0);
2870 }
2871 ctxt->valueMax *= 2;
2872 ctxt->valueTab = tmp;
2873 }
2874 ctxt->valueTab[ctxt->valueNr] = value;
2875 ctxt->value = value;
2876 return (ctxt->valueNr++);
2877 }
2878
2879 /**
2880 * xmlXPathPopBoolean:
2881 * @ctxt: an XPath parser context
2882 *
2883 * Pops a boolean from the stack, handling conversion if needed.
2884 * Check error with #xmlXPathCheckError.
2885 *
2886 * Returns the boolean
2887 */
2888 int
2889 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2890 xmlXPathObjectPtr obj;
2891 int ret;
2892
2893 obj = valuePop(ctxt);
2894 if (obj == NULL) {
2895 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2896 return(0);
2897 }
2898 if (obj->type != XPATH_BOOLEAN)
2899 ret = xmlXPathCastToBoolean(obj);
2900 else
2901 ret = obj->boolval;
2902 xmlXPathReleaseObject(ctxt->context, obj);
2903 return(ret);
2904 }
2905
2906 /**
2907 * xmlXPathPopNumber:
2908 * @ctxt: an XPath parser context
2909 *
2910 * Pops a number from the stack, handling conversion if needed.
2911 * Check error with #xmlXPathCheckError.
2912 *
2913 * Returns the number
2914 */
2915 double
2916 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2917 xmlXPathObjectPtr obj;
2918 double ret;
2919
2920 obj = valuePop(ctxt);
2921 if (obj == NULL) {
2922 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2923 return(0);
2924 }
2925 if (obj->type != XPATH_NUMBER)
2926 ret = xmlXPathCastToNumber(obj);
2927 else
2928 ret = obj->floatval;
2929 xmlXPathReleaseObject(ctxt->context, obj);
2930 return(ret);
2931 }
2932
2933 /**
2934 * xmlXPathPopString:
2935 * @ctxt: an XPath parser context
2936 *
2937 * Pops a string from the stack, handling conversion if needed.
2938 * Check error with #xmlXPathCheckError.
2939 *
2940 * Returns the string
2941 */
2942 xmlChar *
2943 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2944 xmlXPathObjectPtr obj;
2945 xmlChar * ret;
2946
2947 obj = valuePop(ctxt);
2948 if (obj == NULL) {
2949 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2950 return(NULL);
2951 }
2952 ret = xmlXPathCastToString(obj); /* this does required strdup */
2953 /* TODO: needs refactoring somewhere else */
2954 if (obj->stringval == ret)
2955 obj->stringval = NULL;
2956 xmlXPathReleaseObject(ctxt->context, obj);
2957 return(ret);
2958 }
2959
2960 /**
2961 * xmlXPathPopNodeSet:
2962 * @ctxt: an XPath parser context
2963 *
2964 * Pops a node-set from the stack, handling conversion if needed.
2965 * Check error with #xmlXPathCheckError.
2966 *
2967 * Returns the node-set
2968 */
2969 xmlNodeSetPtr
2970 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2971 xmlXPathObjectPtr obj;
2972 xmlNodeSetPtr ret;
2973
2974 if (ctxt == NULL) return(NULL);
2975 if (ctxt->value == NULL) {
2976 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2977 return(NULL);
2978 }
2979 if (!xmlXPathStackIsNodeSet(ctxt)) {
2980 xmlXPathSetTypeError(ctxt);
2981 return(NULL);
2982 }
2983 obj = valuePop(ctxt);
2984 ret = obj->nodesetval;
2985 #if 0
2986 /* to fix memory leak of not clearing obj->user */
2987 if (obj->boolval && obj->user != NULL)
2988 xmlFreeNodeList((xmlNodePtr) obj->user);
2989 #endif
2990 obj->nodesetval = NULL;
2991 xmlXPathReleaseObject(ctxt->context, obj);
2992 return(ret);
2993 }
2994
2995 /**
2996 * xmlXPathPopExternal:
2997 * @ctxt: an XPath parser context
2998 *
2999 * Pops an external object from the stack, handling conversion if needed.
3000 * Check error with #xmlXPathCheckError.
3001 *
3002 * Returns the object
3003 */
3004 void *
3005 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3006 xmlXPathObjectPtr obj;
3007 void * ret;
3008
3009 if ((ctxt == NULL) || (ctxt->value == NULL)) {
3010 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3011 return(NULL);
3012 }
3013 if (ctxt->value->type != XPATH_USERS) {
3014 xmlXPathSetTypeError(ctxt);
3015 return(NULL);
3016 }
3017 obj = valuePop(ctxt);
3018 ret = obj->user;
3019 obj->user = NULL;
3020 xmlXPathReleaseObject(ctxt->context, obj);
3021 return(ret);
3022 }
3023
3024 /*
3025 * Macros for accessing the content. Those should be used only by the parser,
3026 * and not exported.
3027 *
3028 * Dirty macros, i.e. one need to make assumption on the context to use them
3029 *
3030 * CUR_PTR return the current pointer to the xmlChar to be parsed.
3031 * CUR returns the current xmlChar value, i.e. a 8 bit value
3032 * in ISO-Latin or UTF-8.
3033 * This should be used internally by the parser
3034 * only to compare to ASCII values otherwise it would break when
3035 * running with UTF-8 encoding.
3036 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
3037 * to compare on ASCII based substring.
3038 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3039 * strings within the parser.
3040 * CURRENT Returns the current char value, with the full decoding of
3041 * UTF-8 if we are using this mode. It returns an int.
3042 * NEXT Skip to the next character, this does the proper decoding
3043 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
3044 * It returns the pointer to the current xmlChar.
3045 */
3046
3047 #define CUR (*ctxt->cur)
3048 #define SKIP(val) ctxt->cur += (val)
3049 #define NXT(val) ctxt->cur[(val)]
3050 #define CUR_PTR ctxt->cur
3051 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3052
3053 #define COPY_BUF(l,b,i,v) \
3054 if (l == 1) b[i++] = (xmlChar) v; \
3055 else i += xmlCopyChar(l,&b[i],v)
3056
3057 #define NEXTL(l) ctxt->cur += l
3058
3059 #define SKIP_BLANKS \
3060 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3061
3062 #define CURRENT (*ctxt->cur)
3063 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
3064
3065
3066 #ifndef DBL_DIG
3067 #define DBL_DIG 16
3068 #endif
3069 #ifndef DBL_EPSILON
3070 #define DBL_EPSILON 1E-9
3071 #endif
3072
3073 #define UPPER_DOUBLE 1E9
3074 #define LOWER_DOUBLE 1E-5
3075 #define LOWER_DOUBLE_EXP 5
3076
3077 #define INTEGER_DIGITS DBL_DIG
3078 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3079 #define EXPONENT_DIGITS (3 + 2)
3080
3081 /**
3082 * xmlXPathFormatNumber:
3083 * @number: number to format
3084 * @buffer: output buffer
3085 * @buffersize: size of output buffer
3086 *
3087 * Convert the number into a string representation.
3088 */
3089 static void
3090 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3091 {
3092 switch (xmlXPathIsInf(number)) {
3093 case 1:
3094 if (buffersize > (int)sizeof("Infinity"))
3095 snprintf(buffer, buffersize, "Infinity");
3096 break;
3097 case -1:
3098 if (buffersize > (int)sizeof("-Infinity"))
3099 snprintf(buffer, buffersize, "-Infinity");
3100 break;
3101 default:
3102 if (xmlXPathIsNaN(number)) {
3103 if (buffersize > (int)sizeof("NaN"))
3104 snprintf(buffer, buffersize, "NaN");
3105 } else if (number == 0) {
3106 /* Omit sign for negative zero. */
3107 snprintf(buffer, buffersize, "0");
3108 } else if ((number > INT_MIN) && (number < INT_MAX) &&
3109 (number == (int) number)) {
3110 char work[30];
3111 char *ptr, *cur;
3112 int value = (int) number;
3113
3114 ptr = &buffer[0];
3115 if (value == 0) {
3116 *ptr++ = '0';
3117 } else {
3118 snprintf(work, 29, "%d", value);
3119 cur = &work[0];
3120 while ((*cur) && (ptr - buffer < buffersize)) {
3121 *ptr++ = *cur++;
3122 }
3123 }
3124 if (ptr - buffer < buffersize) {
3125 *ptr = 0;
3126 } else if (buffersize > 0) {
3127 ptr--;
3128 *ptr = 0;
3129 }
3130 } else {
3131 /*
3132 For the dimension of work,
3133 DBL_DIG is number of significant digits
3134 EXPONENT is only needed for "scientific notation"
3135 3 is sign, decimal point, and terminating zero
3136 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3137 Note that this dimension is slightly (a few characters)
3138 larger than actually necessary.
3139 */
3140 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3141 int integer_place, fraction_place;
3142 char *ptr;
3143 char *after_fraction;
3144 double absolute_value;
3145 int size;
3146
3147 absolute_value = fabs(number);
3148
3149 /*
3150 * First choose format - scientific or regular floating point.
3151 * In either case, result is in work, and after_fraction points
3152 * just past the fractional part.
3153 */
3154 if ( ((absolute_value > UPPER_DOUBLE) ||
3155 (absolute_value < LOWER_DOUBLE)) &&
3156 (absolute_value != 0.0) ) {
3157 /* Use scientific notation */
3158 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3159 fraction_place = DBL_DIG - 1;
3160 size = snprintf(work, sizeof(work),"%*.*e",
3161 integer_place, fraction_place, number);
3162 while ((size > 0) && (work[size] != 'e')) size--;
3163
3164 }
3165 else {
3166 /* Use regular notation */
3167 if (absolute_value > 0.0) {
3168 integer_place = (int)log10(absolute_value);
3169 if (integer_place > 0)
3170 fraction_place = DBL_DIG - integer_place - 1;
3171 else
3172 fraction_place = DBL_DIG - integer_place;
3173 } else {
3174 fraction_place = 1;
3175 }
3176 size = snprintf(work, sizeof(work), "%0.*f",
3177 fraction_place, number);
3178 }
3179
3180 /* Remove leading spaces sometimes inserted by snprintf */
3181 while (work[0] == ' ') {
3182 for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3183 size--;
3184 }
3185
3186 /* Remove fractional trailing zeroes */
3187 after_fraction = work + size;
3188 ptr = after_fraction;
3189 while (*(--ptr) == '0')
3190 ;
3191 if (*ptr != '.')
3192 ptr++;
3193 while ((*ptr++ = *after_fraction++) != 0);
3194
3195 /* Finally copy result back to caller */
3196 size = strlen(work) + 1;
3197 if (size > buffersize) {
3198 work[buffersize - 1] = 0;
3199 size = buffersize;
3200 }
3201 memmove(buffer, work, size);
3202 }
3203 break;
3204 }
3205 }
3206
3207
3208 /************************************************************************
3209 * *
3210 * Routines to handle NodeSets *
3211 * *
3212 ************************************************************************/
3213
3214 /**
3215 * xmlXPathOrderDocElems:
3216 * @doc: an input document
3217 *
3218 * Call this routine to speed up XPath computation on static documents.
3219 * This stamps all the element nodes with the document order
3220 * Like for line information, the order is kept in the element->content
3221 * field, the value stored is actually - the node number (starting at -1)
3222 * to be able to differentiate from line numbers.
3223 *
3224 * Returns the number of elements found in the document or -1 in case
3225 * of error.
3226 */
3227 long
3228 xmlXPathOrderDocElems(xmlDocPtr doc) {
3229 ptrdiff_t count = 0;
3230 xmlNodePtr cur;
3231
3232 if (doc == NULL)
3233 return(-1);
3234 cur = doc->children;
3235 while (cur != NULL) {
3236 if (cur->type == XML_ELEMENT_NODE) {
3237 cur->content = (void *) (-(++count));
3238 if (cur->children != NULL) {
3239 cur = cur->children;
3240 continue;
3241 }
3242 }
3243 if (cur->next != NULL) {
3244 cur = cur->next;
3245 continue;
3246 }
3247 do {
3248 cur = cur->parent;
3249 if (cur == NULL)
3250 break;
3251 if (cur == (xmlNodePtr) doc) {
3252 cur = NULL;
3253 break;
3254 }
3255 if (cur->next != NULL) {
3256 cur = cur->next;
3257 break;
3258 }
3259 } while (cur != NULL);
3260 }
3261 return((long) count);
3262 }
3263
3264 /**
3265 * xmlXPathCmpNodes:
3266 * @node1: the first node
3267 * @node2: the second node
3268 *
3269 * Compare two nodes w.r.t document order
3270 *
3271 * Returns -2 in case of error 1 if first point < second point, 0 if
3272 * it's the same node, -1 otherwise
3273 */
3274 int
3275 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3276 int depth1, depth2;
3277 int attr1 = 0, attr2 = 0;
3278 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3279 xmlNodePtr cur, root;
3280
3281 if ((node1 == NULL) || (node2 == NULL))
3282 return(-2);
3283 /*
3284 * a couple of optimizations which will avoid computations in most cases
3285 */
3286 if (node1 == node2) /* trivial case */
3287 return(0);
3288 if (node1->type == XML_ATTRIBUTE_NODE) {
3289 attr1 = 1;
3290 attrNode1 = node1;
3291 node1 = node1->parent;
3292 }
3293 if (node2->type == XML_ATTRIBUTE_NODE) {
3294 attr2 = 1;
3295 attrNode2 = node2;
3296 node2 = node2->parent;
3297 }
3298 if (node1 == node2) {
3299 if (attr1 == attr2) {
3300 /* not required, but we keep attributes in order */
3301 if (attr1 != 0) {
3302 cur = attrNode2->prev;
3303 while (cur != NULL) {
3304 if (cur == attrNode1)
3305 return (1);
3306 cur = cur->prev;
3307 }
3308 return (-1);
3309 }
3310 return(0);
3311 }
3312 if (attr2 == 1)
3313 return(1);
3314 return(-1);
3315 }
3316 if ((node1->type == XML_NAMESPACE_DECL) ||
3317 (node2->type == XML_NAMESPACE_DECL))
3318 return(1);
3319 if (node1 == node2->prev)
3320 return(1);
3321 if (node1 == node2->next)
3322 return(-1);
3323
3324 /*
3325 * Speedup using document order if availble.
3326 */
3327 if ((node1->type == XML_ELEMENT_NODE) &&
3328 (node2->type == XML_ELEMENT_NODE) &&
3329 (0 > (ptrdiff_t) node1->content) &&
3330 (0 > (ptrdiff_t) node2->content) &&
3331 (node1->doc == node2->doc)) {
3332 ptrdiff_t l1, l2;
3333
3334 l1 = -((ptrdiff_t) node1->content);
3335 l2 = -((ptrdiff_t) node2->content);
3336 if (l1 < l2)
3337 return(1);
3338 if (l1 > l2)
3339 return(-1);
3340 }
3341
3342 /*
3343 * compute depth to root
3344 */
3345 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3346 if (cur->parent == node1)
3347 return(1);
3348 depth2++;
3349 }
3350 root = cur;
3351 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3352 if (cur->parent == node2)
3353 return(-1);
3354 depth1++;
3355 }
3356 /*
3357 * Distinct document (or distinct entities :-( ) case.
3358 */
3359 if (root != cur) {
3360 return(-2);
3361 }
3362 /*
3363 * get the nearest common ancestor.
3364 */
3365 while (depth1 > depth2) {
3366 depth1--;
3367 node1 = node1->parent;
3368 }
3369 while (depth2 > depth1) {
3370 depth2--;
3371 node2 = node2->parent;
3372 }
3373 while (node1->parent != node2->parent) {
3374 node1 = node1->parent;
3375 node2 = node2->parent;
3376 /* should not happen but just in case ... */
3377 if ((node1 == NULL) || (node2 == NULL))
3378 return(-2);
3379 }
3380 /*
3381 * Find who's first.
3382 */
3383 if (node1 == node2->prev)
3384 return(1);
3385 if (node1 == node2->next)
3386 return(-1);
3387 /*
3388 * Speedup using document order if availble.
3389 */
3390 if ((node1->type == XML_ELEMENT_NODE) &&
3391 (node2->type == XML_ELEMENT_NODE) &&
3392 (0 > (ptrdiff_t) node1->content) &&
3393 (0 > (ptrdiff_t) node2->content) &&
3394 (node1->doc == node2->doc)) {
3395 ptrdiff_t l1, l2;
3396
3397 l1 = -((ptrdiff_t) node1->content);
3398 l2 = -((ptrdiff_t) node2->content);
3399 if (l1 < l2)
3400 return(1);
3401 if (l1 > l2)
3402 return(-1);
3403 }
3404
3405 for (cur = node1->next;cur != NULL;cur = cur->next)
3406 if (cur == node2)
3407 return(1);
3408 return(-1); /* assume there is no sibling list corruption */
3409 }
3410
3411 /**
3412 * xmlXPathNodeSetSort:
3413 * @set: the node set
3414 *
3415 * Sort the node set in document order
3416 */
3417 void
3418 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3419 #ifndef WITH_TIM_SORT
3420 int i, j, incr, len;
3421 xmlNodePtr tmp;
3422 #endif
3423
3424 if (set == NULL)
3425 return;
3426
3427 #ifndef WITH_TIM_SORT
3428 /*
3429 * Use the old Shell's sort implementation to sort the node-set
3430 * Timsort ought to be quite faster
3431 */
3432 len = set->nodeNr;
3433 for (incr = len / 2; incr > 0; incr /= 2) {
3434 for (i = incr; i < len; i++) {
3435 j = i - incr;
3436 while (j >= 0) {
3437 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3438 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3439 set->nodeTab[j + incr]) == -1)
3440 #else
3441 if (xmlXPathCmpNodes(set->nodeTab[j],
3442 set->nodeTab[j + incr]) == -1)
3443 #endif
3444 {
3445 tmp = set->nodeTab[j];
3446 set->nodeTab[j] = set->nodeTab[j + incr];
3447 set->nodeTab[j + incr] = tmp;
3448 j -= incr;
3449 } else
3450 break;
3451 }
3452 }
3453 }
3454 #else /* WITH_TIM_SORT */
3455 libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3456 #endif /* WITH_TIM_SORT */
3457 }
3458
3459 #define XML_NODESET_DEFAULT 10
3460 /**
3461 * xmlXPathNodeSetDupNs:
3462 * @node: the parent node of the namespace XPath node
3463 * @ns: the libxml namespace declaration node.
3464 *
3465 * Namespace node in libxml don't match the XPath semantic. In a node set
3466 * the namespace nodes are duplicated and the next pointer is set to the
3467 * parent node in the XPath semantic.
3468 *
3469 * Returns the newly created object.
3470 */
3471 static xmlNodePtr
3472 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3473 xmlNsPtr cur;
3474
3475 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3476 return(NULL);
3477 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3478 return((xmlNodePtr) ns);
3479
3480 /*
3481 * Allocate a new Namespace and fill the fields.
3482 */
3483 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3484 if (cur == NULL) {
3485 xmlXPathErrMemory(NULL, "duplicating namespace\n");
3486 return(NULL);
3487 }
3488 memset(cur, 0, sizeof(xmlNs));
3489 cur->type = XML_NAMESPACE_DECL;
3490 if (ns->href != NULL)
3491 cur->href = xmlStrdup(ns->href);
3492 if (ns->prefix != NULL)
3493 cur->prefix = xmlStrdup(ns->prefix);
3494 cur->next = (xmlNsPtr) node;
3495 return((xmlNodePtr) cur);
3496 }
3497
3498 /**
3499 * xmlXPathNodeSetFreeNs:
3500 * @ns: the XPath namespace node found in a nodeset.
3501 *
3502 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3503 * the namespace nodes are duplicated and the next pointer is set to the
3504 * parent node in the XPath semantic. Check if such a node needs to be freed
3505 */
3506 void
3507 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3508 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3509 return;
3510
3511 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3512 if (ns->href != NULL)
3513 xmlFree((xmlChar *)ns->href);
3514 if (ns->prefix != NULL)
3515 xmlFree((xmlChar *)ns->prefix);
3516 xmlFree(ns);
3517 }
3518 }
3519
3520 /**
3521 * xmlXPathNodeSetCreate:
3522 * @val: an initial xmlNodePtr, or NULL
3523 *
3524 * Create a new xmlNodeSetPtr of type double and of value @val
3525 *
3526 * Returns the newly created object.
3527 */
3528 xmlNodeSetPtr
3529 xmlXPathNodeSetCreate(xmlNodePtr val) {
3530 xmlNodeSetPtr ret;
3531
3532 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3533 if (ret == NULL) {
3534 xmlXPathErrMemory(NULL, "creating nodeset\n");
3535 return(NULL);
3536 }
3537 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3538 if (val != NULL) {
3539 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3540 sizeof(xmlNodePtr));
3541 if (ret->nodeTab == NULL) {
3542 xmlXPathErrMemory(NULL, "creating nodeset\n");
3543 xmlFree(ret);
3544 return(NULL);
3545 }
3546 memset(ret->nodeTab, 0 ,
3547 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3548 ret->nodeMax = XML_NODESET_DEFAULT;
3549 if (val->type == XML_NAMESPACE_DECL) {
3550 xmlNsPtr ns = (xmlNsPtr) val;
3551
3552 ret->nodeTab[ret->nodeNr++] =
3553 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3554 } else
3555 ret->nodeTab[ret->nodeNr++] = val;
3556 }
3557 return(ret);
3558 }
3559
3560 /**
3561 * xmlXPathNodeSetCreateSize:
3562 * @size: the initial size of the set
3563 *
3564 * Create a new xmlNodeSetPtr of type double and of value @val
3565 *
3566 * Returns the newly created object.
3567 */
3568 static xmlNodeSetPtr
3569 xmlXPathNodeSetCreateSize(int size) {
3570 xmlNodeSetPtr ret;
3571
3572 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3573 if (ret == NULL) {
3574 xmlXPathErrMemory(NULL, "creating nodeset\n");
3575 return(NULL);
3576 }
3577 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3578 if (size < XML_NODESET_DEFAULT)
3579 size = XML_NODESET_DEFAULT;
3580 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3581 if (ret->nodeTab == NULL) {
3582 xmlXPathErrMemory(NULL, "creating nodeset\n");
3583 xmlFree(ret);
3584 return(NULL);
3585 }
3586 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3587 ret->nodeMax = size;
3588 return(ret);
3589 }
3590
3591 /**
3592 * xmlXPathNodeSetContains:
3593 * @cur: the node-set
3594 * @val: the node
3595 *
3596 * checks whether @cur contains @val
3597 *
3598 * Returns true (1) if @cur contains @val, false (0) otherwise
3599 */
3600 int
3601 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3602 int i;
3603
3604 if ((cur == NULL) || (val == NULL)) return(0);
3605 if (val->type == XML_NAMESPACE_DECL) {
3606 for (i = 0; i < cur->nodeNr; i++) {
3607 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3608 xmlNsPtr ns1, ns2;
3609
3610 ns1 = (xmlNsPtr) val;
3611 ns2 = (xmlNsPtr) cur->nodeTab[i];
3612 if (ns1 == ns2)
3613 return(1);
3614 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3615 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3616 return(1);
3617 }
3618 }
3619 } else {
3620 for (i = 0; i < cur->nodeNr; i++) {
3621 if (cur->nodeTab[i] == val)
3622 return(1);
3623 }
3624 }
3625 return(0);
3626 }
3627
3628 /**
3629 * xmlXPathNodeSetAddNs:
3630 * @cur: the initial node set
3631 * @node: the hosting node
3632 * @ns: a the namespace node
3633 *
3634 * add a new namespace node to an existing NodeSet
3635 *
3636 * Returns 0 in case of success and -1 in case of error
3637 */
3638 int
3639 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3640 int i;
3641
3642
3643 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3644 (ns->type != XML_NAMESPACE_DECL) ||
3645 (node->type != XML_ELEMENT_NODE))
3646 return(-1);
3647
3648 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3649 /*
3650 * prevent duplicates
3651 */
3652 for (i = 0;i < cur->nodeNr;i++) {
3653 if ((cur->nodeTab[i] != NULL) &&
3654 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3655 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3656 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3657 return(0);
3658 }
3659
3660 /*
3661 * grow the nodeTab if needed
3662 */
3663 if (cur->nodeMax == 0) {
3664 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3665 sizeof(xmlNodePtr));
3666 if (cur->nodeTab == NULL) {
3667 xmlXPathErrMemory(NULL, "growing nodeset\n");
3668 return(-1);
3669 }
3670 memset(cur->nodeTab, 0 ,
3671 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3672 cur->nodeMax = XML_NODESET_DEFAULT;
3673 } else if (cur->nodeNr == cur->nodeMax) {
3674 xmlNodePtr *temp;
3675
3676 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3677 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3678 return(-1);
3679 }
3680 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3681 sizeof(xmlNodePtr));
3682 if (temp == NULL) {
3683 xmlXPathErrMemory(NULL, "growing nodeset\n");
3684 return(-1);
3685 }
3686 cur->nodeMax *= 2;
3687 cur->nodeTab = temp;
3688 }
3689 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3690 return(0);
3691 }
3692
3693 /**
3694 * xmlXPathNodeSetAdd:
3695 * @cur: the initial node set
3696 * @val: a new xmlNodePtr
3697 *
3698 * add a new xmlNodePtr to an existing NodeSet
3699 *
3700 * Returns 0 in case of success, and -1 in case of error
3701 */
3702 int
3703 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3704 int i;
3705
3706 if ((cur == NULL) || (val == NULL)) return(-1);
3707
3708 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3709 /*
3710 * prevent duplicates
3711 */
3712 for (i = 0;i < cur->nodeNr;i++)
3713 if (cur->nodeTab[i] == val) return(0);
3714
3715 /*
3716 * grow the nodeTab if needed
3717 */
3718 if (cur->nodeMax == 0) {
3719 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3720 sizeof(xmlNodePtr));
3721 if (cur->nodeTab == NULL) {
3722 xmlXPathErrMemory(NULL, "growing nodeset\n");
3723 return(-1);
3724 }
3725 memset(cur->nodeTab, 0 ,
3726 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3727 cur->nodeMax = XML_NODESET_DEFAULT;
3728 } else if (cur->nodeNr == cur->nodeMax) {
3729 xmlNodePtr *temp;
3730
3731 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3732 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3733 return(-1);
3734 }
3735 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3736 sizeof(xmlNodePtr));
3737 if (temp == NULL) {
3738 xmlXPathErrMemory(NULL, "growing nodeset\n");
3739 return(-1);
3740 }
3741 cur->nodeMax *= 2;
3742 cur->nodeTab = temp;
3743 }
3744 if (val->type == XML_NAMESPACE_DECL) {
3745 xmlNsPtr ns = (xmlNsPtr) val;
3746
3747 cur->nodeTab[cur->nodeNr++] =
3748 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3749 } else
3750 cur->nodeTab[cur->nodeNr++] = val;
3751 return(0);
3752 }
3753
3754 /**
3755 * xmlXPathNodeSetAddUnique:
3756 * @cur: the initial node set
3757 * @val: a new xmlNodePtr
3758 *
3759 * add a new xmlNodePtr to an existing NodeSet, optimized version
3760 * when we are sure the node is not already in the set.
3761 *
3762 * Returns 0 in case of success and -1 in case of failure
3763 */
3764 int
3765 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3766 if ((cur == NULL) || (val == NULL)) return(-1);
3767
3768 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3769 /*
3770 * grow the nodeTab if needed
3771 */
3772 if (cur->nodeMax == 0) {
3773 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3774 sizeof(xmlNodePtr));
3775 if (cur->nodeTab == NULL) {
3776 xmlXPathErrMemory(NULL, "growing nodeset\n");
3777 return(-1);
3778 }
3779 memset(cur->nodeTab, 0 ,
3780 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3781 cur->nodeMax = XML_NODESET_DEFAULT;
3782 } else if (cur->nodeNr == cur->nodeMax) {
3783 xmlNodePtr *temp;
3784
3785 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3786 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3787 return(-1);
3788 }
3789 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3790 sizeof(xmlNodePtr));
3791 if (temp == NULL) {
3792 xmlXPathErrMemory(NULL, "growing nodeset\n");
3793 return(-1);
3794 }
3795 cur->nodeTab = temp;
3796 cur->nodeMax *= 2;
3797 }
3798 if (val->type == XML_NAMESPACE_DECL) {
3799 xmlNsPtr ns = (xmlNsPtr) val;
3800
3801 cur->nodeTab[cur->nodeNr++] =
3802 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3803 } else
3804 cur->nodeTab[cur->nodeNr++] = val;
3805 return(0);
3806 }
3807
3808 /**
3809 * xmlXPathNodeSetMerge:
3810 * @val1: the first NodeSet or NULL
3811 * @val2: the second NodeSet
3812 *
3813 * Merges two nodesets, all nodes from @val2 are added to @val1
3814 * if @val1 is NULL, a new set is created and copied from @val2
3815 *
3816 * Returns @val1 once extended or NULL in case of error.
3817 */
3818 xmlNodeSetPtr
3819 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3820 int i, j, initNr, skip;
3821 xmlNodePtr n1, n2;
3822
3823 if (val2 == NULL) return(val1);
3824 if (val1 == NULL) {
3825 val1 = xmlXPathNodeSetCreate(NULL);
3826 if (val1 == NULL)
3827 return (NULL);
3828 #if 0
3829 /*
3830 * TODO: The optimization won't work in every case, since
3831 * those nasty namespace nodes need to be added with
3832 * xmlXPathNodeSetDupNs() to the set; thus a pure
3833 * memcpy is not possible.
3834 * If there was a flag on the nodesetval, indicating that
3835 * some temporary nodes are in, that would be helpfull.
3836 */
3837 /*
3838 * Optimization: Create an equally sized node-set
3839 * and memcpy the content.
3840 */
3841 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3842 if (val1 == NULL)
3843 return(NULL);
3844 if (val2->nodeNr != 0) {
3845 if (val2->nodeNr == 1)
3846 *(val1->nodeTab) = *(val2->nodeTab);
3847 else {
3848 memcpy(val1->nodeTab, val2->nodeTab,
3849 val2->nodeNr * sizeof(xmlNodePtr));
3850 }
3851 val1->nodeNr = val2->nodeNr;
3852 }
3853 return(val1);
3854 #endif
3855 }
3856
3857 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3858 initNr = val1->nodeNr;
3859
3860 for (i = 0;i < val2->nodeNr;i++) {
3861 n2 = val2->nodeTab[i];
3862 /*
3863 * check against duplicates
3864 */
3865 skip = 0;
3866 for (j = 0; j < initNr; j++) {
3867 n1 = val1->nodeTab[j];
3868 if (n1 == n2) {
3869 skip = 1;
3870 break;
3871 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3872 (n2->type == XML_NAMESPACE_DECL)) {
3873 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3874 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3875 ((xmlNsPtr) n2)->prefix)))
3876 {
3877 skip = 1;
3878 break;
3879 }
3880 }
3881 }
3882 if (skip)
3883 continue;
3884
3885 /*
3886 * grow the nodeTab if needed
3887 */
3888 if (val1->nodeMax == 0) {
3889 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3890 sizeof(xmlNodePtr));
3891 if (val1->nodeTab == NULL) {
3892 xmlXPathErrMemory(NULL, "merging nodeset\n");
3893 return(NULL);
3894 }
3895 memset(val1->nodeTab, 0 ,
3896 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3897 val1->nodeMax = XML_NODESET_DEFAULT;
3898 } else if (val1->nodeNr == val1->nodeMax) {
3899 xmlNodePtr *temp;
3900
3901 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3902 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3903 return(NULL);
3904 }
3905 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3906 sizeof(xmlNodePtr));
3907 if (temp == NULL) {
3908 xmlXPathErrMemory(NULL, "merging nodeset\n");
3909 return(NULL);
3910 }
3911 val1->nodeTab = temp;
3912 val1->nodeMax *= 2;
3913 }
3914 if (n2->type == XML_NAMESPACE_DECL) {
3915 xmlNsPtr ns = (xmlNsPtr) n2;
3916
3917 val1->nodeTab[val1->nodeNr++] =
3918 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3919 } else
3920 val1->nodeTab[val1->nodeNr++] = n2;
3921 }
3922
3923 return(val1);
3924 }
3925
3926
3927 /**
3928 * xmlXPathNodeSetMergeAndClear:
3929 * @set1: the first NodeSet or NULL
3930 * @set2: the second NodeSet
3931 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3932 *
3933 * Merges two nodesets, all nodes from @set2 are added to @set1
3934 * if @set1 is NULL, a new set is created and copied from @set2.
3935 * Checks for duplicate nodes. Clears set2.
3936 *
3937 * Returns @set1 once extended or NULL in case of error.
3938 */
3939 static xmlNodeSetPtr
3940 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3941 int hasNullEntries)
3942 {
3943 if ((set1 == NULL) && (hasNullEntries == 0)) {
3944 /*
3945 * Note that doing a memcpy of the list, namespace nodes are
3946 * just assigned to set1, since set2 is cleared anyway.
3947 */
3948 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3949 if (set1 == NULL)
3950 return(NULL);
3951 if (set2->nodeNr != 0) {
3952 memcpy(set1->nodeTab, set2->nodeTab,
3953 set2->nodeNr * sizeof(xmlNodePtr));
3954 set1->nodeNr = set2->nodeNr;
3955 }
3956 } else {
3957 int i, j, initNbSet1;
3958 xmlNodePtr n1, n2;
3959
3960 if (set1 == NULL)
3961 set1 = xmlXPathNodeSetCreate(NULL);
3962 if (set1 == NULL)
3963 return (NULL);
3964
3965 initNbSet1 = set1->nodeNr;
3966 for (i = 0;i < set2->nodeNr;i++) {
3967 n2 = set2->nodeTab[i];
3968 /*
3969 * Skip NULLed entries.
3970 */
3971 if (n2 == NULL)
3972 continue;
3973 /*
3974 * Skip duplicates.
3975 */
3976 for (j = 0; j < initNbSet1; j++) {
3977 n1 = set1->nodeTab[j];
3978 if (n1 == n2) {
3979 goto skip_node;
3980 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3981 (n2->type == XML_NAMESPACE_DECL))
3982 {
3983 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3984 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3985 ((xmlNsPtr) n2)->prefix)))
3986 {
3987 /*
3988 * Free the namespace node.
3989 */
3990 set2->nodeTab[i] = NULL;
3991 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3992 goto skip_node;
3993 }
3994 }
3995 }
3996 /*
3997 * grow the nodeTab if needed
3998 */
3999 if (set1->nodeMax == 0) {
4000 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4001 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4002 if (set1->nodeTab == NULL) {
4003 xmlXPathErrMemory(NULL, "merging nodeset\n");
4004 return(NULL);
4005 }
4006 memset(set1->nodeTab, 0,
4007 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4008 set1->nodeMax = XML_NODESET_DEFAULT;
4009 } else if (set1->nodeNr >= set1->nodeMax) {
4010 xmlNodePtr *temp;
4011
4012 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4013 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4014 return(NULL);
4015 }
4016 temp = (xmlNodePtr *) xmlRealloc(
4017 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4018 if (temp == NULL) {
4019 xmlXPathErrMemory(NULL, "merging nodeset\n");
4020 return(NULL);
4021 }
4022 set1->nodeTab = temp;
4023 set1->nodeMax *= 2;
4024 }
4025 set1->nodeTab[set1->nodeNr++] = n2;
4026 skip_node:
4027 {}
4028 }
4029 }
4030 set2->nodeNr = 0;
4031 return(set1);
4032 }
4033
4034 /**
4035 * xmlXPathNodeSetMergeAndClearNoDupls:
4036 * @set1: the first NodeSet or NULL
4037 * @set2: the second NodeSet
4038 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
4039 *
4040 * Merges two nodesets, all nodes from @set2 are added to @set1
4041 * if @set1 is NULL, a new set is created and copied from @set2.
4042 * Doesn't chack for duplicate nodes. Clears set2.
4043 *
4044 * Returns @set1 once extended or NULL in case of error.
4045 */
4046 static xmlNodeSetPtr
4047 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
4048 int hasNullEntries)
4049 {
4050 if (set2 == NULL)
4051 return(set1);
4052 if ((set1 == NULL) && (hasNullEntries == 0)) {
4053 /*
4054 * Note that doing a memcpy of the list, namespace nodes are
4055 * just assigned to set1, since set2 is cleared anyway.
4056 */
4057 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
4058 if (set1 == NULL)
4059 return(NULL);
4060 if (set2->nodeNr != 0) {
4061 memcpy(set1->nodeTab, set2->nodeTab,
4062 set2->nodeNr * sizeof(xmlNodePtr));
4063 set1->nodeNr = set2->nodeNr;
4064 }
4065 } else {
4066 int i;
4067 xmlNodePtr n2;
4068
4069 if (set1 == NULL)
4070 set1 = xmlXPathNodeSetCreate(NULL);
4071 if (set1 == NULL)
4072 return (NULL);
4073
4074 for (i = 0;i < set2->nodeNr;i++) {
4075 n2 = set2->nodeTab[i];
4076 /*
4077 * Skip NULLed entries.
4078 */
4079 if (n2 == NULL)
4080 continue;
4081 if (set1->nodeMax == 0) {
4082 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4083 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4084 if (set1->nodeTab == NULL) {
4085 xmlXPathErrMemory(NULL, "merging nodeset\n");
4086 return(NULL);
4087 }
4088 memset(set1->nodeTab, 0,
4089 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4090 set1->nodeMax = XML_NODESET_DEFAULT;
4091 } else if (set1->nodeNr >= set1->nodeMax) {
4092 xmlNodePtr *temp;
4093
4094 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4095 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4096 return(NULL);
4097 }
4098 temp = (xmlNodePtr *) xmlRealloc(
4099 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4100 if (temp == NULL) {
4101 xmlXPathErrMemory(NULL, "merging nodeset\n");
4102 return(NULL);
4103 }
4104 set1->nodeTab = temp;
4105 set1->nodeMax *= 2;
4106 }
4107 set1->nodeTab[set1->nodeNr++] = n2;
4108 }
4109 }
4110 set2->nodeNr = 0;
4111 return(set1);
4112 }
4113
4114 /**
4115 * xmlXPathNodeSetDel:
4116 * @cur: the initial node set
4117 * @val: an xmlNodePtr
4118 *
4119 * Removes an xmlNodePtr from an existing NodeSet
4120 */
4121 void
4122 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4123 int i;
4124
4125 if (cur == NULL) return;
4126 if (val == NULL) return;
4127
4128 /*
4129 * find node in nodeTab
4130 */
4131 for (i = 0;i < cur->nodeNr;i++)
4132 if (cur->nodeTab[i] == val) break;
4133
4134 if (i >= cur->nodeNr) { /* not found */
4135 #ifdef DEBUG
4136 xmlGenericError(xmlGenericErrorContext,
4137 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4138 val->name);
4139 #endif
4140 return;
4141 }
4142 if ((cur->nodeTab[i] != NULL) &&
4143 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4144 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4145 cur->nodeNr--;
4146 for (;i < cur->nodeNr;i++)
4147 cur->nodeTab[i] = cur->nodeTab[i + 1];
4148 cur->nodeTab[cur->nodeNr] = NULL;
4149 }
4150
4151 /**
4152 * xmlXPathNodeSetRemove:
4153 * @cur: the initial node set
4154 * @val: the index to remove
4155 *
4156 * Removes an entry from an existing NodeSet list.
4157 */
4158 void
4159 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4160 if (cur == NULL) return;
4161 if (val >= cur->nodeNr) return;
4162 if ((cur->nodeTab[val] != NULL) &&
4163 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4164 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4165 cur->nodeNr--;
4166 for (;val < cur->nodeNr;val++)
4167 cur->nodeTab[val] = cur->nodeTab[val + 1];
4168 cur->nodeTab[cur->nodeNr] = NULL;
4169 }
4170
4171 /**
4172 * xmlXPathFreeNodeSet:
4173 * @obj: the xmlNodeSetPtr to free
4174 *
4175 * Free the NodeSet compound (not the actual nodes !).
4176 */
4177 void
4178 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4179 if (obj == NULL) return;
4180 if (obj->nodeTab != NULL) {
4181 int i;
4182
4183 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4184 for (i = 0;i < obj->nodeNr;i++)
4185 if ((obj->nodeTab[i] != NULL) &&
4186 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4187 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4188 xmlFree(obj->nodeTab);
4189 }
4190 xmlFree(obj);
4191 }
4192
4193 /**
4194 * xmlXPathNodeSetClearFromPos:
4195 * @set: the node set to be cleared
4196 * @pos: the start position to clear from
4197 *
4198 * Clears the list from temporary XPath objects (e.g. namespace nodes
4199 * are feed) starting with the entry at @pos, but does *not* free the list
4200 * itself. Sets the length of the list to @pos.
4201 */
4202 static void
4203 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4204 {
4205 if ((set == NULL) || (pos >= set->nodeNr))
4206 return;
4207 else if ((hasNsNodes)) {
4208 int i;
4209 xmlNodePtr node;
4210
4211 for (i = pos; i < set->nodeNr; i++) {
4212 node = set->nodeTab[i];
4213 if ((node != NULL) &&
4214 (node->type == XML_NAMESPACE_DECL))
4215 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4216 }
4217 }
4218 set->nodeNr = pos;
4219 }
4220
4221 /**
4222 * xmlXPathNodeSetClear:
4223 * @set: the node set to clear
4224 *
4225 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4226 * are feed), but does *not* free the list itself. Sets the length of the
4227 * list to 0.
4228 */
4229 static void
4230 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4231 {
4232 xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4233 }
4234
4235 /**
4236 * xmlXPathNodeSetKeepLast:
4237 * @set: the node set to be cleared
4238 *
4239 * Move the last node to the first position and clear temporary XPath objects
4240 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4241 * to 1.
4242 */
4243 static void
4244 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4245 {
4246 int i;
4247 xmlNodePtr node;
4248
4249 if ((set == NULL) || (set->nodeNr <= 1))
4250 return;
4251 for (i = 0; i < set->nodeNr - 1; i++) {
4252 node = set->nodeTab[i];
4253 if ((node != NULL) &&
4254 (node->type == XML_NAMESPACE_DECL))
4255 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4256 }
4257 set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4258 set->nodeNr = 1;
4259 }
4260
4261 /**
4262 * xmlXPathFreeValueTree:
4263 * @obj: the xmlNodeSetPtr to free
4264 *
4265 * Free the NodeSet compound and the actual tree, this is different
4266 * from xmlXPathFreeNodeSet()
4267 */
4268 static void
4269 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4270 int i;
4271
4272 if (obj == NULL) return;
4273
4274 if (obj->nodeTab != NULL) {
4275 for (i = 0;i < obj->nodeNr;i++) {
4276 if (obj->nodeTab[i] != NULL) {
4277 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4278 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4279 } else {
4280 xmlFreeNodeList(obj->nodeTab[i]);
4281 }
4282 }
4283 }
4284 xmlFree(obj->nodeTab);
4285 }
4286 xmlFree(obj);
4287 }
4288
4289 #if defined(DEBUG) || defined(DEBUG_STEP)
4290 /**
4291 * xmlGenericErrorContextNodeSet:
4292 * @output: a FILE * for the output
4293 * @obj: the xmlNodeSetPtr to display
4294 *
4295 * Quick display of a NodeSet
4296 */
4297 void
4298 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4299 int i;
4300
4301 if (output == NULL) output = xmlGenericErrorContext;
4302 if (obj == NULL) {
4303 fprintf(output, "NodeSet == NULL !\n");
4304 return;
4305 }
4306 if (obj->nodeNr == 0) {
4307 fprintf(output, "NodeSet is empty\n");
4308 return;
4309 }
4310 if (obj->nodeTab == NULL) {
4311 fprintf(output, " nodeTab == NULL !\n");
4312 return;
4313 }
4314 for (i = 0; i < obj->nodeNr; i++) {
4315 if (obj->nodeTab[i] == NULL) {
4316 fprintf(output, " NULL !\n");
4317 return;
4318 }
4319 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4320 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4321 fprintf(output, " /");
4322 else if (obj->nodeTab[i]->name == NULL)
4323 fprintf(output, " noname!");
4324 else fprintf(output, " %s", obj->nodeTab[i]->name);
4325 }
4326 fprintf(output, "\n");
4327 }
4328 #endif
4329
4330 /**
4331 * xmlXPathNewNodeSet:
4332 * @val: the NodePtr value
4333 *
4334 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4335 * it with the single Node @val
4336 *
4337 * Returns the newly created object.
4338 */
4339 xmlXPathObjectPtr
4340 xmlXPathNewNodeSet(xmlNodePtr val) {
4341 xmlXPathObjectPtr ret;
4342
4343 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4344 if (ret == NULL) {
4345 xmlXPathErrMemory(NULL, "creating nodeset\n");
4346 return(NULL);
4347 }
4348 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4349 ret->type = XPATH_NODESET;
4350 ret->boolval = 0;
4351 ret->nodesetval = xmlXPathNodeSetCreate(val);
4352 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4353 #ifdef XP_DEBUG_OBJ_USAGE
4354 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4355 #endif
4356 return(ret);
4357 }
4358
4359 /**
4360 * xmlXPathNewValueTree:
4361 * @val: the NodePtr value
4362 *
4363 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4364 * it with the tree root @val
4365 *
4366 * Returns the newly created object.
4367 */
4368 xmlXPathObjectPtr
4369 xmlXPathNewValueTree(xmlNodePtr val) {
4370 xmlXPathObjectPtr ret;
4371
4372 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4373 if (ret == NULL) {
4374 xmlXPathErrMemory(NULL, "creating result value tree\n");
4375 return(NULL);
4376 }
4377 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4378 ret->type = XPATH_XSLT_TREE;
4379 ret->boolval = 1;
4380 ret->user = (void *) val;
4381 ret->nodesetval = xmlXPathNodeSetCreate(val);
4382 #ifdef XP_DEBUG_OBJ_USAGE
4383 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4384 #endif
4385 return(ret);
4386 }
4387
4388 /**
4389 * xmlXPathNewNodeSetList:
4390 * @val: an existing NodeSet
4391 *
4392 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4393 * it with the Nodeset @val
4394 *
4395 * Returns the newly created object.
4396 */
4397 xmlXPathObjectPtr
4398 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4399 {
4400 xmlXPathObjectPtr ret;
4401 int i;
4402
4403 if (val == NULL)
4404 ret = NULL;
4405 else if (val->nodeTab == NULL)
4406 ret = xmlXPathNewNodeSet(NULL);
4407 else {
4408 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4409 if (ret) {
4410 for (i = 1; i < val->nodeNr; ++i) {
4411 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4412 < 0) break;
4413 }
4414 }
4415 }
4416
4417 return (ret);
4418 }
4419
4420 /**
4421 * xmlXPathWrapNodeSet:
4422 * @val: the NodePtr value
4423 *
4424 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4425 *
4426 * Returns the newly created object.
4427 */
4428 xmlXPathObjectPtr
4429 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4430 xmlXPathObjectPtr ret;
4431
4432 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4433 if (ret == NULL) {
4434 xmlXPathErrMemory(NULL, "creating node set object\n");
4435 return(NULL);
4436 }
4437 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4438 ret->type = XPATH_NODESET;
4439 ret->nodesetval = val;
4440 #ifdef XP_DEBUG_OBJ_USAGE
4441 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4442 #endif
4443 return(ret);
4444 }
4445
4446 /**
4447 * xmlXPathFreeNodeSetList:
4448 * @obj: an existing NodeSetList object
4449 *
4450 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4451 * the list contrary to xmlXPathFreeObject().
4452 */
4453 void
4454 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4455 if (obj == NULL) return;
4456 #ifdef XP_DEBUG_OBJ_USAGE
4457 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4458 #endif
4459 xmlFree(obj);
4460 }
4461
4462 /**
4463 * xmlXPathDifference:
4464 * @nodes1: a node-set
4465 * @nodes2: a node-set
4466 *
4467 * Implements the EXSLT - Sets difference() function:
4468 * node-set set:difference (node-set, node-set)
4469 *
4470 * Returns the difference between the two node sets, or nodes1 if
4471 * nodes2 is empty
4472 */
4473 xmlNodeSetPtr
4474 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4475 xmlNodeSetPtr ret;
4476 int i, l1;
4477 xmlNodePtr cur;
4478
4479 if (xmlXPathNodeSetIsEmpty(nodes2))
4480 return(nodes1);
4481
4482 ret = xmlXPathNodeSetCreate(NULL);
4483 if (xmlXPathNodeSetIsEmpty(nodes1))
4484 return(ret);
4485
4486 l1 = xmlXPathNodeSetGetLength(nodes1);
4487
4488 for (i = 0; i < l1; i++) {
4489 cur = xmlXPathNodeSetItem(nodes1, i);
4490 if (!xmlXPathNodeSetContains(nodes2, cur)) {
4491 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4492 break;
4493 }
4494 }
4495 return(ret);
4496 }
4497
4498 /**
4499 * xmlXPathIntersection:
4500 * @nodes1: a node-set
4501 * @nodes2: a node-set
4502 *
4503 * Implements the EXSLT - Sets intersection() function:
4504 * node-set set:intersection (node-set, node-set)
4505 *
4506 * Returns a node set comprising the nodes that are within both the
4507 * node sets passed as arguments
4508 */
4509 xmlNodeSetPtr
4510 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4511 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4512 int i, l1;
4513 xmlNodePtr cur;
4514
4515 if (ret == NULL)
4516 return(ret);
4517 if (xmlXPathNodeSetIsEmpty(nodes1))
4518 return(ret);
4519 if (xmlXPathNodeSetIsEmpty(nodes2))
4520 return(ret);
4521
4522 l1 = xmlXPathNodeSetGetLength(nodes1);
4523
4524 for (i = 0; i < l1; i++) {
4525 cur = xmlXPathNodeSetItem(nodes1, i);
4526 if (xmlXPathNodeSetContains(nodes2, cur)) {
4527 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4528 break;
4529 }
4530 }
4531 return(ret);
4532 }
4533
4534 /**
4535 * xmlXPathDistinctSorted:
4536 * @nodes: a node-set, sorted by document order
4537 *
4538 * Implements the EXSLT - Sets distinct() function:
4539 * node-set set:distinct (node-set)
4540 *
4541 * Returns a subset of the nodes contained in @nodes, or @nodes if
4542 * it is empty
4543 */
4544 xmlNodeSetPtr
4545 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4546 xmlNodeSetPtr ret;
4547 xmlHashTablePtr hash;
4548 int i, l;
4549 xmlChar * strval;
4550 xmlNodePtr cur;
4551
4552 if (xmlXPathNodeSetIsEmpty(nodes))
4553 return(nodes);
4554
4555 ret = xmlXPathNodeSetCreate(NULL);
4556 if (ret == NULL)
4557 return(ret);
4558 l = xmlXPathNodeSetGetLength(nodes);
4559 hash = xmlHashCreate (l);
4560 for (i = 0; i < l; i++) {
4561 cur = xmlXPathNodeSetItem(nodes, i);
4562 strval = xmlXPathCastNodeToString(cur);
4563 if (xmlHashLookup(hash, strval) == NULL) {
4564 xmlHashAddEntry(hash, strval, strval);
4565 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4566 break;
4567 } else {
4568 xmlFree(strval);
4569 }
4570 }
4571 xmlHashFree(hash, xmlHashDefaultDeallocator);
4572 return(ret);
4573 }
4574
4575 /**
4576 * xmlXPathDistinct:
4577 * @nodes: a node-set
4578 *
4579 * Implements the EXSLT - Sets distinct() function:
4580 * node-set set:distinct (node-set)
4581 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4582 * is called with the sorted node-set
4583 *
4584 * Returns a subset of the nodes contained in @nodes, or @nodes if
4585 * it is empty
4586 */
4587 xmlNodeSetPtr
4588 xmlXPathDistinct (xmlNodeSetPtr nodes) {
4589 if (xmlXPathNodeSetIsEmpty(nodes))
4590 return(nodes);
4591
4592 xmlXPathNodeSetSort(nodes);
4593 return(xmlXPathDistinctSorted(nodes));
4594 }
4595
4596 /**
4597 * xmlXPathHasSameNodes:
4598 * @nodes1: a node-set
4599 * @nodes2: a node-set
4600 *
4601 * Implements the EXSLT - Sets has-same-nodes function:
4602 * boolean set:has-same-node(node-set, node-set)
4603 *
4604 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4605 * otherwise
4606 */
4607 int
4608 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4609 int i, l;
4610 xmlNodePtr cur;
4611
4612 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4613 xmlXPathNodeSetIsEmpty(nodes2))
4614 return(0);
4615
4616 l = xmlXPathNodeSetGetLength(nodes1);
4617 for (i = 0; i < l; i++) {
4618 cur = xmlXPathNodeSetItem(nodes1, i);
4619 if (xmlXPathNodeSetContains(nodes2, cur))
4620 return(1);
4621 }
4622 return(0);
4623 }
4624
4625 /**
4626 * xmlXPathNodeLeadingSorted:
4627 * @nodes: a node-set, sorted by document order
4628 * @node: a node
4629 *
4630 * Implements the EXSLT - Sets leading() function:
4631 * node-set set:leading (node-set, node-set)
4632 *
4633 * Returns the nodes in @nodes that precede @node in document order,
4634 * @nodes if @node is NULL or an empty node-set if @nodes
4635 * doesn't contain @node
4636 */
4637 xmlNodeSetPtr
4638 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4639 int i, l;
4640 xmlNodePtr cur;
4641 xmlNodeSetPtr ret;
4642
4643 if (node == NULL)
4644 return(nodes);
4645
4646 ret = xmlXPathNodeSetCreate(NULL);
4647 if (ret == NULL)
4648 return(ret);
4649 if (xmlXPathNodeSetIsEmpty(nodes) ||
4650 (!xmlXPathNodeSetContains(nodes, node)))
4651 return(ret);
4652
4653 l = xmlXPathNodeSetGetLength(nodes);
4654 for (i = 0; i < l; i++) {
4655 cur = xmlXPathNodeSetItem(nodes, i);
4656 if (cur == node)
4657 break;
4658 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4659 break;
4660 }
4661 return(ret);
4662 }
4663
4664 /**
4665 * xmlXPathNodeLeading:
4666 * @nodes: a node-set
4667 * @node: a node
4668 *
4669 * Implements the EXSLT - Sets leading() function:
4670 * node-set set:leading (node-set, node-set)
4671 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4672 * is called.
4673 *
4674 * Returns the nodes in @nodes that precede @node in document order,
4675 * @nodes if @node is NULL or an empty node-set if @nodes
4676 * doesn't contain @node
4677 */
4678 xmlNodeSetPtr
4679 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4680 xmlXPathNodeSetSort(nodes);
4681 return(xmlXPathNodeLeadingSorted(nodes, node));
4682 }
4683
4684 /**
4685 * xmlXPathLeadingSorted:
4686 * @nodes1: a node-set, sorted by document order
4687 * @nodes2: a node-set, sorted by document order
4688 *
4689 * Implements the EXSLT - Sets leading() function:
4690 * node-set set:leading (node-set, node-set)
4691 *
4692 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4693 * in document order, @nodes1 if @nodes2 is NULL or empty or
4694 * an empty node-set if @nodes1 doesn't contain @nodes2
4695 */
4696 xmlNodeSetPtr
4697 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4698 if (xmlXPathNodeSetIsEmpty(nodes2))
4699 return(nodes1);
4700 return(xmlXPathNodeLeadingSorted(nodes1,
4701 xmlXPathNodeSetItem(nodes2, 1)));
4702 }
4703
4704 /**
4705 * xmlXPathLeading:
4706 * @nodes1: a node-set
4707 * @nodes2: a node-set
4708 *
4709 * Implements the EXSLT - Sets leading() function:
4710 * node-set set:leading (node-set, node-set)
4711 * @nodes1 and @nodes2 are sorted by document order, then
4712 * #exslSetsLeadingSorted is called.
4713 *
4714 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4715 * in document order, @nodes1 if @nodes2 is NULL or empty or
4716 * an empty node-set if @nodes1 doesn't contain @nodes2
4717 */
4718 xmlNodeSetPtr
4719 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4720 if (xmlXPathNodeSetIsEmpty(nodes2))
4721 return(nodes1);
4722 if (xmlXPathNodeSetIsEmpty(nodes1))
4723 return(xmlXPathNodeSetCreate(NULL));
4724 xmlXPathNodeSetSort(nodes1);
4725 xmlXPathNodeSetSort(nodes2);
4726 return(xmlXPathNodeLeadingSorted(nodes1,
4727 xmlXPathNodeSetItem(nodes2, 1)));
4728 }
4729
4730 /**
4731 * xmlXPathNodeTrailingSorted:
4732 * @nodes: a node-set, sorted by document order
4733 * @node: a node
4734 *
4735 * Implements the EXSLT - Sets trailing() function:
4736 * node-set set:trailing (node-set, node-set)
4737 *
4738 * Returns the nodes in @nodes that follow @node in document order,
4739 * @nodes if @node is NULL or an empty node-set if @nodes
4740 * doesn't contain @node
4741 */
4742 xmlNodeSetPtr
4743 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4744 int i, l;
4745 xmlNodePtr cur;
4746 xmlNodeSetPtr ret;
4747
4748 if (node == NULL)
4749 return(nodes);
4750
4751 ret = xmlXPathNodeSetCreate(NULL);
4752 if (ret == NULL)
4753 return(ret);
4754 if (xmlXPathNodeSetIsEmpty(nodes) ||
4755 (!xmlXPathNodeSetContains(nodes, node)))
4756 return(ret);
4757
4758 l = xmlXPathNodeSetGetLength(nodes);
4759 for (i = l - 1; i >= 0; i--) {
4760 cur = xmlXPathNodeSetItem(nodes, i);
4761 if (cur == node)
4762 break;
4763 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4764 break;
4765 }
4766 xmlXPathNodeSetSort(ret); /* bug 413451 */
4767 return(ret);
4768 }
4769
4770 /**
4771 * xmlXPathNodeTrailing:
4772 * @nodes: a node-set
4773 * @node: a node
4774 *
4775 * Implements the EXSLT - Sets trailing() function:
4776 * node-set set:trailing (node-set, node-set)
4777 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4778 * is called.
4779 *
4780 * Returns the nodes in @nodes that follow @node in document order,
4781 * @nodes if @node is NULL or an empty node-set if @nodes
4782 * doesn't contain @node
4783 */
4784 xmlNodeSetPtr
4785 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4786 xmlXPathNodeSetSort(nodes);
4787 return(xmlXPathNodeTrailingSorted(nodes, node));
4788 }
4789
4790 /**
4791 * xmlXPathTrailingSorted:
4792 * @nodes1: a node-set, sorted by document order
4793 * @nodes2: a node-set, sorted by document order
4794 *
4795 * Implements the EXSLT - Sets trailing() function:
4796 * node-set set:trailing (node-set, node-set)
4797 *
4798 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4799 * in document order, @nodes1 if @nodes2 is NULL or empty or
4800 * an empty node-set if @nodes1 doesn't contain @nodes2
4801 */
4802 xmlNodeSetPtr
4803 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4804 if (xmlXPathNodeSetIsEmpty(nodes2))
4805 return(nodes1);
4806 return(xmlXPathNodeTrailingSorted(nodes1,
4807 xmlXPathNodeSetItem(nodes2, 0)));
4808 }
4809
4810 /**
4811 * xmlXPathTrailing:
4812 * @nodes1: a node-set
4813 * @nodes2: a node-set
4814 *
4815 * Implements the EXSLT - Sets trailing() function:
4816 * node-set set:trailing (node-set, node-set)
4817 * @nodes1 and @nodes2 are sorted by document order, then
4818 * #xmlXPathTrailingSorted is called.
4819 *
4820 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4821 * in document order, @nodes1 if @nodes2 is NULL or empty or
4822 * an empty node-set if @nodes1 doesn't contain @nodes2
4823 */
4824 xmlNodeSetPtr
4825 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4826 if (xmlXPathNodeSetIsEmpty(nodes2))
4827 return(nodes1);
4828 if (xmlXPathNodeSetIsEmpty(nodes1))
4829 return(xmlXPathNodeSetCreate(NULL));
4830 xmlXPathNodeSetSort(nodes1);
4831 xmlXPathNodeSetSort(nodes2);
4832 return(xmlXPathNodeTrailingSorted(nodes1,
4833 xmlXPathNodeSetItem(nodes2, 0)));
4834 }
4835
4836 /************************************************************************
4837 * *
4838 * Routines to handle extra functions *
4839 * *
4840 ************************************************************************/
4841
4842 /**
4843 * xmlXPathRegisterFunc:
4844 * @ctxt: the XPath context
4845 * @name: the function name
4846 * @f: the function implementation or NULL
4847 *
4848 * Register a new function. If @f is NULL it unregisters the function
4849 *
4850 * Returns 0 in case of success, -1 in case of error
4851 */
4852 int
4853 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4854 xmlXPathFunction f) {
4855 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4856 }
4857
4858 /**
4859 * xmlXPathRegisterFuncNS:
4860 * @ctxt: the XPath context
4861 * @name: the function name
4862 * @ns_uri: the function namespace URI
4863 * @f: the function implementation or NULL
4864 *
4865 * Register a new function. If @f is NULL it unregisters the function
4866 *
4867 * Returns 0 in case of success, -1 in case of error
4868 */
4869 int
4870 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4871 const xmlChar *ns_uri, xmlXPathFunction f) {
4872 if (ctxt == NULL)
4873 return(-1);
4874 if (name == NULL)
4875 return(-1);
4876
4877 if (ctxt->funcHash == NULL)
4878 ctxt->funcHash = xmlHashCreate(0);
4879 if (ctxt->funcHash == NULL)
4880 return(-1);
4881 if (f == NULL)
4882 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4883 XML_IGNORE_PEDANTIC_WARNINGS
4884 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4885 XML_POP_WARNINGS
4886 }
4887
4888 /**
4889 * xmlXPathRegisterFuncLookup:
4890 * @ctxt: the XPath context
4891 * @f: the lookup function
4892 * @funcCtxt: the lookup data
4893 *
4894 * Registers an external mechanism to do function lookup.
4895 */
4896 void
4897 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4898 xmlXPathFuncLookupFunc f,
4899 void *funcCtxt) {
4900 if (ctxt == NULL)
4901 return;
4902 ctxt->funcLookupFunc = f;
4903 ctxt->funcLookupData = funcCtxt;
4904 }
4905
4906 /**
4907 * xmlXPathFunctionLookup:
4908 * @ctxt: the XPath context
4909 * @name: the function name
4910 *
4911 * Search in the Function array of the context for the given
4912 * function.
4913 *
4914 * Returns the xmlXPathFunction or NULL if not found
4915 */
4916 xmlXPathFunction
4917 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4918 if (ctxt == NULL)
4919 return (NULL);
4920
4921 if (ctxt->funcLookupFunc != NULL) {
4922 xmlXPathFunction ret;
4923 xmlXPathFuncLookupFunc f;
4924
4925 f = ctxt->funcLookupFunc;
4926 ret = f(ctxt->funcLookupData, name, NULL);
4927 if (ret != NULL)
4928 return(ret);
4929 }
4930 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4931 }
4932
4933 /**
4934 * xmlXPathFunctionLookupNS:
4935 * @ctxt: the XPath context
4936 * @name: the function name
4937 * @ns_uri: the function namespace URI
4938 *
4939 * Search in the Function array of the context for the given
4940 * function.
4941 *
4942 * Returns the xmlXPathFunction or NULL if not found
4943 */
4944 xmlXPathFunction
4945 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4946 const xmlChar *ns_uri) {
4947 xmlXPathFunction ret;
4948
4949 if (ctxt == NULL)
4950 return(NULL);
4951 if (name == NULL)
4952 return(NULL);
4953
4954 if (ctxt->funcLookupFunc != NULL) {
4955 xmlXPathFuncLookupFunc f;
4956
4957 f = ctxt->funcLookupFunc;
4958 ret = f(ctxt->funcLookupData, name, ns_uri);
4959 if (ret != NULL)
4960 return(ret);
4961 }
4962
4963 if (ctxt->funcHash == NULL)
4964 return(NULL);
4965
4966 XML_IGNORE_PEDANTIC_WARNINGS
4967 ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4968 XML_POP_WARNINGS
4969 return(ret);
4970 }
4971
4972 /**
4973 * xmlXPathRegisteredFuncsCleanup:
4974 * @ctxt: the XPath context
4975 *
4976 * Cleanup the XPath context data associated to registered functions
4977 */
4978 void
4979 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4980 if (ctxt == NULL)
4981 return;
4982
4983 xmlHashFree(ctxt->funcHash, NULL);
4984 ctxt->funcHash = NULL;
4985 }
4986
4987 /************************************************************************
4988 * *
4989 * Routines to handle Variables *
4990 * *
4991 ************************************************************************/
4992
4993 /**
4994 * xmlXPathRegisterVariable:
4995 * @ctxt: the XPath context
4996 * @name: the variable name
4997 * @value: the variable value or NULL
4998 *
4999 * Register a new variable value. If @value is NULL it unregisters
5000 * the variable
5001 *
5002 * Returns 0 in case of success, -1 in case of error
5003 */
5004 int
5005 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
5006 xmlXPathObjectPtr value) {
5007 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
5008 }
5009
5010 /**
5011 * xmlXPathRegisterVariableNS:
5012 * @ctxt: the XPath context
5013 * @name: the variable name
5014 * @ns_uri: the variable namespace URI
5015 * @value: the variable value or NULL
5016 *
5017 * Register a new variable value. If @value is NULL it unregisters
5018 * the variable
5019 *
5020 * Returns 0 in case of success, -1 in case of error
5021 */
5022 int
5023 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5024 const xmlChar *ns_uri,
5025 xmlXPathObjectPtr value) {
5026 if (ctxt == NULL)
5027 return(-1);
5028 if (name == NULL)
5029 return(-1);
5030
5031 if (ctxt->varHash == NULL)
5032 ctxt->varHash = xmlHashCreate(0);
5033 if (ctxt->varHash == NULL)
5034 return(-1);
5035 if (value == NULL)
5036 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5037 xmlXPathFreeObjectEntry));
5038 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5039 (void *) value, xmlXPathFreeObjectEntry));
5040 }
5041
5042 /**
5043 * xmlXPathRegisterVariableLookup:
5044 * @ctxt: the XPath context
5045 * @f: the lookup function
5046 * @data: the lookup data
5047 *
5048 * register an external mechanism to do variable lookup
5049 */
5050 void
5051 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5052 xmlXPathVariableLookupFunc f, void *data) {
5053 if (ctxt == NULL)
5054 return;
5055 ctxt->varLookupFunc = f;
5056 ctxt->varLookupData = data;
5057 }
5058
5059 /**
5060 * xmlXPathVariableLookup:
5061 * @ctxt: the XPath context
5062 * @name: the variable name
5063 *
5064 * Search in the Variable array of the context for the given
5065 * variable value.
5066 *
5067 * Returns a copy of the value or NULL if not found
5068 */
5069 xmlXPathObjectPtr
5070 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5071 if (ctxt == NULL)
5072 return(NULL);
5073
5074 if (ctxt->varLookupFunc != NULL) {
5075 xmlXPathObjectPtr ret;
5076
5077 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5078 (ctxt->varLookupData, name, NULL);
5079 return(ret);
5080 }
5081 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5082 }
5083
5084 /**
5085 * xmlXPathVariableLookupNS:
5086 * @ctxt: the XPath context
5087 * @name: the variable name
5088 * @ns_uri: the variable namespace URI
5089 *
5090 * Search in the Variable array of the context for the given
5091 * variable value.
5092 *
5093 * Returns the a copy of the value or NULL if not found
5094 */
5095 xmlXPathObjectPtr
5096 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5097 const xmlChar *ns_uri) {
5098 if (ctxt == NULL)
5099 return(NULL);
5100
5101 if (ctxt->varLookupFunc != NULL) {
5102 xmlXPathObjectPtr ret;
5103
5104 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5105 (ctxt->varLookupData, name, ns_uri);
5106 if (ret != NULL) return(ret);
5107 }
5108
5109 if (ctxt->varHash == NULL)
5110 return(NULL);
5111 if (name == NULL)
5112 return(NULL);
5113
5114 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5115 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5116 }
5117
5118 /**
5119 * xmlXPathRegisteredVariablesCleanup:
5120 * @ctxt: the XPath context
5121 *
5122 * Cleanup the XPath context data associated to registered variables
5123 */
5124 void
5125 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5126 if (ctxt == NULL)
5127 return;
5128
5129 xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
5130 ctxt->varHash = NULL;
5131 }
5132
5133 /**
5134 * xmlXPathRegisterNs:
5135 * @ctxt: the XPath context
5136 * @prefix: the namespace prefix cannot be NULL or empty string
5137 * @ns_uri: the namespace name
5138 *
5139 * Register a new namespace. If @ns_uri is NULL it unregisters
5140 * the namespace
5141 *
5142 * Returns 0 in case of success, -1 in case of error
5143 */
5144 int
5145 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5146 const xmlChar *ns_uri) {
5147 if (ctxt == NULL)
5148 return(-1);
5149 if (prefix == NULL)
5150 return(-1);
5151 if (prefix[0] == 0)
5152 return(-1);
5153
5154 if (ctxt->nsHash == NULL)
5155 ctxt->nsHash = xmlHashCreate(10);
5156 if (ctxt->nsHash == NULL)
5157 return(-1);
5158 if (ns_uri == NULL)
5159 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5160 xmlHashDefaultDeallocator));
5161 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5162 xmlHashDefaultDeallocator));
5163 }
5164
5165 /**
5166 * xmlXPathNsLookup:
5167 * @ctxt: the XPath context
5168 * @prefix: the namespace prefix value
5169 *
5170 * Search in the namespace declaration array of the context for the given
5171 * namespace name associated to the given prefix
5172 *
5173 * Returns the value or NULL if not found
5174 */
5175 const xmlChar *
5176 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5177 if (ctxt == NULL)
5178 return(NULL);
5179 if (prefix == NULL)
5180 return(NULL);
5181
5182 #ifdef XML_XML_NAMESPACE
5183 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5184 return(XML_XML_NAMESPACE);
5185 #endif
5186
5187 if (ctxt->namespaces != NULL) {
5188 int i;
5189
5190 for (i = 0;i < ctxt->nsNr;i++) {
5191 if ((ctxt->namespaces[i] != NULL) &&
5192 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5193 return(ctxt->namespaces[i]->href);
5194 }
5195 }
5196
5197 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5198 }
5199
5200 /**
5201 * xmlXPathRegisteredNsCleanup:
5202 * @ctxt: the XPath context
5203 *
5204 * Cleanup the XPath context data associated to registered variables
5205 */
5206 void
5207 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5208 if (ctxt == NULL)
5209 return;
5210
5211 xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
5212 ctxt->nsHash = NULL;
5213 }
5214
5215 /************************************************************************
5216 * *
5217 * Routines to handle Values *
5218 * *
5219 ************************************************************************/
5220
5221 /* Allocations are terrible, one needs to optimize all this !!! */
5222
5223 /**
5224 * xmlXPathNewFloat:
5225 * @val: the double value
5226 *
5227 * Create a new xmlXPathObjectPtr of type double and of value @val
5228 *
5229 * Returns the newly created object.
5230 */
5231 xmlXPathObjectPtr
5232 xmlXPathNewFloat(double val) {
5233 xmlXPathObjectPtr ret;
5234
5235 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5236 if (ret == NULL) {
5237 xmlXPathErrMemory(NULL, "creating float object\n");
5238 return(NULL);
5239 }
5240 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5241 ret->type = XPATH_NUMBER;
5242 ret->floatval = val;
5243 #ifdef XP_DEBUG_OBJ_USAGE
5244 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5245 #endif
5246 return(ret);
5247 }
5248
5249 /**
5250 * xmlXPathNewBoolean:
5251 * @val: the boolean value
5252 *
5253 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5254 *
5255 * Returns the newly created object.
5256 */
5257 xmlXPathObjectPtr
5258 xmlXPathNewBoolean(int val) {
5259 xmlXPathObjectPtr ret;
5260
5261 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5262 if (ret == NULL) {
5263 xmlXPathErrMemory(NULL, "creating boolean object\n");
5264 return(NULL);
5265 }
5266 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5267 ret->type = XPATH_BOOLEAN;
5268 ret->boolval = (val != 0);
5269 #ifdef XP_DEBUG_OBJ_USAGE
5270 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5271 #endif
5272 return(ret);
5273 }
5274
5275 /**
5276 * xmlXPathNewString:
5277 * @val: the xmlChar * value
5278 *
5279 * Create a new xmlXPathObjectPtr of type string and of value @val
5280 *
5281 * Returns the newly created object.
5282 */
5283 xmlXPathObjectPtr
5284 xmlXPathNewString(const xmlChar *val) {
5285 xmlXPathObjectPtr ret;
5286
5287 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5288 if (ret == NULL) {
5289 xmlXPathErrMemory(NULL, "creating string object\n");
5290 return(NULL);
5291 }
5292 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5293 ret->type = XPATH_STRING;
5294 if (val != NULL)
5295 ret->stringval = xmlStrdup(val);
5296 else
5297 ret->stringval = xmlStrdup((const xmlChar *)"");
5298 #ifdef XP_DEBUG_OBJ_USAGE
5299 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5300 #endif
5301 return(ret);
5302 }
5303
5304 /**
5305 * xmlXPathWrapString:
5306 * @val: the xmlChar * value
5307 *
5308 * Wraps the @val string into an XPath object.
5309 *
5310 * Returns the newly created object.
5311 */
5312 xmlXPathObjectPtr
5313 xmlXPathWrapString (xmlChar *val) {
5314 xmlXPathObjectPtr ret;
5315
5316 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5317 if (ret == NULL) {
5318 xmlXPathErrMemory(NULL, "creating string object\n");
5319 return(NULL);
5320 }
5321 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5322 ret->type = XPATH_STRING;
5323 ret->stringval = val;
5324 #ifdef XP_DEBUG_OBJ_USAGE
5325 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5326 #endif
5327 return(ret);
5328 }
5329
5330 /**
5331 * xmlXPathNewCString:
5332 * @val: the char * value
5333 *
5334 * Create a new xmlXPathObjectPtr of type string and of value @val
5335 *
5336 * Returns the newly created object.
5337 */
5338 xmlXPathObjectPtr
5339 xmlXPathNewCString(const char *val) {
5340 xmlXPathObjectPtr ret;
5341
5342 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5343 if (ret == NULL) {
5344 xmlXPathErrMemory(NULL, "creating string object\n");
5345 return(NULL);
5346 }
5347 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5348 ret->type = XPATH_STRING;
5349 ret->stringval = xmlStrdup(BAD_CAST val);
5350 #ifdef XP_DEBUG_OBJ_USAGE
5351 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5352 #endif
5353 return(ret);
5354 }
5355
5356 /**
5357 * xmlXPathWrapCString:
5358 * @val: the char * value
5359 *
5360 * Wraps a string into an XPath object.
5361 *
5362 * Returns the newly created object.
5363 */
5364 xmlXPathObjectPtr
5365 xmlXPathWrapCString (char * val) {
5366 return(xmlXPathWrapString((xmlChar *)(val)));
5367 }
5368
5369 /**
5370 * xmlXPathWrapExternal:
5371 * @val: the user data
5372 *
5373 * Wraps the @val data into an XPath object.
5374 *
5375 * Returns the newly created object.
5376 */
5377 xmlXPathObjectPtr
5378 xmlXPathWrapExternal (void *val) {
5379 xmlXPathObjectPtr ret;
5380
5381 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5382 if (ret == NULL) {
5383 xmlXPathErrMemory(NULL, "creating user object\n");
5384 return(NULL);
5385 }
5386 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5387 ret->type = XPATH_USERS;
5388 ret->user = val;
5389 #ifdef XP_DEBUG_OBJ_USAGE
5390 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5391 #endif
5392 return(ret);
5393 }
5394
5395 /**
5396 * xmlXPathObjectCopy:
5397 * @val: the original object
5398 *
5399 * allocate a new copy of a given object
5400 *
5401 * Returns the newly created object.
5402 */
5403 xmlXPathObjectPtr
5404 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5405 xmlXPathObjectPtr ret;
5406
5407 if (val == NULL)
5408 return(NULL);
5409
5410 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5411 if (ret == NULL) {
5412 xmlXPathErrMemory(NULL, "copying object\n");
5413 return(NULL);
5414 }
5415 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5416 #ifdef XP_DEBUG_OBJ_USAGE
5417 xmlXPathDebugObjUsageRequested(NULL, val->type);
5418 #endif
5419 switch (val->type) {
5420 case XPATH_BOOLEAN:
5421 case XPATH_NUMBER:
5422 case XPATH_POINT:
5423 case XPATH_RANGE:
5424 break;
5425 case XPATH_STRING:
5426 ret->stringval = xmlStrdup(val->stringval);
5427 break;
5428 case XPATH_XSLT_TREE:
5429 #if 0
5430 /*
5431 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5432 this previous handling is no longer correct, and can cause some serious
5433 problems (ref. bug 145547)
5434 */
5435 if ((val->nodesetval != NULL) &&
5436 (val->nodesetval->nodeTab != NULL)) {
5437 xmlNodePtr cur, tmp;
5438 xmlDocPtr top;
5439
5440 ret->boolval = 1;
5441 top = xmlNewDoc(NULL);
5442 top->name = (char *)
5443 xmlStrdup(val->nodesetval->nodeTab[0]->name);
5444 ret->user = top;
5445 if (top != NULL) {
5446 top->doc = top;
5447 cur = val->nodesetval->nodeTab[0]->children;
5448 while (cur != NULL) {
5449 tmp = xmlDocCopyNode(cur, top, 1);
5450 xmlAddChild((xmlNodePtr) top, tmp);
5451 cur = cur->next;
5452 }
5453 }
5454
5455 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5456 } else
5457 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5458 /* Deallocate the copied tree value */
5459 break;
5460 #endif
5461 case XPATH_NODESET:
5462 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5463 /* Do not deallocate the copied tree value */
5464 ret->boolval = 0;
5465 break;
5466 case XPATH_LOCATIONSET:
5467 #ifdef LIBXML_XPTR_ENABLED
5468 {
5469 xmlLocationSetPtr loc = val->user;
5470 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5471 break;
5472 }
5473 #endif
5474 case XPATH_USERS:
5475 ret->user = val->user;
5476 break;
5477 case XPATH_UNDEFINED:
5478 xmlGenericError(xmlGenericErrorContext,
5479 "xmlXPathObjectCopy: unsupported type %d\n",
5480 val->type);
5481 break;
5482 }
5483 return(ret);
5484 }
5485
5486 /**
5487 * xmlXPathFreeObject:
5488 * @obj: the object to free
5489 *
5490 * Free up an xmlXPathObjectPtr object.
5491 */
5492 void
5493 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5494 if (obj == NULL) return;
5495 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5496 if (obj->boolval) {
5497 #if 0
5498 if (obj->user != NULL) {
5499 xmlXPathFreeNodeSet(obj->nodesetval);
5500 xmlFreeNodeList((xmlNodePtr) obj->user);
5501 } else
5502 #endif
5503 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5504 if (obj->nodesetval != NULL)
5505 xmlXPathFreeValueTree(obj->nodesetval);
5506 } else {
5507 if (obj->nodesetval != NULL)
5508 xmlXPathFreeNodeSet(obj->nodesetval);
5509 }
5510 #ifdef LIBXML_XPTR_ENABLED
5511 } else if (obj->type == XPATH_LOCATIONSET) {
5512 if (obj->user != NULL)
5513 xmlXPtrFreeLocationSet(obj->user);
5514 #endif
5515 } else if (obj->type == XPATH_STRING) {
5516 if (obj->stringval != NULL)
5517 xmlFree(obj->stringval);
5518 }
5519 #ifdef XP_DEBUG_OBJ_USAGE
5520 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5521 #endif
5522 xmlFree(obj);
5523 }
5524
5525 static void
5526 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
5527 xmlXPathFreeObject((xmlXPathObjectPtr) obj);
5528 }
5529
5530 /**
5531 * xmlXPathReleaseObject:
5532 * @obj: the xmlXPathObjectPtr to free or to cache
5533 *
5534 * Depending on the state of the cache this frees the given
5535 * XPath object or stores it in the cache.
5536 */
5537 static void
5538 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5539 {
5540 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5541 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5542 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5543
5544 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5545
5546 if (obj == NULL)
5547 return;
5548 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5549 xmlXPathFreeObject(obj);
5550 } else {
5551 xmlXPathContextCachePtr cache =
5552 (xmlXPathContextCachePtr) ctxt->cache;
5553
5554 switch (obj->type) {
5555 case XPATH_NODESET:
5556 case XPATH_XSLT_TREE:
5557 if (obj->nodesetval != NULL) {
5558 if (obj->boolval) {
5559 /*
5560 * It looks like the @boolval is used for
5561 * evaluation if this an XSLT Result Tree Fragment.
5562 * TODO: Check if this assumption is correct.
5563 */
5564 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5565 xmlXPathFreeValueTree(obj->nodesetval);
5566 obj->nodesetval = NULL;
5567 } else if ((obj->nodesetval->nodeMax <= 40) &&
5568 (XP_CACHE_WANTS(cache->nodesetObjs,
5569 cache->maxNodeset)))
5570 {
5571 XP_CACHE_ADD(cache->nodesetObjs, obj);
5572 goto obj_cached;
5573 } else {
5574 xmlXPathFreeNodeSet(obj->nodesetval);
5575 obj->nodesetval = NULL;
5576 }
5577 }
5578 break;
5579 case XPATH_STRING:
5580 if (obj->stringval != NULL)
5581 xmlFree(obj->stringval);
5582
5583 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5584 XP_CACHE_ADD(cache->stringObjs, obj);
5585 goto obj_cached;
5586 }
5587 break;
5588 case XPATH_BOOLEAN:
5589 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5590 XP_CACHE_ADD(cache->booleanObjs, obj);
5591 goto obj_cached;
5592 }
5593 break;
5594 case XPATH_NUMBER:
5595 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5596 XP_CACHE_ADD(cache->numberObjs, obj);
5597 goto obj_cached;
5598 }
5599 break;
5600 #ifdef LIBXML_XPTR_ENABLED
5601 case XPATH_LOCATIONSET:
5602 if (obj->user != NULL) {
5603 xmlXPtrFreeLocationSet(obj->user);
5604 }
5605 goto free_obj;
5606 #endif
5607 default:
5608 goto free_obj;
5609 }
5610
5611 /*
5612 * Fallback to adding to the misc-objects slot.
5613 */
5614 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5615 XP_CACHE_ADD(cache->miscObjs, obj);
5616 } else
5617 goto free_obj;
5618
5619 obj_cached:
5620
5621 #ifdef XP_DEBUG_OBJ_USAGE
5622 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5623 #endif
5624
5625 if (obj->nodesetval != NULL) {
5626 xmlNodeSetPtr tmpset = obj->nodesetval;
5627
5628 /*
5629 * TODO: Due to those nasty ns-nodes, we need to traverse
5630 * the list and free the ns-nodes.
5631 * URGENT TODO: Check if it's actually slowing things down.
5632 * Maybe we shouldn't try to preserve the list.
5633 */
5634 if (tmpset->nodeNr > 1) {
5635 int i;
5636 xmlNodePtr node;
5637
5638 for (i = 0; i < tmpset->nodeNr; i++) {
5639 node = tmpset->nodeTab[i];
5640 if ((node != NULL) &&
5641 (node->type == XML_NAMESPACE_DECL))
5642 {
5643 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5644 }
5645 }
5646 } else if (tmpset->nodeNr == 1) {
5647 if ((tmpset->nodeTab[0] != NULL) &&
5648 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5649 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5650 }
5651 tmpset->nodeNr = 0;
5652 memset(obj, 0, sizeof(xmlXPathObject));
5653 obj->nodesetval = tmpset;
5654 } else
5655 memset(obj, 0, sizeof(xmlXPathObject));
5656
5657 return;
5658
5659 free_obj:
5660 /*
5661 * Cache is full; free the object.
5662 */
5663 if (obj->nodesetval != NULL)
5664 xmlXPathFreeNodeSet(obj->nodesetval);
5665 #ifdef XP_DEBUG_OBJ_USAGE
5666 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5667 #endif
5668 xmlFree(obj);
5669 }
5670 return;
5671 }
5672
5673
5674 /************************************************************************
5675 * *
5676 * Type Casting Routines *
5677 * *
5678 ************************************************************************/
5679
5680 /**
5681 * xmlXPathCastBooleanToString:
5682 * @val: a boolean
5683 *
5684 * Converts a boolean to its string value.
5685 *
5686 * Returns a newly allocated string.
5687 */
5688 xmlChar *
5689 xmlXPathCastBooleanToString (int val) {
5690 xmlChar *ret;
5691 if (val)
5692 ret = xmlStrdup((const xmlChar *) "true");
5693 else
5694 ret = xmlStrdup((const xmlChar *) "false");
5695 return(ret);
5696 }
5697
5698 /**
5699 * xmlXPathCastNumberToString:
5700 * @val: a number
5701 *
5702 * Converts a number to its string value.
5703 *
5704 * Returns a newly allocated string.
5705 */
5706 xmlChar *
5707 xmlXPathCastNumberToString (double val) {
5708 xmlChar *ret;
5709 switch (xmlXPathIsInf(val)) {
5710 case 1:
5711 ret = xmlStrdup((const xmlChar *) "Infinity");
5712 break;
5713 case -1:
5714 ret = xmlStrdup((const xmlChar *) "-Infinity");
5715 break;
5716 default:
5717 if (xmlXPathIsNaN(val)) {
5718 ret = xmlStrdup((const xmlChar *) "NaN");
5719 } else if (val == 0) {
5720 /* Omit sign for negative zero. */
5721 ret = xmlStrdup((const xmlChar *) "0");
5722 } else {
5723 /* could be improved */
5724 char buf[100];
5725 xmlXPathFormatNumber(val, buf, 99);
5726 buf[99] = 0;
5727 ret = xmlStrdup((const xmlChar *) buf);
5728 }
5729 }
5730 return(ret);
5731 }
5732
5733 /**
5734 * xmlXPathCastNodeToString:
5735 * @node: a node
5736 *
5737 * Converts a node to its string value.
5738 *
5739 * Returns a newly allocated string.
5740 */
5741 xmlChar *
5742 xmlXPathCastNodeToString (xmlNodePtr node) {
5743 xmlChar *ret;
5744 if ((ret = xmlNodeGetContent(node)) == NULL)
5745 ret = xmlStrdup((const xmlChar *) "");
5746 return(ret);
5747 }
5748
5749 /**
5750 * xmlXPathCastNodeSetToString:
5751 * @ns: a node-set
5752 *
5753 * Converts a node-set to its string value.
5754 *
5755 * Returns a newly allocated string.
5756 */
5757 xmlChar *
5758 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5759 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5760 return(xmlStrdup((const xmlChar *) ""));
5761
5762 if (ns->nodeNr > 1)
5763 xmlXPathNodeSetSort(ns);
5764 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5765 }
5766
5767 /**
5768 * xmlXPathCastToString:
5769 * @val: an XPath object
5770 *
5771 * Converts an existing object to its string() equivalent
5772 *
5773 * Returns the allocated string value of the object, NULL in case of error.
5774 * It's up to the caller to free the string memory with xmlFree().
5775 */
5776 xmlChar *
5777 xmlXPathCastToString(xmlXPathObjectPtr val) {
5778 xmlChar *ret = NULL;
5779
5780 if (val == NULL)
5781 return(xmlStrdup((const xmlChar *) ""));
5782 switch (val->type) {
5783 case XPATH_UNDEFINED:
5784 #ifdef DEBUG_EXPR
5785 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5786 #endif
5787 ret = xmlStrdup((const xmlChar *) "");
5788 break;
5789 case XPATH_NODESET:
5790 case XPATH_XSLT_TREE:
5791 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5792 break;
5793 case XPATH_STRING:
5794 return(xmlStrdup(val->stringval));
5795 case XPATH_BOOLEAN:
5796 ret = xmlXPathCastBooleanToString(val->boolval);
5797 break;
5798 case XPATH_NUMBER: {
5799 ret = xmlXPathCastNumberToString(val->floatval);
5800 break;
5801 }
5802 case XPATH_USERS:
5803 case XPATH_POINT:
5804 case XPATH_RANGE:
5805 case XPATH_LOCATIONSET:
5806 TODO
5807 ret = xmlStrdup((const xmlChar *) "");
5808 break;
5809 }
5810 return(ret);
5811 }
5812
5813 /**
5814 * xmlXPathConvertString:
5815 * @val: an XPath object
5816 *
5817 * Converts an existing object to its string() equivalent
5818 *
5819 * Returns the new object, the old one is freed (or the operation
5820 * is done directly on @val)
5821 */
5822 xmlXPathObjectPtr
5823 xmlXPathConvertString(xmlXPathObjectPtr val) {
5824 xmlChar *res = NULL;
5825
5826 if (val == NULL)
5827 return(xmlXPathNewCString(""));
5828
5829 switch (val->type) {
5830 case XPATH_UNDEFINED:
5831 #ifdef DEBUG_EXPR
5832 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5833 #endif
5834 break;
5835 case XPATH_NODESET:
5836 case XPATH_XSLT_TREE:
5837 res = xmlXPathCastNodeSetToString(val->nodesetval);
5838 break;
5839 case XPATH_STRING:
5840 return(val);
5841 case XPATH_BOOLEAN:
5842 res = xmlXPathCastBooleanToString(val->boolval);
5843 break;
5844 case XPATH_NUMBER:
5845 res = xmlXPathCastNumberToString(val->floatval);
5846 break;
5847 case XPATH_USERS:
5848 case XPATH_POINT:
5849 case XPATH_RANGE:
5850 case XPATH_LOCATIONSET:
5851 TODO;
5852 break;
5853 }
5854 xmlXPathFreeObject(val);
5855 if (res == NULL)
5856 return(xmlXPathNewCString(""));
5857 return(xmlXPathWrapString(res));
5858 }
5859
5860 /**
5861 * xmlXPathCastBooleanToNumber:
5862 * @val: a boolean
5863 *
5864 * Converts a boolean to its number value
5865 *
5866 * Returns the number value
5867 */
5868 double
5869 xmlXPathCastBooleanToNumber(int val) {
5870 if (val)
5871 return(1.0);
5872 return(0.0);
5873 }
5874
5875 /**
5876 * xmlXPathCastStringToNumber:
5877 * @val: a string
5878 *
5879 * Converts a string to its number value
5880 *
5881 * Returns the number value
5882 */
5883 double
5884 xmlXPathCastStringToNumber(const xmlChar * val) {
5885 return(xmlXPathStringEvalNumber(val));
5886 }
5887
5888 /**
5889 * xmlXPathCastNodeToNumber:
5890 * @node: a node
5891 *
5892 * Converts a node to its number value
5893 *
5894 * Returns the number value
5895 */
5896 double
5897 xmlXPathCastNodeToNumber (xmlNodePtr node) {
5898 xmlChar *strval;
5899 double ret;
5900
5901 if (node == NULL)
5902 return(NAN);
5903 strval = xmlXPathCastNodeToString(node);
5904 if (strval == NULL)
5905 return(NAN);
5906 ret = xmlXPathCastStringToNumber(strval);
5907 xmlFree(strval);
5908
5909 return(ret);
5910 }
5911
5912 /**
5913 * xmlXPathCastNodeSetToNumber:
5914 * @ns: a node-set
5915 *
5916 * Converts a node-set to its number value
5917 *
5918 * Returns the number value
5919 */
5920 double
5921 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5922 xmlChar *str;
5923 double ret;
5924
5925 if (ns == NULL)
5926 return(NAN);
5927 str = xmlXPathCastNodeSetToString(ns);
5928 ret = xmlXPathCastStringToNumber(str);
5929 xmlFree(str);
5930 return(ret);
5931 }
5932
5933 /**
5934 * xmlXPathCastToNumber:
5935 * @val: an XPath object
5936 *
5937 * Converts an XPath object to its number value
5938 *
5939 * Returns the number value
5940 */
5941 double
5942 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5943 double ret = 0.0;
5944
5945 if (val == NULL)
5946 return(NAN);
5947 switch (val->type) {
5948 case XPATH_UNDEFINED:
5949 #ifdef DEGUB_EXPR
5950 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5951 #endif
5952 ret = NAN;
5953 break;
5954 case XPATH_NODESET:
5955 case XPATH_XSLT_TREE:
5956 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5957 break;
5958 case XPATH_STRING:
5959 ret = xmlXPathCastStringToNumber(val->stringval);
5960 break;
5961 case XPATH_NUMBER:
5962 ret = val->floatval;
5963 break;
5964 case XPATH_BOOLEAN:
5965 ret = xmlXPathCastBooleanToNumber(val->boolval);
5966 break;
5967 case XPATH_USERS:
5968 case XPATH_POINT:
5969 case XPATH_RANGE:
5970 case XPATH_LOCATIONSET:
5971 TODO;
5972 ret = NAN;
5973 break;
5974 }
5975 return(ret);
5976 }
5977
5978 /**
5979 * xmlXPathConvertNumber:
5980 * @val: an XPath object
5981 *
5982 * Converts an existing object to its number() equivalent
5983 *
5984 * Returns the new object, the old one is freed (or the operation
5985 * is done directly on @val)
5986 */
5987 xmlXPathObjectPtr
5988 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5989 xmlXPathObjectPtr ret;
5990
5991 if (val == NULL)
5992 return(xmlXPathNewFloat(0.0));
5993 if (val->type == XPATH_NUMBER)
5994 return(val);
5995 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5996 xmlXPathFreeObject(val);
5997 return(ret);
5998 }
5999
6000 /**
6001 * xmlXPathCastNumberToBoolean:
6002 * @val: a number
6003 *
6004 * Converts a number to its boolean value
6005 *
6006 * Returns the boolean value
6007 */
6008 int
6009 xmlXPathCastNumberToBoolean (double val) {
6010 if (xmlXPathIsNaN(val) || (val == 0.0))
6011 return(0);
6012 return(1);
6013 }
6014
6015 /**
6016 * xmlXPathCastStringToBoolean:
6017 * @val: a string
6018 *
6019 * Converts a string to its boolean value
6020 *
6021 * Returns the boolean value
6022 */
6023 int
6024 xmlXPathCastStringToBoolean (const xmlChar *val) {
6025 if ((val == NULL) || (xmlStrlen(val) == 0))
6026 return(0);
6027 return(1);
6028 }
6029
6030 /**
6031 * xmlXPathCastNodeSetToBoolean:
6032 * @ns: a node-set
6033 *
6034 * Converts a node-set to its boolean value
6035 *
6036 * Returns the boolean value
6037 */
6038 int
6039 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6040 if ((ns == NULL) || (ns->nodeNr == 0))
6041 return(0);
6042 return(1);
6043 }
6044
6045 /**
6046 * xmlXPathCastToBoolean:
6047 * @val: an XPath object
6048 *
6049 * Converts an XPath object to its boolean value
6050 *
6051 * Returns the boolean value
6052 */
6053 int
6054 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6055 int ret = 0;
6056
6057 if (val == NULL)
6058 return(0);
6059 switch (val->type) {
6060 case XPATH_UNDEFINED:
6061 #ifdef DEBUG_EXPR
6062 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6063 #endif
6064 ret = 0;
6065 break;
6066 case XPATH_NODESET:
6067 case XPATH_XSLT_TREE:
6068 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6069 break;
6070 case XPATH_STRING:
6071 ret = xmlXPathCastStringToBoolean(val->stringval);
6072 break;
6073 case XPATH_NUMBER:
6074 ret = xmlXPathCastNumberToBoolean(val->floatval);
6075 break;
6076 case XPATH_BOOLEAN:
6077 ret = val->boolval;
6078 break;
6079 case XPATH_USERS:
6080 case XPATH_POINT:
6081 case XPATH_RANGE:
6082 case XPATH_LOCATIONSET:
6083 TODO;
6084 ret = 0;
6085 break;
6086 }
6087 return(ret);
6088 }
6089
6090
6091 /**
6092 * xmlXPathConvertBoolean:
6093 * @val: an XPath object
6094 *
6095 * Converts an existing object to its boolean() equivalent
6096 *
6097 * Returns the new object, the old one is freed (or the operation
6098 * is done directly on @val)
6099 */
6100 xmlXPathObjectPtr
6101 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6102 xmlXPathObjectPtr ret;
6103
6104 if (val == NULL)
6105 return(xmlXPathNewBoolean(0));
6106 if (val->type == XPATH_BOOLEAN)
6107 return(val);
6108 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6109 xmlXPathFreeObject(val);
6110 return(ret);
6111 }
6112
6113 /************************************************************************
6114 * *
6115 * Routines to handle XPath contexts *
6116 * *
6117 ************************************************************************/
6118
6119 /**
6120 * xmlXPathNewContext:
6121 * @doc: the XML document
6122 *
6123 * Create a new xmlXPathContext
6124 *
6125 * Returns the xmlXPathContext just allocated. The caller will need to free it.
6126 */
6127 xmlXPathContextPtr
6128 xmlXPathNewContext(xmlDocPtr doc) {
6129 xmlXPathContextPtr ret;
6130
6131 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6132 if (ret == NULL) {
6133 xmlXPathErrMemory(NULL, "creating context\n");
6134 return(NULL);
6135 }
6136 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6137 ret->doc = doc;
6138 ret->node = NULL;
6139
6140 ret->varHash = NULL;
6141
6142 ret->nb_types = 0;
6143 ret->max_types = 0;
6144 ret->types = NULL;
6145
6146 ret->funcHash = xmlHashCreate(0);
6147
6148 ret->nb_axis = 0;
6149 ret->max_axis = 0;
6150 ret->axis = NULL;
6151
6152 ret->nsHash = NULL;
6153 ret->user = NULL;
6154
6155 ret->contextSize = -1;
6156 ret->proximityPosition = -1;
6157
6158 #ifdef XP_DEFAULT_CACHE_ON
6159 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6160 xmlXPathFreeContext(ret);
6161 return(NULL);
6162 }
6163 #endif
6164
6165 xmlXPathRegisterAllFunctions(ret);
6166
6167 return(ret);
6168 }
6169
6170 /**
6171 * xmlXPathFreeContext:
6172 * @ctxt: the context to free
6173 *
6174 * Free up an xmlXPathContext
6175 */
6176 void
6177 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6178 if (ctxt == NULL) return;
6179
6180 if (ctxt->cache != NULL)
6181 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6182 xmlXPathRegisteredNsCleanup(ctxt);
6183 xmlXPathRegisteredFuncsCleanup(ctxt);
6184 xmlXPathRegisteredVariablesCleanup(ctxt);
6185 xmlResetError(&ctxt->lastError);
6186 xmlFree(ctxt);
6187 }
6188
6189 /************************************************************************
6190 * *
6191 * Routines to handle XPath parser contexts *
6192 * *
6193 ************************************************************************/
6194
6195 #define CHECK_CTXT(ctxt) \
6196 if (ctxt == NULL) { \
6197 __xmlRaiseError(NULL, NULL, NULL, \
6198 NULL, NULL, XML_FROM_XPATH, \
6199 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6200 __FILE__, __LINE__, \
6201 NULL, NULL, NULL, 0, 0, \
6202 "NULL context pointer\n"); \
6203 return(NULL); \
6204 } \
6205
6206 #define CHECK_CTXT_NEG(ctxt) \
6207 if (ctxt == NULL) { \
6208 __xmlRaiseError(NULL, NULL, NULL, \
6209 NULL, NULL, XML_FROM_XPATH, \
6210 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6211 __FILE__, __LINE__, \
6212 NULL, NULL, NULL, 0, 0, \
6213 "NULL context pointer\n"); \
6214 return(-1); \
6215 } \
6216
6217
6218 #define CHECK_CONTEXT(ctxt) \
6219 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
6220 (ctxt->doc->children == NULL)) { \
6221 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
6222 return(NULL); \
6223 }
6224
6225
6226 /**
6227 * xmlXPathNewParserContext:
6228 * @str: the XPath expression
6229 * @ctxt: the XPath context
6230 *
6231 * Create a new xmlXPathParserContext
6232 *
6233 * Returns the xmlXPathParserContext just allocated.
6234 */
6235 xmlXPathParserContextPtr
6236 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6237 xmlXPathParserContextPtr ret;
6238
6239 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6240 if (ret == NULL) {
6241 xmlXPathErrMemory(ctxt, "creating parser context\n");
6242 return(NULL);
6243 }
6244 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6245 ret->cur = ret->base = str;
6246 ret->context = ctxt;
6247
6248 ret->comp = xmlXPathNewCompExpr();
6249 if (ret->comp == NULL) {
6250 xmlFree(ret->valueTab);
6251 xmlFree(ret);
6252 return(NULL);
6253 }
6254 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6255 ret->comp->dict = ctxt->dict;
6256 xmlDictReference(ret->comp->dict);
6257 }
6258
6259 return(ret);
6260 }
6261
6262 /**
6263 * xmlXPathCompParserContext:
6264 * @comp: the XPath compiled expression
6265 * @ctxt: the XPath context
6266 *
6267 * Create a new xmlXPathParserContext when processing a compiled expression
6268 *
6269 * Returns the xmlXPathParserContext just allocated.
6270 */
6271 static xmlXPathParserContextPtr
6272 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6273 xmlXPathParserContextPtr ret;
6274
6275 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6276 if (ret == NULL) {
6277 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6278 return(NULL);
6279 }
6280 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6281
6282 /* Allocate the value stack */
6283 ret->valueTab = (xmlXPathObjectPtr *)
6284 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6285 if (ret->valueTab == NULL) {
6286 xmlFree(ret);
6287 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6288 return(NULL);
6289 }
6290 ret->valueNr = 0;
6291 ret->valueMax = 10;
6292 ret->value = NULL;
6293 ret->valueFrame = 0;
6294
6295 ret->context = ctxt;
6296 ret->comp = comp;
6297
6298 return(ret);
6299 }
6300
6301 /**
6302 * xmlXPathFreeParserContext:
6303 * @ctxt: the context to free
6304 *
6305 * Free up an xmlXPathParserContext
6306 */
6307 void
6308 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6309 int i;
6310
6311 if (ctxt->valueTab != NULL) {
6312 for (i = 0; i < ctxt->valueNr; i++) {
6313 if (ctxt->context)
6314 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6315 else
6316 xmlXPathFreeObject(ctxt->valueTab[i]);
6317 }
6318 xmlFree(ctxt->valueTab);
6319 }
6320 if (ctxt->comp != NULL) {
6321 #ifdef XPATH_STREAMING
6322 if (ctxt->comp->stream != NULL) {
6323 xmlFreePatternList(ctxt->comp->stream);
6324 ctxt->comp->stream = NULL;
6325 }
6326 #endif
6327 xmlXPathFreeCompExpr(ctxt->comp);
6328 }
6329 xmlFree(ctxt);
6330 }
6331
6332 /************************************************************************
6333 * *
6334 * The implicit core function library *
6335 * *
6336 ************************************************************************/
6337
6338 /**
6339 * xmlXPathNodeValHash:
6340 * @node: a node pointer
6341 *
6342 * Function computing the beginning of the string value of the node,
6343 * used to speed up comparisons
6344 *
6345 * Returns an int usable as a hash
6346 */
6347 static unsigned int
6348 xmlXPathNodeValHash(xmlNodePtr node) {
6349 int len = 2;
6350 const xmlChar * string = NULL;
6351 xmlNodePtr tmp = NULL;
6352 unsigned int ret = 0;
6353
6354 if (node == NULL)
6355 return(0);
6356
6357 if (node->type == XML_DOCUMENT_NODE) {
6358 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6359 if (tmp == NULL)
6360 node = node->children;
6361 else
6362 node = tmp;
6363
6364 if (node == NULL)
6365 return(0);
6366 }
6367
6368 switch (node->type) {
6369 case XML_COMMENT_NODE:
6370 case XML_PI_NODE:
6371 case XML_CDATA_SECTION_NODE:
6372 case XML_TEXT_NODE:
6373 string = node->content;
6374 if (string == NULL)
6375 return(0);
6376 if (string[0] == 0)
6377 return(0);
6378 return(((unsigned int) string[0]) +
6379 (((unsigned int) string[1]) << 8));
6380 case XML_NAMESPACE_DECL:
6381 string = ((xmlNsPtr)node)->href;
6382 if (string == NULL)
6383 return(0);
6384 if (string[0] == 0)
6385 return(0);
6386 return(((unsigned int) string[0]) +
6387 (((unsigned int) string[1]) << 8));
6388 case XML_ATTRIBUTE_NODE:
6389 tmp = ((xmlAttrPtr) node)->children;
6390 break;
6391 case XML_ELEMENT_NODE:
6392 tmp = node->children;
6393 break;
6394 default:
6395 return(0);
6396 }
6397 while (tmp != NULL) {
6398 switch (tmp->type) {
6399 case XML_CDATA_SECTION_NODE:
6400 case XML_TEXT_NODE:
6401 string = tmp->content;
6402 break;
6403 default:
6404 string = NULL;
6405 break;
6406 }
6407 if ((string != NULL) && (string[0] != 0)) {
6408 if (len == 1) {
6409 return(ret + (((unsigned int) string[0]) << 8));
6410 }
6411 if (string[1] == 0) {
6412 len = 1;
6413 ret = (unsigned int) string[0];
6414 } else {
6415 return(((unsigned int) string[0]) +
6416 (((unsigned int) string[1]) << 8));
6417 }
6418 }
6419 /*
6420 * Skip to next node
6421 */
6422 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6423 if (tmp->children->type != XML_ENTITY_DECL) {
6424 tmp = tmp->children;
6425 continue;
6426 }
6427 }
6428 if (tmp == node)
6429 break;
6430
6431 if (tmp->next != NULL) {
6432 tmp = tmp->next;
6433 continue;
6434 }
6435
6436 do {
6437 tmp = tmp->parent;
6438 if (tmp == NULL)
6439 break;
6440 if (tmp == node) {
6441 tmp = NULL;
6442 break;
6443 }
6444 if (tmp->next != NULL) {
6445 tmp = tmp->next;
6446 break;
6447 }
6448 } while (tmp != NULL);
6449 }
6450 return(ret);
6451 }
6452
6453 /**
6454 * xmlXPathStringHash:
6455 * @string: a string
6456 *
6457 * Function computing the beginning of the string value of the node,
6458 * used to speed up comparisons
6459 *
6460 * Returns an int usable as a hash
6461 */
6462 static unsigned int
6463 xmlXPathStringHash(const xmlChar * string) {
6464 if (string == NULL)
6465 return((unsigned int) 0);
6466 if (string[0] == 0)
6467 return(0);
6468 return(((unsigned int) string[0]) +
6469 (((unsigned int) string[1]) << 8));
6470 }
6471
6472 /**
6473 * xmlXPathCompareNodeSetFloat:
6474 * @ctxt: the XPath Parser context
6475 * @inf: less than (1) or greater than (0)
6476 * @strict: is the comparison strict
6477 * @arg: the node set
6478 * @f: the value
6479 *
6480 * Implement the compare operation between a nodeset and a number
6481 * @ns < @val (1, 1, ...
6482 * @ns <= @val (1, 0, ...
6483 * @ns > @val (0, 1, ...
6484 * @ns >= @val (0, 0, ...
6485 *
6486 * If one object to be compared is a node-set and the other is a number,
6487 * then the comparison will be true if and only if there is a node in the
6488 * node-set such that the result of performing the comparison on the number
6489 * to be compared and on the result of converting the string-value of that
6490 * node to a number using the number function is true.
6491 *
6492 * Returns 0 or 1 depending on the results of the test.
6493 */
6494 static int
6495 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6496 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6497 int i, ret = 0;
6498 xmlNodeSetPtr ns;
6499 xmlChar *str2;
6500
6501 if ((f == NULL) || (arg == NULL) ||
6502 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6503 xmlXPathReleaseObject(ctxt->context, arg);
6504 xmlXPathReleaseObject(ctxt->context, f);
6505 return(0);
6506 }
6507 ns = arg->nodesetval;
6508 if (ns != NULL) {
6509 for (i = 0;i < ns->nodeNr;i++) {
6510 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6511 if (str2 != NULL) {
6512 valuePush(ctxt,
6513 xmlXPathCacheNewString(ctxt->context, str2));
6514 xmlFree(str2);
6515 xmlXPathNumberFunction(ctxt, 1);
6516 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6517 ret = xmlXPathCompareValues(ctxt, inf, strict);
6518 if (ret)
6519 break;
6520 }
6521 }
6522 }
6523 xmlXPathReleaseObject(ctxt->context, arg);
6524 xmlXPathReleaseObject(ctxt->context, f);
6525 return(ret);
6526 }
6527
6528 /**
6529 * xmlXPathCompareNodeSetString:
6530 * @ctxt: the XPath Parser context
6531 * @inf: less than (1) or greater than (0)
6532 * @strict: is the comparison strict
6533 * @arg: the node set
6534 * @s: the value
6535 *
6536 * Implement the compare operation between a nodeset and a string
6537 * @ns < @val (1, 1, ...
6538 * @ns <= @val (1, 0, ...
6539 * @ns > @val (0, 1, ...
6540 * @ns >= @val (0, 0, ...
6541 *
6542 * If one object to be compared is a node-set and the other is a string,
6543 * then the comparison will be true if and only if there is a node in
6544 * the node-set such that the result of performing the comparison on the
6545 * string-value of the node and the other string is true.
6546 *
6547 * Returns 0 or 1 depending on the results of the test.
6548 */
6549 static int
6550 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6551 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6552 int i, ret = 0;
6553 xmlNodeSetPtr ns;
6554 xmlChar *str2;
6555
6556 if ((s == NULL) || (arg == NULL) ||
6557 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6558 xmlXPathReleaseObject(ctxt->context, arg);
6559 xmlXPathReleaseObject(ctxt->context, s);
6560 return(0);
6561 }
6562 ns = arg->nodesetval;
6563 if (ns != NULL) {
6564 for (i = 0;i < ns->nodeNr;i++) {
6565 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6566 if (str2 != NULL) {
6567 valuePush(ctxt,
6568 xmlXPathCacheNewString(ctxt->context, str2));
6569 xmlFree(str2);
6570 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6571 ret = xmlXPathCompareValues(ctxt, inf, strict);
6572 if (ret)
6573 break;
6574 }
6575 }
6576 }
6577 xmlXPathReleaseObject(ctxt->context, arg);
6578 xmlXPathReleaseObject(ctxt->context, s);
6579 return(ret);
6580 }
6581
6582 /**
6583 * xmlXPathCompareNodeSets:
6584 * @inf: less than (1) or greater than (0)
6585 * @strict: is the comparison strict
6586 * @arg1: the first node set object
6587 * @arg2: the second node set object
6588 *
6589 * Implement the compare operation on nodesets:
6590 *
6591 * If both objects to be compared are node-sets, then the comparison
6592 * will be true if and only if there is a node in the first node-set
6593 * and a node in the second node-set such that the result of performing
6594 * the comparison on the string-values of the two nodes is true.
6595 * ....
6596 * When neither object to be compared is a node-set and the operator
6597 * is <=, <, >= or >, then the objects are compared by converting both
6598 * objects to numbers and comparing the numbers according to IEEE 754.
6599 * ....
6600 * The number function converts its argument to a number as follows:
6601 * - a string that consists of optional whitespace followed by an
6602 * optional minus sign followed by a Number followed by whitespace
6603 * is converted to the IEEE 754 number that is nearest (according
6604 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6605 * represented by the string; any other string is converted to NaN
6606 *
6607 * Conclusion all nodes need to be converted first to their string value
6608 * and then the comparison must be done when possible
6609 */
6610 static int
6611 xmlXPathCompareNodeSets(int inf, int strict,
6612 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6613 int i, j, init = 0;
6614 double val1;
6615 double *values2;
6616 int ret = 0;
6617 xmlNodeSetPtr ns1;
6618 xmlNodeSetPtr ns2;
6619
6620 if ((arg1 == NULL) ||
6621 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6622 xmlXPathFreeObject(arg2);
6623 return(0);
6624 }
6625 if ((arg2 == NULL) ||
6626 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6627 xmlXPathFreeObject(arg1);
6628 xmlXPathFreeObject(arg2);
6629 return(0);
6630 }
6631
6632 ns1 = arg1->nodesetval;
6633 ns2 = arg2->nodesetval;
6634
6635 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6636 xmlXPathFreeObject(arg1);
6637 xmlXPathFreeObject(arg2);
6638 return(0);
6639 }
6640 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6641 xmlXPathFreeObject(arg1);
6642 xmlXPathFreeObject(arg2);
6643 return(0);
6644 }
6645
6646 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6647 if (values2 == NULL) {
6648 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6649 xmlXPathFreeObject(arg1);
6650 xmlXPathFreeObject(arg2);
6651 return(0);
6652 }
6653 for (i = 0;i < ns1->nodeNr;i++) {
6654 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6655 if (xmlXPathIsNaN(val1))
6656 continue;
6657 for (j = 0;j < ns2->nodeNr;j++) {
6658 if (init == 0) {
6659 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6660 }
6661 if (xmlXPathIsNaN(values2[j]))
6662 continue;
6663 if (inf && strict)
6664 ret = (val1 < values2[j]);
6665 else if (inf && !strict)
6666 ret = (val1 <= values2[j]);
6667 else if (!inf && strict)
6668 ret = (val1 > values2[j]);
6669 else if (!inf && !strict)
6670 ret = (val1 >= values2[j]);
6671 if (ret)
6672 break;
6673 }
6674 if (ret)
6675 break;
6676 init = 1;
6677 }
6678 xmlFree(values2);
6679 xmlXPathFreeObject(arg1);
6680 xmlXPathFreeObject(arg2);
6681 return(ret);
6682 }
6683
6684 /**
6685 * xmlXPathCompareNodeSetValue:
6686 * @ctxt: the XPath Parser context
6687 * @inf: less than (1) or greater than (0)
6688 * @strict: is the comparison strict
6689 * @arg: the node set
6690 * @val: the value
6691 *
6692 * Implement the compare operation between a nodeset and a value
6693 * @ns < @val (1, 1, ...
6694 * @ns <= @val (1, 0, ...
6695 * @ns > @val (0, 1, ...
6696 * @ns >= @val (0, 0, ...
6697 *
6698 * If one object to be compared is a node-set and the other is a boolean,
6699 * then the comparison will be true if and only if the result of performing
6700 * the comparison on the boolean and on the result of converting
6701 * the node-set to a boolean using the boolean function is true.
6702 *
6703 * Returns 0 or 1 depending on the results of the test.
6704 */
6705 static int
6706 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6707 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6708 if ((val == NULL) || (arg == NULL) ||
6709 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6710 return(0);
6711
6712 switch(val->type) {
6713 case XPATH_NUMBER:
6714 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6715 case XPATH_NODESET:
6716 case XPATH_XSLT_TREE:
6717 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6718 case XPATH_STRING:
6719 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6720 case XPATH_BOOLEAN:
6721 valuePush(ctxt, arg);
6722 xmlXPathBooleanFunction(ctxt, 1);
6723 valuePush(ctxt, val);
6724 return(xmlXPathCompareValues(ctxt, inf, strict));
6725 default:
6726 xmlGenericError(xmlGenericErrorContext,
6727 "xmlXPathCompareNodeSetValue: Can't compare node set "
6728 "and object of type %d\n",
6729 val->type);
6730 xmlXPathReleaseObject(ctxt->context, arg);
6731 xmlXPathReleaseObject(ctxt->context, val);
6732 XP_ERROR0(XPATH_INVALID_TYPE);
6733 }
6734 return(0);
6735 }
6736
6737 /**
6738 * xmlXPathEqualNodeSetString:
6739 * @arg: the nodeset object argument
6740 * @str: the string to compare to.
6741 * @neq: flag to show whether for '=' (0) or '!=' (1)
6742 *
6743 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6744 * If one object to be compared is a node-set and the other is a string,
6745 * then the comparison will be true if and only if there is a node in
6746 * the node-set such that the result of performing the comparison on the
6747 * string-value of the node and the other string is true.
6748 *
6749 * Returns 0 or 1 depending on the results of the test.
6750 */
6751 static int
6752 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6753 {
6754 int i;
6755 xmlNodeSetPtr ns;
6756 xmlChar *str2;
6757 unsigned int hash;
6758
6759 if ((str == NULL) || (arg == NULL) ||
6760 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6761 return (0);
6762 ns = arg->nodesetval;
6763 /*
6764 * A NULL nodeset compared with a string is always false
6765 * (since there is no node equal, and no node not equal)
6766 */
6767 if ((ns == NULL) || (ns->nodeNr <= 0) )
6768 return (0);
6769 hash = xmlXPathStringHash(str);
6770 for (i = 0; i < ns->nodeNr; i++) {
6771 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6772 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6773 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6774 xmlFree(str2);
6775 if (neq)
6776 continue;
6777 return (1);
6778 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6779 if (neq)
6780 continue;
6781 return (1);
6782 } else if (neq) {
6783 if (str2 != NULL)
6784 xmlFree(str2);
6785 return (1);
6786 }
6787 if (str2 != NULL)
6788 xmlFree(str2);
6789 } else if (neq)
6790 return (1);
6791 }
6792 return (0);
6793 }
6794
6795 /**
6796 * xmlXPathEqualNodeSetFloat:
6797 * @arg: the nodeset object argument
6798 * @f: the float to compare to
6799 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
6800 *
6801 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6802 * If one object to be compared is a node-set and the other is a number,
6803 * then the comparison will be true if and only if there is a node in
6804 * the node-set such that the result of performing the comparison on the
6805 * number to be compared and on the result of converting the string-value
6806 * of that node to a number using the number function is true.
6807 *
6808 * Returns 0 or 1 depending on the results of the test.
6809 */
6810 static int
6811 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6812 xmlXPathObjectPtr arg, double f, int neq) {
6813 int i, ret=0;
6814 xmlNodeSetPtr ns;
6815 xmlChar *str2;
6816 xmlXPathObjectPtr val;
6817 double v;
6818
6819 if ((arg == NULL) ||
6820 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6821 return(0);
6822
6823 ns = arg->nodesetval;
6824 if (ns != NULL) {
6825 for (i=0;i<ns->nodeNr;i++) {
6826 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6827 if (str2 != NULL) {
6828 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6829 xmlFree(str2);
6830 xmlXPathNumberFunction(ctxt, 1);
6831 val = valuePop(ctxt);
6832 v = val->floatval;
6833 xmlXPathReleaseObject(ctxt->context, val);
6834 if (!xmlXPathIsNaN(v)) {
6835 if ((!neq) && (v==f)) {
6836 ret = 1;
6837 break;
6838 } else if ((neq) && (v!=f)) {
6839 ret = 1;
6840 break;
6841 }
6842 } else { /* NaN is unequal to any value */
6843 if (neq)
6844 ret = 1;
6845 }
6846 }
6847 }
6848 }
6849
6850 return(ret);
6851 }
6852
6853
6854 /**
6855 * xmlXPathEqualNodeSets:
6856 * @arg1: first nodeset object argument
6857 * @arg2: second nodeset object argument
6858 * @neq: flag to show whether to test '=' (0) or '!=' (1)
6859 *
6860 * Implement the equal / not equal operation on XPath nodesets:
6861 * @arg1 == @arg2 or @arg1 != @arg2
6862 * If both objects to be compared are node-sets, then the comparison
6863 * will be true if and only if there is a node in the first node-set and
6864 * a node in the second node-set such that the result of performing the
6865 * comparison on the string-values of the two nodes is true.
6866 *
6867 * (needless to say, this is a costly operation)
6868 *
6869 * Returns 0 or 1 depending on the results of the test.
6870 */
6871 static int
6872 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6873 int i, j;
6874 unsigned int *hashs1;
6875 unsigned int *hashs2;
6876 xmlChar **values1;
6877 xmlChar **values2;
6878 int ret = 0;
6879 xmlNodeSetPtr ns1;
6880 xmlNodeSetPtr ns2;
6881
6882 if ((arg1 == NULL) ||
6883 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6884 return(0);
6885 if ((arg2 == NULL) ||
6886 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6887 return(0);
6888
6889 ns1 = arg1->nodesetval;
6890 ns2 = arg2->nodesetval;
6891
6892 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6893 return(0);
6894 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6895 return(0);
6896
6897 /*
6898 * for equal, check if there is a node pertaining to both sets
6899 */
6900 if (neq == 0)
6901 for (i = 0;i < ns1->nodeNr;i++)
6902 for (j = 0;j < ns2->nodeNr;j++)
6903 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6904 return(1);
6905
6906 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6907 if (values1 == NULL) {
6908 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6909 return(0);
6910 }
6911 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6912 if (hashs1 == NULL) {
6913 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6914 xmlFree(values1);
6915 return(0);
6916 }
6917 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6918 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6919 if (values2 == NULL) {
6920 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6921 xmlFree(hashs1);
6922 xmlFree(values1);
6923 return(0);
6924 }
6925 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6926 if (hashs2 == NULL) {
6927 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6928 xmlFree(hashs1);
6929 xmlFree(values1);
6930 xmlFree(values2);
6931 return(0);
6932 }
6933 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6934 for (i = 0;i < ns1->nodeNr;i++) {
6935 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6936 for (j = 0;j < ns2->nodeNr;j++) {
6937 if (i == 0)
6938 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6939 if (hashs1[i] != hashs2[j]) {
6940 if (neq) {
6941 ret = 1;
6942 break;
6943 }
6944 }
6945 else {
6946 if (values1[i] == NULL)
6947 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6948 if (values2[j] == NULL)
6949 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6950 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6951 if (ret)
6952 break;
6953 }
6954 }
6955 if (ret)
6956 break;
6957 }
6958 for (i = 0;i < ns1->nodeNr;i++)
6959 if (values1[i] != NULL)
6960 xmlFree(values1[i]);
6961 for (j = 0;j < ns2->nodeNr;j++)
6962 if (values2[j] != NULL)
6963 xmlFree(values2[j]);
6964 xmlFree(values1);
6965 xmlFree(values2);
6966 xmlFree(hashs1);
6967 xmlFree(hashs2);
6968 return(ret);
6969 }
6970
6971 static int
6972 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6973 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6974 int ret = 0;
6975 /*
6976 *At this point we are assured neither arg1 nor arg2
6977 *is a nodeset, so we can just pick the appropriate routine.
6978 */
6979 switch (arg1->type) {
6980 case XPATH_UNDEFINED:
6981 #ifdef DEBUG_EXPR
6982 xmlGenericError(xmlGenericErrorContext,
6983 "Equal: undefined\n");
6984 #endif
6985 break;
6986 case XPATH_BOOLEAN:
6987 switch (arg2->type) {
6988 case XPATH_UNDEFINED:
6989 #ifdef DEBUG_EXPR
6990 xmlGenericError(xmlGenericErrorContext,
6991 "Equal: undefined\n");
6992 #endif
6993 break;
6994 case XPATH_BOOLEAN:
6995 #ifdef DEBUG_EXPR
6996 xmlGenericError(xmlGenericErrorContext,
6997 "Equal: %d boolean %d \n",
6998 arg1->boolval, arg2->boolval);
6999 #endif
7000 ret = (arg1->boolval == arg2->boolval);
7001 break;
7002 case XPATH_NUMBER:
7003 ret = (arg1->boolval ==
7004 xmlXPathCastNumberToBoolean(arg2->floatval));
7005 break;
7006 case XPATH_STRING:
7007 if ((arg2->stringval == NULL) ||
7008 (arg2->stringval[0] == 0)) ret = 0;
7009 else
7010 ret = 1;
7011 ret = (arg1->boolval == ret);
7012 break;
7013 case XPATH_USERS:
7014 case XPATH_POINT:
7015 case XPATH_RANGE:
7016 case XPATH_LOCATIONSET:
7017 TODO
7018 break;
7019 case XPATH_NODESET:
7020 case XPATH_XSLT_TREE:
7021 break;
7022 }
7023 break;
7024 case XPATH_NUMBER:
7025 switch (arg2->type) {
7026 case XPATH_UNDEFINED:
7027 #ifdef DEBUG_EXPR
7028 xmlGenericError(xmlGenericErrorContext,
7029 "Equal: undefined\n");
7030 #endif
7031 break;
7032 case XPATH_BOOLEAN:
7033 ret = (arg2->boolval==
7034 xmlXPathCastNumberToBoolean(arg1->floatval));
7035 break;
7036 case XPATH_STRING:
7037 valuePush(ctxt, arg2);
7038 xmlXPathNumberFunction(ctxt, 1);
7039 arg2 = valuePop(ctxt);
7040 /* Falls through. */
7041 case XPATH_NUMBER:
7042 /* Hand check NaN and Infinity equalities */
7043 if (xmlXPathIsNaN(arg1->floatval) ||
7044 xmlXPathIsNaN(arg2->floatval)) {
7045 ret = 0;
7046 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7047 if (xmlXPathIsInf(arg2->floatval) == 1)
7048 ret = 1;
7049 else
7050 ret = 0;
7051 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7052 if (xmlXPathIsInf(arg2->floatval) == -1)
7053 ret = 1;
7054 else
7055 ret = 0;
7056 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7057 if (xmlXPathIsInf(arg1->floatval) == 1)
7058 ret = 1;
7059 else
7060 ret = 0;
7061 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7062 if (xmlXPathIsInf(arg1->floatval) == -1)
7063 ret = 1;
7064 else
7065 ret = 0;
7066 } else {
7067 ret = (arg1->floatval == arg2->floatval);
7068 }
7069 break;
7070 case XPATH_USERS:
7071 case XPATH_POINT:
7072 case XPATH_RANGE:
7073 case XPATH_LOCATIONSET:
7074 TODO
7075 break;
7076 case XPATH_NODESET:
7077 case XPATH_XSLT_TREE:
7078 break;
7079 }
7080 break;
7081 case XPATH_STRING:
7082 switch (arg2->type) {
7083 case XPATH_UNDEFINED:
7084 #ifdef DEBUG_EXPR
7085 xmlGenericError(xmlGenericErrorContext,
7086 "Equal: undefined\n");
7087 #endif
7088 break;
7089 case XPATH_BOOLEAN:
7090 if ((arg1->stringval == NULL) ||
7091 (arg1->stringval[0] == 0)) ret = 0;
7092 else
7093 ret = 1;
7094 ret = (arg2->boolval == ret);
7095 break;
7096 case XPATH_STRING:
7097 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7098 break;
7099 case XPATH_NUMBER:
7100 valuePush(ctxt, arg1);
7101 xmlXPathNumberFunction(ctxt, 1);
7102 arg1 = valuePop(ctxt);
7103 /* Hand check NaN and Infinity equalities */
7104 if (xmlXPathIsNaN(arg1->floatval) ||
7105 xmlXPathIsNaN(arg2->floatval)) {
7106 ret = 0;
7107 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7108 if (xmlXPathIsInf(arg2->floatval) == 1)
7109 ret = 1;
7110 else
7111 ret = 0;
7112 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7113 if (xmlXPathIsInf(arg2->floatval) == -1)
7114 ret = 1;
7115 else
7116 ret = 0;
7117 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7118 if (xmlXPathIsInf(arg1->floatval) == 1)
7119 ret = 1;
7120 else
7121 ret = 0;
7122 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7123 if (xmlXPathIsInf(arg1->floatval) == -1)
7124 ret = 1;
7125 else
7126 ret = 0;
7127 } else {
7128 ret = (arg1->floatval == arg2->floatval);
7129 }
7130 break;
7131 case XPATH_USERS:
7132 case XPATH_POINT:
7133 case XPATH_RANGE:
7134 case XPATH_LOCATIONSET:
7135 TODO
7136 break;
7137 case XPATH_NODESET:
7138 case XPATH_XSLT_TREE:
7139 break;
7140 }
7141 break;
7142 case XPATH_USERS:
7143 case XPATH_POINT:
7144 case XPATH_RANGE:
7145 case XPATH_LOCATIONSET:
7146 TODO
7147 break;
7148 case XPATH_NODESET:
7149 case XPATH_XSLT_TREE:
7150 break;
7151 }
7152 xmlXPathReleaseObject(ctxt->context, arg1);
7153 xmlXPathReleaseObject(ctxt->context, arg2);
7154 return(ret);
7155 }
7156
7157 /**
7158 * xmlXPathEqualValues:
7159 * @ctxt: the XPath Parser context
7160 *
7161 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7162 *
7163 * Returns 0 or 1 depending on the results of the test.
7164 */
7165 int
7166 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7167 xmlXPathObjectPtr arg1, arg2, argtmp;
7168 int ret = 0;
7169
7170 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7171 arg2 = valuePop(ctxt);
7172 arg1 = valuePop(ctxt);
7173 if ((arg1 == NULL) || (arg2 == NULL)) {
7174 if (arg1 != NULL)
7175 xmlXPathReleaseObject(ctxt->context, arg1);
7176 else
7177 xmlXPathReleaseObject(ctxt->context, arg2);
7178 XP_ERROR0(XPATH_INVALID_OPERAND);
7179 }
7180
7181 if (arg1 == arg2) {
7182 #ifdef DEBUG_EXPR
7183 xmlGenericError(xmlGenericErrorContext,
7184 "Equal: by pointer\n");
7185 #endif
7186 xmlXPathFreeObject(arg1);
7187 return(1);
7188 }
7189
7190 /*
7191 *If either argument is a nodeset, it's a 'special case'
7192 */
7193 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7194 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7195 /*
7196 *Hack it to assure arg1 is the nodeset
7197 */
7198 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7199 argtmp = arg2;
7200 arg2 = arg1;
7201 arg1 = argtmp;
7202 }
7203 switch (arg2->type) {
7204 case XPATH_UNDEFINED:
7205 #ifdef DEBUG_EXPR
7206 xmlGenericError(xmlGenericErrorContext,
7207 "Equal: undefined\n");
7208 #endif
7209 break;
7210 case XPATH_NODESET:
7211 case XPATH_XSLT_TREE:
7212 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7213 break;
7214 case XPATH_BOOLEAN:
7215 if ((arg1->nodesetval == NULL) ||
7216 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7217 else
7218 ret = 1;
7219 ret = (ret == arg2->boolval);
7220 break;
7221 case XPATH_NUMBER:
7222 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7223 break;
7224 case XPATH_STRING:
7225 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7226 break;
7227 case XPATH_USERS:
7228 case XPATH_POINT:
7229 case XPATH_RANGE:
7230 case XPATH_LOCATIONSET:
7231 TODO
7232 break;
7233 }
7234 xmlXPathReleaseObject(ctxt->context, arg1);
7235 xmlXPathReleaseObject(ctxt->context, arg2);
7236 return(ret);
7237 }
7238
7239 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7240 }
7241
7242 /**
7243 * xmlXPathNotEqualValues:
7244 * @ctxt: the XPath Parser context
7245 *
7246 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7247 *
7248 * Returns 0 or 1 depending on the results of the test.
7249 */
7250 int
7251 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7252 xmlXPathObjectPtr arg1, arg2, argtmp;
7253 int ret = 0;
7254
7255 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7256 arg2 = valuePop(ctxt);
7257 arg1 = valuePop(ctxt);
7258 if ((arg1 == NULL) || (arg2 == NULL)) {
7259 if (arg1 != NULL)
7260 xmlXPathReleaseObject(ctxt->context, arg1);
7261 else
7262 xmlXPathReleaseObject(ctxt->context, arg2);
7263 XP_ERROR0(XPATH_INVALID_OPERAND);
7264 }
7265
7266 if (arg1 == arg2) {
7267 #ifdef DEBUG_EXPR
7268 xmlGenericError(xmlGenericErrorContext,
7269 "NotEqual: by pointer\n");
7270 #endif
7271 xmlXPathReleaseObject(ctxt->context, arg1);
7272 return(0);
7273 }
7274
7275 /*
7276 *If either argument is a nodeset, it's a 'special case'
7277 */
7278 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7279 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7280 /*
7281 *Hack it to assure arg1 is the nodeset
7282 */
7283 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7284 argtmp = arg2;
7285 arg2 = arg1;
7286 arg1 = argtmp;
7287 }
7288 switch (arg2->type) {
7289 case XPATH_UNDEFINED:
7290 #ifdef DEBUG_EXPR
7291 xmlGenericError(xmlGenericErrorContext,
7292 "NotEqual: undefined\n");
7293 #endif
7294 break;
7295 case XPATH_NODESET:
7296 case XPATH_XSLT_TREE:
7297 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7298 break;
7299 case XPATH_BOOLEAN:
7300 if ((arg1->nodesetval == NULL) ||
7301 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7302 else
7303 ret = 1;
7304 ret = (ret != arg2->boolval);
7305 break;
7306 case XPATH_NUMBER:
7307 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7308 break;
7309 case XPATH_STRING:
7310 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7311 break;
7312 case XPATH_USERS:
7313 case XPATH_POINT:
7314 case XPATH_RANGE:
7315 case XPATH_LOCATIONSET:
7316 TODO
7317 break;
7318 }
7319 xmlXPathReleaseObject(ctxt->context, arg1);
7320 xmlXPathReleaseObject(ctxt->context, arg2);
7321 return(ret);
7322 }
7323
7324 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7325 }
7326
7327 /**
7328 * xmlXPathCompareValues:
7329 * @ctxt: the XPath Parser context
7330 * @inf: less than (1) or greater than (0)
7331 * @strict: is the comparison strict
7332 *
7333 * Implement the compare operation on XPath objects:
7334 * @arg1 < @arg2 (1, 1, ...
7335 * @arg1 <= @arg2 (1, 0, ...
7336 * @arg1 > @arg2 (0, 1, ...
7337 * @arg1 >= @arg2 (0, 0, ...
7338 *
7339 * When neither object to be compared is a node-set and the operator is
7340 * <=, <, >=, >, then the objects are compared by converted both objects
7341 * to numbers and comparing the numbers according to IEEE 754. The <
7342 * comparison will be true if and only if the first number is less than the
7343 * second number. The <= comparison will be true if and only if the first
7344 * number is less than or equal to the second number. The > comparison
7345 * will be true if and only if the first number is greater than the second
7346 * number. The >= comparison will be true if and only if the first number
7347 * is greater than or equal to the second number.
7348 *
7349 * Returns 1 if the comparison succeeded, 0 if it failed
7350 */
7351 int
7352 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7353 int ret = 0, arg1i = 0, arg2i = 0;
7354 xmlXPathObjectPtr arg1, arg2;
7355
7356 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7357 arg2 = valuePop(ctxt);
7358 arg1 = valuePop(ctxt);
7359 if ((arg1 == NULL) || (arg2 == NULL)) {
7360 if (arg1 != NULL)
7361 xmlXPathReleaseObject(ctxt->context, arg1);
7362 else
7363 xmlXPathReleaseObject(ctxt->context, arg2);
7364 XP_ERROR0(XPATH_INVALID_OPERAND);
7365 }
7366
7367 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7368 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7369 /*
7370 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7371 * are not freed from within this routine; they will be freed from the
7372 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7373 */
7374 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7375 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7376 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7377 } else {
7378 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7379 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7380 arg1, arg2);
7381 } else {
7382 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7383 arg2, arg1);
7384 }
7385 }
7386 return(ret);
7387 }
7388
7389 if (arg1->type != XPATH_NUMBER) {
7390 valuePush(ctxt, arg1);
7391 xmlXPathNumberFunction(ctxt, 1);
7392 arg1 = valuePop(ctxt);
7393 }
7394 if (arg1->type != XPATH_NUMBER) {
7395 xmlXPathFreeObject(arg1);
7396 xmlXPathFreeObject(arg2);
7397 XP_ERROR0(XPATH_INVALID_OPERAND);
7398 }
7399 if (arg2->type != XPATH_NUMBER) {
7400 valuePush(ctxt, arg2);
7401 xmlXPathNumberFunction(ctxt, 1);
7402 arg2 = valuePop(ctxt);
7403 }
7404 if (arg2->type != XPATH_NUMBER) {
7405 xmlXPathReleaseObject(ctxt->context, arg1);
7406 xmlXPathReleaseObject(ctxt->context, arg2);
7407 XP_ERROR0(XPATH_INVALID_OPERAND);
7408 }
7409 /*
7410 * Add tests for infinity and nan
7411 * => feedback on 3.4 for Inf and NaN
7412 */
7413 /* Hand check NaN and Infinity comparisons */
7414 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7415 ret=0;
7416 } else {
7417 arg1i=xmlXPathIsInf(arg1->floatval);
7418 arg2i=xmlXPathIsInf(arg2->floatval);
7419 if (inf && strict) {
7420 if ((arg1i == -1 && arg2i != -1) ||
7421 (arg2i == 1 && arg1i != 1)) {
7422 ret = 1;
7423 } else if (arg1i == 0 && arg2i == 0) {
7424 ret = (arg1->floatval < arg2->floatval);
7425 } else {
7426 ret = 0;
7427 }
7428 }
7429 else if (inf && !strict) {
7430 if (arg1i == -1 || arg2i == 1) {
7431 ret = 1;
7432 } else if (arg1i == 0 && arg2i == 0) {
7433 ret = (arg1->floatval <= arg2->floatval);
7434 } else {
7435 ret = 0;
7436 }
7437 }
7438 else if (!inf && strict) {
7439 if ((arg1i == 1 && arg2i != 1) ||
7440 (arg2i == -1 && arg1i != -1)) {
7441 ret = 1;
7442 } else if (arg1i == 0 && arg2i == 0) {
7443 ret = (arg1->floatval > arg2->floatval);
7444 } else {
7445 ret = 0;
7446 }
7447 }
7448 else if (!inf && !strict) {
7449 if (arg1i == 1 || arg2i == -1) {
7450 ret = 1;
7451 } else if (arg1i == 0 && arg2i == 0) {
7452 ret = (arg1->floatval >= arg2->floatval);
7453 } else {
7454 ret = 0;
7455 }
7456 }
7457 }
7458 xmlXPathReleaseObject(ctxt->context, arg1);
7459 xmlXPathReleaseObject(ctxt->context, arg2);
7460 return(ret);
7461 }
7462
7463 /**
7464 * xmlXPathValueFlipSign:
7465 * @ctxt: the XPath Parser context
7466 *
7467 * Implement the unary - operation on an XPath object
7468 * The numeric operators convert their operands to numbers as if
7469 * by calling the number function.
7470 */
7471 void
7472 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7473 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7474 CAST_TO_NUMBER;
7475 CHECK_TYPE(XPATH_NUMBER);
7476 ctxt->value->floatval = -ctxt->value->floatval;
7477 }
7478
7479 /**
7480 * xmlXPathAddValues:
7481 * @ctxt: the XPath Parser context
7482 *
7483 * Implement the add operation on XPath objects:
7484 * The numeric operators convert their operands to numbers as if
7485 * by calling the number function.
7486 */
7487 void
7488 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7489 xmlXPathObjectPtr arg;
7490 double val;
7491
7492 arg = valuePop(ctxt);
7493 if (arg == NULL)
7494 XP_ERROR(XPATH_INVALID_OPERAND);
7495 val = xmlXPathCastToNumber(arg);
7496 xmlXPathReleaseObject(ctxt->context, arg);
7497 CAST_TO_NUMBER;
7498 CHECK_TYPE(XPATH_NUMBER);
7499 ctxt->value->floatval += val;
7500 }
7501
7502 /**
7503 * xmlXPathSubValues:
7504 * @ctxt: the XPath Parser context
7505 *
7506 * Implement the subtraction operation on XPath objects:
7507 * The numeric operators convert their operands to numbers as if
7508 * by calling the number function.
7509 */
7510 void
7511 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7512 xmlXPathObjectPtr arg;
7513 double val;
7514
7515 arg = valuePop(ctxt);
7516 if (arg == NULL)
7517 XP_ERROR(XPATH_INVALID_OPERAND);
7518 val = xmlXPathCastToNumber(arg);
7519 xmlXPathReleaseObject(ctxt->context, arg);
7520 CAST_TO_NUMBER;
7521 CHECK_TYPE(XPATH_NUMBER);
7522 ctxt->value->floatval -= val;
7523 }
7524
7525 /**
7526 * xmlXPathMultValues:
7527 * @ctxt: the XPath Parser context
7528 *
7529 * Implement the multiply operation on XPath objects:
7530 * The numeric operators convert their operands to numbers as if
7531 * by calling the number function.
7532 */
7533 void
7534 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7535 xmlXPathObjectPtr arg;
7536 double val;
7537
7538 arg = valuePop(ctxt);
7539 if (arg == NULL)
7540 XP_ERROR(XPATH_INVALID_OPERAND);
7541 val = xmlXPathCastToNumber(arg);
7542 xmlXPathReleaseObject(ctxt->context, arg);
7543 CAST_TO_NUMBER;
7544 CHECK_TYPE(XPATH_NUMBER);
7545 ctxt->value->floatval *= val;
7546 }
7547
7548 /**
7549 * xmlXPathDivValues:
7550 * @ctxt: the XPath Parser context
7551 *
7552 * Implement the div operation on XPath objects @arg1 / @arg2:
7553 * The numeric operators convert their operands to numbers as if
7554 * by calling the number function.
7555 */
7556 void
7557 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7558 xmlXPathObjectPtr arg;
7559 double val;
7560
7561 arg = valuePop(ctxt);
7562 if (arg == NULL)
7563 XP_ERROR(XPATH_INVALID_OPERAND);
7564 val = xmlXPathCastToNumber(arg);
7565 xmlXPathReleaseObject(ctxt->context, arg);
7566 CAST_TO_NUMBER;
7567 CHECK_TYPE(XPATH_NUMBER);
7568 ctxt->value->floatval /= val;
7569 }
7570
7571 /**
7572 * xmlXPathModValues:
7573 * @ctxt: the XPath Parser context
7574 *
7575 * Implement the mod operation on XPath objects: @arg1 / @arg2
7576 * The numeric operators convert their operands to numbers as if
7577 * by calling the number function.
7578 */
7579 void
7580 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7581 xmlXPathObjectPtr arg;
7582 double arg1, arg2;
7583
7584 arg = valuePop(ctxt);
7585 if (arg == NULL)
7586 XP_ERROR(XPATH_INVALID_OPERAND);
7587 arg2 = xmlXPathCastToNumber(arg);
7588 xmlXPathReleaseObject(ctxt->context, arg);
7589 CAST_TO_NUMBER;
7590 CHECK_TYPE(XPATH_NUMBER);
7591 arg1 = ctxt->value->floatval;
7592 if (arg2 == 0)
7593 ctxt->value->floatval = NAN;
7594 else {
7595 ctxt->value->floatval = fmod(arg1, arg2);
7596 }
7597 }
7598
7599 /************************************************************************
7600 * *
7601 * The traversal functions *
7602 * *
7603 ************************************************************************/
7604
7605 /*
7606 * A traversal function enumerates nodes along an axis.
7607 * Initially it must be called with NULL, and it indicates
7608 * termination on the axis by returning NULL.
7609 */
7610 typedef xmlNodePtr (*xmlXPathTraversalFunction)
7611 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7612
7613 /*
7614 * xmlXPathTraversalFunctionExt:
7615 * A traversal function enumerates nodes along an axis.
7616 * Initially it must be called with NULL, and it indicates
7617 * termination on the axis by returning NULL.
7618 * The context node of the traversal is specified via @contextNode.
7619 */
7620 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7621 (xmlNodePtr cur, xmlNodePtr contextNode);
7622
7623 /*
7624 * xmlXPathNodeSetMergeFunction:
7625 * Used for merging node sets in xmlXPathCollectAndTest().
7626 */
7627 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7628 (xmlNodeSetPtr, xmlNodeSetPtr, int);
7629
7630
7631 /**
7632 * xmlXPathNextSelf:
7633 * @ctxt: the XPath Parser context
7634 * @cur: the current node in the traversal
7635 *
7636 * Traversal function for the "self" direction
7637 * The self axis contains just the context node itself
7638 *
7639 * Returns the next element following that axis
7640 */
7641 xmlNodePtr
7642 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7643 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7644 if (cur == NULL)
7645 return(ctxt->context->node);
7646 return(NULL);
7647 }
7648
7649 /**
7650 * xmlXPathNextChild:
7651 * @ctxt: the XPath Parser context
7652 * @cur: the current node in the traversal
7653 *
7654 * Traversal function for the "child" direction
7655 * The child axis contains the children of the context node in document order.
7656 *
7657 * Returns the next element following that axis
7658 */
7659 xmlNodePtr
7660 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7661 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7662 if (cur == NULL) {
7663 if (ctxt->context->node == NULL) return(NULL);
7664 switch (ctxt->context->node->type) {
7665 case XML_ELEMENT_NODE:
7666 case XML_TEXT_NODE:
7667 case XML_CDATA_SECTION_NODE:
7668 case XML_ENTITY_REF_NODE:
7669 case XML_ENTITY_NODE:
7670 case XML_PI_NODE:
7671 case XML_COMMENT_NODE:
7672 case XML_NOTATION_NODE:
7673 case XML_DTD_NODE:
7674 return(ctxt->context->node->children);
7675 case XML_DOCUMENT_NODE:
7676 case XML_DOCUMENT_TYPE_NODE:
7677 case XML_DOCUMENT_FRAG_NODE:
7678 case XML_HTML_DOCUMENT_NODE:
7679 #ifdef LIBXML_DOCB_ENABLED
7680 case XML_DOCB_DOCUMENT_NODE:
7681 #endif
7682 return(((xmlDocPtr) ctxt->context->node)->children);
7683 case XML_ELEMENT_DECL:
7684 case XML_ATTRIBUTE_DECL:
7685 case XML_ENTITY_DECL:
7686 case XML_ATTRIBUTE_NODE:
7687 case XML_NAMESPACE_DECL:
7688 case XML_XINCLUDE_START:
7689 case XML_XINCLUDE_END:
7690 return(NULL);
7691 }
7692 return(NULL);
7693 }
7694 if ((cur->type == XML_DOCUMENT_NODE) ||
7695 (cur->type == XML_HTML_DOCUMENT_NODE))
7696 return(NULL);
7697 return(cur->next);
7698 }
7699
7700 /**
7701 * xmlXPathNextChildElement:
7702 * @ctxt: the XPath Parser context
7703 * @cur: the current node in the traversal
7704 *
7705 * Traversal function for the "child" direction and nodes of type element.
7706 * The child axis contains the children of the context node in document order.
7707 *
7708 * Returns the next element following that axis
7709 */
7710 static xmlNodePtr
7711 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7712 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7713 if (cur == NULL) {
7714 cur = ctxt->context->node;
7715 if (cur == NULL) return(NULL);
7716 /*
7717 * Get the first element child.
7718 */
7719 switch (cur->type) {
7720 case XML_ELEMENT_NODE:
7721 case XML_DOCUMENT_FRAG_NODE:
7722 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7723 case XML_ENTITY_NODE:
7724 cur = cur->children;
7725 if (cur != NULL) {
7726 if (cur->type == XML_ELEMENT_NODE)
7727 return(cur);
7728 do {
7729 cur = cur->next;
7730 } while ((cur != NULL) &&
7731 (cur->type != XML_ELEMENT_NODE));
7732 return(cur);
7733 }
7734 return(NULL);
7735 case XML_DOCUMENT_NODE:
7736 case XML_HTML_DOCUMENT_NODE:
7737 #ifdef LIBXML_DOCB_ENABLED
7738 case XML_DOCB_DOCUMENT_NODE:
7739 #endif
7740 return(xmlDocGetRootElement((xmlDocPtr) cur));
7741 default:
7742 return(NULL);
7743 }
7744 return(NULL);
7745 }
7746 /*
7747 * Get the next sibling element node.
7748 */
7749 switch (cur->type) {
7750 case XML_ELEMENT_NODE:
7751 case XML_TEXT_NODE:
7752 case XML_ENTITY_REF_NODE:
7753 case XML_ENTITY_NODE:
7754 case XML_CDATA_SECTION_NODE:
7755 case XML_PI_NODE:
7756 case XML_COMMENT_NODE:
7757 case XML_XINCLUDE_END:
7758 break;
7759 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7760 default:
7761 return(NULL);
7762 }
7763 if (cur->next != NULL) {
7764 if (cur->next->type == XML_ELEMENT_NODE)
7765 return(cur->next);
7766 cur = cur->next;
7767 do {
7768 cur = cur->next;
7769 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7770 return(cur);
7771 }
7772 return(NULL);
7773 }
7774
7775 #if 0
7776 /**
7777 * xmlXPathNextDescendantOrSelfElemParent:
7778 * @ctxt: the XPath Parser context
7779 * @cur: the current node in the traversal
7780 *
7781 * Traversal function for the "descendant-or-self" axis.
7782 * Additionally it returns only nodes which can be parents of
7783 * element nodes.
7784 *
7785 *
7786 * Returns the next element following that axis
7787 */
7788 static xmlNodePtr
7789 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7790 xmlNodePtr contextNode)
7791 {
7792 if (cur == NULL) {
7793 if (contextNode == NULL)
7794 return(NULL);
7795 switch (contextNode->type) {
7796 case XML_ELEMENT_NODE:
7797 case XML_XINCLUDE_START:
7798 case XML_DOCUMENT_FRAG_NODE:
7799 case XML_DOCUMENT_NODE:
7800 #ifdef LIBXML_DOCB_ENABLED
7801 case XML_DOCB_DOCUMENT_NODE:
7802 #endif
7803 case XML_HTML_DOCUMENT_NODE:
7804 return(contextNode);
7805 default:
7806 return(NULL);
7807 }
7808 return(NULL);
7809 } else {
7810 xmlNodePtr start = cur;
7811
7812 while (cur != NULL) {
7813 switch (cur->type) {
7814 case XML_ELEMENT_NODE:
7815 /* TODO: OK to have XInclude here? */
7816 case XML_XINCLUDE_START:
7817 case XML_DOCUMENT_FRAG_NODE:
7818 if (cur != start)
7819 return(cur);
7820 if (cur->children != NULL) {
7821 cur = cur->children;
7822 continue;
7823 }
7824 break;
7825 /* Not sure if we need those here. */
7826 case XML_DOCUMENT_NODE:
7827 #ifdef LIBXML_DOCB_ENABLED
7828 case XML_DOCB_DOCUMENT_NODE:
7829 #endif
7830 case XML_HTML_DOCUMENT_NODE:
7831 if (cur != start)
7832 return(cur);
7833 return(xmlDocGetRootElement((xmlDocPtr) cur));
7834 default:
7835 break;
7836 }
7837
7838 next_sibling:
7839 if ((cur == NULL) || (cur == contextNode))
7840 return(NULL);
7841 if (cur->next != NULL) {
7842 cur = cur->next;
7843 } else {
7844 cur = cur->parent;
7845 goto next_sibling;
7846 }
7847 }
7848 }
7849 return(NULL);
7850 }
7851 #endif
7852
7853 /**
7854 * xmlXPathNextDescendant:
7855 * @ctxt: the XPath Parser context
7856 * @cur: the current node in the traversal
7857 *
7858 * Traversal function for the "descendant" direction
7859 * the descendant axis contains the descendants of the context node in document
7860 * order; a descendant is a child or a child of a child and so on.
7861 *
7862 * Returns the next element following that axis
7863 */
7864 xmlNodePtr
7865 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7866 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7867 if (cur == NULL) {
7868 if (ctxt->context->node == NULL)
7869 return(NULL);
7870 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7871 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7872 return(NULL);
7873
7874 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7875 return(ctxt->context->doc->children);
7876 return(ctxt->context->node->children);
7877 }
7878
7879 if (cur->type == XML_NAMESPACE_DECL)
7880 return(NULL);
7881 if (cur->children != NULL) {
7882 /*
7883 * Do not descend on entities declarations
7884 */
7885 if (cur->children->type != XML_ENTITY_DECL) {
7886 cur = cur->children;
7887 /*
7888 * Skip DTDs
7889 */
7890 if (cur->type != XML_DTD_NODE)
7891 return(cur);
7892 }
7893 }
7894
7895 if (cur == ctxt->context->node) return(NULL);
7896
7897 while (cur->next != NULL) {
7898 cur = cur->next;
7899 if ((cur->type != XML_ENTITY_DECL) &&
7900 (cur->type != XML_DTD_NODE))
7901 return(cur);
7902 }
7903
7904 do {
7905 cur = cur->parent;
7906 if (cur == NULL) break;
7907 if (cur == ctxt->context->node) return(NULL);
7908 if (cur->next != NULL) {
7909 cur = cur->next;
7910 return(cur);
7911 }
7912 } while (cur != NULL);
7913 return(cur);
7914 }
7915
7916 /**
7917 * xmlXPathNextDescendantOrSelf:
7918 * @ctxt: the XPath Parser context
7919 * @cur: the current node in the traversal
7920 *
7921 * Traversal function for the "descendant-or-self" direction
7922 * the descendant-or-self axis contains the context node and the descendants
7923 * of the context node in document order; thus the context node is the first
7924 * node on the axis, and the first child of the context node is the second node
7925 * on the axis
7926 *
7927 * Returns the next element following that axis
7928 */
7929 xmlNodePtr
7930 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7931 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7932 if (cur == NULL)
7933 return(ctxt->context->node);
7934
7935 if (ctxt->context->node == NULL)
7936 return(NULL);
7937 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7938 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7939 return(NULL);
7940
7941 return(xmlXPathNextDescendant(ctxt, cur));
7942 }
7943
7944 /**
7945 * xmlXPathNextParent:
7946 * @ctxt: the XPath Parser context
7947 * @cur: the current node in the traversal
7948 *
7949 * Traversal function for the "parent" direction
7950 * The parent axis contains the parent of the context node, if there is one.
7951 *
7952 * Returns the next element following that axis
7953 */
7954 xmlNodePtr
7955 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7956 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7957 /*
7958 * the parent of an attribute or namespace node is the element
7959 * to which the attribute or namespace node is attached
7960 * Namespace handling !!!
7961 */
7962 if (cur == NULL) {
7963 if (ctxt->context->node == NULL) return(NULL);
7964 switch (ctxt->context->node->type) {
7965 case XML_ELEMENT_NODE:
7966 case XML_TEXT_NODE:
7967 case XML_CDATA_SECTION_NODE:
7968 case XML_ENTITY_REF_NODE:
7969 case XML_ENTITY_NODE:
7970 case XML_PI_NODE:
7971 case XML_COMMENT_NODE:
7972 case XML_NOTATION_NODE:
7973 case XML_DTD_NODE:
7974 case XML_ELEMENT_DECL:
7975 case XML_ATTRIBUTE_DECL:
7976 case XML_XINCLUDE_START:
7977 case XML_XINCLUDE_END:
7978 case XML_ENTITY_DECL:
7979 if (ctxt->context->node->parent == NULL)
7980 return((xmlNodePtr) ctxt->context->doc);
7981 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7982 ((ctxt->context->node->parent->name[0] == ' ') ||
7983 (xmlStrEqual(ctxt->context->node->parent->name,
7984 BAD_CAST "fake node libxslt"))))
7985 return(NULL);
7986 return(ctxt->context->node->parent);
7987 case XML_ATTRIBUTE_NODE: {
7988 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7989
7990 return(att->parent);
7991 }
7992 case XML_DOCUMENT_NODE:
7993 case XML_DOCUMENT_TYPE_NODE:
7994 case XML_DOCUMENT_FRAG_NODE:
7995 case XML_HTML_DOCUMENT_NODE:
7996 #ifdef LIBXML_DOCB_ENABLED
7997 case XML_DOCB_DOCUMENT_NODE:
7998 #endif
7999 return(NULL);
8000 case XML_NAMESPACE_DECL: {
8001 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8002
8003 if ((ns->next != NULL) &&
8004 (ns->next->type != XML_NAMESPACE_DECL))
8005 return((xmlNodePtr) ns->next);
8006 return(NULL);
8007 }
8008 }
8009 }
8010 return(NULL);
8011 }
8012
8013 /**
8014 * xmlXPathNextAncestor:
8015 * @ctxt: the XPath Parser context
8016 * @cur: the current node in the traversal
8017 *
8018 * Traversal function for the "ancestor" direction
8019 * the ancestor axis contains the ancestors of the context node; the ancestors
8020 * of the context node consist of the parent of context node and the parent's
8021 * parent and so on; the nodes are ordered in reverse document order; thus the
8022 * parent is the first node on the axis, and the parent's parent is the second
8023 * node on the axis
8024 *
8025 * Returns the next element following that axis
8026 */
8027 xmlNodePtr
8028 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8029 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8030 /*
8031 * the parent of an attribute or namespace node is the element
8032 * to which the attribute or namespace node is attached
8033 * !!!!!!!!!!!!!
8034 */
8035 if (cur == NULL) {
8036 if (ctxt->context->node == NULL) return(NULL);
8037 switch (ctxt->context->node->type) {
8038 case XML_ELEMENT_NODE:
8039 case XML_TEXT_NODE:
8040 case XML_CDATA_SECTION_NODE:
8041 case XML_ENTITY_REF_NODE:
8042 case XML_ENTITY_NODE:
8043 case XML_PI_NODE:
8044 case XML_COMMENT_NODE:
8045 case XML_DTD_NODE:
8046 case XML_ELEMENT_DECL:
8047 case XML_ATTRIBUTE_DECL:
8048 case XML_ENTITY_DECL:
8049 case XML_NOTATION_NODE:
8050 case XML_XINCLUDE_START:
8051 case XML_XINCLUDE_END:
8052 if (ctxt->context->node->parent == NULL)
8053 return((xmlNodePtr) ctxt->context->doc);
8054 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8055 ((ctxt->context->node->parent->name[0] == ' ') ||
8056 (xmlStrEqual(ctxt->context->node->parent->name,
8057 BAD_CAST "fake node libxslt"))))
8058 return(NULL);
8059 return(ctxt->context->node->parent);
8060 case XML_ATTRIBUTE_NODE: {
8061 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8062
8063 return(tmp->parent);
8064 }
8065 case XML_DOCUMENT_NODE:
8066 case XML_DOCUMENT_TYPE_NODE:
8067 case XML_DOCUMENT_FRAG_NODE:
8068 case XML_HTML_DOCUMENT_NODE:
8069 #ifdef LIBXML_DOCB_ENABLED
8070 case XML_DOCB_DOCUMENT_NODE:
8071 #endif
8072 return(NULL);
8073 case XML_NAMESPACE_DECL: {
8074 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8075
8076 if ((ns->next != NULL) &&
8077 (ns->next->type != XML_NAMESPACE_DECL))
8078 return((xmlNodePtr) ns->next);
8079 /* Bad, how did that namespace end up here ? */
8080 return(NULL);
8081 }
8082 }
8083 return(NULL);
8084 }
8085 if (cur == ctxt->context->doc->children)
8086 return((xmlNodePtr) ctxt->context->doc);
8087 if (cur == (xmlNodePtr) ctxt->context->doc)
8088 return(NULL);
8089 switch (cur->type) {
8090 case XML_ELEMENT_NODE:
8091 case XML_TEXT_NODE:
8092 case XML_CDATA_SECTION_NODE:
8093 case XML_ENTITY_REF_NODE:
8094 case XML_ENTITY_NODE:
8095 case XML_PI_NODE:
8096 case XML_COMMENT_NODE:
8097 case XML_NOTATION_NODE:
8098 case XML_DTD_NODE:
8099 case XML_ELEMENT_DECL:
8100 case XML_ATTRIBUTE_DECL:
8101 case XML_ENTITY_DECL:
8102 case XML_XINCLUDE_START:
8103 case XML_XINCLUDE_END:
8104 if (cur->parent == NULL)
8105 return(NULL);
8106 if ((cur->parent->type == XML_ELEMENT_NODE) &&
8107 ((cur->parent->name[0] == ' ') ||
8108 (xmlStrEqual(cur->parent->name,
8109 BAD_CAST "fake node libxslt"))))
8110 return(NULL);
8111 return(cur->parent);
8112 case XML_ATTRIBUTE_NODE: {
8113 xmlAttrPtr att = (xmlAttrPtr) cur;
8114
8115 return(att->parent);
8116 }
8117 case XML_NAMESPACE_DECL: {
8118 xmlNsPtr ns = (xmlNsPtr) cur;
8119
8120 if ((ns->next != NULL) &&
8121 (ns->next->type != XML_NAMESPACE_DECL))
8122 return((xmlNodePtr) ns->next);
8123 /* Bad, how did that namespace end up here ? */
8124 return(NULL);
8125 }
8126 case XML_DOCUMENT_NODE:
8127 case XML_DOCUMENT_TYPE_NODE:
8128 case XML_DOCUMENT_FRAG_NODE:
8129 case XML_HTML_DOCUMENT_NODE:
8130 #ifdef LIBXML_DOCB_ENABLED
8131 case XML_DOCB_DOCUMENT_NODE:
8132 #endif
8133 return(NULL);
8134 }
8135 return(NULL);
8136 }
8137
8138 /**
8139 * xmlXPathNextAncestorOrSelf:
8140 * @ctxt: the XPath Parser context
8141 * @cur: the current node in the traversal
8142 *
8143 * Traversal function for the "ancestor-or-self" direction
8144 * he ancestor-or-self axis contains the context node and ancestors of
8145 * the context node in reverse document order; thus the context node is
8146 * the first node on the axis, and the context node's parent the second;
8147 * parent here is defined the same as with the parent axis.
8148 *
8149 * Returns the next element following that axis
8150 */
8151 xmlNodePtr
8152 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8153 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8154 if (cur == NULL)
8155 return(ctxt->context->node);
8156 return(xmlXPathNextAncestor(ctxt, cur));
8157 }
8158
8159 /**
8160 * xmlXPathNextFollowingSibling:
8161 * @ctxt: the XPath Parser context
8162 * @cur: the current node in the traversal
8163 *
8164 * Traversal function for the "following-sibling" direction
8165 * The following-sibling axis contains the following siblings of the context
8166 * node in document order.
8167 *
8168 * Returns the next element following that axis
8169 */
8170 xmlNodePtr
8171 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8172 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8173 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8174 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8175 return(NULL);
8176 if (cur == (xmlNodePtr) ctxt->context->doc)
8177 return(NULL);
8178 if (cur == NULL)
8179 return(ctxt->context->node->next);
8180 return(cur->next);
8181 }
8182
8183 /**
8184 * xmlXPathNextPrecedingSibling:
8185 * @ctxt: the XPath Parser context
8186 * @cur: the current node in the traversal
8187 *
8188 * Traversal function for the "preceding-sibling" direction
8189 * The preceding-sibling axis contains the preceding siblings of the context
8190 * node in reverse document order; the first preceding sibling is first on the
8191 * axis; the sibling preceding that node is the second on the axis and so on.
8192 *
8193 * Returns the next element following that axis
8194 */
8195 xmlNodePtr
8196 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8197 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8198 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8199 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8200 return(NULL);
8201 if (cur == (xmlNodePtr) ctxt->context->doc)
8202 return(NULL);
8203 if (cur == NULL)
8204 return(ctxt->context->node->prev);
8205 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8206 cur = cur->prev;
8207 if (cur == NULL)
8208 return(ctxt->context->node->prev);
8209 }
8210 return(cur->prev);
8211 }
8212
8213 /**
8214 * xmlXPathNextFollowing:
8215 * @ctxt: the XPath Parser context
8216 * @cur: the current node in the traversal
8217 *
8218 * Traversal function for the "following" direction
8219 * The following axis contains all nodes in the same document as the context
8220 * node that are after the context node in document order, excluding any
8221 * descendants and excluding attribute nodes and namespace nodes; the nodes
8222 * are ordered in document order
8223 *
8224 * Returns the next element following that axis
8225 */
8226 xmlNodePtr
8227 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8228 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8229 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
8230 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8231 return(cur->children);
8232
8233 if (cur == NULL) {
8234 cur = ctxt->context->node;
8235 if (cur->type == XML_ATTRIBUTE_NODE) {
8236 cur = cur->parent;
8237 } else if (cur->type == XML_NAMESPACE_DECL) {
8238 xmlNsPtr ns = (xmlNsPtr) cur;
8239
8240 if ((ns->next == NULL) ||
8241 (ns->next->type == XML_NAMESPACE_DECL))
8242 return (NULL);
8243 cur = (xmlNodePtr) ns->next;
8244 }
8245 }
8246 if (cur == NULL) return(NULL) ; /* ERROR */
8247 if (cur->next != NULL) return(cur->next) ;
8248 do {
8249 cur = cur->parent;
8250 if (cur == NULL) break;
8251 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8252 if (cur->next != NULL) return(cur->next);
8253 } while (cur != NULL);
8254 return(cur);
8255 }
8256
8257 /*
8258 * xmlXPathIsAncestor:
8259 * @ancestor: the ancestor node
8260 * @node: the current node
8261 *
8262 * Check that @ancestor is a @node's ancestor
8263 *
8264 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8265 */
8266 static int
8267 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8268 if ((ancestor == NULL) || (node == NULL)) return(0);
8269 if (node->type == XML_NAMESPACE_DECL)
8270 return(0);
8271 if (ancestor->type == XML_NAMESPACE_DECL)
8272 return(0);
8273 /* nodes need to be in the same document */
8274 if (ancestor->doc != node->doc) return(0);
8275 /* avoid searching if ancestor or node is the root node */
8276 if (ancestor == (xmlNodePtr) node->doc) return(1);
8277 if (node == (xmlNodePtr) ancestor->doc) return(0);
8278 while (node->parent != NULL) {
8279 if (node->parent == ancestor)
8280 return(1);
8281 node = node->parent;
8282 }
8283 return(0);
8284 }
8285
8286 /**
8287 * xmlXPathNextPreceding:
8288 * @ctxt: the XPath Parser context
8289 * @cur: the current node in the traversal
8290 *
8291 * Traversal function for the "preceding" direction
8292 * the preceding axis contains all nodes in the same document as the context
8293 * node that are before the context node in document order, excluding any
8294 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8295 * ordered in reverse document order
8296 *
8297 * Returns the next element following that axis
8298 */
8299 xmlNodePtr
8300 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8301 {
8302 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8303 if (cur == NULL) {
8304 cur = ctxt->context->node;
8305 if (cur->type == XML_ATTRIBUTE_NODE) {
8306 cur = cur->parent;
8307 } else if (cur->type == XML_NAMESPACE_DECL) {
8308 xmlNsPtr ns = (xmlNsPtr) cur;
8309
8310 if ((ns->next == NULL) ||
8311 (ns->next->type == XML_NAMESPACE_DECL))
8312 return (NULL);
8313 cur = (xmlNodePtr) ns->next;
8314 }
8315 }
8316 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8317 return (NULL);
8318 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8319 cur = cur->prev;
8320 do {
8321 if (cur->prev != NULL) {
8322 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8323 return (cur);
8324 }
8325
8326 cur = cur->parent;
8327 if (cur == NULL)
8328 return (NULL);
8329 if (cur == ctxt->context->doc->children)
8330 return (NULL);
8331 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8332 return (cur);
8333 }
8334
8335 /**
8336 * xmlXPathNextPrecedingInternal:
8337 * @ctxt: the XPath Parser context
8338 * @cur: the current node in the traversal
8339 *
8340 * Traversal function for the "preceding" direction
8341 * the preceding axis contains all nodes in the same document as the context
8342 * node that are before the context node in document order, excluding any
8343 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8344 * ordered in reverse document order
8345 * This is a faster implementation but internal only since it requires a
8346 * state kept in the parser context: ctxt->ancestor.
8347 *
8348 * Returns the next element following that axis
8349 */
8350 static xmlNodePtr
8351 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8352 xmlNodePtr cur)
8353 {
8354 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8355 if (cur == NULL) {
8356 cur = ctxt->context->node;
8357 if (cur == NULL)
8358 return (NULL);
8359 if (cur->type == XML_ATTRIBUTE_NODE) {
8360 cur = cur->parent;
8361 } else if (cur->type == XML_NAMESPACE_DECL) {
8362 xmlNsPtr ns = (xmlNsPtr) cur;
8363
8364 if ((ns->next == NULL) ||
8365 (ns->next->type == XML_NAMESPACE_DECL))
8366 return (NULL);
8367 cur = (xmlNodePtr) ns->next;
8368 }
8369 ctxt->ancestor = cur->parent;
8370 }
8371 if (cur->type == XML_NAMESPACE_DECL)
8372 return(NULL);
8373 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8374 cur = cur->prev;
8375 while (cur->prev == NULL) {
8376 cur = cur->parent;
8377 if (cur == NULL)
8378 return (NULL);
8379 if (cur == ctxt->context->doc->children)
8380 return (NULL);
8381 if (cur != ctxt->ancestor)
8382 return (cur);
8383 ctxt->ancestor = cur->parent;
8384 }
8385 cur = cur->prev;
8386 while (cur->last != NULL)
8387 cur = cur->last;
8388 return (cur);
8389 }
8390
8391 /**
8392 * xmlXPathNextNamespace:
8393 * @ctxt: the XPath Parser context
8394 * @cur: the current attribute in the traversal
8395 *
8396 * Traversal function for the "namespace" direction
8397 * the namespace axis contains the namespace nodes of the context node;
8398 * the order of nodes on this axis is implementation-defined; the axis will
8399 * be empty unless the context node is an element
8400 *
8401 * We keep the XML namespace node at the end of the list.
8402 *
8403 * Returns the next element following that axis
8404 */
8405 xmlNodePtr
8406 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8407 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8408 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8409 if (cur == NULL) {
8410 if (ctxt->context->tmpNsList != NULL)
8411 xmlFree(ctxt->context->tmpNsList);
8412 ctxt->context->tmpNsList =
8413 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8414 ctxt->context->tmpNsNr = 0;
8415 if (ctxt->context->tmpNsList != NULL) {
8416 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8417 ctxt->context->tmpNsNr++;
8418 }
8419 }
8420 return((xmlNodePtr) xmlXPathXMLNamespace);
8421 }
8422 if (ctxt->context->tmpNsNr > 0) {
8423 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8424 } else {
8425 if (ctxt->context->tmpNsList != NULL)
8426 xmlFree(ctxt->context->tmpNsList);
8427 ctxt->context->tmpNsList = NULL;
8428 return(NULL);
8429 }
8430 }
8431
8432 /**
8433 * xmlXPathNextAttribute:
8434 * @ctxt: the XPath Parser context
8435 * @cur: the current attribute in the traversal
8436 *
8437 * Traversal function for the "attribute" direction
8438 * TODO: support DTD inherited default attributes
8439 *
8440 * Returns the next element following that axis
8441 */
8442 xmlNodePtr
8443 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8444 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8445 if (ctxt->context->node == NULL)
8446 return(NULL);
8447 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8448 return(NULL);
8449 if (cur == NULL) {
8450 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8451 return(NULL);
8452 return((xmlNodePtr)ctxt->context->node->properties);
8453 }
8454 return((xmlNodePtr)cur->next);
8455 }
8456
8457 /************************************************************************
8458 * *
8459 * NodeTest Functions *
8460 * *
8461 ************************************************************************/
8462
8463 #define IS_FUNCTION 200
8464
8465
8466 /************************************************************************
8467 * *
8468 * Implicit tree core function library *
8469 * *
8470 ************************************************************************/
8471
8472 /**
8473 * xmlXPathRoot:
8474 * @ctxt: the XPath Parser context
8475 *
8476 * Initialize the context to the root of the document
8477 */
8478 void
8479 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8480 if ((ctxt == NULL) || (ctxt->context == NULL))
8481 return;
8482 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
8483 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8484 ctxt->context->node));
8485 }
8486
8487 /************************************************************************
8488 * *
8489 * The explicit core function library *
8490 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8491 * *
8492 ************************************************************************/
8493
8494
8495 /**
8496 * xmlXPathLastFunction:
8497 * @ctxt: the XPath Parser context
8498 * @nargs: the number of arguments
8499 *
8500 * Implement the last() XPath function
8501 * number last()
8502 * The last function returns the number of nodes in the context node list.
8503 */
8504 void
8505 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8506 CHECK_ARITY(0);
8507 if (ctxt->context->contextSize >= 0) {
8508 valuePush(ctxt,
8509 xmlXPathCacheNewFloat(ctxt->context,
8510 (double) ctxt->context->contextSize));
8511 #ifdef DEBUG_EXPR
8512 xmlGenericError(xmlGenericErrorContext,
8513 "last() : %d\n", ctxt->context->contextSize);
8514 #endif
8515 } else {
8516 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8517 }
8518 }
8519
8520 /**
8521 * xmlXPathPositionFunction:
8522 * @ctxt: the XPath Parser context
8523 * @nargs: the number of arguments
8524 *
8525 * Implement the position() XPath function
8526 * number position()
8527 * The position function returns the position of the context node in the
8528 * context node list. The first position is 1, and so the last position
8529 * will be equal to last().
8530 */
8531 void
8532 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8533 CHECK_ARITY(0);
8534 if (ctxt->context->proximityPosition >= 0) {
8535 valuePush(ctxt,
8536 xmlXPathCacheNewFloat(ctxt->context,
8537 (double) ctxt->context->proximityPosition));
8538 #ifdef DEBUG_EXPR
8539 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8540 ctxt->context->proximityPosition);
8541 #endif
8542 } else {
8543 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8544 }
8545 }
8546
8547 /**
8548 * xmlXPathCountFunction:
8549 * @ctxt: the XPath Parser context
8550 * @nargs: the number of arguments
8551 *
8552 * Implement the count() XPath function
8553 * number count(node-set)
8554 */
8555 void
8556 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8557 xmlXPathObjectPtr cur;
8558
8559 CHECK_ARITY(1);
8560 if ((ctxt->value == NULL) ||
8561 ((ctxt->value->type != XPATH_NODESET) &&
8562 (ctxt->value->type != XPATH_XSLT_TREE)))
8563 XP_ERROR(XPATH_INVALID_TYPE);
8564 cur = valuePop(ctxt);
8565
8566 if ((cur == NULL) || (cur->nodesetval == NULL))
8567 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8568 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8569 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8570 (double) cur->nodesetval->nodeNr));
8571 } else {
8572 if ((cur->nodesetval->nodeNr != 1) ||
8573 (cur->nodesetval->nodeTab == NULL)) {
8574 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8575 } else {
8576 xmlNodePtr tmp;
8577 int i = 0;
8578
8579 tmp = cur->nodesetval->nodeTab[0];
8580 if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
8581 tmp = tmp->children;
8582 while (tmp != NULL) {
8583 tmp = tmp->next;
8584 i++;
8585 }
8586 }
8587 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8588 }
8589 }
8590 xmlXPathReleaseObject(ctxt->context, cur);
8591 }
8592
8593 /**
8594 * xmlXPathGetElementsByIds:
8595 * @doc: the document
8596 * @ids: a whitespace separated list of IDs
8597 *
8598 * Selects elements by their unique ID.
8599 *
8600 * Returns a node-set of selected elements.
8601 */
8602 static xmlNodeSetPtr
8603 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8604 xmlNodeSetPtr ret;
8605 const xmlChar *cur = ids;
8606 xmlChar *ID;
8607 xmlAttrPtr attr;
8608 xmlNodePtr elem = NULL;
8609
8610 if (ids == NULL) return(NULL);
8611
8612 ret = xmlXPathNodeSetCreate(NULL);
8613 if (ret == NULL)
8614 return(ret);
8615
8616 while (IS_BLANK_CH(*cur)) cur++;
8617 while (*cur != 0) {
8618 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8619 cur++;
8620
8621 ID = xmlStrndup(ids, cur - ids);
8622 if (ID != NULL) {
8623 /*
8624 * We used to check the fact that the value passed
8625 * was an NCName, but this generated much troubles for
8626 * me and Aleksey Sanin, people blatantly violated that
8627 * constaint, like Visa3D spec.
8628 * if (xmlValidateNCName(ID, 1) == 0)
8629 */
8630 attr = xmlGetID(doc, ID);
8631 if (attr != NULL) {
8632 if (attr->type == XML_ATTRIBUTE_NODE)
8633 elem = attr->parent;
8634 else if (attr->type == XML_ELEMENT_NODE)
8635 elem = (xmlNodePtr) attr;
8636 else
8637 elem = NULL;
8638 if (elem != NULL)
8639 xmlXPathNodeSetAdd(ret, elem);
8640 }
8641 xmlFree(ID);
8642 }
8643
8644 while (IS_BLANK_CH(*cur)) cur++;
8645 ids = cur;
8646 }
8647 return(ret);
8648 }
8649
8650 /**
8651 * xmlXPathIdFunction:
8652 * @ctxt: the XPath Parser context
8653 * @nargs: the number of arguments
8654 *
8655 * Implement the id() XPath function
8656 * node-set id(object)
8657 * The id function selects elements by their unique ID
8658 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8659 * then the result is the union of the result of applying id to the
8660 * string value of each of the nodes in the argument node-set. When the
8661 * argument to id is of any other type, the argument is converted to a
8662 * string as if by a call to the string function; the string is split
8663 * into a whitespace-separated list of tokens (whitespace is any sequence
8664 * of characters matching the production S); the result is a node-set
8665 * containing the elements in the same document as the context node that
8666 * have a unique ID equal to any of the tokens in the list.
8667 */
8668 void
8669 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8670 xmlChar *tokens;
8671 xmlNodeSetPtr ret;
8672 xmlXPathObjectPtr obj;
8673
8674 CHECK_ARITY(1);
8675 obj = valuePop(ctxt);
8676 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8677 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8678 xmlNodeSetPtr ns;
8679 int i;
8680
8681 ret = xmlXPathNodeSetCreate(NULL);
8682 /*
8683 * FIXME -- in an out-of-memory condition this will behave badly.
8684 * The solution is not clear -- we already popped an item from
8685 * ctxt, so the object is in a corrupt state.
8686 */
8687
8688 if (obj->nodesetval != NULL) {
8689 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8690 tokens =
8691 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8692 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8693 ret = xmlXPathNodeSetMerge(ret, ns);
8694 xmlXPathFreeNodeSet(ns);
8695 if (tokens != NULL)
8696 xmlFree(tokens);
8697 }
8698 }
8699 xmlXPathReleaseObject(ctxt->context, obj);
8700 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8701 return;
8702 }
8703 obj = xmlXPathCacheConvertString(ctxt->context, obj);
8704 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8705 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8706 xmlXPathReleaseObject(ctxt->context, obj);
8707 return;
8708 }
8709
8710 /**
8711 * xmlXPathLocalNameFunction:
8712 * @ctxt: the XPath Parser context
8713 * @nargs: the number of arguments
8714 *
8715 * Implement the local-name() XPath function
8716 * string local-name(node-set?)
8717 * The local-name function returns a string containing the local part
8718 * of the name of the node in the argument node-set that is first in
8719 * document order. If the node-set is empty or the first node has no
8720 * name, an empty string is returned. If the argument is omitted it
8721 * defaults to the context node.
8722 */
8723 void
8724 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8725 xmlXPathObjectPtr cur;
8726
8727 if (ctxt == NULL) return;
8728
8729 if (nargs == 0) {
8730 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8731 ctxt->context->node));
8732 nargs = 1;
8733 }
8734
8735 CHECK_ARITY(1);
8736 if ((ctxt->value == NULL) ||
8737 ((ctxt->value->type != XPATH_NODESET) &&
8738 (ctxt->value->type != XPATH_XSLT_TREE)))
8739 XP_ERROR(XPATH_INVALID_TYPE);
8740 cur = valuePop(ctxt);
8741
8742 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8743 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8744 } else {
8745 int i = 0; /* Should be first in document order !!!!! */
8746 switch (cur->nodesetval->nodeTab[i]->type) {
8747 case XML_ELEMENT_NODE:
8748 case XML_ATTRIBUTE_NODE:
8749 case XML_PI_NODE:
8750 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8751 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8752 else
8753 valuePush(ctxt,
8754 xmlXPathCacheNewString(ctxt->context,
8755 cur->nodesetval->nodeTab[i]->name));
8756 break;
8757 case XML_NAMESPACE_DECL:
8758 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8759 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8760 break;
8761 default:
8762 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8763 }
8764 }
8765 xmlXPathReleaseObject(ctxt->context, cur);
8766 }
8767
8768 /**
8769 * xmlXPathNamespaceURIFunction:
8770 * @ctxt: the XPath Parser context
8771 * @nargs: the number of arguments
8772 *
8773 * Implement the namespace-uri() XPath function
8774 * string namespace-uri(node-set?)
8775 * The namespace-uri function returns a string containing the
8776 * namespace URI of the expanded name of the node in the argument
8777 * node-set that is first in document order. If the node-set is empty,
8778 * the first node has no name, or the expanded name has no namespace
8779 * URI, an empty string is returned. If the argument is omitted it
8780 * defaults to the context node.
8781 */
8782 void
8783 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8784 xmlXPathObjectPtr cur;
8785
8786 if (ctxt == NULL) return;
8787
8788 if (nargs == 0) {
8789 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8790 ctxt->context->node));
8791 nargs = 1;
8792 }
8793 CHECK_ARITY(1);
8794 if ((ctxt->value == NULL) ||
8795 ((ctxt->value->type != XPATH_NODESET) &&
8796 (ctxt->value->type != XPATH_XSLT_TREE)))
8797 XP_ERROR(XPATH_INVALID_TYPE);
8798 cur = valuePop(ctxt);
8799
8800 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8801 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8802 } else {
8803 int i = 0; /* Should be first in document order !!!!! */
8804 switch (cur->nodesetval->nodeTab[i]->type) {
8805 case XML_ELEMENT_NODE:
8806 case XML_ATTRIBUTE_NODE:
8807 if (cur->nodesetval->nodeTab[i]->ns == NULL)
8808 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8809 else
8810 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8811 cur->nodesetval->nodeTab[i]->ns->href));
8812 break;
8813 default:
8814 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8815 }
8816 }
8817 xmlXPathReleaseObject(ctxt->context, cur);
8818 }
8819
8820 /**
8821 * xmlXPathNameFunction:
8822 * @ctxt: the XPath Parser context
8823 * @nargs: the number of arguments
8824 *
8825 * Implement the name() XPath function
8826 * string name(node-set?)
8827 * The name function returns a string containing a QName representing
8828 * the name of the node in the argument node-set that is first in document
8829 * order. The QName must represent the name with respect to the namespace
8830 * declarations in effect on the node whose name is being represented.
8831 * Typically, this will be the form in which the name occurred in the XML
8832 * source. This need not be the case if there are namespace declarations
8833 * in effect on the node that associate multiple prefixes with the same
8834 * namespace. However, an implementation may include information about
8835 * the original prefix in its representation of nodes; in this case, an
8836 * implementation can ensure that the returned string is always the same
8837 * as the QName used in the XML source. If the argument it omitted it
8838 * defaults to the context node.
8839 * Libxml keep the original prefix so the "real qualified name" used is
8840 * returned.
8841 */
8842 static void
8843 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8844 {
8845 xmlXPathObjectPtr cur;
8846
8847 if (nargs == 0) {
8848 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8849 ctxt->context->node));
8850 nargs = 1;
8851 }
8852
8853 CHECK_ARITY(1);
8854 if ((ctxt->value == NULL) ||
8855 ((ctxt->value->type != XPATH_NODESET) &&
8856 (ctxt->value->type != XPATH_XSLT_TREE)))
8857 XP_ERROR(XPATH_INVALID_TYPE);
8858 cur = valuePop(ctxt);
8859
8860 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8861 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8862 } else {
8863 int i = 0; /* Should be first in document order !!!!! */
8864
8865 switch (cur->nodesetval->nodeTab[i]->type) {
8866 case XML_ELEMENT_NODE:
8867 case XML_ATTRIBUTE_NODE:
8868 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8869 valuePush(ctxt,
8870 xmlXPathCacheNewCString(ctxt->context, ""));
8871 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8872 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8873 valuePush(ctxt,
8874 xmlXPathCacheNewString(ctxt->context,
8875 cur->nodesetval->nodeTab[i]->name));
8876 } else {
8877 xmlChar *fullname;
8878
8879 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8880 cur->nodesetval->nodeTab[i]->ns->prefix,
8881 NULL, 0);
8882 if (fullname == cur->nodesetval->nodeTab[i]->name)
8883 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8884 if (fullname == NULL) {
8885 XP_ERROR(XPATH_MEMORY_ERROR);
8886 }
8887 valuePush(ctxt, xmlXPathCacheWrapString(
8888 ctxt->context, fullname));
8889 }
8890 break;
8891 default:
8892 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8893 cur->nodesetval->nodeTab[i]));
8894 xmlXPathLocalNameFunction(ctxt, 1);
8895 }
8896 }
8897 xmlXPathReleaseObject(ctxt->context, cur);
8898 }
8899
8900
8901 /**
8902 * xmlXPathStringFunction:
8903 * @ctxt: the XPath Parser context
8904 * @nargs: the number of arguments
8905 *
8906 * Implement the string() XPath function
8907 * string string(object?)
8908 * The string function converts an object to a string as follows:
8909 * - A node-set is converted to a string by returning the value of
8910 * the node in the node-set that is first in document order.
8911 * If the node-set is empty, an empty string is returned.
8912 * - A number is converted to a string as follows
8913 * + NaN is converted to the string NaN
8914 * + positive zero is converted to the string 0
8915 * + negative zero is converted to the string 0
8916 * + positive infinity is converted to the string Infinity
8917 * + negative infinity is converted to the string -Infinity
8918 * + if the number is an integer, the number is represented in
8919 * decimal form as a Number with no decimal point and no leading
8920 * zeros, preceded by a minus sign (-) if the number is negative
8921 * + otherwise, the number is represented in decimal form as a
8922 * Number including a decimal point with at least one digit
8923 * before the decimal point and at least one digit after the
8924 * decimal point, preceded by a minus sign (-) if the number
8925 * is negative; there must be no leading zeros before the decimal
8926 * point apart possibly from the one required digit immediately
8927 * before the decimal point; beyond the one required digit
8928 * after the decimal point there must be as many, but only as
8929 * many, more digits as are needed to uniquely distinguish the
8930 * number from all other IEEE 754 numeric values.
8931 * - The boolean false value is converted to the string false.
8932 * The boolean true value is converted to the string true.
8933 *
8934 * If the argument is omitted, it defaults to a node-set with the
8935 * context node as its only member.
8936 */
8937 void
8938 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8939 xmlXPathObjectPtr cur;
8940
8941 if (ctxt == NULL) return;
8942 if (nargs == 0) {
8943 valuePush(ctxt,
8944 xmlXPathCacheWrapString(ctxt->context,
8945 xmlXPathCastNodeToString(ctxt->context->node)));
8946 return;
8947 }
8948
8949 CHECK_ARITY(1);
8950 cur = valuePop(ctxt);
8951 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8952 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8953 }
8954
8955 /**
8956 * xmlXPathStringLengthFunction:
8957 * @ctxt: the XPath Parser context
8958 * @nargs: the number of arguments
8959 *
8960 * Implement the string-length() XPath function
8961 * number string-length(string?)
8962 * The string-length returns the number of characters in the string
8963 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8964 * the context node converted to a string, in other words the value
8965 * of the context node.
8966 */
8967 void
8968 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8969 xmlXPathObjectPtr cur;
8970
8971 if (nargs == 0) {
8972 if ((ctxt == NULL) || (ctxt->context == NULL))
8973 return;
8974 if (ctxt->context->node == NULL) {
8975 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8976 } else {
8977 xmlChar *content;
8978
8979 content = xmlXPathCastNodeToString(ctxt->context->node);
8980 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8981 xmlUTF8Strlen(content)));
8982 xmlFree(content);
8983 }
8984 return;
8985 }
8986 CHECK_ARITY(1);
8987 CAST_TO_STRING;
8988 CHECK_TYPE(XPATH_STRING);
8989 cur = valuePop(ctxt);
8990 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8991 xmlUTF8Strlen(cur->stringval)));
8992 xmlXPathReleaseObject(ctxt->context, cur);
8993 }
8994
8995 /**
8996 * xmlXPathConcatFunction:
8997 * @ctxt: the XPath Parser context
8998 * @nargs: the number of arguments
8999 *
9000 * Implement the concat() XPath function
9001 * string concat(string, string, string*)
9002 * The concat function returns the concatenation of its arguments.
9003 */
9004 void
9005 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9006 xmlXPathObjectPtr cur, newobj;
9007 xmlChar *tmp;
9008
9009 if (ctxt == NULL) return;
9010 if (nargs < 2) {
9011 CHECK_ARITY(2);
9012 }
9013
9014 CAST_TO_STRING;
9015 cur = valuePop(ctxt);
9016 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
9017 xmlXPathReleaseObject(ctxt->context, cur);
9018 return;
9019 }
9020 nargs--;
9021
9022 while (nargs > 0) {
9023 CAST_TO_STRING;
9024 newobj = valuePop(ctxt);
9025 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
9026 xmlXPathReleaseObject(ctxt->context, newobj);
9027 xmlXPathReleaseObject(ctxt->context, cur);
9028 XP_ERROR(XPATH_INVALID_TYPE);
9029 }
9030 tmp = xmlStrcat(newobj->stringval, cur->stringval);
9031 newobj->stringval = cur->stringval;
9032 cur->stringval = tmp;
9033 xmlXPathReleaseObject(ctxt->context, newobj);
9034 nargs--;
9035 }
9036 valuePush(ctxt, cur);
9037 }
9038
9039 /**
9040 * xmlXPathContainsFunction:
9041 * @ctxt: the XPath Parser context
9042 * @nargs: the number of arguments
9043 *
9044 * Implement the contains() XPath function
9045 * boolean contains(string, string)
9046 * The contains function returns true if the first argument string
9047 * contains the second argument string, and otherwise returns false.
9048 */
9049 void
9050 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9051 xmlXPathObjectPtr hay, needle;
9052
9053 CHECK_ARITY(2);
9054 CAST_TO_STRING;
9055 CHECK_TYPE(XPATH_STRING);
9056 needle = valuePop(ctxt);
9057 CAST_TO_STRING;
9058 hay = valuePop(ctxt);
9059
9060 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9061 xmlXPathReleaseObject(ctxt->context, hay);
9062 xmlXPathReleaseObject(ctxt->context, needle);
9063 XP_ERROR(XPATH_INVALID_TYPE);
9064 }
9065 if (xmlStrstr(hay->stringval, needle->stringval))
9066 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9067 else
9068 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9069 xmlXPathReleaseObject(ctxt->context, hay);
9070 xmlXPathReleaseObject(ctxt->context, needle);
9071 }
9072
9073 /**
9074 * xmlXPathStartsWithFunction:
9075 * @ctxt: the XPath Parser context
9076 * @nargs: the number of arguments
9077 *
9078 * Implement the starts-with() XPath function
9079 * boolean starts-with(string, string)
9080 * The starts-with function returns true if the first argument string
9081 * starts with the second argument string, and otherwise returns false.
9082 */
9083 void
9084 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9085 xmlXPathObjectPtr hay, needle;
9086 int n;
9087
9088 CHECK_ARITY(2);
9089 CAST_TO_STRING;
9090 CHECK_TYPE(XPATH_STRING);
9091 needle = valuePop(ctxt);
9092 CAST_TO_STRING;
9093 hay = valuePop(ctxt);
9094
9095 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9096 xmlXPathReleaseObject(ctxt->context, hay);
9097 xmlXPathReleaseObject(ctxt->context, needle);
9098 XP_ERROR(XPATH_INVALID_TYPE);
9099 }
9100 n = xmlStrlen(needle->stringval);
9101 if (xmlStrncmp(hay->stringval, needle->stringval, n))
9102 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9103 else
9104 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9105 xmlXPathReleaseObject(ctxt->context, hay);
9106 xmlXPathReleaseObject(ctxt->context, needle);
9107 }
9108
9109 /**
9110 * xmlXPathSubstringFunction:
9111 * @ctxt: the XPath Parser context
9112 * @nargs: the number of arguments
9113 *
9114 * Implement the substring() XPath function
9115 * string substring(string, number, number?)
9116 * The substring function returns the substring of the first argument
9117 * starting at the position specified in the second argument with
9118 * length specified in the third argument. For example,
9119 * substring("12345",2,3) returns "234". If the third argument is not
9120 * specified, it returns the substring starting at the position specified
9121 * in the second argument and continuing to the end of the string. For
9122 * example, substring("12345",2) returns "2345". More precisely, each
9123 * character in the string (see [3.6 Strings]) is considered to have a
9124 * numeric position: the position of the first character is 1, the position
9125 * of the second character is 2 and so on. The returned substring contains
9126 * those characters for which the position of the character is greater than
9127 * or equal to the second argument and, if the third argument is specified,
9128 * less than the sum of the second and third arguments; the comparisons
9129 * and addition used for the above follow the standard IEEE 754 rules. Thus:
9130 * - substring("12345", 1.5, 2.6) returns "234"
9131 * - substring("12345", 0, 3) returns "12"
9132 * - substring("12345", 0 div 0, 3) returns ""
9133 * - substring("12345", 1, 0 div 0) returns ""
9134 * - substring("12345", -42, 1 div 0) returns "12345"
9135 * - substring("12345", -1 div 0, 1 div 0) returns ""
9136 */
9137 void
9138 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9139 xmlXPathObjectPtr str, start, len;
9140 double le=0, in;
9141 int i, l, m;
9142 xmlChar *ret;
9143
9144 if (nargs < 2) {
9145 CHECK_ARITY(2);
9146 }
9147 if (nargs > 3) {
9148 CHECK_ARITY(3);
9149 }
9150 /*
9151 * take care of possible last (position) argument
9152 */
9153 if (nargs == 3) {
9154 CAST_TO_NUMBER;
9155 CHECK_TYPE(XPATH_NUMBER);
9156 len = valuePop(ctxt);
9157 le = len->floatval;
9158 xmlXPathReleaseObject(ctxt->context, len);
9159 }
9160
9161 CAST_TO_NUMBER;
9162 CHECK_TYPE(XPATH_NUMBER);
9163 start = valuePop(ctxt);
9164 in = start->floatval;
9165 xmlXPathReleaseObject(ctxt->context, start);
9166 CAST_TO_STRING;
9167 CHECK_TYPE(XPATH_STRING);
9168 str = valuePop(ctxt);
9169 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
9170
9171 /*
9172 * If last pos not present, calculate last position
9173 */
9174 if (nargs != 3) {
9175 le = (double)m;
9176 if (in < 1.0)
9177 in = 1.0;
9178 }
9179
9180 /* Need to check for the special cases where either
9181 * the index is NaN, the length is NaN, or both
9182 * arguments are infinity (relying on Inf + -Inf = NaN)
9183 */
9184 if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
9185 /*
9186 * To meet the requirements of the spec, the arguments
9187 * must be converted to integer format before
9188 * initial index calculations are done
9189 *
9190 * First we go to integer form, rounding up
9191 * and checking for special cases
9192 */
9193 i = (int) in;
9194 if (((double)i)+0.5 <= in) i++;
9195
9196 if (xmlXPathIsInf(le) == 1) {
9197 l = m;
9198 if (i < 1)
9199 i = 1;
9200 }
9201 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9202 l = 0;
9203 else {
9204 l = (int) le;
9205 if (((double)l)+0.5 <= le) l++;
9206 }
9207
9208 /* Now we normalize inidices */
9209 i -= 1;
9210 l += i;
9211 if (i < 0)
9212 i = 0;
9213 if (l > m)
9214 l = m;
9215
9216 /* number of chars to copy */
9217 l -= i;
9218
9219 ret = xmlUTF8Strsub(str->stringval, i, l);
9220 }
9221 else {
9222 ret = NULL;
9223 }
9224 if (ret == NULL)
9225 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9226 else {
9227 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9228 xmlFree(ret);
9229 }
9230 xmlXPathReleaseObject(ctxt->context, str);
9231 }
9232
9233 /**
9234 * xmlXPathSubstringBeforeFunction:
9235 * @ctxt: the XPath Parser context
9236 * @nargs: the number of arguments
9237 *
9238 * Implement the substring-before() XPath function
9239 * string substring-before(string, string)
9240 * The substring-before function returns the substring of the first
9241 * argument string that precedes the first occurrence of the second
9242 * argument string in the first argument string, or the empty string
9243 * if the first argument string does not contain the second argument
9244 * string. For example, substring-before("1999/04/01","/") returns 1999.
9245 */
9246 void
9247 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9248 xmlXPathObjectPtr str;
9249 xmlXPathObjectPtr find;
9250 xmlBufPtr target;
9251 const xmlChar *point;
9252 int offset;
9253
9254 CHECK_ARITY(2);
9255 CAST_TO_STRING;
9256 find = valuePop(ctxt);
9257 CAST_TO_STRING;
9258 str = valuePop(ctxt);
9259
9260 target = xmlBufCreate();
9261 if (target) {
9262 point = xmlStrstr(str->stringval, find->stringval);
9263 if (point) {
9264 offset = (int)(point - str->stringval);
9265 xmlBufAdd(target, str->stringval, offset);
9266 }
9267 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9268 xmlBufContent(target)));
9269 xmlBufFree(target);
9270 }
9271 xmlXPathReleaseObject(ctxt->context, str);
9272 xmlXPathReleaseObject(ctxt->context, find);
9273 }
9274
9275 /**
9276 * xmlXPathSubstringAfterFunction:
9277 * @ctxt: the XPath Parser context
9278 * @nargs: the number of arguments
9279 *
9280 * Implement the substring-after() XPath function
9281 * string substring-after(string, string)
9282 * The substring-after function returns the substring of the first
9283 * argument string that follows the first occurrence of the second
9284 * argument string in the first argument string, or the empty stringi
9285 * if the first argument string does not contain the second argument
9286 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9287 * and substring-after("1999/04/01","19") returns 99/04/01.
9288 */
9289 void
9290 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9291 xmlXPathObjectPtr str;
9292 xmlXPathObjectPtr find;
9293 xmlBufPtr target;
9294 const xmlChar *point;
9295 int offset;
9296
9297 CHECK_ARITY(2);
9298 CAST_TO_STRING;
9299 find = valuePop(ctxt);
9300 CAST_TO_STRING;
9301 str = valuePop(ctxt);
9302
9303 target = xmlBufCreate();
9304 if (target) {
9305 point = xmlStrstr(str->stringval, find->stringval);
9306 if (point) {
9307 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9308 xmlBufAdd(target, &str->stringval[offset],
9309 xmlStrlen(str->stringval) - offset);
9310 }
9311 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9312 xmlBufContent(target)));
9313 xmlBufFree(target);
9314 }
9315 xmlXPathReleaseObject(ctxt->context, str);
9316 xmlXPathReleaseObject(ctxt->context, find);
9317 }
9318
9319 /**
9320 * xmlXPathNormalizeFunction:
9321 * @ctxt: the XPath Parser context
9322 * @nargs: the number of arguments
9323 *
9324 * Implement the normalize-space() XPath function
9325 * string normalize-space(string?)
9326 * The normalize-space function returns the argument string with white
9327 * space normalized by stripping leading and trailing whitespace
9328 * and replacing sequences of whitespace characters by a single
9329 * space. Whitespace characters are the same allowed by the S production
9330 * in XML. If the argument is omitted, it defaults to the context
9331 * node converted to a string, in other words the value of the context node.
9332 */
9333 void
9334 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9335 xmlXPathObjectPtr obj = NULL;
9336 xmlChar *source = NULL;
9337 xmlBufPtr target;
9338 xmlChar blank;
9339
9340 if (ctxt == NULL) return;
9341 if (nargs == 0) {
9342 /* Use current context node */
9343 valuePush(ctxt,
9344 xmlXPathCacheWrapString(ctxt->context,
9345 xmlXPathCastNodeToString(ctxt->context->node)));
9346 nargs = 1;
9347 }
9348
9349 CHECK_ARITY(1);
9350 CAST_TO_STRING;
9351 CHECK_TYPE(XPATH_STRING);
9352 obj = valuePop(ctxt);
9353 source = obj->stringval;
9354
9355 target = xmlBufCreate();
9356 if (target && source) {
9357
9358 /* Skip leading whitespaces */
9359 while (IS_BLANK_CH(*source))
9360 source++;
9361
9362 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9363 blank = 0;
9364 while (*source) {
9365 if (IS_BLANK_CH(*source)) {
9366 blank = 0x20;
9367 } else {
9368 if (blank) {
9369 xmlBufAdd(target, &blank, 1);
9370 blank = 0;
9371 }
9372 xmlBufAdd(target, source, 1);
9373 }
9374 source++;
9375 }
9376 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9377 xmlBufContent(target)));
9378 xmlBufFree(target);
9379 }
9380 xmlXPathReleaseObject(ctxt->context, obj);
9381 }
9382
9383 /**
9384 * xmlXPathTranslateFunction:
9385 * @ctxt: the XPath Parser context
9386 * @nargs: the number of arguments
9387 *
9388 * Implement the translate() XPath function
9389 * string translate(string, string, string)
9390 * The translate function returns the first argument string with
9391 * occurrences of characters in the second argument string replaced
9392 * by the character at the corresponding position in the third argument
9393 * string. For example, translate("bar","abc","ABC") returns the string
9394 * BAr. If there is a character in the second argument string with no
9395 * character at a corresponding position in the third argument string
9396 * (because the second argument string is longer than the third argument
9397 * string), then occurrences of that character in the first argument
9398 * string are removed. For example, translate("--aaa--","abc-","ABC")
9399 * returns "AAA". If a character occurs more than once in second
9400 * argument string, then the first occurrence determines the replacement
9401 * character. If the third argument string is longer than the second
9402 * argument string, then excess characters are ignored.
9403 */
9404 void
9405 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9406 xmlXPathObjectPtr str;
9407 xmlXPathObjectPtr from;
9408 xmlXPathObjectPtr to;
9409 xmlBufPtr target;
9410 int offset, max;
9411 xmlChar ch;
9412 const xmlChar *point;
9413 xmlChar *cptr;
9414
9415 CHECK_ARITY(3);
9416
9417 CAST_TO_STRING;
9418 to = valuePop(ctxt);
9419 CAST_TO_STRING;
9420 from = valuePop(ctxt);
9421 CAST_TO_STRING;
9422 str = valuePop(ctxt);
9423
9424 target = xmlBufCreate();
9425 if (target) {
9426 max = xmlUTF8Strlen(to->stringval);
9427 for (cptr = str->stringval; (ch=*cptr); ) {
9428 offset = xmlUTF8Strloc(from->stringval, cptr);
9429 if (offset >= 0) {
9430 if (offset < max) {
9431 point = xmlUTF8Strpos(to->stringval, offset);
9432 if (point)
9433 xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9434 }
9435 } else
9436 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9437
9438 /* Step to next character in input */
9439 cptr++;
9440 if ( ch & 0x80 ) {
9441 /* if not simple ascii, verify proper format */
9442 if ( (ch & 0xc0) != 0xc0 ) {
9443 xmlGenericError(xmlGenericErrorContext,
9444 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9445 /* not asserting an XPath error is probably better */
9446 break;
9447 }
9448 /* then skip over remaining bytes for this char */
9449 while ( (ch <<= 1) & 0x80 )
9450 if ( (*cptr++ & 0xc0) != 0x80 ) {
9451 xmlGenericError(xmlGenericErrorContext,
9452 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9453 /* not asserting an XPath error is probably better */
9454 break;
9455 }
9456 if (ch & 0x80) /* must have had error encountered */
9457 break;
9458 }
9459 }
9460 }
9461 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9462 xmlBufContent(target)));
9463 xmlBufFree(target);
9464 xmlXPathReleaseObject(ctxt->context, str);
9465 xmlXPathReleaseObject(ctxt->context, from);
9466 xmlXPathReleaseObject(ctxt->context, to);
9467 }
9468
9469 /**
9470 * xmlXPathBooleanFunction:
9471 * @ctxt: the XPath Parser context
9472 * @nargs: the number of arguments
9473 *
9474 * Implement the boolean() XPath function
9475 * boolean boolean(object)
9476 * The boolean function converts its argument to a boolean as follows:
9477 * - a number is true if and only if it is neither positive or
9478 * negative zero nor NaN
9479 * - a node-set is true if and only if it is non-empty
9480 * - a string is true if and only if its length is non-zero
9481 */
9482 void
9483 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9484 xmlXPathObjectPtr cur;
9485
9486 CHECK_ARITY(1);
9487 cur = valuePop(ctxt);
9488 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9489 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9490 valuePush(ctxt, cur);
9491 }
9492
9493 /**
9494 * xmlXPathNotFunction:
9495 * @ctxt: the XPath Parser context
9496 * @nargs: the number of arguments
9497 *
9498 * Implement the not() XPath function
9499 * boolean not(boolean)
9500 * The not function returns true if its argument is false,
9501 * and false otherwise.
9502 */
9503 void
9504 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9505 CHECK_ARITY(1);
9506 CAST_TO_BOOLEAN;
9507 CHECK_TYPE(XPATH_BOOLEAN);
9508 ctxt->value->boolval = ! ctxt->value->boolval;
9509 }
9510
9511 /**
9512 * xmlXPathTrueFunction:
9513 * @ctxt: the XPath Parser context
9514 * @nargs: the number of arguments
9515 *
9516 * Implement the true() XPath function
9517 * boolean true()
9518 */
9519 void
9520 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9521 CHECK_ARITY(0);
9522 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9523 }
9524
9525 /**
9526 * xmlXPathFalseFunction:
9527 * @ctxt: the XPath Parser context
9528 * @nargs: the number of arguments
9529 *
9530 * Implement the false() XPath function
9531 * boolean false()
9532 */
9533 void
9534 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9535 CHECK_ARITY(0);
9536 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9537 }
9538
9539 /**
9540 * xmlXPathLangFunction:
9541 * @ctxt: the XPath Parser context
9542 * @nargs: the number of arguments
9543 *
9544 * Implement the lang() XPath function
9545 * boolean lang(string)
9546 * The lang function returns true or false depending on whether the
9547 * language of the context node as specified by xml:lang attributes
9548 * is the same as or is a sublanguage of the language specified by
9549 * the argument string. The language of the context node is determined
9550 * by the value of the xml:lang attribute on the context node, or, if
9551 * the context node has no xml:lang attribute, by the value of the
9552 * xml:lang attribute on the nearest ancestor of the context node that
9553 * has an xml:lang attribute. If there is no such attribute, then lang
9554 * returns false. If there is such an attribute, then lang returns
9555 * true if the attribute value is equal to the argument ignoring case,
9556 * or if there is some suffix starting with - such that the attribute
9557 * value is equal to the argument ignoring that suffix of the attribute
9558 * value and ignoring case.
9559 */
9560 void
9561 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9562 xmlXPathObjectPtr val = NULL;
9563 const xmlChar *theLang = NULL;
9564 const xmlChar *lang;
9565 int ret = 0;
9566 int i;
9567
9568 CHECK_ARITY(1);
9569 CAST_TO_STRING;
9570 CHECK_TYPE(XPATH_STRING);
9571 val = valuePop(ctxt);
9572 lang = val->stringval;
9573 theLang = xmlNodeGetLang(ctxt->context->node);
9574 if ((theLang != NULL) && (lang != NULL)) {
9575 for (i = 0;lang[i] != 0;i++)
9576 if (toupper(lang[i]) != toupper(theLang[i]))
9577 goto not_equal;
9578 if ((theLang[i] == 0) || (theLang[i] == '-'))
9579 ret = 1;
9580 }
9581 not_equal:
9582 if (theLang != NULL)
9583 xmlFree((void *)theLang);
9584
9585 xmlXPathReleaseObject(ctxt->context, val);
9586 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9587 }
9588
9589 /**
9590 * xmlXPathNumberFunction:
9591 * @ctxt: the XPath Parser context
9592 * @nargs: the number of arguments
9593 *
9594 * Implement the number() XPath function
9595 * number number(object?)
9596 */
9597 void
9598 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9599 xmlXPathObjectPtr cur;
9600 double res;
9601
9602 if (ctxt == NULL) return;
9603 if (nargs == 0) {
9604 if (ctxt->context->node == NULL) {
9605 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9606 } else {
9607 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9608
9609 res = xmlXPathStringEvalNumber(content);
9610 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9611 xmlFree(content);
9612 }
9613 return;
9614 }
9615
9616 CHECK_ARITY(1);
9617 cur = valuePop(ctxt);
9618 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9619 }
9620
9621 /**
9622 * xmlXPathSumFunction:
9623 * @ctxt: the XPath Parser context
9624 * @nargs: the number of arguments
9625 *
9626 * Implement the sum() XPath function
9627 * number sum(node-set)
9628 * The sum function returns the sum of the values of the nodes in
9629 * the argument node-set.
9630 */
9631 void
9632 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9633 xmlXPathObjectPtr cur;
9634 int i;
9635 double res = 0.0;
9636
9637 CHECK_ARITY(1);
9638 if ((ctxt->value == NULL) ||
9639 ((ctxt->value->type != XPATH_NODESET) &&
9640 (ctxt->value->type != XPATH_XSLT_TREE)))
9641 XP_ERROR(XPATH_INVALID_TYPE);
9642 cur = valuePop(ctxt);
9643
9644 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9645 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9646 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9647 }
9648 }
9649 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9650 xmlXPathReleaseObject(ctxt->context, cur);
9651 }
9652
9653 /**
9654 * xmlXPathFloorFunction:
9655 * @ctxt: the XPath Parser context
9656 * @nargs: the number of arguments
9657 *
9658 * Implement the floor() XPath function
9659 * number floor(number)
9660 * The floor function returns the largest (closest to positive infinity)
9661 * number that is not greater than the argument and that is an integer.
9662 */
9663 void
9664 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9665 CHECK_ARITY(1);
9666 CAST_TO_NUMBER;
9667 CHECK_TYPE(XPATH_NUMBER);
9668
9669 ctxt->value->floatval = floor(ctxt->value->floatval);
9670 }
9671
9672 /**
9673 * xmlXPathCeilingFunction:
9674 * @ctxt: the XPath Parser context
9675 * @nargs: the number of arguments
9676 *
9677 * Implement the ceiling() XPath function
9678 * number ceiling(number)
9679 * The ceiling function returns the smallest (closest to negative infinity)
9680 * number that is not less than the argument and that is an integer.
9681 */
9682 void
9683 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9684 CHECK_ARITY(1);
9685 CAST_TO_NUMBER;
9686 CHECK_TYPE(XPATH_NUMBER);
9687
9688 ctxt->value->floatval = ceil(ctxt->value->floatval);
9689 }
9690
9691 /**
9692 * xmlXPathRoundFunction:
9693 * @ctxt: the XPath Parser context
9694 * @nargs: the number of arguments
9695 *
9696 * Implement the round() XPath function
9697 * number round(number)
9698 * The round function returns the number that is closest to the
9699 * argument and that is an integer. If there are two such numbers,
9700 * then the one that is closest to positive infinity is returned.
9701 */
9702 void
9703 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9704 double f;
9705
9706 CHECK_ARITY(1);
9707 CAST_TO_NUMBER;
9708 CHECK_TYPE(XPATH_NUMBER);
9709
9710 f = ctxt->value->floatval;
9711
9712 if ((f >= -0.5) && (f < 0.5)) {
9713 /* Handles negative zero. */
9714 ctxt->value->floatval *= 0.0;
9715 }
9716 else {
9717 double rounded = floor(f);
9718 if (f - rounded >= 0.5)
9719 rounded += 1.0;
9720 ctxt->value->floatval = rounded;
9721 }
9722 }
9723
9724 /************************************************************************
9725 * *
9726 * The Parser *
9727 * *
9728 ************************************************************************/
9729
9730 /*
9731 * a few forward declarations since we use a recursive call based
9732 * implementation.
9733 */
9734 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9735 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9736 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9737 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9738 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9739 int qualified);
9740
9741 /**
9742 * xmlXPathCurrentChar:
9743 * @ctxt: the XPath parser context
9744 * @cur: pointer to the beginning of the char
9745 * @len: pointer to the length of the char read
9746 *
9747 * The current char value, if using UTF-8 this may actually span multiple
9748 * bytes in the input buffer.
9749 *
9750 * Returns the current char value and its length
9751 */
9752
9753 static int
9754 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9755 unsigned char c;
9756 unsigned int val;
9757 const xmlChar *cur;
9758
9759 if (ctxt == NULL)
9760 return(0);
9761 cur = ctxt->cur;
9762
9763 /*
9764 * We are supposed to handle UTF8, check it's valid
9765 * From rfc2044: encoding of the Unicode values on UTF-8:
9766 *
9767 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9768 * 0000 0000-0000 007F 0xxxxxxx
9769 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
9770 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
9771 *
9772 * Check for the 0x110000 limit too
9773 */
9774 c = *cur;
9775 if (c & 0x80) {
9776 if ((cur[1] & 0xc0) != 0x80)
9777 goto encoding_error;
9778 if ((c & 0xe0) == 0xe0) {
9779
9780 if ((cur[2] & 0xc0) != 0x80)
9781 goto encoding_error;
9782 if ((c & 0xf0) == 0xf0) {
9783 if (((c & 0xf8) != 0xf0) ||
9784 ((cur[3] & 0xc0) != 0x80))
9785 goto encoding_error;
9786 /* 4-byte code */
9787 *len = 4;
9788 val = (cur[0] & 0x7) << 18;
9789 val |= (cur[1] & 0x3f) << 12;
9790 val |= (cur[2] & 0x3f) << 6;
9791 val |= cur[3] & 0x3f;
9792 } else {
9793 /* 3-byte code */
9794 *len = 3;
9795 val = (cur[0] & 0xf) << 12;
9796 val |= (cur[1] & 0x3f) << 6;
9797 val |= cur[2] & 0x3f;
9798 }
9799 } else {
9800 /* 2-byte code */
9801 *len = 2;
9802 val = (cur[0] & 0x1f) << 6;
9803 val |= cur[1] & 0x3f;
9804 }
9805 if (!IS_CHAR(val)) {
9806 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9807 }
9808 return(val);
9809 } else {
9810 /* 1-byte code */
9811 *len = 1;
9812 return((int) *cur);
9813 }
9814 encoding_error:
9815 /*
9816 * If we detect an UTF8 error that probably means that the
9817 * input encoding didn't get properly advertised in the
9818 * declaration header. Report the error and switch the encoding
9819 * to ISO-Latin-1 (if you don't like this policy, just declare the
9820 * encoding !)
9821 */
9822 *len = 0;
9823 XP_ERROR0(XPATH_ENCODING_ERROR);
9824 }
9825
9826 /**
9827 * xmlXPathParseNCName:
9828 * @ctxt: the XPath Parser context
9829 *
9830 * parse an XML namespace non qualified name.
9831 *
9832 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9833 *
9834 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9835 * CombiningChar | Extender
9836 *
9837 * Returns the namespace name or NULL
9838 */
9839
9840 xmlChar *
9841 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9842 const xmlChar *in;
9843 xmlChar *ret;
9844 int count = 0;
9845
9846 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9847 /*
9848 * Accelerator for simple ASCII names
9849 */
9850 in = ctxt->cur;
9851 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9852 ((*in >= 0x41) && (*in <= 0x5A)) ||
9853 (*in == '_')) {
9854 in++;
9855 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9856 ((*in >= 0x41) && (*in <= 0x5A)) ||
9857 ((*in >= 0x30) && (*in <= 0x39)) ||
9858 (*in == '_') || (*in == '.') ||
9859 (*in == '-'))
9860 in++;
9861 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9862 (*in == '[') || (*in == ']') || (*in == ':') ||
9863 (*in == '@') || (*in == '*')) {
9864 count = in - ctxt->cur;
9865 if (count == 0)
9866 return(NULL);
9867 ret = xmlStrndup(ctxt->cur, count);
9868 ctxt->cur = in;
9869 return(ret);
9870 }
9871 }
9872 return(xmlXPathParseNameComplex(ctxt, 0));
9873 }
9874
9875
9876 /**
9877 * xmlXPathParseQName:
9878 * @ctxt: the XPath Parser context
9879 * @prefix: a xmlChar **
9880 *
9881 * parse an XML qualified name
9882 *
9883 * [NS 5] QName ::= (Prefix ':')? LocalPart
9884 *
9885 * [NS 6] Prefix ::= NCName
9886 *
9887 * [NS 7] LocalPart ::= NCName
9888 *
9889 * Returns the function returns the local part, and prefix is updated
9890 * to get the Prefix if any.
9891 */
9892
9893 static xmlChar *
9894 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9895 xmlChar *ret = NULL;
9896
9897 *prefix = NULL;
9898 ret = xmlXPathParseNCName(ctxt);
9899 if (ret && CUR == ':') {
9900 *prefix = ret;
9901 NEXT;
9902 ret = xmlXPathParseNCName(ctxt);
9903 }
9904 return(ret);
9905 }
9906
9907 /**
9908 * xmlXPathParseName:
9909 * @ctxt: the XPath Parser context
9910 *
9911 * parse an XML name
9912 *
9913 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9914 * CombiningChar | Extender
9915 *
9916 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9917 *
9918 * Returns the namespace name or NULL
9919 */
9920
9921 xmlChar *
9922 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9923 const xmlChar *in;
9924 xmlChar *ret;
9925 size_t count = 0;
9926
9927 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9928 /*
9929 * Accelerator for simple ASCII names
9930 */
9931 in = ctxt->cur;
9932 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9933 ((*in >= 0x41) && (*in <= 0x5A)) ||
9934 (*in == '_') || (*in == ':')) {
9935 in++;
9936 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9937 ((*in >= 0x41) && (*in <= 0x5A)) ||
9938 ((*in >= 0x30) && (*in <= 0x39)) ||
9939 (*in == '_') || (*in == '-') ||
9940 (*in == ':') || (*in == '.'))
9941 in++;
9942 if ((*in > 0) && (*in < 0x80)) {
9943 count = in - ctxt->cur;
9944 if (count > XML_MAX_NAME_LENGTH) {
9945 ctxt->cur = in;
9946 XP_ERRORNULL(XPATH_EXPR_ERROR);
9947 }
9948 ret = xmlStrndup(ctxt->cur, count);
9949 ctxt->cur = in;
9950 return(ret);
9951 }
9952 }
9953 return(xmlXPathParseNameComplex(ctxt, 1));
9954 }
9955
9956 static xmlChar *
9957 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9958 xmlChar buf[XML_MAX_NAMELEN + 5];
9959 int len = 0, l;
9960 int c;
9961
9962 /*
9963 * Handler for more complex cases
9964 */
9965 c = CUR_CHAR(l);
9966 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9967 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9968 (c == '*') || /* accelerators */
9969 (!IS_LETTER(c) && (c != '_') &&
9970 ((!qualified) || (c != ':')))) {
9971 return(NULL);
9972 }
9973
9974 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9975 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9976 (c == '.') || (c == '-') ||
9977 (c == '_') || ((qualified) && (c == ':')) ||
9978 (IS_COMBINING(c)) ||
9979 (IS_EXTENDER(c)))) {
9980 COPY_BUF(l,buf,len,c);
9981 NEXTL(l);
9982 c = CUR_CHAR(l);
9983 if (len >= XML_MAX_NAMELEN) {
9984 /*
9985 * Okay someone managed to make a huge name, so he's ready to pay
9986 * for the processing speed.
9987 */
9988 xmlChar *buffer;
9989 int max = len * 2;
9990
9991 if (len > XML_MAX_NAME_LENGTH) {
9992 XP_ERRORNULL(XPATH_EXPR_ERROR);
9993 }
9994 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
9995 if (buffer == NULL) {
9996 XP_ERRORNULL(XPATH_MEMORY_ERROR);
9997 }
9998 memcpy(buffer, buf, len);
9999 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
10000 (c == '.') || (c == '-') ||
10001 (c == '_') || ((qualified) && (c == ':')) ||
10002 (IS_COMBINING(c)) ||
10003 (IS_EXTENDER(c))) {
10004 if (len + 10 > max) {
10005 if (max > XML_MAX_NAME_LENGTH) {
10006 XP_ERRORNULL(XPATH_EXPR_ERROR);
10007 }
10008 max *= 2;
10009 buffer = (xmlChar *) xmlRealloc(buffer,
10010 max * sizeof(xmlChar));
10011 if (buffer == NULL) {
10012 XP_ERRORNULL(XPATH_MEMORY_ERROR);
10013 }
10014 }
10015 COPY_BUF(l,buffer,len,c);
10016 NEXTL(l);
10017 c = CUR_CHAR(l);
10018 }
10019 buffer[len] = 0;
10020 return(buffer);
10021 }
10022 }
10023 if (len == 0)
10024 return(NULL);
10025 return(xmlStrndup(buf, len));
10026 }
10027
10028 #define MAX_FRAC 20
10029
10030 /**
10031 * xmlXPathStringEvalNumber:
10032 * @str: A string to scan
10033 *
10034 * [30a] Float ::= Number ('e' Digits?)?
10035 *
10036 * [30] Number ::= Digits ('.' Digits?)?
10037 * | '.' Digits
10038 * [31] Digits ::= [0-9]+
10039 *
10040 * Compile a Number in the string
10041 * In complement of the Number expression, this function also handles
10042 * negative values : '-' Number.
10043 *
10044 * Returns the double value.
10045 */
10046 double
10047 xmlXPathStringEvalNumber(const xmlChar *str) {
10048 const xmlChar *cur = str;
10049 double ret;
10050 int ok = 0;
10051 int isneg = 0;
10052 int exponent = 0;
10053 int is_exponent_negative = 0;
10054 #ifdef __GNUC__
10055 unsigned long tmp = 0;
10056 double temp;
10057 #endif
10058 if (cur == NULL) return(0);
10059 while (IS_BLANK_CH(*cur)) cur++;
10060 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10061 return(NAN);
10062 }
10063 if (*cur == '-') {
10064 isneg = 1;
10065 cur++;
10066 }
10067
10068 #ifdef __GNUC__
10069 /*
10070 * tmp/temp is a workaround against a gcc compiler bug
10071 * http://veillard.com/gcc.bug
10072 */
10073 ret = 0;
10074 while ((*cur >= '0') && (*cur <= '9')) {
10075 ret = ret * 10;
10076 tmp = (*cur - '0');
10077 ok = 1;
10078 cur++;
10079 temp = (double) tmp;
10080 ret = ret + temp;
10081 }
10082 #else
10083 ret = 0;
10084 while ((*cur >= '0') && (*cur <= '9')) {
10085 ret = ret * 10 + (*cur - '0');
10086 ok = 1;
10087 cur++;
10088 }
10089 #endif
10090
10091 if (*cur == '.') {
10092 int v, frac = 0, max;
10093 double fraction = 0;
10094
10095 cur++;
10096 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10097 return(NAN);
10098 }
10099 while (*cur == '0') {
10100 frac = frac + 1;
10101 cur++;
10102 }
10103 max = frac + MAX_FRAC;
10104 while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
10105 v = (*cur - '0');
10106 fraction = fraction * 10 + v;
10107 frac = frac + 1;
10108 cur++;
10109 }
10110 fraction /= pow(10.0, frac);
10111 ret = ret + fraction;
10112 while ((*cur >= '0') && (*cur <= '9'))
10113 cur++;
10114 }
10115 if ((*cur == 'e') || (*cur == 'E')) {
10116 cur++;
10117 if (*cur == '-') {
10118 is_exponent_negative = 1;
10119 cur++;
10120 } else if (*cur == '+') {
10121 cur++;
10122 }
10123 while ((*cur >= '0') && (*cur <= '9')) {
10124 if (exponent < 1000000)
10125 exponent = exponent * 10 + (*cur - '0');
10126 cur++;
10127 }
10128 }
10129 while (IS_BLANK_CH(*cur)) cur++;
10130 if (*cur != 0) return(NAN);
10131 if (isneg) ret = -ret;
10132 if (is_exponent_negative) exponent = -exponent;
10133 ret *= pow(10.0, (double)exponent);
10134 return(ret);
10135 }
10136
10137 /**
10138 * xmlXPathCompNumber:
10139 * @ctxt: the XPath Parser context
10140 *
10141 * [30] Number ::= Digits ('.' Digits?)?
10142 * | '.' Digits
10143 * [31] Digits ::= [0-9]+
10144 *
10145 * Compile a Number, then push it on the stack
10146 *
10147 */
10148 static void
10149 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10150 {
10151 double ret = 0.0;
10152 int ok = 0;
10153 int exponent = 0;
10154 int is_exponent_negative = 0;
10155 #ifdef __GNUC__
10156 unsigned long tmp = 0;
10157 double temp;
10158 #endif
10159
10160 CHECK_ERROR;
10161 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10162 XP_ERROR(XPATH_NUMBER_ERROR);
10163 }
10164 #ifdef __GNUC__
10165 /*
10166 * tmp/temp is a workaround against a gcc compiler bug
10167 * http://veillard.com/gcc.bug
10168 */
10169 ret = 0;
10170 while ((CUR >= '0') && (CUR <= '9')) {
10171 ret = ret * 10;
10172 tmp = (CUR - '0');
10173 ok = 1;
10174 NEXT;
10175 temp = (double) tmp;
10176 ret = ret + temp;
10177 }
10178 #else
10179 ret = 0;
10180 while ((CUR >= '0') && (CUR <= '9')) {
10181 ret = ret * 10 + (CUR - '0');
10182 ok = 1;
10183 NEXT;
10184 }
10185 #endif
10186 if (CUR == '.') {
10187 int v, frac = 0, max;
10188 double fraction = 0;
10189
10190 NEXT;
10191 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10192 XP_ERROR(XPATH_NUMBER_ERROR);
10193 }
10194 while (CUR == '0') {
10195 frac = frac + 1;
10196 NEXT;
10197 }
10198 max = frac + MAX_FRAC;
10199 while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
10200 v = (CUR - '0');
10201 fraction = fraction * 10 + v;
10202 frac = frac + 1;
10203 NEXT;
10204 }
10205 fraction /= pow(10.0, frac);
10206 ret = ret + fraction;
10207 while ((CUR >= '0') && (CUR <= '9'))
10208 NEXT;
10209 }
10210 if ((CUR == 'e') || (CUR == 'E')) {
10211 NEXT;
10212 if (CUR == '-') {
10213 is_exponent_negative = 1;
10214 NEXT;
10215 } else if (CUR == '+') {
10216 NEXT;
10217 }
10218 while ((CUR >= '0') && (CUR <= '9')) {
10219 if (exponent < 1000000)
10220 exponent = exponent * 10 + (CUR - '0');
10221 NEXT;
10222 }
10223 if (is_exponent_negative)
10224 exponent = -exponent;
10225 ret *= pow(10.0, (double) exponent);
10226 }
10227 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10228 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10229 }
10230
10231 /**
10232 * xmlXPathParseLiteral:
10233 * @ctxt: the XPath Parser context
10234 *
10235 * Parse a Literal
10236 *
10237 * [29] Literal ::= '"' [^"]* '"'
10238 * | "'" [^']* "'"
10239 *
10240 * Returns the value found or NULL in case of error
10241 */
10242 static xmlChar *
10243 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10244 const xmlChar *q;
10245 xmlChar *ret = NULL;
10246
10247 if (CUR == '"') {
10248 NEXT;
10249 q = CUR_PTR;
10250 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10251 NEXT;
10252 if (!IS_CHAR_CH(CUR)) {
10253 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10254 } else {
10255 ret = xmlStrndup(q, CUR_PTR - q);
10256 NEXT;
10257 }
10258 } else if (CUR == '\'') {
10259 NEXT;
10260 q = CUR_PTR;
10261 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10262 NEXT;
10263 if (!IS_CHAR_CH(CUR)) {
10264 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10265 } else {
10266 ret = xmlStrndup(q, CUR_PTR - q);
10267 NEXT;
10268 }
10269 } else {
10270 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10271 }
10272 return(ret);
10273 }
10274
10275 /**
10276 * xmlXPathCompLiteral:
10277 * @ctxt: the XPath Parser context
10278 *
10279 * Parse a Literal and push it on the stack.
10280 *
10281 * [29] Literal ::= '"' [^"]* '"'
10282 * | "'" [^']* "'"
10283 *
10284 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10285 */
10286 static void
10287 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10288 const xmlChar *q;
10289 xmlChar *ret = NULL;
10290
10291 if (CUR == '"') {
10292 NEXT;
10293 q = CUR_PTR;
10294 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10295 NEXT;
10296 if (!IS_CHAR_CH(CUR)) {
10297 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10298 } else {
10299 ret = xmlStrndup(q, CUR_PTR - q);
10300 NEXT;
10301 }
10302 } else if (CUR == '\'') {
10303 NEXT;
10304 q = CUR_PTR;
10305 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10306 NEXT;
10307 if (!IS_CHAR_CH(CUR)) {
10308 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10309 } else {
10310 ret = xmlStrndup(q, CUR_PTR - q);
10311 NEXT;
10312 }
10313 } else {
10314 XP_ERROR(XPATH_START_LITERAL_ERROR);
10315 }
10316 if (ret == NULL) return;
10317 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10318 xmlXPathCacheNewString(ctxt->context, ret), NULL);
10319 xmlFree(ret);
10320 }
10321
10322 /**
10323 * xmlXPathCompVariableReference:
10324 * @ctxt: the XPath Parser context
10325 *
10326 * Parse a VariableReference, evaluate it and push it on the stack.
10327 *
10328 * The variable bindings consist of a mapping from variable names
10329 * to variable values. The value of a variable is an object, which can be
10330 * of any of the types that are possible for the value of an expression,
10331 * and may also be of additional types not specified here.
10332 *
10333 * Early evaluation is possible since:
10334 * The variable bindings [...] used to evaluate a subexpression are
10335 * always the same as those used to evaluate the containing expression.
10336 *
10337 * [36] VariableReference ::= '$' QName
10338 */
10339 static void
10340 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10341 xmlChar *name;
10342 xmlChar *prefix;
10343
10344 SKIP_BLANKS;
10345 if (CUR != '$') {
10346 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10347 }
10348 NEXT;
10349 name = xmlXPathParseQName(ctxt, &prefix);
10350 if (name == NULL) {
10351 xmlFree(prefix);
10352 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10353 }
10354 ctxt->comp->last = -1;
10355 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10356 name, prefix);
10357 SKIP_BLANKS;
10358 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10359 XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10360 }
10361 }
10362
10363 /**
10364 * xmlXPathIsNodeType:
10365 * @name: a name string
10366 *
10367 * Is the name given a NodeType one.
10368 *
10369 * [38] NodeType ::= 'comment'
10370 * | 'text'
10371 * | 'processing-instruction'
10372 * | 'node'
10373 *
10374 * Returns 1 if true 0 otherwise
10375 */
10376 int
10377 xmlXPathIsNodeType(const xmlChar *name) {
10378 if (name == NULL)
10379 return(0);
10380
10381 if (xmlStrEqual(name, BAD_CAST "node"))
10382 return(1);
10383 if (xmlStrEqual(name, BAD_CAST "text"))
10384 return(1);
10385 if (xmlStrEqual(name, BAD_CAST "comment"))
10386 return(1);
10387 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10388 return(1);
10389 return(0);
10390 }
10391
10392 /**
10393 * xmlXPathCompFunctionCall:
10394 * @ctxt: the XPath Parser context
10395 *
10396 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10397 * [17] Argument ::= Expr
10398 *
10399 * Compile a function call, the evaluation of all arguments are
10400 * pushed on the stack
10401 */
10402 static void
10403 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10404 xmlChar *name;
10405 xmlChar *prefix;
10406 int nbargs = 0;
10407 int sort = 1;
10408
10409 name = xmlXPathParseQName(ctxt, &prefix);
10410 if (name == NULL) {
10411 xmlFree(prefix);
10412 XP_ERROR(XPATH_EXPR_ERROR);
10413 }
10414 SKIP_BLANKS;
10415 #ifdef DEBUG_EXPR
10416 if (prefix == NULL)
10417 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10418 name);
10419 else
10420 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10421 prefix, name);
10422 #endif
10423
10424 if (CUR != '(') {
10425 xmlFree(name);
10426 xmlFree(prefix);
10427 XP_ERROR(XPATH_EXPR_ERROR);
10428 }
10429 NEXT;
10430 SKIP_BLANKS;
10431
10432 /*
10433 * Optimization for count(): we don't need the node-set to be sorted.
10434 */
10435 if ((prefix == NULL) && (name[0] == 'c') &&
10436 xmlStrEqual(name, BAD_CAST "count"))
10437 {
10438 sort = 0;
10439 }
10440 ctxt->comp->last = -1;
10441 if (CUR != ')') {
10442 while (CUR != 0) {
10443 int op1 = ctxt->comp->last;
10444 ctxt->comp->last = -1;
10445 xmlXPathCompileExpr(ctxt, sort);
10446 if (ctxt->error != XPATH_EXPRESSION_OK) {
10447 xmlFree(name);
10448 xmlFree(prefix);
10449 return;
10450 }
10451 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10452 nbargs++;
10453 if (CUR == ')') break;
10454 if (CUR != ',') {
10455 xmlFree(name);
10456 xmlFree(prefix);
10457 XP_ERROR(XPATH_EXPR_ERROR);
10458 }
10459 NEXT;
10460 SKIP_BLANKS;
10461 }
10462 }
10463 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10464 name, prefix);
10465 NEXT;
10466 SKIP_BLANKS;
10467 }
10468
10469 /**
10470 * xmlXPathCompPrimaryExpr:
10471 * @ctxt: the XPath Parser context
10472 *
10473 * [15] PrimaryExpr ::= VariableReference
10474 * | '(' Expr ')'
10475 * | Literal
10476 * | Number
10477 * | FunctionCall
10478 *
10479 * Compile a primary expression.
10480 */
10481 static void
10482 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10483 SKIP_BLANKS;
10484 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10485 else if (CUR == '(') {
10486 NEXT;
10487 SKIP_BLANKS;
10488 xmlXPathCompileExpr(ctxt, 1);
10489 CHECK_ERROR;
10490 if (CUR != ')') {
10491 XP_ERROR(XPATH_EXPR_ERROR);
10492 }
10493 NEXT;
10494 SKIP_BLANKS;
10495 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10496 xmlXPathCompNumber(ctxt);
10497 } else if ((CUR == '\'') || (CUR == '"')) {
10498 xmlXPathCompLiteral(ctxt);
10499 } else {
10500 xmlXPathCompFunctionCall(ctxt);
10501 }
10502 SKIP_BLANKS;
10503 }
10504
10505 /**
10506 * xmlXPathCompFilterExpr:
10507 * @ctxt: the XPath Parser context
10508 *
10509 * [20] FilterExpr ::= PrimaryExpr
10510 * | FilterExpr Predicate
10511 *
10512 * Compile a filter expression.
10513 * Square brackets are used to filter expressions in the same way that
10514 * they are used in location paths. It is an error if the expression to
10515 * be filtered does not evaluate to a node-set. The context node list
10516 * used for evaluating the expression in square brackets is the node-set
10517 * to be filtered listed in document order.
10518 */
10519
10520 static void
10521 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10522 xmlXPathCompPrimaryExpr(ctxt);
10523 CHECK_ERROR;
10524 SKIP_BLANKS;
10525
10526 while (CUR == '[') {
10527 xmlXPathCompPredicate(ctxt, 1);
10528 SKIP_BLANKS;
10529 }
10530
10531
10532 }
10533
10534 /**
10535 * xmlXPathScanName:
10536 * @ctxt: the XPath Parser context
10537 *
10538 * Trickery: parse an XML name but without consuming the input flow
10539 * Needed to avoid insanity in the parser state.
10540 *
10541 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10542 * CombiningChar | Extender
10543 *
10544 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10545 *
10546 * [6] Names ::= Name (S Name)*
10547 *
10548 * Returns the Name parsed or NULL
10549 */
10550
10551 static xmlChar *
10552 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10553 int len = 0, l;
10554 int c;
10555 const xmlChar *cur;
10556 xmlChar *ret;
10557
10558 cur = ctxt->cur;
10559
10560 c = CUR_CHAR(l);
10561 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10562 (!IS_LETTER(c) && (c != '_') &&
10563 (c != ':'))) {
10564 return(NULL);
10565 }
10566
10567 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10568 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10569 (c == '.') || (c == '-') ||
10570 (c == '_') || (c == ':') ||
10571 (IS_COMBINING(c)) ||
10572 (IS_EXTENDER(c)))) {
10573 len += l;
10574 NEXTL(l);
10575 c = CUR_CHAR(l);
10576 }
10577 ret = xmlStrndup(cur, ctxt->cur - cur);
10578 ctxt->cur = cur;
10579 return(ret);
10580 }
10581
10582 /**
10583 * xmlXPathCompPathExpr:
10584 * @ctxt: the XPath Parser context
10585 *
10586 * [19] PathExpr ::= LocationPath
10587 * | FilterExpr
10588 * | FilterExpr '/' RelativeLocationPath
10589 * | FilterExpr '//' RelativeLocationPath
10590 *
10591 * Compile a path expression.
10592 * The / operator and // operators combine an arbitrary expression
10593 * and a relative location path. It is an error if the expression
10594 * does not evaluate to a node-set.
10595 * The / operator does composition in the same way as when / is
10596 * used in a location path. As in location paths, // is short for
10597 * /descendant-or-self::node()/.
10598 */
10599
10600 static void
10601 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10602 int lc = 1; /* Should we branch to LocationPath ? */
10603 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10604
10605 SKIP_BLANKS;
10606 if ((CUR == '$') || (CUR == '(') ||
10607 (IS_ASCII_DIGIT(CUR)) ||
10608 (CUR == '\'') || (CUR == '"') ||
10609 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10610 lc = 0;
10611 } else if (CUR == '*') {
10612 /* relative or absolute location path */
10613 lc = 1;
10614 } else if (CUR == '/') {
10615 /* relative or absolute location path */
10616 lc = 1;
10617 } else if (CUR == '@') {
10618 /* relative abbreviated attribute location path */
10619 lc = 1;
10620 } else if (CUR == '.') {
10621 /* relative abbreviated attribute location path */
10622 lc = 1;
10623 } else {
10624 /*
10625 * Problem is finding if we have a name here whether it's:
10626 * - a nodetype
10627 * - a function call in which case it's followed by '('
10628 * - an axis in which case it's followed by ':'
10629 * - a element name
10630 * We do an a priori analysis here rather than having to
10631 * maintain parsed token content through the recursive function
10632 * calls. This looks uglier but makes the code easier to
10633 * read/write/debug.
10634 */
10635 SKIP_BLANKS;
10636 name = xmlXPathScanName(ctxt);
10637 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10638 #ifdef DEBUG_STEP
10639 xmlGenericError(xmlGenericErrorContext,
10640 "PathExpr: Axis\n");
10641 #endif
10642 lc = 1;
10643 xmlFree(name);
10644 } else if (name != NULL) {
10645 int len =xmlStrlen(name);
10646
10647
10648 while (NXT(len) != 0) {
10649 if (NXT(len) == '/') {
10650 /* element name */
10651 #ifdef DEBUG_STEP
10652 xmlGenericError(xmlGenericErrorContext,
10653 "PathExpr: AbbrRelLocation\n");
10654 #endif
10655 lc = 1;
10656 break;
10657 } else if (IS_BLANK_CH(NXT(len))) {
10658 /* ignore blanks */
10659 ;
10660 } else if (NXT(len) == ':') {
10661 #ifdef DEBUG_STEP
10662 xmlGenericError(xmlGenericErrorContext,
10663 "PathExpr: AbbrRelLocation\n");
10664 #endif
10665 lc = 1;
10666 break;
10667 } else if ((NXT(len) == '(')) {
10668 /* Node Type or Function */
10669 if (xmlXPathIsNodeType(name)) {
10670 #ifdef DEBUG_STEP
10671 xmlGenericError(xmlGenericErrorContext,
10672 "PathExpr: Type search\n");
10673 #endif
10674 lc = 1;
10675 #ifdef LIBXML_XPTR_ENABLED
10676 } else if (ctxt->xptr &&
10677 xmlStrEqual(name, BAD_CAST "range-to")) {
10678 lc = 1;
10679 #endif
10680 } else {
10681 #ifdef DEBUG_STEP
10682 xmlGenericError(xmlGenericErrorContext,
10683 "PathExpr: function call\n");
10684 #endif
10685 lc = 0;
10686 }
10687 break;
10688 } else if ((NXT(len) == '[')) {
10689 /* element name */
10690 #ifdef DEBUG_STEP
10691 xmlGenericError(xmlGenericErrorContext,
10692 "PathExpr: AbbrRelLocation\n");
10693 #endif
10694 lc = 1;
10695 break;
10696 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10697 (NXT(len) == '=')) {
10698 lc = 1;
10699 break;
10700 } else {
10701 lc = 1;
10702 break;
10703 }
10704 len++;
10705 }
10706 if (NXT(len) == 0) {
10707 #ifdef DEBUG_STEP
10708 xmlGenericError(xmlGenericErrorContext,
10709 "PathExpr: AbbrRelLocation\n");
10710 #endif
10711 /* element name */
10712 lc = 1;
10713 }
10714 xmlFree(name);
10715 } else {
10716 /* make sure all cases are covered explicitly */
10717 XP_ERROR(XPATH_EXPR_ERROR);
10718 }
10719 }
10720
10721 if (lc) {
10722 if (CUR == '/') {
10723 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10724 } else {
10725 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10726 }
10727 xmlXPathCompLocationPath(ctxt);
10728 } else {
10729 xmlXPathCompFilterExpr(ctxt);
10730 CHECK_ERROR;
10731 if ((CUR == '/') && (NXT(1) == '/')) {
10732 SKIP(2);
10733 SKIP_BLANKS;
10734
10735 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10736 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10737 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10738
10739 xmlXPathCompRelativeLocationPath(ctxt);
10740 } else if (CUR == '/') {
10741 xmlXPathCompRelativeLocationPath(ctxt);
10742 }
10743 }
10744 SKIP_BLANKS;
10745 }
10746
10747 /**
10748 * xmlXPathCompUnionExpr:
10749 * @ctxt: the XPath Parser context
10750 *
10751 * [18] UnionExpr ::= PathExpr
10752 * | UnionExpr '|' PathExpr
10753 *
10754 * Compile an union expression.
10755 */
10756
10757 static void
10758 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10759 xmlXPathCompPathExpr(ctxt);
10760 CHECK_ERROR;
10761 SKIP_BLANKS;
10762 while (CUR == '|') {
10763 int op1 = ctxt->comp->last;
10764 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10765
10766 NEXT;
10767 SKIP_BLANKS;
10768 xmlXPathCompPathExpr(ctxt);
10769
10770 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10771
10772 SKIP_BLANKS;
10773 }
10774 }
10775
10776 /**
10777 * xmlXPathCompUnaryExpr:
10778 * @ctxt: the XPath Parser context
10779 *
10780 * [27] UnaryExpr ::= UnionExpr
10781 * | '-' UnaryExpr
10782 *
10783 * Compile an unary expression.
10784 */
10785
10786 static void
10787 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10788 int minus = 0;
10789 int found = 0;
10790
10791 SKIP_BLANKS;
10792 while (CUR == '-') {
10793 minus = 1 - minus;
10794 found = 1;
10795 NEXT;
10796 SKIP_BLANKS;
10797 }
10798
10799 xmlXPathCompUnionExpr(ctxt);
10800 CHECK_ERROR;
10801 if (found) {
10802 if (minus)
10803 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10804 else
10805 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10806 }
10807 }
10808
10809 /**
10810 * xmlXPathCompMultiplicativeExpr:
10811 * @ctxt: the XPath Parser context
10812 *
10813 * [26] MultiplicativeExpr ::= UnaryExpr
10814 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10815 * | MultiplicativeExpr 'div' UnaryExpr
10816 * | MultiplicativeExpr 'mod' UnaryExpr
10817 * [34] MultiplyOperator ::= '*'
10818 *
10819 * Compile an Additive expression.
10820 */
10821
10822 static void
10823 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10824 xmlXPathCompUnaryExpr(ctxt);
10825 CHECK_ERROR;
10826 SKIP_BLANKS;
10827 while ((CUR == '*') ||
10828 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10829 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10830 int op = -1;
10831 int op1 = ctxt->comp->last;
10832
10833 if (CUR == '*') {
10834 op = 0;
10835 NEXT;
10836 } else if (CUR == 'd') {
10837 op = 1;
10838 SKIP(3);
10839 } else if (CUR == 'm') {
10840 op = 2;
10841 SKIP(3);
10842 }
10843 SKIP_BLANKS;
10844 xmlXPathCompUnaryExpr(ctxt);
10845 CHECK_ERROR;
10846 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10847 SKIP_BLANKS;
10848 }
10849 }
10850
10851 /**
10852 * xmlXPathCompAdditiveExpr:
10853 * @ctxt: the XPath Parser context
10854 *
10855 * [25] AdditiveExpr ::= MultiplicativeExpr
10856 * | AdditiveExpr '+' MultiplicativeExpr
10857 * | AdditiveExpr '-' MultiplicativeExpr
10858 *
10859 * Compile an Additive expression.
10860 */
10861
10862 static void
10863 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10864
10865 xmlXPathCompMultiplicativeExpr(ctxt);
10866 CHECK_ERROR;
10867 SKIP_BLANKS;
10868 while ((CUR == '+') || (CUR == '-')) {
10869 int plus;
10870 int op1 = ctxt->comp->last;
10871
10872 if (CUR == '+') plus = 1;
10873 else plus = 0;
10874 NEXT;
10875 SKIP_BLANKS;
10876 xmlXPathCompMultiplicativeExpr(ctxt);
10877 CHECK_ERROR;
10878 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10879 SKIP_BLANKS;
10880 }
10881 }
10882
10883 /**
10884 * xmlXPathCompRelationalExpr:
10885 * @ctxt: the XPath Parser context
10886 *
10887 * [24] RelationalExpr ::= AdditiveExpr
10888 * | RelationalExpr '<' AdditiveExpr
10889 * | RelationalExpr '>' AdditiveExpr
10890 * | RelationalExpr '<=' AdditiveExpr
10891 * | RelationalExpr '>=' AdditiveExpr
10892 *
10893 * A <= B > C is allowed ? Answer from James, yes with
10894 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10895 * which is basically what got implemented.
10896 *
10897 * Compile a Relational expression, then push the result
10898 * on the stack
10899 */
10900
10901 static void
10902 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10903 xmlXPathCompAdditiveExpr(ctxt);
10904 CHECK_ERROR;
10905 SKIP_BLANKS;
10906 while ((CUR == '<') ||
10907 (CUR == '>') ||
10908 ((CUR == '<') && (NXT(1) == '=')) ||
10909 ((CUR == '>') && (NXT(1) == '='))) {
10910 int inf, strict;
10911 int op1 = ctxt->comp->last;
10912
10913 if (CUR == '<') inf = 1;
10914 else inf = 0;
10915 if (NXT(1) == '=') strict = 0;
10916 else strict = 1;
10917 NEXT;
10918 if (!strict) NEXT;
10919 SKIP_BLANKS;
10920 xmlXPathCompAdditiveExpr(ctxt);
10921 CHECK_ERROR;
10922 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10923 SKIP_BLANKS;
10924 }
10925 }
10926
10927 /**
10928 * xmlXPathCompEqualityExpr:
10929 * @ctxt: the XPath Parser context
10930 *
10931 * [23] EqualityExpr ::= RelationalExpr
10932 * | EqualityExpr '=' RelationalExpr
10933 * | EqualityExpr '!=' RelationalExpr
10934 *
10935 * A != B != C is allowed ? Answer from James, yes with
10936 * (RelationalExpr = RelationalExpr) = RelationalExpr
10937 * (RelationalExpr != RelationalExpr) != RelationalExpr
10938 * which is basically what got implemented.
10939 *
10940 * Compile an Equality expression.
10941 *
10942 */
10943 static void
10944 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10945 xmlXPathCompRelationalExpr(ctxt);
10946 CHECK_ERROR;
10947 SKIP_BLANKS;
10948 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10949 int eq;
10950 int op1 = ctxt->comp->last;
10951
10952 if (CUR == '=') eq = 1;
10953 else eq = 0;
10954 NEXT;
10955 if (!eq) NEXT;
10956 SKIP_BLANKS;
10957 xmlXPathCompRelationalExpr(ctxt);
10958 CHECK_ERROR;
10959 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10960 SKIP_BLANKS;
10961 }
10962 }
10963
10964 /**
10965 * xmlXPathCompAndExpr:
10966 * @ctxt: the XPath Parser context
10967 *
10968 * [22] AndExpr ::= EqualityExpr
10969 * | AndExpr 'and' EqualityExpr
10970 *
10971 * Compile an AND expression.
10972 *
10973 */
10974 static void
10975 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10976 xmlXPathCompEqualityExpr(ctxt);
10977 CHECK_ERROR;
10978 SKIP_BLANKS;
10979 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10980 int op1 = ctxt->comp->last;
10981 SKIP(3);
10982 SKIP_BLANKS;
10983 xmlXPathCompEqualityExpr(ctxt);
10984 CHECK_ERROR;
10985 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10986 SKIP_BLANKS;
10987 }
10988 }
10989
10990 /**
10991 * xmlXPathCompileExpr:
10992 * @ctxt: the XPath Parser context
10993 *
10994 * [14] Expr ::= OrExpr
10995 * [21] OrExpr ::= AndExpr
10996 * | OrExpr 'or' AndExpr
10997 *
10998 * Parse and compile an expression
10999 */
11000 static void
11001 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
11002 xmlXPathCompAndExpr(ctxt);
11003 CHECK_ERROR;
11004 SKIP_BLANKS;
11005 while ((CUR == 'o') && (NXT(1) == 'r')) {
11006 int op1 = ctxt->comp->last;
11007 SKIP(2);
11008 SKIP_BLANKS;
11009 xmlXPathCompAndExpr(ctxt);
11010 CHECK_ERROR;
11011 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
11012 SKIP_BLANKS;
11013 }
11014 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
11015 /* more ops could be optimized too */
11016 /*
11017 * This is the main place to eliminate sorting for
11018 * operations which don't require a sorted node-set.
11019 * E.g. count().
11020 */
11021 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
11022 }
11023 }
11024
11025 /**
11026 * xmlXPathCompPredicate:
11027 * @ctxt: the XPath Parser context
11028 * @filter: act as a filter
11029 *
11030 * [8] Predicate ::= '[' PredicateExpr ']'
11031 * [9] PredicateExpr ::= Expr
11032 *
11033 * Compile a predicate expression
11034 */
11035 static void
11036 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
11037 int op1 = ctxt->comp->last;
11038
11039 SKIP_BLANKS;
11040 if (CUR != '[') {
11041 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11042 }
11043 NEXT;
11044 SKIP_BLANKS;
11045
11046 ctxt->comp->last = -1;
11047 /*
11048 * This call to xmlXPathCompileExpr() will deactivate sorting
11049 * of the predicate result.
11050 * TODO: Sorting is still activated for filters, since I'm not
11051 * sure if needed. Normally sorting should not be needed, since
11052 * a filter can only diminish the number of items in a sequence,
11053 * but won't change its order; so if the initial sequence is sorted,
11054 * subsequent sorting is not needed.
11055 */
11056 if (! filter)
11057 xmlXPathCompileExpr(ctxt, 0);
11058 else
11059 xmlXPathCompileExpr(ctxt, 1);
11060 CHECK_ERROR;
11061
11062 if (CUR != ']') {
11063 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11064 }
11065
11066 if (filter)
11067 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11068 else
11069 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11070
11071 NEXT;
11072 SKIP_BLANKS;
11073 }
11074
11075 /**
11076 * xmlXPathCompNodeTest:
11077 * @ctxt: the XPath Parser context
11078 * @test: pointer to a xmlXPathTestVal
11079 * @type: pointer to a xmlXPathTypeVal
11080 * @prefix: placeholder for a possible name prefix
11081 *
11082 * [7] NodeTest ::= NameTest
11083 * | NodeType '(' ')'
11084 * | 'processing-instruction' '(' Literal ')'
11085 *
11086 * [37] NameTest ::= '*'
11087 * | NCName ':' '*'
11088 * | QName
11089 * [38] NodeType ::= 'comment'
11090 * | 'text'
11091 * | 'processing-instruction'
11092 * | 'node'
11093 *
11094 * Returns the name found and updates @test, @type and @prefix appropriately
11095 */
11096 static xmlChar *
11097 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11098 xmlXPathTypeVal *type, const xmlChar **prefix,
11099 xmlChar *name) {
11100 int blanks;
11101
11102 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11103 STRANGE;
11104 return(NULL);
11105 }
11106 *type = (xmlXPathTypeVal) 0;
11107 *test = (xmlXPathTestVal) 0;
11108 *prefix = NULL;
11109 SKIP_BLANKS;
11110
11111 if ((name == NULL) && (CUR == '*')) {
11112 /*
11113 * All elements
11114 */
11115 NEXT;
11116 *test = NODE_TEST_ALL;
11117 return(NULL);
11118 }
11119
11120 if (name == NULL)
11121 name = xmlXPathParseNCName(ctxt);
11122 if (name == NULL) {
11123 XP_ERRORNULL(XPATH_EXPR_ERROR);
11124 }
11125
11126 blanks = IS_BLANK_CH(CUR);
11127 SKIP_BLANKS;
11128 if (CUR == '(') {
11129 NEXT;
11130 /*
11131 * NodeType or PI search
11132 */
11133 if (xmlStrEqual(name, BAD_CAST "comment"))
11134 *type = NODE_TYPE_COMMENT;
11135 else if (xmlStrEqual(name, BAD_CAST "node"))
11136 *type = NODE_TYPE_NODE;
11137 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11138 *type = NODE_TYPE_PI;
11139 else if (xmlStrEqual(name, BAD_CAST "text"))
11140 *type = NODE_TYPE_TEXT;
11141 else {
11142 if (name != NULL)
11143 xmlFree(name);
11144 XP_ERRORNULL(XPATH_EXPR_ERROR);
11145 }
11146
11147 *test = NODE_TEST_TYPE;
11148
11149 SKIP_BLANKS;
11150 if (*type == NODE_TYPE_PI) {
11151 /*
11152 * Specific case: search a PI by name.
11153 */
11154 if (name != NULL)
11155 xmlFree(name);
11156 name = NULL;
11157 if (CUR != ')') {
11158 name = xmlXPathParseLiteral(ctxt);
11159 CHECK_ERROR NULL;
11160 *test = NODE_TEST_PI;
11161 SKIP_BLANKS;
11162 }
11163 }
11164 if (CUR != ')') {
11165 if (name != NULL)
11166 xmlFree(name);
11167 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11168 }
11169 NEXT;
11170 return(name);
11171 }
11172 *test = NODE_TEST_NAME;
11173 if ((!blanks) && (CUR == ':')) {
11174 NEXT;
11175
11176 /*
11177 * Since currently the parser context don't have a
11178 * namespace list associated:
11179 * The namespace name for this prefix can be computed
11180 * only at evaluation time. The compilation is done
11181 * outside of any context.
11182 */
11183 #if 0
11184 *prefix = xmlXPathNsLookup(ctxt->context, name);
11185 if (name != NULL)
11186 xmlFree(name);
11187 if (*prefix == NULL) {
11188 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11189 }
11190 #else
11191 *prefix = name;
11192 #endif
11193
11194 if (CUR == '*') {
11195 /*
11196 * All elements
11197 */
11198 NEXT;
11199 *test = NODE_TEST_ALL;
11200 return(NULL);
11201 }
11202
11203 name = xmlXPathParseNCName(ctxt);
11204 if (name == NULL) {
11205 XP_ERRORNULL(XPATH_EXPR_ERROR);
11206 }
11207 }
11208 return(name);
11209 }
11210
11211 /**
11212 * xmlXPathIsAxisName:
11213 * @name: a preparsed name token
11214 *
11215 * [6] AxisName ::= 'ancestor'
11216 * | 'ancestor-or-self'
11217 * | 'attribute'
11218 * | 'child'
11219 * | 'descendant'
11220 * | 'descendant-or-self'
11221 * | 'following'
11222 * | 'following-sibling'
11223 * | 'namespace'
11224 * | 'parent'
11225 * | 'preceding'
11226 * | 'preceding-sibling'
11227 * | 'self'
11228 *
11229 * Returns the axis or 0
11230 */
11231 static xmlXPathAxisVal
11232 xmlXPathIsAxisName(const xmlChar *name) {
11233 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11234 switch (name[0]) {
11235 case 'a':
11236 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11237 ret = AXIS_ANCESTOR;
11238 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11239 ret = AXIS_ANCESTOR_OR_SELF;
11240 if (xmlStrEqual(name, BAD_CAST "attribute"))
11241 ret = AXIS_ATTRIBUTE;
11242 break;
11243 case 'c':
11244 if (xmlStrEqual(name, BAD_CAST "child"))
11245 ret = AXIS_CHILD;
11246 break;
11247 case 'd':
11248 if (xmlStrEqual(name, BAD_CAST "descendant"))
11249 ret = AXIS_DESCENDANT;
11250 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11251 ret = AXIS_DESCENDANT_OR_SELF;
11252 break;
11253 case 'f':
11254 if (xmlStrEqual(name, BAD_CAST "following"))
11255 ret = AXIS_FOLLOWING;
11256 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11257 ret = AXIS_FOLLOWING_SIBLING;
11258 break;
11259 case 'n':
11260 if (xmlStrEqual(name, BAD_CAST "namespace"))
11261 ret = AXIS_NAMESPACE;
11262 break;
11263 case 'p':
11264 if (xmlStrEqual(name, BAD_CAST "parent"))
11265 ret = AXIS_PARENT;
11266 if (xmlStrEqual(name, BAD_CAST "preceding"))
11267 ret = AXIS_PRECEDING;
11268 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11269 ret = AXIS_PRECEDING_SIBLING;
11270 break;
11271 case 's':
11272 if (xmlStrEqual(name, BAD_CAST "self"))
11273 ret = AXIS_SELF;
11274 break;
11275 }
11276 return(ret);
11277 }
11278
11279 /**
11280 * xmlXPathCompStep:
11281 * @ctxt: the XPath Parser context
11282 *
11283 * [4] Step ::= AxisSpecifier NodeTest Predicate*
11284 * | AbbreviatedStep
11285 *
11286 * [12] AbbreviatedStep ::= '.' | '..'
11287 *
11288 * [5] AxisSpecifier ::= AxisName '::'
11289 * | AbbreviatedAxisSpecifier
11290 *
11291 * [13] AbbreviatedAxisSpecifier ::= '@'?
11292 *
11293 * Modified for XPtr range support as:
11294 *
11295 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11296 * | AbbreviatedStep
11297 * | 'range-to' '(' Expr ')' Predicate*
11298 *
11299 * Compile one step in a Location Path
11300 * A location step of . is short for self::node(). This is
11301 * particularly useful in conjunction with //. For example, the
11302 * location path .//para is short for
11303 * self::node()/descendant-or-self::node()/child::para
11304 * and so will select all para descendant elements of the context
11305 * node.
11306 * Similarly, a location step of .. is short for parent::node().
11307 * For example, ../title is short for parent::node()/child::title
11308 * and so will select the title children of the parent of the context
11309 * node.
11310 */
11311 static void
11312 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11313 #ifdef LIBXML_XPTR_ENABLED
11314 int rangeto = 0;
11315 int op2 = -1;
11316 #endif
11317
11318 SKIP_BLANKS;
11319 if ((CUR == '.') && (NXT(1) == '.')) {
11320 SKIP(2);
11321 SKIP_BLANKS;
11322 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11323 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11324 } else if (CUR == '.') {
11325 NEXT;
11326 SKIP_BLANKS;
11327 } else {
11328 xmlChar *name = NULL;
11329 const xmlChar *prefix = NULL;
11330 xmlXPathTestVal test = (xmlXPathTestVal) 0;
11331 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11332 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11333 int op1;
11334
11335 /*
11336 * The modification needed for XPointer change to the production
11337 */
11338 #ifdef LIBXML_XPTR_ENABLED
11339 if (ctxt->xptr) {
11340 name = xmlXPathParseNCName(ctxt);
11341 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11342 op2 = ctxt->comp->last;
11343 xmlFree(name);
11344 SKIP_BLANKS;
11345 if (CUR != '(') {
11346 XP_ERROR(XPATH_EXPR_ERROR);
11347 }
11348 NEXT;
11349 SKIP_BLANKS;
11350
11351 xmlXPathCompileExpr(ctxt, 1);
11352 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11353 CHECK_ERROR;
11354
11355 SKIP_BLANKS;
11356 if (CUR != ')') {
11357 XP_ERROR(XPATH_EXPR_ERROR);
11358 }
11359 NEXT;
11360 rangeto = 1;
11361 goto eval_predicates;
11362 }
11363 }
11364 #endif
11365 if (CUR == '*') {
11366 axis = AXIS_CHILD;
11367 } else {
11368 if (name == NULL)
11369 name = xmlXPathParseNCName(ctxt);
11370 if (name != NULL) {
11371 axis = xmlXPathIsAxisName(name);
11372 if (axis != 0) {
11373 SKIP_BLANKS;
11374 if ((CUR == ':') && (NXT(1) == ':')) {
11375 SKIP(2);
11376 xmlFree(name);
11377 name = NULL;
11378 } else {
11379 /* an element name can conflict with an axis one :-\ */
11380 axis = AXIS_CHILD;
11381 }
11382 } else {
11383 axis = AXIS_CHILD;
11384 }
11385 } else if (CUR == '@') {
11386 NEXT;
11387 axis = AXIS_ATTRIBUTE;
11388 } else {
11389 axis = AXIS_CHILD;
11390 }
11391 }
11392
11393 if (ctxt->error != XPATH_EXPRESSION_OK) {
11394 xmlFree(name);
11395 return;
11396 }
11397
11398 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11399 if (test == 0)
11400 return;
11401
11402 if ((prefix != NULL) && (ctxt->context != NULL) &&
11403 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11404 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11405 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11406 }
11407 }
11408 #ifdef DEBUG_STEP
11409 xmlGenericError(xmlGenericErrorContext,
11410 "Basis : computing new set\n");
11411 #endif
11412
11413 #ifdef DEBUG_STEP
11414 xmlGenericError(xmlGenericErrorContext, "Basis : ");
11415 if (ctxt->value == NULL)
11416 xmlGenericError(xmlGenericErrorContext, "no value\n");
11417 else if (ctxt->value->nodesetval == NULL)
11418 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11419 else
11420 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11421 #endif
11422
11423 #ifdef LIBXML_XPTR_ENABLED
11424 eval_predicates:
11425 #endif
11426 op1 = ctxt->comp->last;
11427 ctxt->comp->last = -1;
11428
11429 SKIP_BLANKS;
11430 while (CUR == '[') {
11431 xmlXPathCompPredicate(ctxt, 0);
11432 }
11433
11434 #ifdef LIBXML_XPTR_ENABLED
11435 if (rangeto) {
11436 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11437 } else
11438 #endif
11439 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11440 test, type, (void *)prefix, (void *)name);
11441
11442 }
11443 #ifdef DEBUG_STEP
11444 xmlGenericError(xmlGenericErrorContext, "Step : ");
11445 if (ctxt->value == NULL)
11446 xmlGenericError(xmlGenericErrorContext, "no value\n");
11447 else if (ctxt->value->nodesetval == NULL)
11448 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11449 else
11450 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11451 ctxt->value->nodesetval);
11452 #endif
11453 }
11454
11455 /**
11456 * xmlXPathCompRelativeLocationPath:
11457 * @ctxt: the XPath Parser context
11458 *
11459 * [3] RelativeLocationPath ::= Step
11460 * | RelativeLocationPath '/' Step
11461 * | AbbreviatedRelativeLocationPath
11462 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
11463 *
11464 * Compile a relative location path.
11465 */
11466 static void
11467 xmlXPathCompRelativeLocationPath
11468 (xmlXPathParserContextPtr ctxt) {
11469 SKIP_BLANKS;
11470 if ((CUR == '/') && (NXT(1) == '/')) {
11471 SKIP(2);
11472 SKIP_BLANKS;
11473 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11474 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11475 } else if (CUR == '/') {
11476 NEXT;
11477 SKIP_BLANKS;
11478 }
11479 xmlXPathCompStep(ctxt);
11480 CHECK_ERROR;
11481 SKIP_BLANKS;
11482 while (CUR == '/') {
11483 if ((CUR == '/') && (NXT(1) == '/')) {
11484 SKIP(2);
11485 SKIP_BLANKS;
11486 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11487 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11488 xmlXPathCompStep(ctxt);
11489 } else if (CUR == '/') {
11490 NEXT;
11491 SKIP_BLANKS;
11492 xmlXPathCompStep(ctxt);
11493 }
11494 SKIP_BLANKS;
11495 }
11496 }
11497
11498 /**
11499 * xmlXPathCompLocationPath:
11500 * @ctxt: the XPath Parser context
11501 *
11502 * [1] LocationPath ::= RelativeLocationPath
11503 * | AbsoluteLocationPath
11504 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
11505 * | AbbreviatedAbsoluteLocationPath
11506 * [10] AbbreviatedAbsoluteLocationPath ::=
11507 * '//' RelativeLocationPath
11508 *
11509 * Compile a location path
11510 *
11511 * // is short for /descendant-or-self::node()/. For example,
11512 * //para is short for /descendant-or-self::node()/child::para and
11513 * so will select any para element in the document (even a para element
11514 * that is a document element will be selected by //para since the
11515 * document element node is a child of the root node); div//para is
11516 * short for div/descendant-or-self::node()/child::para and so will
11517 * select all para descendants of div children.
11518 */
11519 static void
11520 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11521 SKIP_BLANKS;
11522 if (CUR != '/') {
11523 xmlXPathCompRelativeLocationPath(ctxt);
11524 } else {
11525 while (CUR == '/') {
11526 if ((CUR == '/') && (NXT(1) == '/')) {
11527 SKIP(2);
11528 SKIP_BLANKS;
11529 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11530 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11531 xmlXPathCompRelativeLocationPath(ctxt);
11532 } else if (CUR == '/') {
11533 NEXT;
11534 SKIP_BLANKS;
11535 if ((CUR != 0 ) &&
11536 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11537 (CUR == '@') || (CUR == '*')))
11538 xmlXPathCompRelativeLocationPath(ctxt);
11539 }
11540 CHECK_ERROR;
11541 }
11542 }
11543 }
11544
11545 /************************************************************************
11546 * *
11547 * XPath precompiled expression evaluation *
11548 * *
11549 ************************************************************************/
11550
11551 static int
11552 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11553
11554 #ifdef DEBUG_STEP
11555 static void
11556 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11557 int nbNodes)
11558 {
11559 xmlGenericError(xmlGenericErrorContext, "new step : ");
11560 switch (op->value) {
11561 case AXIS_ANCESTOR:
11562 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11563 break;
11564 case AXIS_ANCESTOR_OR_SELF:
11565 xmlGenericError(xmlGenericErrorContext,
11566 "axis 'ancestors-or-self' ");
11567 break;
11568 case AXIS_ATTRIBUTE:
11569 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11570 break;
11571 case AXIS_CHILD:
11572 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11573 break;
11574 case AXIS_DESCENDANT:
11575 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11576 break;
11577 case AXIS_DESCENDANT_OR_SELF:
11578 xmlGenericError(xmlGenericErrorContext,
11579 "axis 'descendant-or-self' ");
11580 break;
11581 case AXIS_FOLLOWING:
11582 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11583 break;
11584 case AXIS_FOLLOWING_SIBLING:
11585 xmlGenericError(xmlGenericErrorContext,
11586 "axis 'following-siblings' ");
11587 break;
11588 case AXIS_NAMESPACE:
11589 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11590 break;
11591 case AXIS_PARENT:
11592 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11593 break;
11594 case AXIS_PRECEDING:
11595 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11596 break;
11597 case AXIS_PRECEDING_SIBLING:
11598 xmlGenericError(xmlGenericErrorContext,
11599 "axis 'preceding-sibling' ");
11600 break;
11601 case AXIS_SELF:
11602 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11603 break;
11604 }
11605 xmlGenericError(xmlGenericErrorContext,
11606 " context contains %d nodes\n", nbNodes);
11607 switch (op->value2) {
11608 case NODE_TEST_NONE:
11609 xmlGenericError(xmlGenericErrorContext,
11610 " searching for none !!!\n");
11611 break;
11612 case NODE_TEST_TYPE:
11613 xmlGenericError(xmlGenericErrorContext,
11614 " searching for type %d\n", op->value3);
11615 break;
11616 case NODE_TEST_PI:
11617 xmlGenericError(xmlGenericErrorContext,
11618 " searching for PI !!!\n");
11619 break;
11620 case NODE_TEST_ALL:
11621 xmlGenericError(xmlGenericErrorContext,
11622 " searching for *\n");
11623 break;
11624 case NODE_TEST_NS:
11625 xmlGenericError(xmlGenericErrorContext,
11626 " searching for namespace %s\n",
11627 op->value5);
11628 break;
11629 case NODE_TEST_NAME:
11630 xmlGenericError(xmlGenericErrorContext,
11631 " searching for name %s\n", op->value5);
11632 if (op->value4)
11633 xmlGenericError(xmlGenericErrorContext,
11634 " with namespace %s\n", op->value4);
11635 break;
11636 }
11637 xmlGenericError(xmlGenericErrorContext, "Testing : ");
11638 }
11639 #endif /* DEBUG_STEP */
11640
11641 static int
11642 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11643 xmlXPathStepOpPtr op,
11644 xmlNodeSetPtr set,
11645 int contextSize,
11646 int hasNsNodes)
11647 {
11648 if (op->ch1 != -1) {
11649 xmlXPathCompExprPtr comp = ctxt->comp;
11650 /*
11651 * Process inner predicates first.
11652 */
11653 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11654 /*
11655 * TODO: raise an internal error.
11656 */
11657 }
11658 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11659 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11660 CHECK_ERROR0;
11661 if (contextSize <= 0)
11662 return(0);
11663 }
11664 if (op->ch2 != -1) {
11665 xmlXPathContextPtr xpctxt = ctxt->context;
11666 xmlNodePtr contextNode, oldContextNode;
11667 xmlDocPtr oldContextDoc;
11668 int i, res, contextPos = 0, newContextSize;
11669 xmlXPathStepOpPtr exprOp;
11670 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11671
11672 #ifdef LIBXML_XPTR_ENABLED
11673 /*
11674 * URGENT TODO: Check the following:
11675 * We don't expect location sets if evaluating prediates, right?
11676 * Only filters should expect location sets, right?
11677 */
11678 #endif
11679 /*
11680 * SPEC XPath 1.0:
11681 * "For each node in the node-set to be filtered, the
11682 * PredicateExpr is evaluated with that node as the
11683 * context node, with the number of nodes in the
11684 * node-set as the context size, and with the proximity
11685 * position of the node in the node-set with respect to
11686 * the axis as the context position;"
11687 * @oldset is the node-set" to be filtered.
11688 *
11689 * SPEC XPath 1.0:
11690 * "only predicates change the context position and
11691 * context size (see [2.4 Predicates])."
11692 * Example:
11693 * node-set context pos
11694 * nA 1
11695 * nB 2
11696 * nC 3
11697 * After applying predicate [position() > 1] :
11698 * node-set context pos
11699 * nB 1
11700 * nC 2
11701 */
11702 oldContextNode = xpctxt->node;
11703 oldContextDoc = xpctxt->doc;
11704 /*
11705 * Get the expression of this predicate.
11706 */
11707 exprOp = &ctxt->comp->steps[op->ch2];
11708 newContextSize = 0;
11709 for (i = 0; i < set->nodeNr; i++) {
11710 if (set->nodeTab[i] == NULL)
11711 continue;
11712
11713 contextNode = set->nodeTab[i];
11714 xpctxt->node = contextNode;
11715 xpctxt->contextSize = contextSize;
11716 xpctxt->proximityPosition = ++contextPos;
11717
11718 /*
11719 * Also set the xpath document in case things like
11720 * key() are evaluated in the predicate.
11721 */
11722 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11723 (contextNode->doc != NULL))
11724 xpctxt->doc = contextNode->doc;
11725 /*
11726 * Evaluate the predicate expression with 1 context node
11727 * at a time; this node is packaged into a node set; this
11728 * node set is handed over to the evaluation mechanism.
11729 */
11730 if (contextObj == NULL)
11731 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11732 else {
11733 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11734 contextNode) < 0) {
11735 ctxt->error = XPATH_MEMORY_ERROR;
11736 goto evaluation_exit;
11737 }
11738 }
11739
11740 valuePush(ctxt, contextObj);
11741
11742 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11743
11744 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11745 xmlXPathNodeSetClear(set, hasNsNodes);
11746 newContextSize = 0;
11747 goto evaluation_exit;
11748 }
11749
11750 if (res != 0) {
11751 newContextSize++;
11752 } else {
11753 /*
11754 * Remove the entry from the initial node set.
11755 */
11756 set->nodeTab[i] = NULL;
11757 if (contextNode->type == XML_NAMESPACE_DECL)
11758 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11759 }
11760 if (ctxt->value == contextObj) {
11761 /*
11762 * Don't free the temporary XPath object holding the
11763 * context node, in order to avoid massive recreation
11764 * inside this loop.
11765 */
11766 valuePop(ctxt);
11767 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11768 } else {
11769 /*
11770 * TODO: The object was lost in the evaluation machinery.
11771 * Can this happen? Maybe in internal-error cases.
11772 */
11773 contextObj = NULL;
11774 }
11775 }
11776
11777 if (contextObj != NULL) {
11778 if (ctxt->value == contextObj)
11779 valuePop(ctxt);
11780 xmlXPathReleaseObject(xpctxt, contextObj);
11781 }
11782 evaluation_exit:
11783 if (exprRes != NULL)
11784 xmlXPathReleaseObject(ctxt->context, exprRes);
11785 /*
11786 * Reset/invalidate the context.
11787 */
11788 xpctxt->node = oldContextNode;
11789 xpctxt->doc = oldContextDoc;
11790 xpctxt->contextSize = -1;
11791 xpctxt->proximityPosition = -1;
11792 return(newContextSize);
11793 }
11794 return(contextSize);
11795 }
11796
11797 static int
11798 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11799 xmlXPathStepOpPtr op,
11800 xmlNodeSetPtr set,
11801 int contextSize,
11802 int minPos,
11803 int maxPos,
11804 int hasNsNodes)
11805 {
11806 if (op->ch1 != -1) {
11807 xmlXPathCompExprPtr comp = ctxt->comp;
11808 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11809 /*
11810 * TODO: raise an internal error.
11811 */
11812 }
11813 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11814 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11815 CHECK_ERROR0;
11816 if (contextSize <= 0)
11817 return(0);
11818 }
11819 /*
11820 * Check if the node set contains a sufficient number of nodes for
11821 * the requested range.
11822 */
11823 if (contextSize < minPos) {
11824 xmlXPathNodeSetClear(set, hasNsNodes);
11825 return(0);
11826 }
11827 if (op->ch2 == -1) {
11828 /*
11829 * TODO: Can this ever happen?
11830 */
11831 return (contextSize);
11832 } else {
11833 xmlDocPtr oldContextDoc;
11834 int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11835 xmlXPathStepOpPtr exprOp;
11836 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11837 xmlNodePtr oldContextNode, contextNode = NULL;
11838 xmlXPathContextPtr xpctxt = ctxt->context;
11839 int frame;
11840
11841 #ifdef LIBXML_XPTR_ENABLED
11842 /*
11843 * URGENT TODO: Check the following:
11844 * We don't expect location sets if evaluating prediates, right?
11845 * Only filters should expect location sets, right?
11846 */
11847 #endif /* LIBXML_XPTR_ENABLED */
11848
11849 /*
11850 * Save old context.
11851 */
11852 oldContextNode = xpctxt->node;
11853 oldContextDoc = xpctxt->doc;
11854 /*
11855 * Get the expression of this predicate.
11856 */
11857 exprOp = &ctxt->comp->steps[op->ch2];
11858 for (i = 0; i < set->nodeNr; i++) {
11859 xmlXPathObjectPtr tmp;
11860
11861 if (set->nodeTab[i] == NULL)
11862 continue;
11863
11864 contextNode = set->nodeTab[i];
11865 xpctxt->node = contextNode;
11866 xpctxt->contextSize = contextSize;
11867 xpctxt->proximityPosition = ++contextPos;
11868
11869 /*
11870 * Initialize the new set.
11871 * Also set the xpath document in case things like
11872 * key() evaluation are attempted on the predicate
11873 */
11874 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11875 (contextNode->doc != NULL))
11876 xpctxt->doc = contextNode->doc;
11877 /*
11878 * Evaluate the predicate expression with 1 context node
11879 * at a time; this node is packaged into a node set; this
11880 * node set is handed over to the evaluation mechanism.
11881 */
11882 if (contextObj == NULL)
11883 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11884 else {
11885 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11886 contextNode) < 0) {
11887 ctxt->error = XPATH_MEMORY_ERROR;
11888 goto evaluation_exit;
11889 }
11890 }
11891
11892 valuePush(ctxt, contextObj);
11893 frame = xmlXPathSetFrame(ctxt);
11894 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11895 xmlXPathPopFrame(ctxt, frame);
11896 tmp = valuePop(ctxt);
11897
11898 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11899 while (tmp != contextObj) {
11900 /*
11901 * Free up the result
11902 * then pop off contextObj, which will be freed later
11903 */
11904 xmlXPathReleaseObject(xpctxt, tmp);
11905 tmp = valuePop(ctxt);
11906 }
11907 goto evaluation_error;
11908 }
11909 /* push the result back onto the stack */
11910 valuePush(ctxt, tmp);
11911
11912 if (res)
11913 pos++;
11914
11915 if (res && (pos >= minPos) && (pos <= maxPos)) {
11916 /*
11917 * Fits in the requested range.
11918 */
11919 newContextSize++;
11920 if (minPos == maxPos) {
11921 /*
11922 * Only 1 node was requested.
11923 */
11924 if (contextNode->type == XML_NAMESPACE_DECL) {
11925 /*
11926 * As always: take care of those nasty
11927 * namespace nodes.
11928 */
11929 set->nodeTab[i] = NULL;
11930 }
11931 xmlXPathNodeSetClear(set, hasNsNodes);
11932 set->nodeNr = 1;
11933 set->nodeTab[0] = contextNode;
11934 goto evaluation_exit;
11935 }
11936 if (pos == maxPos) {
11937 /*
11938 * We are done.
11939 */
11940 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11941 goto evaluation_exit;
11942 }
11943 } else {
11944 /*
11945 * Remove the entry from the initial node set.
11946 */
11947 set->nodeTab[i] = NULL;
11948 if (contextNode->type == XML_NAMESPACE_DECL)
11949 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11950 }
11951 if (exprRes != NULL) {
11952 xmlXPathReleaseObject(ctxt->context, exprRes);
11953 exprRes = NULL;
11954 }
11955 if (ctxt->value == contextObj) {
11956 /*
11957 * Don't free the temporary XPath object holding the
11958 * context node, in order to avoid massive recreation
11959 * inside this loop.
11960 */
11961 valuePop(ctxt);
11962 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11963 } else {
11964 /*
11965 * The object was lost in the evaluation machinery.
11966 * Can this happen? Maybe in case of internal-errors.
11967 */
11968 contextObj = NULL;
11969 }
11970 }
11971 goto evaluation_exit;
11972
11973 evaluation_error:
11974 xmlXPathNodeSetClear(set, hasNsNodes);
11975 newContextSize = 0;
11976
11977 evaluation_exit:
11978 if (contextObj != NULL) {
11979 if (ctxt->value == contextObj)
11980 valuePop(ctxt);
11981 xmlXPathReleaseObject(xpctxt, contextObj);
11982 }
11983 if (exprRes != NULL)
11984 xmlXPathReleaseObject(ctxt->context, exprRes);
11985 /*
11986 * Reset/invalidate the context.
11987 */
11988 xpctxt->node = oldContextNode;
11989 xpctxt->doc = oldContextDoc;
11990 xpctxt->contextSize = -1;
11991 xpctxt->proximityPosition = -1;
11992 return(newContextSize);
11993 }
11994 return(contextSize);
11995 }
11996
11997 static int
11998 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11999 xmlXPathStepOpPtr op,
12000 int *maxPos)
12001 {
12002
12003 xmlXPathStepOpPtr exprOp;
12004
12005 /*
12006 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
12007 */
12008
12009 /*
12010 * If not -1, then ch1 will point to:
12011 * 1) For predicates (XPATH_OP_PREDICATE):
12012 * - an inner predicate operator
12013 * 2) For filters (XPATH_OP_FILTER):
12014 * - an inner filter operater OR
12015 * - an expression selecting the node set.
12016 * E.g. "key('a', 'b')" or "(//foo | //bar)".
12017 */
12018 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
12019 return(0);
12020
12021 if (op->ch2 != -1) {
12022 exprOp = &ctxt->comp->steps[op->ch2];
12023 } else
12024 return(0);
12025
12026 if ((exprOp != NULL) &&
12027 (exprOp->op == XPATH_OP_VALUE) &&
12028 (exprOp->value4 != NULL) &&
12029 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
12030 {
12031 double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
12032
12033 /*
12034 * We have a "[n]" predicate here.
12035 * TODO: Unfortunately this simplistic test here is not
12036 * able to detect a position() predicate in compound
12037 * expressions like "[@attr = 'a" and position() = 1],
12038 * and even not the usage of position() in
12039 * "[position() = 1]"; thus - obviously - a position-range,
12040 * like it "[position() < 5]", is also not detected.
12041 * Maybe we could rewrite the AST to ease the optimization.
12042 */
12043
12044 if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
12045 *maxPos = (int) floatval;
12046 if (floatval == (double) *maxPos)
12047 return(1);
12048 }
12049 }
12050 return(0);
12051 }
12052
12053 static int
12054 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
12055 xmlXPathStepOpPtr op,
12056 xmlNodePtr * first, xmlNodePtr * last,
12057 int toBool)
12058 {
12059
12060 #define XP_TEST_HIT \
12061 if (hasAxisRange != 0) { \
12062 if (++pos == maxPos) { \
12063 if (addNode(seq, cur) < 0) \
12064 ctxt->error = XPATH_MEMORY_ERROR; \
12065 goto axis_range_end; } \
12066 } else { \
12067 if (addNode(seq, cur) < 0) \
12068 ctxt->error = XPATH_MEMORY_ERROR; \
12069 if (breakOnFirstHit) goto first_hit; }
12070
12071 #define XP_TEST_HIT_NS \
12072 if (hasAxisRange != 0) { \
12073 if (++pos == maxPos) { \
12074 hasNsNodes = 1; \
12075 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12076 ctxt->error = XPATH_MEMORY_ERROR; \
12077 goto axis_range_end; } \
12078 } else { \
12079 hasNsNodes = 1; \
12080 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12081 ctxt->error = XPATH_MEMORY_ERROR; \
12082 if (breakOnFirstHit) goto first_hit; }
12083
12084 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
12085 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12086 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12087 const xmlChar *prefix = op->value4;
12088 const xmlChar *name = op->value5;
12089 const xmlChar *URI = NULL;
12090
12091 #ifdef DEBUG_STEP
12092 int nbMatches = 0, prevMatches = 0;
12093 #endif
12094 int total = 0, hasNsNodes = 0;
12095 /* The popped object holding the context nodes */
12096 xmlXPathObjectPtr obj;
12097 /* The set of context nodes for the node tests */
12098 xmlNodeSetPtr contextSeq;
12099 int contextIdx;
12100 xmlNodePtr contextNode;
12101 /* The final resulting node set wrt to all context nodes */
12102 xmlNodeSetPtr outSeq;
12103 /*
12104 * The temporary resulting node set wrt 1 context node.
12105 * Used to feed predicate evaluation.
12106 */
12107 xmlNodeSetPtr seq;
12108 xmlNodePtr cur;
12109 /* First predicate operator */
12110 xmlXPathStepOpPtr predOp;
12111 int maxPos; /* The requested position() (when a "[n]" predicate) */
12112 int hasPredicateRange, hasAxisRange, pos, size, newSize;
12113 int breakOnFirstHit;
12114
12115 xmlXPathTraversalFunction next = NULL;
12116 int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12117 xmlXPathNodeSetMergeFunction mergeAndClear;
12118 xmlNodePtr oldContextNode;
12119 xmlXPathContextPtr xpctxt = ctxt->context;
12120
12121
12122 CHECK_TYPE0(XPATH_NODESET);
12123 obj = valuePop(ctxt);
12124 /*
12125 * Setup namespaces.
12126 */
12127 if (prefix != NULL) {
12128 URI = xmlXPathNsLookup(xpctxt, prefix);
12129 if (URI == NULL) {
12130 xmlXPathReleaseObject(xpctxt, obj);
12131 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12132 }
12133 }
12134 /*
12135 * Setup axis.
12136 *
12137 * MAYBE FUTURE TODO: merging optimizations:
12138 * - If the nodes to be traversed wrt to the initial nodes and
12139 * the current axis cannot overlap, then we could avoid searching
12140 * for duplicates during the merge.
12141 * But the question is how/when to evaluate if they cannot overlap.
12142 * Example: if we know that for two initial nodes, the one is
12143 * not in the ancestor-or-self axis of the other, then we could safely
12144 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12145 * the descendant-or-self axis.
12146 */
12147 mergeAndClear = xmlXPathNodeSetMergeAndClear;
12148 switch (axis) {
12149 case AXIS_ANCESTOR:
12150 first = NULL;
12151 next = xmlXPathNextAncestor;
12152 break;
12153 case AXIS_ANCESTOR_OR_SELF:
12154 first = NULL;
12155 next = xmlXPathNextAncestorOrSelf;
12156 break;
12157 case AXIS_ATTRIBUTE:
12158 first = NULL;
12159 last = NULL;
12160 next = xmlXPathNextAttribute;
12161 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12162 break;
12163 case AXIS_CHILD:
12164 last = NULL;
12165 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12166 (type == NODE_TYPE_NODE))
12167 {
12168 /*
12169 * Optimization if an element node type is 'element'.
12170 */
12171 next = xmlXPathNextChildElement;
12172 } else
12173 next = xmlXPathNextChild;
12174 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12175 break;
12176 case AXIS_DESCENDANT:
12177 last = NULL;
12178 next = xmlXPathNextDescendant;
12179 break;
12180 case AXIS_DESCENDANT_OR_SELF:
12181 last = NULL;
12182 next = xmlXPathNextDescendantOrSelf;
12183 break;
12184 case AXIS_FOLLOWING:
12185 last = NULL;
12186 next = xmlXPathNextFollowing;
12187 break;
12188 case AXIS_FOLLOWING_SIBLING:
12189 last = NULL;
12190 next = xmlXPathNextFollowingSibling;
12191 break;
12192 case AXIS_NAMESPACE:
12193 first = NULL;
12194 last = NULL;
12195 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12196 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12197 break;
12198 case AXIS_PARENT:
12199 first = NULL;
12200 next = xmlXPathNextParent;
12201 break;
12202 case AXIS_PRECEDING:
12203 first = NULL;
12204 next = xmlXPathNextPrecedingInternal;
12205 break;
12206 case AXIS_PRECEDING_SIBLING:
12207 first = NULL;
12208 next = xmlXPathNextPrecedingSibling;
12209 break;
12210 case AXIS_SELF:
12211 first = NULL;
12212 last = NULL;
12213 next = xmlXPathNextSelf;
12214 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12215 break;
12216 }
12217
12218 #ifdef DEBUG_STEP
12219 xmlXPathDebugDumpStepAxis(op,
12220 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12221 #endif
12222
12223 if (next == NULL) {
12224 xmlXPathReleaseObject(xpctxt, obj);
12225 return(0);
12226 }
12227 contextSeq = obj->nodesetval;
12228 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12229 xmlXPathReleaseObject(xpctxt, obj);
12230 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12231 return(0);
12232 }
12233 /*
12234 * Predicate optimization ---------------------------------------------
12235 * If this step has a last predicate, which contains a position(),
12236 * then we'll optimize (although not exactly "position()", but only
12237 * the short-hand form, i.e., "[n]".
12238 *
12239 * Example - expression "/foo[parent::bar][1]":
12240 *
12241 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12242 * ROOT -- op->ch1
12243 * PREDICATE -- op->ch2 (predOp)
12244 * PREDICATE -- predOp->ch1 = [parent::bar]
12245 * SORT
12246 * COLLECT 'parent' 'name' 'node' bar
12247 * NODE
12248 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12249 *
12250 */
12251 maxPos = 0;
12252 predOp = NULL;
12253 hasPredicateRange = 0;
12254 hasAxisRange = 0;
12255 if (op->ch2 != -1) {
12256 /*
12257 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12258 */
12259 predOp = &ctxt->comp->steps[op->ch2];
12260 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12261 if (predOp->ch1 != -1) {
12262 /*
12263 * Use the next inner predicate operator.
12264 */
12265 predOp = &ctxt->comp->steps[predOp->ch1];
12266 hasPredicateRange = 1;
12267 } else {
12268 /*
12269 * There's no other predicate than the [n] predicate.
12270 */
12271 predOp = NULL;
12272 hasAxisRange = 1;
12273 }
12274 }
12275 }
12276 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12277 /*
12278 * Axis traversal -----------------------------------------------------
12279 */
12280 /*
12281 * 2.3 Node Tests
12282 * - For the attribute axis, the principal node type is attribute.
12283 * - For the namespace axis, the principal node type is namespace.
12284 * - For other axes, the principal node type is element.
12285 *
12286 * A node test * is true for any node of the
12287 * principal node type. For example, child::* will
12288 * select all element children of the context node
12289 */
12290 oldContextNode = xpctxt->node;
12291 addNode = xmlXPathNodeSetAddUnique;
12292 outSeq = NULL;
12293 seq = NULL;
12294 contextNode = NULL;
12295 contextIdx = 0;
12296
12297
12298 while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12299 (ctxt->error == XPATH_EXPRESSION_OK)) {
12300 xpctxt->node = contextSeq->nodeTab[contextIdx++];
12301
12302 if (seq == NULL) {
12303 seq = xmlXPathNodeSetCreate(NULL);
12304 if (seq == NULL) {
12305 total = 0;
12306 goto error;
12307 }
12308 }
12309 /*
12310 * Traverse the axis and test the nodes.
12311 */
12312 pos = 0;
12313 cur = NULL;
12314 hasNsNodes = 0;
12315 do {
12316 cur = next(ctxt, cur);
12317 if (cur == NULL)
12318 break;
12319
12320 /*
12321 * QUESTION TODO: What does the "first" and "last" stuff do?
12322 */
12323 if ((first != NULL) && (*first != NULL)) {
12324 if (*first == cur)
12325 break;
12326 if (((total % 256) == 0) &&
12327 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12328 (xmlXPathCmpNodesExt(*first, cur) >= 0))
12329 #else
12330 (xmlXPathCmpNodes(*first, cur) >= 0))
12331 #endif
12332 {
12333 break;
12334 }
12335 }
12336 if ((last != NULL) && (*last != NULL)) {
12337 if (*last == cur)
12338 break;
12339 if (((total % 256) == 0) &&
12340 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12341 (xmlXPathCmpNodesExt(cur, *last) >= 0))
12342 #else
12343 (xmlXPathCmpNodes(cur, *last) >= 0))
12344 #endif
12345 {
12346 break;
12347 }
12348 }
12349
12350 total++;
12351
12352 #ifdef DEBUG_STEP
12353 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12354 #endif
12355
12356 switch (test) {
12357 case NODE_TEST_NONE:
12358 total = 0;
12359 STRANGE
12360 goto error;
12361 case NODE_TEST_TYPE:
12362 if (type == NODE_TYPE_NODE) {
12363 switch (cur->type) {
12364 case XML_DOCUMENT_NODE:
12365 case XML_HTML_DOCUMENT_NODE:
12366 #ifdef LIBXML_DOCB_ENABLED
12367 case XML_DOCB_DOCUMENT_NODE:
12368 #endif
12369 case XML_ELEMENT_NODE:
12370 case XML_ATTRIBUTE_NODE:
12371 case XML_PI_NODE:
12372 case XML_COMMENT_NODE:
12373 case XML_CDATA_SECTION_NODE:
12374 case XML_TEXT_NODE:
12375 XP_TEST_HIT
12376 break;
12377 case XML_NAMESPACE_DECL: {
12378 if (axis == AXIS_NAMESPACE) {
12379 XP_TEST_HIT_NS
12380 } else {
12381 hasNsNodes = 1;
12382 XP_TEST_HIT
12383 }
12384 break;
12385 }
12386 default:
12387 break;
12388 }
12389 } else if (cur->type == (xmlElementType) type) {
12390 if (cur->type == XML_NAMESPACE_DECL)
12391 XP_TEST_HIT_NS
12392 else
12393 XP_TEST_HIT
12394 } else if ((type == NODE_TYPE_TEXT) &&
12395 (cur->type == XML_CDATA_SECTION_NODE))
12396 {
12397 XP_TEST_HIT
12398 }
12399 break;
12400 case NODE_TEST_PI:
12401 if ((cur->type == XML_PI_NODE) &&
12402 ((name == NULL) || xmlStrEqual(name, cur->name)))
12403 {
12404 XP_TEST_HIT
12405 }
12406 break;
12407 case NODE_TEST_ALL:
12408 if (axis == AXIS_ATTRIBUTE) {
12409 if (cur->type == XML_ATTRIBUTE_NODE)
12410 {
12411 if (prefix == NULL)
12412 {
12413 XP_TEST_HIT
12414 } else if ((cur->ns != NULL) &&
12415 (xmlStrEqual(URI, cur->ns->href)))
12416 {
12417 XP_TEST_HIT
12418 }
12419 }
12420 } else if (axis == AXIS_NAMESPACE) {
12421 if (cur->type == XML_NAMESPACE_DECL)
12422 {
12423 XP_TEST_HIT_NS
12424 }
12425 } else {
12426 if (cur->type == XML_ELEMENT_NODE) {
12427 if (prefix == NULL)
12428 {
12429 XP_TEST_HIT
12430
12431 } else if ((cur->ns != NULL) &&
12432 (xmlStrEqual(URI, cur->ns->href)))
12433 {
12434 XP_TEST_HIT
12435 }
12436 }
12437 }
12438 break;
12439 case NODE_TEST_NS:{
12440 TODO;
12441 break;
12442 }
12443 case NODE_TEST_NAME:
12444 if (axis == AXIS_ATTRIBUTE) {
12445 if (cur->type != XML_ATTRIBUTE_NODE)
12446 break;
12447 } else if (axis == AXIS_NAMESPACE) {
12448 if (cur->type != XML_NAMESPACE_DECL)
12449 break;
12450 } else {
12451 if (cur->type != XML_ELEMENT_NODE)
12452 break;
12453 }
12454 switch (cur->type) {
12455 case XML_ELEMENT_NODE:
12456 if (xmlStrEqual(name, cur->name)) {
12457 if (prefix == NULL) {
12458 if (cur->ns == NULL)
12459 {
12460 XP_TEST_HIT
12461 }
12462 } else {
12463 if ((cur->ns != NULL) &&
12464 (xmlStrEqual(URI, cur->ns->href)))
12465 {
12466 XP_TEST_HIT
12467 }
12468 }
12469 }
12470 break;
12471 case XML_ATTRIBUTE_NODE:{
12472 xmlAttrPtr attr = (xmlAttrPtr) cur;
12473
12474 if (xmlStrEqual(name, attr->name)) {
12475 if (prefix == NULL) {
12476 if ((attr->ns == NULL) ||
12477 (attr->ns->prefix == NULL))
12478 {
12479 XP_TEST_HIT
12480 }
12481 } else {
12482 if ((attr->ns != NULL) &&
12483 (xmlStrEqual(URI,
12484 attr->ns->href)))
12485 {
12486 XP_TEST_HIT
12487 }
12488 }
12489 }
12490 break;
12491 }
12492 case XML_NAMESPACE_DECL:
12493 if (cur->type == XML_NAMESPACE_DECL) {
12494 xmlNsPtr ns = (xmlNsPtr) cur;
12495
12496 if ((ns->prefix != NULL) && (name != NULL)
12497 && (xmlStrEqual(ns->prefix, name)))
12498 {
12499 XP_TEST_HIT_NS
12500 }
12501 }
12502 break;
12503 default:
12504 break;
12505 }
12506 break;
12507 } /* switch(test) */
12508 } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12509
12510 goto apply_predicates;
12511
12512 axis_range_end: /* ----------------------------------------------------- */
12513 /*
12514 * We have a "/foo[n]", and position() = n was reached.
12515 * Note that we can have as well "/foo/::parent::foo[1]", so
12516 * a duplicate-aware merge is still needed.
12517 * Merge with the result.
12518 */
12519 if (outSeq == NULL) {
12520 outSeq = seq;
12521 seq = NULL;
12522 } else
12523 outSeq = mergeAndClear(outSeq, seq, 0);
12524 /*
12525 * Break if only a true/false result was requested.
12526 */
12527 if (toBool)
12528 break;
12529 continue;
12530
12531 first_hit: /* ---------------------------------------------------------- */
12532 /*
12533 * Break if only a true/false result was requested and
12534 * no predicates existed and a node test succeeded.
12535 */
12536 if (outSeq == NULL) {
12537 outSeq = seq;
12538 seq = NULL;
12539 } else
12540 outSeq = mergeAndClear(outSeq, seq, 0);
12541 break;
12542
12543 #ifdef DEBUG_STEP
12544 if (seq != NULL)
12545 nbMatches += seq->nodeNr;
12546 #endif
12547
12548 apply_predicates: /* --------------------------------------------------- */
12549 if (ctxt->error != XPATH_EXPRESSION_OK)
12550 goto error;
12551
12552 /*
12553 * Apply predicates.
12554 */
12555 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12556 /*
12557 * E.g. when we have a "/foo[some expression][n]".
12558 */
12559 /*
12560 * QUESTION TODO: The old predicate evaluation took into
12561 * account location-sets.
12562 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12563 * Do we expect such a set here?
12564 * All what I learned now from the evaluation semantics
12565 * does not indicate that a location-set will be processed
12566 * here, so this looks OK.
12567 */
12568 /*
12569 * Iterate over all predicates, starting with the outermost
12570 * predicate.
12571 * TODO: Problem: we cannot execute the inner predicates first
12572 * since we cannot go back *up* the operator tree!
12573 * Options we have:
12574 * 1) Use of recursive functions (like is it currently done
12575 * via xmlXPathCompOpEval())
12576 * 2) Add a predicate evaluation information stack to the
12577 * context struct
12578 * 3) Change the way the operators are linked; we need a
12579 * "parent" field on xmlXPathStepOp
12580 *
12581 * For the moment, I'll try to solve this with a recursive
12582 * function: xmlXPathCompOpEvalPredicate().
12583 */
12584 size = seq->nodeNr;
12585 if (hasPredicateRange != 0)
12586 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12587 predOp, seq, size, maxPos, maxPos, hasNsNodes);
12588 else
12589 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12590 predOp, seq, size, hasNsNodes);
12591
12592 if (ctxt->error != XPATH_EXPRESSION_OK) {
12593 total = 0;
12594 goto error;
12595 }
12596 /*
12597 * Add the filtered set of nodes to the result node set.
12598 */
12599 if (newSize == 0) {
12600 /*
12601 * The predicates filtered all nodes out.
12602 */
12603 xmlXPathNodeSetClear(seq, hasNsNodes);
12604 } else if (seq->nodeNr > 0) {
12605 /*
12606 * Add to result set.
12607 */
12608 if (outSeq == NULL) {
12609 if (size != newSize) {
12610 /*
12611 * We need to merge and clear here, since
12612 * the sequence will contained NULLed entries.
12613 */
12614 outSeq = mergeAndClear(NULL, seq, 1);
12615 } else {
12616 outSeq = seq;
12617 seq = NULL;
12618 }
12619 } else
12620 outSeq = mergeAndClear(outSeq, seq,
12621 (size != newSize) ? 1: 0);
12622 /*
12623 * Break if only a true/false result was requested.
12624 */
12625 if (toBool)
12626 break;
12627 }
12628 } else if (seq->nodeNr > 0) {
12629 /*
12630 * Add to result set.
12631 */
12632 if (outSeq == NULL) {
12633 outSeq = seq;
12634 seq = NULL;
12635 } else {
12636 outSeq = mergeAndClear(outSeq, seq, 0);
12637 }
12638 }
12639 }
12640
12641 error:
12642 if ((obj->boolval) && (obj->user != NULL)) {
12643 /*
12644 * QUESTION TODO: What does this do and why?
12645 * TODO: Do we have to do this also for the "error"
12646 * cleanup further down?
12647 */
12648 ctxt->value->boolval = 1;
12649 ctxt->value->user = obj->user;
12650 obj->user = NULL;
12651 obj->boolval = 0;
12652 }
12653 xmlXPathReleaseObject(xpctxt, obj);
12654
12655 /*
12656 * Ensure we return at least an emtpy set.
12657 */
12658 if (outSeq == NULL) {
12659 if ((seq != NULL) && (seq->nodeNr == 0))
12660 outSeq = seq;
12661 else
12662 outSeq = xmlXPathNodeSetCreate(NULL);
12663 /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12664 }
12665 if ((seq != NULL) && (seq != outSeq)) {
12666 xmlXPathFreeNodeSet(seq);
12667 }
12668 /*
12669 * Hand over the result. Better to push the set also in
12670 * case of errors.
12671 */
12672 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12673 /*
12674 * Reset the context node.
12675 */
12676 xpctxt->node = oldContextNode;
12677 /*
12678 * When traversing the namespace axis in "toBool" mode, it's
12679 * possible that tmpNsList wasn't freed.
12680 */
12681 if (xpctxt->tmpNsList != NULL) {
12682 xmlFree(xpctxt->tmpNsList);
12683 xpctxt->tmpNsList = NULL;
12684 }
12685
12686 #ifdef DEBUG_STEP
12687 xmlGenericError(xmlGenericErrorContext,
12688 "\nExamined %d nodes, found %d nodes at that step\n",
12689 total, nbMatches);
12690 #endif
12691
12692 return(total);
12693 }
12694
12695 static int
12696 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12697 xmlXPathStepOpPtr op, xmlNodePtr * first);
12698
12699 /**
12700 * xmlXPathCompOpEvalFirst:
12701 * @ctxt: the XPath parser context with the compiled expression
12702 * @op: an XPath compiled operation
12703 * @first: the first elem found so far
12704 *
12705 * Evaluate the Precompiled XPath operation searching only the first
12706 * element in document order
12707 *
12708 * Returns the number of examined objects.
12709 */
12710 static int
12711 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12712 xmlXPathStepOpPtr op, xmlNodePtr * first)
12713 {
12714 int total = 0, cur;
12715 xmlXPathCompExprPtr comp;
12716 xmlXPathObjectPtr arg1, arg2;
12717
12718 CHECK_ERROR0;
12719 comp = ctxt->comp;
12720 switch (op->op) {
12721 case XPATH_OP_END:
12722 return (0);
12723 case XPATH_OP_UNION:
12724 total =
12725 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12726 first);
12727 CHECK_ERROR0;
12728 if ((ctxt->value != NULL)
12729 && (ctxt->value->type == XPATH_NODESET)
12730 && (ctxt->value->nodesetval != NULL)
12731 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12732 /*
12733 * limit tree traversing to first node in the result
12734 */
12735 /*
12736 * OPTIMIZE TODO: This implicitely sorts
12737 * the result, even if not needed. E.g. if the argument
12738 * of the count() function, no sorting is needed.
12739 * OPTIMIZE TODO: How do we know if the node-list wasn't
12740 * aready sorted?
12741 */
12742 if (ctxt->value->nodesetval->nodeNr > 1)
12743 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12744 *first = ctxt->value->nodesetval->nodeTab[0];
12745 }
12746 cur =
12747 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12748 first);
12749 CHECK_ERROR0;
12750
12751 arg2 = valuePop(ctxt);
12752 arg1 = valuePop(ctxt);
12753 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12754 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12755 xmlXPathReleaseObject(ctxt->context, arg1);
12756 xmlXPathReleaseObject(ctxt->context, arg2);
12757 XP_ERROR0(XPATH_INVALID_TYPE);
12758 }
12759
12760 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12761 arg2->nodesetval);
12762 valuePush(ctxt, arg1);
12763 xmlXPathReleaseObject(ctxt->context, arg2);
12764 /* optimizer */
12765 if (total > cur)
12766 xmlXPathCompSwap(op);
12767 return (total + cur);
12768 case XPATH_OP_ROOT:
12769 xmlXPathRoot(ctxt);
12770 return (0);
12771 case XPATH_OP_NODE:
12772 if (op->ch1 != -1)
12773 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12774 CHECK_ERROR0;
12775 if (op->ch2 != -1)
12776 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12777 CHECK_ERROR0;
12778 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12779 ctxt->context->node));
12780 return (total);
12781 case XPATH_OP_RESET:
12782 if (op->ch1 != -1)
12783 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12784 CHECK_ERROR0;
12785 if (op->ch2 != -1)
12786 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12787 CHECK_ERROR0;
12788 ctxt->context->node = NULL;
12789 return (total);
12790 case XPATH_OP_COLLECT:{
12791 if (op->ch1 == -1)
12792 return (total);
12793
12794 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12795 CHECK_ERROR0;
12796
12797 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12798 return (total);
12799 }
12800 case XPATH_OP_VALUE:
12801 valuePush(ctxt,
12802 xmlXPathCacheObjectCopy(ctxt->context,
12803 (xmlXPathObjectPtr) op->value4));
12804 return (0);
12805 case XPATH_OP_SORT:
12806 if (op->ch1 != -1)
12807 total +=
12808 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12809 first);
12810 CHECK_ERROR0;
12811 if ((ctxt->value != NULL)
12812 && (ctxt->value->type == XPATH_NODESET)
12813 && (ctxt->value->nodesetval != NULL)
12814 && (ctxt->value->nodesetval->nodeNr > 1))
12815 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12816 return (total);
12817 #ifdef XP_OPTIMIZED_FILTER_FIRST
12818 case XPATH_OP_FILTER:
12819 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12820 return (total);
12821 #endif
12822 default:
12823 return (xmlXPathCompOpEval(ctxt, op));
12824 }
12825 }
12826
12827 /**
12828 * xmlXPathCompOpEvalLast:
12829 * @ctxt: the XPath parser context with the compiled expression
12830 * @op: an XPath compiled operation
12831 * @last: the last elem found so far
12832 *
12833 * Evaluate the Precompiled XPath operation searching only the last
12834 * element in document order
12835 *
12836 * Returns the number of nodes traversed
12837 */
12838 static int
12839 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12840 xmlNodePtr * last)
12841 {
12842 int total = 0, cur;
12843 xmlXPathCompExprPtr comp;
12844 xmlXPathObjectPtr arg1, arg2;
12845 xmlNodePtr bak;
12846 xmlDocPtr bakd;
12847 int pp;
12848 int cs;
12849
12850 CHECK_ERROR0;
12851 comp = ctxt->comp;
12852 switch (op->op) {
12853 case XPATH_OP_END:
12854 return (0);
12855 case XPATH_OP_UNION:
12856 bakd = ctxt->context->doc;
12857 bak = ctxt->context->node;
12858 pp = ctxt->context->proximityPosition;
12859 cs = ctxt->context->contextSize;
12860 total =
12861 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12862 CHECK_ERROR0;
12863 if ((ctxt->value != NULL)
12864 && (ctxt->value->type == XPATH_NODESET)
12865 && (ctxt->value->nodesetval != NULL)
12866 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12867 /*
12868 * limit tree traversing to first node in the result
12869 */
12870 if (ctxt->value->nodesetval->nodeNr > 1)
12871 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12872 *last =
12873 ctxt->value->nodesetval->nodeTab[ctxt->value->
12874 nodesetval->nodeNr -
12875 1];
12876 }
12877 ctxt->context->doc = bakd;
12878 ctxt->context->node = bak;
12879 ctxt->context->proximityPosition = pp;
12880 ctxt->context->contextSize = cs;
12881 cur =
12882 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12883 CHECK_ERROR0;
12884 if ((ctxt->value != NULL)
12885 && (ctxt->value->type == XPATH_NODESET)
12886 && (ctxt->value->nodesetval != NULL)
12887 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12888 }
12889
12890 arg2 = valuePop(ctxt);
12891 arg1 = valuePop(ctxt);
12892 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12893 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12894 xmlXPathReleaseObject(ctxt->context, arg1);
12895 xmlXPathReleaseObject(ctxt->context, arg2);
12896 XP_ERROR0(XPATH_INVALID_TYPE);
12897 }
12898
12899 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12900 arg2->nodesetval);
12901 valuePush(ctxt, arg1);
12902 xmlXPathReleaseObject(ctxt->context, arg2);
12903 /* optimizer */
12904 if (total > cur)
12905 xmlXPathCompSwap(op);
12906 return (total + cur);
12907 case XPATH_OP_ROOT:
12908 xmlXPathRoot(ctxt);
12909 return (0);
12910 case XPATH_OP_NODE:
12911 if (op->ch1 != -1)
12912 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12913 CHECK_ERROR0;
12914 if (op->ch2 != -1)
12915 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12916 CHECK_ERROR0;
12917 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12918 ctxt->context->node));
12919 return (total);
12920 case XPATH_OP_RESET:
12921 if (op->ch1 != -1)
12922 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12923 CHECK_ERROR0;
12924 if (op->ch2 != -1)
12925 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12926 CHECK_ERROR0;
12927 ctxt->context->node = NULL;
12928 return (total);
12929 case XPATH_OP_COLLECT:{
12930 if (op->ch1 == -1)
12931 return (0);
12932
12933 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12934 CHECK_ERROR0;
12935
12936 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12937 return (total);
12938 }
12939 case XPATH_OP_VALUE:
12940 valuePush(ctxt,
12941 xmlXPathCacheObjectCopy(ctxt->context,
12942 (xmlXPathObjectPtr) op->value4));
12943 return (0);
12944 case XPATH_OP_SORT:
12945 if (op->ch1 != -1)
12946 total +=
12947 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12948 last);
12949 CHECK_ERROR0;
12950 if ((ctxt->value != NULL)
12951 && (ctxt->value->type == XPATH_NODESET)
12952 && (ctxt->value->nodesetval != NULL)
12953 && (ctxt->value->nodesetval->nodeNr > 1))
12954 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12955 return (total);
12956 default:
12957 return (xmlXPathCompOpEval(ctxt, op));
12958 }
12959 }
12960
12961 #ifdef XP_OPTIMIZED_FILTER_FIRST
12962 static int
12963 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12964 xmlXPathStepOpPtr op, xmlNodePtr * first)
12965 {
12966 int total = 0;
12967 xmlXPathCompExprPtr comp;
12968 xmlXPathObjectPtr res;
12969 xmlXPathObjectPtr obj;
12970 xmlNodeSetPtr oldset;
12971 xmlNodePtr oldnode;
12972 xmlDocPtr oldDoc;
12973 int i;
12974
12975 CHECK_ERROR0;
12976 comp = ctxt->comp;
12977 /*
12978 * Optimization for ()[last()] selection i.e. the last elem
12979 */
12980 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12981 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12982 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12983 int f = comp->steps[op->ch2].ch1;
12984
12985 if ((f != -1) &&
12986 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12987 (comp->steps[f].value5 == NULL) &&
12988 (comp->steps[f].value == 0) &&
12989 (comp->steps[f].value4 != NULL) &&
12990 (xmlStrEqual
12991 (comp->steps[f].value4, BAD_CAST "last"))) {
12992 xmlNodePtr last = NULL;
12993
12994 total +=
12995 xmlXPathCompOpEvalLast(ctxt,
12996 &comp->steps[op->ch1],
12997 &last);
12998 CHECK_ERROR0;
12999 /*
13000 * The nodeset should be in document order,
13001 * Keep only the last value
13002 */
13003 if ((ctxt->value != NULL) &&
13004 (ctxt->value->type == XPATH_NODESET) &&
13005 (ctxt->value->nodesetval != NULL) &&
13006 (ctxt->value->nodesetval->nodeTab != NULL) &&
13007 (ctxt->value->nodesetval->nodeNr > 1)) {
13008 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13009 *first = *(ctxt->value->nodesetval->nodeTab);
13010 }
13011 return (total);
13012 }
13013 }
13014
13015 if (op->ch1 != -1)
13016 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13017 CHECK_ERROR0;
13018 if (op->ch2 == -1)
13019 return (total);
13020 if (ctxt->value == NULL)
13021 return (total);
13022
13023 #ifdef LIBXML_XPTR_ENABLED
13024 oldnode = ctxt->context->node;
13025 /*
13026 * Hum are we filtering the result of an XPointer expression
13027 */
13028 if (ctxt->value->type == XPATH_LOCATIONSET) {
13029 xmlXPathObjectPtr tmp = NULL;
13030 xmlLocationSetPtr newlocset = NULL;
13031 xmlLocationSetPtr oldlocset;
13032
13033 /*
13034 * Extract the old locset, and then evaluate the result of the
13035 * expression for all the element in the locset. use it to grow
13036 * up a new locset.
13037 */
13038 CHECK_TYPE0(XPATH_LOCATIONSET);
13039 obj = valuePop(ctxt);
13040 oldlocset = obj->user;
13041 ctxt->context->node = NULL;
13042
13043 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13044 ctxt->context->contextSize = 0;
13045 ctxt->context->proximityPosition = 0;
13046 if (op->ch2 != -1)
13047 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13048 res = valuePop(ctxt);
13049 if (res != NULL) {
13050 xmlXPathReleaseObject(ctxt->context, res);
13051 }
13052 valuePush(ctxt, obj);
13053 CHECK_ERROR0;
13054 return (total);
13055 }
13056 newlocset = xmlXPtrLocationSetCreate(NULL);
13057
13058 for (i = 0; i < oldlocset->locNr; i++) {
13059 /*
13060 * Run the evaluation with a node list made of a
13061 * single item in the nodelocset.
13062 */
13063 ctxt->context->node = oldlocset->locTab[i]->user;
13064 ctxt->context->contextSize = oldlocset->locNr;
13065 ctxt->context->proximityPosition = i + 1;
13066 if (tmp == NULL) {
13067 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13068 ctxt->context->node);
13069 } else {
13070 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13071 ctxt->context->node) < 0) {
13072 ctxt->error = XPATH_MEMORY_ERROR;
13073 }
13074 }
13075 valuePush(ctxt, tmp);
13076 if (op->ch2 != -1)
13077 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13078 if (ctxt->error != XPATH_EXPRESSION_OK) {
13079 xmlXPathFreeObject(obj);
13080 return(0);
13081 }
13082 /*
13083 * The result of the evaluation need to be tested to
13084 * decided whether the filter succeeded or not
13085 */
13086 res = valuePop(ctxt);
13087 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13088 xmlXPtrLocationSetAdd(newlocset,
13089 xmlXPathCacheObjectCopy(ctxt->context,
13090 oldlocset->locTab[i]));
13091 }
13092 /*
13093 * Cleanup
13094 */
13095 if (res != NULL) {
13096 xmlXPathReleaseObject(ctxt->context, res);
13097 }
13098 if (ctxt->value == tmp) {
13099 valuePop(ctxt);
13100 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13101 /*
13102 * REVISIT TODO: Don't create a temporary nodeset
13103 * for everly iteration.
13104 */
13105 /* OLD: xmlXPathFreeObject(res); */
13106 } else
13107 tmp = NULL;
13108 ctxt->context->node = NULL;
13109 /*
13110 * Only put the first node in the result, then leave.
13111 */
13112 if (newlocset->locNr > 0) {
13113 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
13114 break;
13115 }
13116 }
13117 if (tmp != NULL) {
13118 xmlXPathReleaseObject(ctxt->context, tmp);
13119 }
13120 /*
13121 * The result is used as the new evaluation locset.
13122 */
13123 xmlXPathReleaseObject(ctxt->context, obj);
13124 ctxt->context->node = NULL;
13125 ctxt->context->contextSize = -1;
13126 ctxt->context->proximityPosition = -1;
13127 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13128 ctxt->context->node = oldnode;
13129 return (total);
13130 }
13131 #endif /* LIBXML_XPTR_ENABLED */
13132
13133 /*
13134 * Extract the old set, and then evaluate the result of the
13135 * expression for all the element in the set. use it to grow
13136 * up a new set.
13137 */
13138 CHECK_TYPE0(XPATH_NODESET);
13139 obj = valuePop(ctxt);
13140 oldset = obj->nodesetval;
13141
13142 oldnode = ctxt->context->node;
13143 oldDoc = ctxt->context->doc;
13144 ctxt->context->node = NULL;
13145
13146 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13147 ctxt->context->contextSize = 0;
13148 ctxt->context->proximityPosition = 0;
13149 /* QUESTION TODO: Why was this code commented out?
13150 if (op->ch2 != -1)
13151 total +=
13152 xmlXPathCompOpEval(ctxt,
13153 &comp->steps[op->ch2]);
13154 CHECK_ERROR0;
13155 res = valuePop(ctxt);
13156 if (res != NULL)
13157 xmlXPathFreeObject(res);
13158 */
13159 valuePush(ctxt, obj);
13160 ctxt->context->node = oldnode;
13161 CHECK_ERROR0;
13162 } else {
13163 xmlNodeSetPtr newset;
13164 xmlXPathObjectPtr tmp = NULL;
13165 /*
13166 * Initialize the new set.
13167 * Also set the xpath document in case things like
13168 * key() evaluation are attempted on the predicate
13169 */
13170 newset = xmlXPathNodeSetCreate(NULL);
13171 /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13172
13173 for (i = 0; i < oldset->nodeNr; i++) {
13174 /*
13175 * Run the evaluation with a node list made of
13176 * a single item in the nodeset.
13177 */
13178 ctxt->context->node = oldset->nodeTab[i];
13179 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13180 (oldset->nodeTab[i]->doc != NULL))
13181 ctxt->context->doc = oldset->nodeTab[i]->doc;
13182 if (tmp == NULL) {
13183 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13184 ctxt->context->node);
13185 } else {
13186 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13187 ctxt->context->node) < 0) {
13188 ctxt->error = XPATH_MEMORY_ERROR;
13189 }
13190 }
13191 valuePush(ctxt, tmp);
13192 ctxt->context->contextSize = oldset->nodeNr;
13193 ctxt->context->proximityPosition = i + 1;
13194 if (op->ch2 != -1)
13195 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13196 if (ctxt->error != XPATH_EXPRESSION_OK) {
13197 xmlXPathFreeNodeSet(newset);
13198 xmlXPathFreeObject(obj);
13199 return(0);
13200 }
13201 /*
13202 * The result of the evaluation needs to be tested to
13203 * decide whether the filter succeeded or not
13204 */
13205 res = valuePop(ctxt);
13206 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13207 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0)
13208 ctxt->error = XPATH_MEMORY_ERROR;
13209 }
13210 /*
13211 * Cleanup
13212 */
13213 if (res != NULL) {
13214 xmlXPathReleaseObject(ctxt->context, res);
13215 }
13216 if (ctxt->value == tmp) {
13217 valuePop(ctxt);
13218 /*
13219 * Don't free the temporary nodeset
13220 * in order to avoid massive recreation inside this
13221 * loop.
13222 */
13223 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13224 } else
13225 tmp = NULL;
13226 ctxt->context->node = NULL;
13227 /*
13228 * Only put the first node in the result, then leave.
13229 */
13230 if (newset->nodeNr > 0) {
13231 *first = *(newset->nodeTab);
13232 break;
13233 }
13234 }
13235 if (tmp != NULL) {
13236 xmlXPathReleaseObject(ctxt->context, tmp);
13237 }
13238 /*
13239 * The result is used as the new evaluation set.
13240 */
13241 xmlXPathReleaseObject(ctxt->context, obj);
13242 ctxt->context->node = NULL;
13243 ctxt->context->contextSize = -1;
13244 ctxt->context->proximityPosition = -1;
13245 /* may want to move this past the '}' later */
13246 ctxt->context->doc = oldDoc;
13247 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13248 }
13249 ctxt->context->node = oldnode;
13250 return(total);
13251 }
13252 #endif /* XP_OPTIMIZED_FILTER_FIRST */
13253
13254 /**
13255 * xmlXPathCompOpEval:
13256 * @ctxt: the XPath parser context with the compiled expression
13257 * @op: an XPath compiled operation
13258 *
13259 * Evaluate the Precompiled XPath operation
13260 * Returns the number of nodes traversed
13261 */
13262 static int
13263 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13264 {
13265 int total = 0;
13266 int equal, ret;
13267 xmlXPathCompExprPtr comp;
13268 xmlXPathObjectPtr arg1, arg2;
13269 xmlNodePtr bak;
13270 xmlDocPtr bakd;
13271 int pp;
13272 int cs;
13273
13274 CHECK_ERROR0;
13275 comp = ctxt->comp;
13276 switch (op->op) {
13277 case XPATH_OP_END:
13278 return (0);
13279 case XPATH_OP_AND:
13280 bakd = ctxt->context->doc;
13281 bak = ctxt->context->node;
13282 pp = ctxt->context->proximityPosition;
13283 cs = ctxt->context->contextSize;
13284 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13285 CHECK_ERROR0;
13286 xmlXPathBooleanFunction(ctxt, 1);
13287 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13288 return (total);
13289 arg2 = valuePop(ctxt);
13290 ctxt->context->doc = bakd;
13291 ctxt->context->node = bak;
13292 ctxt->context->proximityPosition = pp;
13293 ctxt->context->contextSize = cs;
13294 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13295 if (ctxt->error) {
13296 xmlXPathFreeObject(arg2);
13297 return(0);
13298 }
13299 xmlXPathBooleanFunction(ctxt, 1);
13300 arg1 = valuePop(ctxt);
13301 arg1->boolval &= arg2->boolval;
13302 valuePush(ctxt, arg1);
13303 xmlXPathReleaseObject(ctxt->context, arg2);
13304 return (total);
13305 case XPATH_OP_OR:
13306 bakd = ctxt->context->doc;
13307 bak = ctxt->context->node;
13308 pp = ctxt->context->proximityPosition;
13309 cs = ctxt->context->contextSize;
13310 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13311 CHECK_ERROR0;
13312 xmlXPathBooleanFunction(ctxt, 1);
13313 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13314 return (total);
13315 arg2 = valuePop(ctxt);
13316 ctxt->context->doc = bakd;
13317 ctxt->context->node = bak;
13318 ctxt->context->proximityPosition = pp;
13319 ctxt->context->contextSize = cs;
13320 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13321 if (ctxt->error) {
13322 xmlXPathFreeObject(arg2);
13323 return(0);
13324 }
13325 xmlXPathBooleanFunction(ctxt, 1);
13326 arg1 = valuePop(ctxt);
13327 arg1->boolval |= arg2->boolval;
13328 valuePush(ctxt, arg1);
13329 xmlXPathReleaseObject(ctxt->context, arg2);
13330 return (total);
13331 case XPATH_OP_EQUAL:
13332 bakd = ctxt->context->doc;
13333 bak = ctxt->context->node;
13334 pp = ctxt->context->proximityPosition;
13335 cs = ctxt->context->contextSize;
13336 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13337 CHECK_ERROR0;
13338 ctxt->context->doc = bakd;
13339 ctxt->context->node = bak;
13340 ctxt->context->proximityPosition = pp;
13341 ctxt->context->contextSize = cs;
13342 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13343 CHECK_ERROR0;
13344 if (op->value)
13345 equal = xmlXPathEqualValues(ctxt);
13346 else
13347 equal = xmlXPathNotEqualValues(ctxt);
13348 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13349 return (total);
13350 case XPATH_OP_CMP:
13351 bakd = ctxt->context->doc;
13352 bak = ctxt->context->node;
13353 pp = ctxt->context->proximityPosition;
13354 cs = ctxt->context->contextSize;
13355 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13356 CHECK_ERROR0;
13357 ctxt->context->doc = bakd;
13358 ctxt->context->node = bak;
13359 ctxt->context->proximityPosition = pp;
13360 ctxt->context->contextSize = cs;
13361 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13362 CHECK_ERROR0;
13363 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13364 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13365 return (total);
13366 case XPATH_OP_PLUS:
13367 bakd = ctxt->context->doc;
13368 bak = ctxt->context->node;
13369 pp = ctxt->context->proximityPosition;
13370 cs = ctxt->context->contextSize;
13371 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13372 CHECK_ERROR0;
13373 if (op->ch2 != -1) {
13374 ctxt->context->doc = bakd;
13375 ctxt->context->node = bak;
13376 ctxt->context->proximityPosition = pp;
13377 ctxt->context->contextSize = cs;
13378 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13379 }
13380 CHECK_ERROR0;
13381 if (op->value == 0)
13382 xmlXPathSubValues(ctxt);
13383 else if (op->value == 1)
13384 xmlXPathAddValues(ctxt);
13385 else if (op->value == 2)
13386 xmlXPathValueFlipSign(ctxt);
13387 else if (op->value == 3) {
13388 CAST_TO_NUMBER;
13389 CHECK_TYPE0(XPATH_NUMBER);
13390 }
13391 return (total);
13392 case XPATH_OP_MULT:
13393 bakd = ctxt->context->doc;
13394 bak = ctxt->context->node;
13395 pp = ctxt->context->proximityPosition;
13396 cs = ctxt->context->contextSize;
13397 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13398 CHECK_ERROR0;
13399 ctxt->context->doc = bakd;
13400 ctxt->context->node = bak;
13401 ctxt->context->proximityPosition = pp;
13402 ctxt->context->contextSize = cs;
13403 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13404 CHECK_ERROR0;
13405 if (op->value == 0)
13406 xmlXPathMultValues(ctxt);
13407 else if (op->value == 1)
13408 xmlXPathDivValues(ctxt);
13409 else if (op->value == 2)
13410 xmlXPathModValues(ctxt);
13411 return (total);
13412 case XPATH_OP_UNION:
13413 bakd = ctxt->context->doc;
13414 bak = ctxt->context->node;
13415 pp = ctxt->context->proximityPosition;
13416 cs = ctxt->context->contextSize;
13417 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13418 CHECK_ERROR0;
13419 ctxt->context->doc = bakd;
13420 ctxt->context->node = bak;
13421 ctxt->context->proximityPosition = pp;
13422 ctxt->context->contextSize = cs;
13423 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13424 CHECK_ERROR0;
13425
13426 arg2 = valuePop(ctxt);
13427 arg1 = valuePop(ctxt);
13428 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13429 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13430 xmlXPathReleaseObject(ctxt->context, arg1);
13431 xmlXPathReleaseObject(ctxt->context, arg2);
13432 XP_ERROR0(XPATH_INVALID_TYPE);
13433 }
13434
13435 if ((arg1->nodesetval == NULL) ||
13436 ((arg2->nodesetval != NULL) &&
13437 (arg2->nodesetval->nodeNr != 0)))
13438 {
13439 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13440 arg2->nodesetval);
13441 }
13442
13443 valuePush(ctxt, arg1);
13444 xmlXPathReleaseObject(ctxt->context, arg2);
13445 return (total);
13446 case XPATH_OP_ROOT:
13447 xmlXPathRoot(ctxt);
13448 return (total);
13449 case XPATH_OP_NODE:
13450 if (op->ch1 != -1)
13451 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13452 CHECK_ERROR0;
13453 if (op->ch2 != -1)
13454 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13455 CHECK_ERROR0;
13456 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13457 ctxt->context->node));
13458 return (total);
13459 case XPATH_OP_RESET:
13460 if (op->ch1 != -1)
13461 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13462 CHECK_ERROR0;
13463 if (op->ch2 != -1)
13464 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13465 CHECK_ERROR0;
13466 ctxt->context->node = NULL;
13467 return (total);
13468 case XPATH_OP_COLLECT:{
13469 if (op->ch1 == -1)
13470 return (total);
13471
13472 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13473 CHECK_ERROR0;
13474
13475 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13476 return (total);
13477 }
13478 case XPATH_OP_VALUE:
13479 valuePush(ctxt,
13480 xmlXPathCacheObjectCopy(ctxt->context,
13481 (xmlXPathObjectPtr) op->value4));
13482 return (total);
13483 case XPATH_OP_VARIABLE:{
13484 xmlXPathObjectPtr val;
13485
13486 if (op->ch1 != -1)
13487 total +=
13488 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13489 if (op->value5 == NULL) {
13490 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13491 if (val == NULL)
13492 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13493 valuePush(ctxt, val);
13494 } else {
13495 const xmlChar *URI;
13496
13497 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13498 if (URI == NULL) {
13499 xmlGenericError(xmlGenericErrorContext,
13500 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13501 (char *) op->value4, (char *)op->value5);
13502 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13503 return (total);
13504 }
13505 val = xmlXPathVariableLookupNS(ctxt->context,
13506 op->value4, URI);
13507 if (val == NULL)
13508 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13509 valuePush(ctxt, val);
13510 }
13511 return (total);
13512 }
13513 case XPATH_OP_FUNCTION:{
13514 xmlXPathFunction func;
13515 const xmlChar *oldFunc, *oldFuncURI;
13516 int i;
13517 int frame;
13518
13519 frame = xmlXPathSetFrame(ctxt);
13520 if (op->ch1 != -1) {
13521 total +=
13522 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13523 if (ctxt->error != XPATH_EXPRESSION_OK) {
13524 xmlXPathPopFrame(ctxt, frame);
13525 return (total);
13526 }
13527 }
13528 if (ctxt->valueNr < ctxt->valueFrame + op->value) {
13529 xmlGenericError(xmlGenericErrorContext,
13530 "xmlXPathCompOpEval: parameter error\n");
13531 ctxt->error = XPATH_INVALID_OPERAND;
13532 xmlXPathPopFrame(ctxt, frame);
13533 return (total);
13534 }
13535 for (i = 0; i < op->value; i++) {
13536 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13537 xmlGenericError(xmlGenericErrorContext,
13538 "xmlXPathCompOpEval: parameter error\n");
13539 ctxt->error = XPATH_INVALID_OPERAND;
13540 xmlXPathPopFrame(ctxt, frame);
13541 return (total);
13542 }
13543 }
13544 if (op->cache != NULL)
13545 func = op->cache;
13546 else {
13547 const xmlChar *URI = NULL;
13548
13549 if (op->value5 == NULL)
13550 func =
13551 xmlXPathFunctionLookup(ctxt->context,
13552 op->value4);
13553 else {
13554 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13555 if (URI == NULL) {
13556 xmlGenericError(xmlGenericErrorContext,
13557 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13558 (char *)op->value4, (char *)op->value5);
13559 xmlXPathPopFrame(ctxt, frame);
13560 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13561 return (total);
13562 }
13563 func = xmlXPathFunctionLookupNS(ctxt->context,
13564 op->value4, URI);
13565 }
13566 if (func == NULL) {
13567 xmlGenericError(xmlGenericErrorContext,
13568 "xmlXPathCompOpEval: function %s not found\n",
13569 (char *)op->value4);
13570 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13571 }
13572 op->cache = func;
13573 op->cacheURI = (void *) URI;
13574 }
13575 oldFunc = ctxt->context->function;
13576 oldFuncURI = ctxt->context->functionURI;
13577 ctxt->context->function = op->value4;
13578 ctxt->context->functionURI = op->cacheURI;
13579 func(ctxt, op->value);
13580 ctxt->context->function = oldFunc;
13581 ctxt->context->functionURI = oldFuncURI;
13582 xmlXPathPopFrame(ctxt, frame);
13583 return (total);
13584 }
13585 case XPATH_OP_ARG:
13586 bakd = ctxt->context->doc;
13587 bak = ctxt->context->node;
13588 pp = ctxt->context->proximityPosition;
13589 cs = ctxt->context->contextSize;
13590 if (op->ch1 != -1) {
13591 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13592 ctxt->context->contextSize = cs;
13593 ctxt->context->proximityPosition = pp;
13594 ctxt->context->node = bak;
13595 ctxt->context->doc = bakd;
13596 CHECK_ERROR0;
13597 }
13598 if (op->ch2 != -1) {
13599 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13600 ctxt->context->contextSize = cs;
13601 ctxt->context->proximityPosition = pp;
13602 ctxt->context->node = bak;
13603 ctxt->context->doc = bakd;
13604 CHECK_ERROR0;
13605 }
13606 return (total);
13607 case XPATH_OP_PREDICATE:
13608 case XPATH_OP_FILTER:{
13609 xmlXPathObjectPtr res;
13610 xmlXPathObjectPtr obj, tmp;
13611 xmlNodeSetPtr newset = NULL;
13612 xmlNodeSetPtr oldset;
13613 xmlNodePtr oldnode;
13614 xmlDocPtr oldDoc;
13615 int i;
13616
13617 /*
13618 * Optimization for ()[1] selection i.e. the first elem
13619 */
13620 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13621 #ifdef XP_OPTIMIZED_FILTER_FIRST
13622 /*
13623 * FILTER TODO: Can we assume that the inner processing
13624 * will result in an ordered list if we have an
13625 * XPATH_OP_FILTER?
13626 * What about an additional field or flag on
13627 * xmlXPathObject like @sorted ? This way we wouln'd need
13628 * to assume anything, so it would be more robust and
13629 * easier to optimize.
13630 */
13631 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13632 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13633 #else
13634 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13635 #endif
13636 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13637 xmlXPathObjectPtr val;
13638
13639 val = comp->steps[op->ch2].value4;
13640 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13641 (val->floatval == 1.0)) {
13642 xmlNodePtr first = NULL;
13643
13644 total +=
13645 xmlXPathCompOpEvalFirst(ctxt,
13646 &comp->steps[op->ch1],
13647 &first);
13648 CHECK_ERROR0;
13649 /*
13650 * The nodeset should be in document order,
13651 * Keep only the first value
13652 */
13653 if ((ctxt->value != NULL) &&
13654 (ctxt->value->type == XPATH_NODESET) &&
13655 (ctxt->value->nodesetval != NULL) &&
13656 (ctxt->value->nodesetval->nodeNr > 1))
13657 xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13658 1, 1);
13659 return (total);
13660 }
13661 }
13662 /*
13663 * Optimization for ()[last()] selection i.e. the last elem
13664 */
13665 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13666 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13667 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13668 int f = comp->steps[op->ch2].ch1;
13669
13670 if ((f != -1) &&
13671 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13672 (comp->steps[f].value5 == NULL) &&
13673 (comp->steps[f].value == 0) &&
13674 (comp->steps[f].value4 != NULL) &&
13675 (xmlStrEqual
13676 (comp->steps[f].value4, BAD_CAST "last"))) {
13677 xmlNodePtr last = NULL;
13678
13679 total +=
13680 xmlXPathCompOpEvalLast(ctxt,
13681 &comp->steps[op->ch1],
13682 &last);
13683 CHECK_ERROR0;
13684 /*
13685 * The nodeset should be in document order,
13686 * Keep only the last value
13687 */
13688 if ((ctxt->value != NULL) &&
13689 (ctxt->value->type == XPATH_NODESET) &&
13690 (ctxt->value->nodesetval != NULL) &&
13691 (ctxt->value->nodesetval->nodeTab != NULL) &&
13692 (ctxt->value->nodesetval->nodeNr > 1))
13693 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13694 return (total);
13695 }
13696 }
13697 /*
13698 * Process inner predicates first.
13699 * Example "index[parent::book][1]":
13700 * ...
13701 * PREDICATE <-- we are here "[1]"
13702 * PREDICATE <-- process "[parent::book]" first
13703 * SORT
13704 * COLLECT 'parent' 'name' 'node' book
13705 * NODE
13706 * ELEM Object is a number : 1
13707 */
13708 if (op->ch1 != -1)
13709 total +=
13710 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13711 CHECK_ERROR0;
13712 if (op->ch2 == -1)
13713 return (total);
13714 if (ctxt->value == NULL)
13715 return (total);
13716
13717 oldnode = ctxt->context->node;
13718
13719 #ifdef LIBXML_XPTR_ENABLED
13720 /*
13721 * Hum are we filtering the result of an XPointer expression
13722 */
13723 if (ctxt->value->type == XPATH_LOCATIONSET) {
13724 xmlLocationSetPtr newlocset = NULL;
13725 xmlLocationSetPtr oldlocset;
13726
13727 /*
13728 * Extract the old locset, and then evaluate the result of the
13729 * expression for all the element in the locset. use it to grow
13730 * up a new locset.
13731 */
13732 CHECK_TYPE0(XPATH_LOCATIONSET);
13733 obj = valuePop(ctxt);
13734 oldlocset = obj->user;
13735 ctxt->context->node = NULL;
13736
13737 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13738 ctxt->context->contextSize = 0;
13739 ctxt->context->proximityPosition = 0;
13740 if (op->ch2 != -1)
13741 total +=
13742 xmlXPathCompOpEval(ctxt,
13743 &comp->steps[op->ch2]);
13744 res = valuePop(ctxt);
13745 if (res != NULL) {
13746 xmlXPathReleaseObject(ctxt->context, res);
13747 }
13748 valuePush(ctxt, obj);
13749 CHECK_ERROR0;
13750 return (total);
13751 }
13752 newlocset = xmlXPtrLocationSetCreate(NULL);
13753
13754 for (i = 0; i < oldlocset->locNr; i++) {
13755 /*
13756 * Run the evaluation with a node list made of a
13757 * single item in the nodelocset.
13758 */
13759 ctxt->context->node = oldlocset->locTab[i]->user;
13760 ctxt->context->contextSize = oldlocset->locNr;
13761 ctxt->context->proximityPosition = i + 1;
13762 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13763 ctxt->context->node);
13764 valuePush(ctxt, tmp);
13765
13766 if (op->ch2 != -1)
13767 total +=
13768 xmlXPathCompOpEval(ctxt,
13769 &comp->steps[op->ch2]);
13770 if (ctxt->error != XPATH_EXPRESSION_OK) {
13771 xmlXPathFreeObject(obj);
13772 return(0);
13773 }
13774
13775 /*
13776 * The result of the evaluation need to be tested to
13777 * decided whether the filter succeeded or not
13778 */
13779 res = valuePop(ctxt);
13780 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13781 xmlXPtrLocationSetAdd(newlocset,
13782 xmlXPathObjectCopy
13783 (oldlocset->locTab[i]));
13784 }
13785
13786 /*
13787 * Cleanup
13788 */
13789 if (res != NULL) {
13790 xmlXPathReleaseObject(ctxt->context, res);
13791 }
13792 if (ctxt->value == tmp) {
13793 res = valuePop(ctxt);
13794 xmlXPathReleaseObject(ctxt->context, res);
13795 }
13796
13797 ctxt->context->node = NULL;
13798 }
13799
13800 /*
13801 * The result is used as the new evaluation locset.
13802 */
13803 xmlXPathReleaseObject(ctxt->context, obj);
13804 ctxt->context->node = NULL;
13805 ctxt->context->contextSize = -1;
13806 ctxt->context->proximityPosition = -1;
13807 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13808 ctxt->context->node = oldnode;
13809 return (total);
13810 }
13811 #endif /* LIBXML_XPTR_ENABLED */
13812
13813 /*
13814 * Extract the old set, and then evaluate the result of the
13815 * expression for all the element in the set. use it to grow
13816 * up a new set.
13817 */
13818 CHECK_TYPE0(XPATH_NODESET);
13819 obj = valuePop(ctxt);
13820 oldset = obj->nodesetval;
13821
13822 oldnode = ctxt->context->node;
13823 oldDoc = ctxt->context->doc;
13824 ctxt->context->node = NULL;
13825
13826 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13827 ctxt->context->contextSize = 0;
13828 ctxt->context->proximityPosition = 0;
13829 /*
13830 if (op->ch2 != -1)
13831 total +=
13832 xmlXPathCompOpEval(ctxt,
13833 &comp->steps[op->ch2]);
13834 CHECK_ERROR0;
13835 res = valuePop(ctxt);
13836 if (res != NULL)
13837 xmlXPathFreeObject(res);
13838 */
13839 valuePush(ctxt, obj);
13840 ctxt->context->node = oldnode;
13841 CHECK_ERROR0;
13842 } else {
13843 tmp = NULL;
13844 /*
13845 * Initialize the new set.
13846 * Also set the xpath document in case things like
13847 * key() evaluation are attempted on the predicate
13848 */
13849 newset = xmlXPathNodeSetCreate(NULL);
13850 /*
13851 * SPEC XPath 1.0:
13852 * "For each node in the node-set to be filtered, the
13853 * PredicateExpr is evaluated with that node as the
13854 * context node, with the number of nodes in the
13855 * node-set as the context size, and with the proximity
13856 * position of the node in the node-set with respect to
13857 * the axis as the context position;"
13858 * @oldset is the node-set" to be filtered.
13859 *
13860 * SPEC XPath 1.0:
13861 * "only predicates change the context position and
13862 * context size (see [2.4 Predicates])."
13863 * Example:
13864 * node-set context pos
13865 * nA 1
13866 * nB 2
13867 * nC 3
13868 * After applying predicate [position() > 1] :
13869 * node-set context pos
13870 * nB 1
13871 * nC 2
13872 *
13873 * removed the first node in the node-set, then
13874 * the context position of the
13875 */
13876 for (i = 0; i < oldset->nodeNr; i++) {
13877 /*
13878 * Run the evaluation with a node list made of
13879 * a single item in the nodeset.
13880 */
13881 ctxt->context->node = oldset->nodeTab[i];
13882 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13883 (oldset->nodeTab[i]->doc != NULL))
13884 ctxt->context->doc = oldset->nodeTab[i]->doc;
13885 if (tmp == NULL) {
13886 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13887 ctxt->context->node);
13888 } else {
13889 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13890 ctxt->context->node) < 0) {
13891 ctxt->error = XPATH_MEMORY_ERROR;
13892 }
13893 }
13894 valuePush(ctxt, tmp);
13895 ctxt->context->contextSize = oldset->nodeNr;
13896 ctxt->context->proximityPosition = i + 1;
13897 /*
13898 * Evaluate the predicate against the context node.
13899 * Can/should we optimize position() predicates
13900 * here (e.g. "[1]")?
13901 */
13902 if (op->ch2 != -1)
13903 total +=
13904 xmlXPathCompOpEval(ctxt,
13905 &comp->steps[op->ch2]);
13906 if (ctxt->error != XPATH_EXPRESSION_OK) {
13907 xmlXPathFreeNodeSet(newset);
13908 xmlXPathFreeObject(obj);
13909 return(0);
13910 }
13911
13912 /*
13913 * The result of the evaluation needs to be tested to
13914 * decide whether the filter succeeded or not
13915 */
13916 /*
13917 * OPTIMIZE TODO: Can we use
13918 * xmlXPathNodeSetAdd*Unique()* instead?
13919 */
13920 res = valuePop(ctxt);
13921 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13922 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i])
13923 < 0)
13924 ctxt->error = XPATH_MEMORY_ERROR;
13925 }
13926
13927 /*
13928 * Cleanup
13929 */
13930 if (res != NULL) {
13931 xmlXPathReleaseObject(ctxt->context, res);
13932 }
13933 if (ctxt->value == tmp) {
13934 valuePop(ctxt);
13935 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13936 /*
13937 * Don't free the temporary nodeset
13938 * in order to avoid massive recreation inside this
13939 * loop.
13940 */
13941 } else
13942 tmp = NULL;
13943 ctxt->context->node = NULL;
13944 }
13945 if (tmp != NULL)
13946 xmlXPathReleaseObject(ctxt->context, tmp);
13947 /*
13948 * The result is used as the new evaluation set.
13949 */
13950 xmlXPathReleaseObject(ctxt->context, obj);
13951 ctxt->context->node = NULL;
13952 ctxt->context->contextSize = -1;
13953 ctxt->context->proximityPosition = -1;
13954 /* may want to move this past the '}' later */
13955 ctxt->context->doc = oldDoc;
13956 valuePush(ctxt,
13957 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13958 }
13959 ctxt->context->node = oldnode;
13960 return (total);
13961 }
13962 case XPATH_OP_SORT:
13963 if (op->ch1 != -1)
13964 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13965 CHECK_ERROR0;
13966 if ((ctxt->value != NULL) &&
13967 (ctxt->value->type == XPATH_NODESET) &&
13968 (ctxt->value->nodesetval != NULL) &&
13969 (ctxt->value->nodesetval->nodeNr > 1))
13970 {
13971 xmlXPathNodeSetSort(ctxt->value->nodesetval);
13972 }
13973 return (total);
13974 #ifdef LIBXML_XPTR_ENABLED
13975 case XPATH_OP_RANGETO:{
13976 xmlXPathObjectPtr range;
13977 xmlXPathObjectPtr res, obj;
13978 xmlXPathObjectPtr tmp;
13979 xmlLocationSetPtr newlocset = NULL;
13980 xmlLocationSetPtr oldlocset;
13981 xmlNodeSetPtr oldset;
13982 int i, j;
13983
13984 if (op->ch1 != -1) {
13985 total +=
13986 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13987 CHECK_ERROR0;
13988 }
13989 if (ctxt->value == NULL) {
13990 XP_ERROR0(XPATH_INVALID_OPERAND);
13991 }
13992 if (op->ch2 == -1)
13993 return (total);
13994
13995 if (ctxt->value->type == XPATH_LOCATIONSET) {
13996 /*
13997 * Extract the old locset, and then evaluate the result of the
13998 * expression for all the element in the locset. use it to grow
13999 * up a new locset.
14000 */
14001 CHECK_TYPE0(XPATH_LOCATIONSET);
14002 obj = valuePop(ctxt);
14003 oldlocset = obj->user;
14004
14005 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
14006 ctxt->context->node = NULL;
14007 ctxt->context->contextSize = 0;
14008 ctxt->context->proximityPosition = 0;
14009 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
14010 res = valuePop(ctxt);
14011 if (res != NULL) {
14012 xmlXPathReleaseObject(ctxt->context, res);
14013 }
14014 valuePush(ctxt, obj);
14015 CHECK_ERROR0;
14016 return (total);
14017 }
14018 newlocset = xmlXPtrLocationSetCreate(NULL);
14019
14020 for (i = 0; i < oldlocset->locNr; i++) {
14021 /*
14022 * Run the evaluation with a node list made of a
14023 * single item in the nodelocset.
14024 */
14025 ctxt->context->node = oldlocset->locTab[i]->user;
14026 ctxt->context->contextSize = oldlocset->locNr;
14027 ctxt->context->proximityPosition = i + 1;
14028 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14029 ctxt->context->node);
14030 valuePush(ctxt, tmp);
14031
14032 if (op->ch2 != -1)
14033 total +=
14034 xmlXPathCompOpEval(ctxt,
14035 &comp->steps[op->ch2]);
14036 if (ctxt->error != XPATH_EXPRESSION_OK) {
14037 xmlXPathFreeObject(obj);
14038 return(0);
14039 }
14040
14041 res = valuePop(ctxt);
14042 if (res->type == XPATH_LOCATIONSET) {
14043 xmlLocationSetPtr rloc =
14044 (xmlLocationSetPtr)res->user;
14045 for (j=0; j<rloc->locNr; j++) {
14046 range = xmlXPtrNewRange(
14047 oldlocset->locTab[i]->user,
14048 oldlocset->locTab[i]->index,
14049 rloc->locTab[j]->user2,
14050 rloc->locTab[j]->index2);
14051 if (range != NULL) {
14052 xmlXPtrLocationSetAdd(newlocset, range);
14053 }
14054 }
14055 } else {
14056 range = xmlXPtrNewRangeNodeObject(
14057 (xmlNodePtr)oldlocset->locTab[i]->user, res);
14058 if (range != NULL) {
14059 xmlXPtrLocationSetAdd(newlocset,range);
14060 }
14061 }
14062
14063 /*
14064 * Cleanup
14065 */
14066 if (res != NULL) {
14067 xmlXPathReleaseObject(ctxt->context, res);
14068 }
14069 if (ctxt->value == tmp) {
14070 res = valuePop(ctxt);
14071 xmlXPathReleaseObject(ctxt->context, res);
14072 }
14073
14074 ctxt->context->node = NULL;
14075 }
14076 } else { /* Not a location set */
14077 CHECK_TYPE0(XPATH_NODESET);
14078 obj = valuePop(ctxt);
14079 oldset = obj->nodesetval;
14080 ctxt->context->node = NULL;
14081
14082 newlocset = xmlXPtrLocationSetCreate(NULL);
14083
14084 if (oldset != NULL) {
14085 for (i = 0; i < oldset->nodeNr; i++) {
14086 /*
14087 * Run the evaluation with a node list made of a single item
14088 * in the nodeset.
14089 */
14090 ctxt->context->node = oldset->nodeTab[i];
14091 /*
14092 * OPTIMIZE TODO: Avoid recreation for every iteration.
14093 */
14094 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14095 ctxt->context->node);
14096 valuePush(ctxt, tmp);
14097
14098 if (op->ch2 != -1)
14099 total +=
14100 xmlXPathCompOpEval(ctxt,
14101 &comp->steps[op->ch2]);
14102 if (ctxt->error != XPATH_EXPRESSION_OK) {
14103 xmlXPathFreeObject(obj);
14104 return(0);
14105 }
14106
14107 res = valuePop(ctxt);
14108 range =
14109 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
14110 res);
14111 if (range != NULL) {
14112 xmlXPtrLocationSetAdd(newlocset, range);
14113 }
14114
14115 /*
14116 * Cleanup
14117 */
14118 if (res != NULL) {
14119 xmlXPathReleaseObject(ctxt->context, res);
14120 }
14121 if (ctxt->value == tmp) {
14122 res = valuePop(ctxt);
14123 xmlXPathReleaseObject(ctxt->context, res);
14124 }
14125
14126 ctxt->context->node = NULL;
14127 }
14128 }
14129 }
14130
14131 /*
14132 * The result is used as the new evaluation set.
14133 */
14134 xmlXPathReleaseObject(ctxt->context, obj);
14135 ctxt->context->node = NULL;
14136 ctxt->context->contextSize = -1;
14137 ctxt->context->proximityPosition = -1;
14138 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
14139 return (total);
14140 }
14141 #endif /* LIBXML_XPTR_ENABLED */
14142 }
14143 xmlGenericError(xmlGenericErrorContext,
14144 "XPath: unknown precompiled operation %d\n", op->op);
14145 ctxt->error = XPATH_INVALID_OPERAND;
14146 return (total);
14147 }
14148
14149 /**
14150 * xmlXPathCompOpEvalToBoolean:
14151 * @ctxt: the XPath parser context
14152 *
14153 * Evaluates if the expression evaluates to true.
14154 *
14155 * Returns 1 if true, 0 if false and -1 on API or internal errors.
14156 */
14157 static int
14158 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
14159 xmlXPathStepOpPtr op,
14160 int isPredicate)
14161 {
14162 xmlXPathObjectPtr resObj = NULL;
14163
14164 start:
14165 /* comp = ctxt->comp; */
14166 switch (op->op) {
14167 case XPATH_OP_END:
14168 return (0);
14169 case XPATH_OP_VALUE:
14170 resObj = (xmlXPathObjectPtr) op->value4;
14171 if (isPredicate)
14172 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14173 return(xmlXPathCastToBoolean(resObj));
14174 case XPATH_OP_SORT:
14175 /*
14176 * We don't need sorting for boolean results. Skip this one.
14177 */
14178 if (op->ch1 != -1) {
14179 op = &ctxt->comp->steps[op->ch1];
14180 goto start;
14181 }
14182 return(0);
14183 case XPATH_OP_COLLECT:
14184 if (op->ch1 == -1)
14185 return(0);
14186
14187 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14188 if (ctxt->error != XPATH_EXPRESSION_OK)
14189 return(-1);
14190
14191 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14192 if (ctxt->error != XPATH_EXPRESSION_OK)
14193 return(-1);
14194
14195 resObj = valuePop(ctxt);
14196 if (resObj == NULL)
14197 return(-1);
14198 break;
14199 default:
14200 /*
14201 * Fallback to call xmlXPathCompOpEval().
14202 */
14203 xmlXPathCompOpEval(ctxt, op);
14204 if (ctxt->error != XPATH_EXPRESSION_OK)
14205 return(-1);
14206
14207 resObj = valuePop(ctxt);
14208 if (resObj == NULL)
14209 return(-1);
14210 break;
14211 }
14212
14213 if (resObj) {
14214 int res;
14215
14216 if (resObj->type == XPATH_BOOLEAN) {
14217 res = resObj->boolval;
14218 } else if (isPredicate) {
14219 /*
14220 * For predicates a result of type "number" is handled
14221 * differently:
14222 * SPEC XPath 1.0:
14223 * "If the result is a number, the result will be converted
14224 * to true if the number is equal to the context position
14225 * and will be converted to false otherwise;"
14226 */
14227 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14228 } else {
14229 res = xmlXPathCastToBoolean(resObj);
14230 }
14231 xmlXPathReleaseObject(ctxt->context, resObj);
14232 return(res);
14233 }
14234
14235 return(0);
14236 }
14237
14238 #ifdef XPATH_STREAMING
14239 /**
14240 * xmlXPathRunStreamEval:
14241 * @ctxt: the XPath parser context with the compiled expression
14242 *
14243 * Evaluate the Precompiled Streamable XPath expression in the given context.
14244 */
14245 static int
14246 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14247 xmlXPathObjectPtr *resultSeq, int toBool)
14248 {
14249 int max_depth, min_depth;
14250 int from_root;
14251 int ret, depth;
14252 int eval_all_nodes;
14253 xmlNodePtr cur = NULL, limit = NULL;
14254 xmlStreamCtxtPtr patstream = NULL;
14255
14256 int nb_nodes = 0;
14257
14258 if ((ctxt == NULL) || (comp == NULL))
14259 return(-1);
14260 max_depth = xmlPatternMaxDepth(comp);
14261 if (max_depth == -1)
14262 return(-1);
14263 if (max_depth == -2)
14264 max_depth = 10000;
14265 min_depth = xmlPatternMinDepth(comp);
14266 if (min_depth == -1)
14267 return(-1);
14268 from_root = xmlPatternFromRoot(comp);
14269 if (from_root < 0)
14270 return(-1);
14271 #if 0
14272 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14273 #endif
14274
14275 if (! toBool) {
14276 if (resultSeq == NULL)
14277 return(-1);
14278 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14279 if (*resultSeq == NULL)
14280 return(-1);
14281 }
14282
14283 /*
14284 * handle the special cases of "/" amd "." being matched
14285 */
14286 if (min_depth == 0) {
14287 if (from_root) {
14288 /* Select "/" */
14289 if (toBool)
14290 return(1);
14291 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14292 (xmlNodePtr) ctxt->doc);
14293 } else {
14294 /* Select "self::node()" */
14295 if (toBool)
14296 return(1);
14297 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14298 }
14299 }
14300 if (max_depth == 0) {
14301 return(0);
14302 }
14303
14304 if (from_root) {
14305 cur = (xmlNodePtr)ctxt->doc;
14306 } else if (ctxt->node != NULL) {
14307 switch (ctxt->node->type) {
14308 case XML_ELEMENT_NODE:
14309 case XML_DOCUMENT_NODE:
14310 case XML_DOCUMENT_FRAG_NODE:
14311 case XML_HTML_DOCUMENT_NODE:
14312 #ifdef LIBXML_DOCB_ENABLED
14313 case XML_DOCB_DOCUMENT_NODE:
14314 #endif
14315 cur = ctxt->node;
14316 break;
14317 case XML_ATTRIBUTE_NODE:
14318 case XML_TEXT_NODE:
14319 case XML_CDATA_SECTION_NODE:
14320 case XML_ENTITY_REF_NODE:
14321 case XML_ENTITY_NODE:
14322 case XML_PI_NODE:
14323 case XML_COMMENT_NODE:
14324 case XML_NOTATION_NODE:
14325 case XML_DTD_NODE:
14326 case XML_DOCUMENT_TYPE_NODE:
14327 case XML_ELEMENT_DECL:
14328 case XML_ATTRIBUTE_DECL:
14329 case XML_ENTITY_DECL:
14330 case XML_NAMESPACE_DECL:
14331 case XML_XINCLUDE_START:
14332 case XML_XINCLUDE_END:
14333 break;
14334 }
14335 limit = cur;
14336 }
14337 if (cur == NULL) {
14338 return(0);
14339 }
14340
14341 patstream = xmlPatternGetStreamCtxt(comp);
14342 if (patstream == NULL) {
14343 /*
14344 * QUESTION TODO: Is this an error?
14345 */
14346 return(0);
14347 }
14348
14349 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14350
14351 if (from_root) {
14352 ret = xmlStreamPush(patstream, NULL, NULL);
14353 if (ret < 0) {
14354 } else if (ret == 1) {
14355 if (toBool)
14356 goto return_1;
14357 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14358 }
14359 }
14360 depth = 0;
14361 goto scan_children;
14362 next_node:
14363 do {
14364 nb_nodes++;
14365
14366 switch (cur->type) {
14367 case XML_ELEMENT_NODE:
14368 case XML_TEXT_NODE:
14369 case XML_CDATA_SECTION_NODE:
14370 case XML_COMMENT_NODE:
14371 case XML_PI_NODE:
14372 if (cur->type == XML_ELEMENT_NODE) {
14373 ret = xmlStreamPush(patstream, cur->name,
14374 (cur->ns ? cur->ns->href : NULL));
14375 } else if (eval_all_nodes)
14376 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14377 else
14378 break;
14379
14380 if (ret < 0) {
14381 /* NOP. */
14382 } else if (ret == 1) {
14383 if (toBool)
14384 goto return_1;
14385 if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
14386 < 0) {
14387 ctxt->lastError.domain = XML_FROM_XPATH;
14388 ctxt->lastError.code = XML_ERR_NO_MEMORY;
14389 }
14390 }
14391 if ((cur->children == NULL) || (depth >= max_depth)) {
14392 ret = xmlStreamPop(patstream);
14393 while (cur->next != NULL) {
14394 cur = cur->next;
14395 if ((cur->type != XML_ENTITY_DECL) &&
14396 (cur->type != XML_DTD_NODE))
14397 goto next_node;
14398 }
14399 }
14400 default:
14401 break;
14402 }
14403
14404 scan_children:
14405 if (cur->type == XML_NAMESPACE_DECL) break;
14406 if ((cur->children != NULL) && (depth < max_depth)) {
14407 /*
14408 * Do not descend on entities declarations
14409 */
14410 if (cur->children->type != XML_ENTITY_DECL) {
14411 cur = cur->children;
14412 depth++;
14413 /*
14414 * Skip DTDs
14415 */
14416 if (cur->type != XML_DTD_NODE)
14417 continue;
14418 }
14419 }
14420
14421 if (cur == limit)
14422 break;
14423
14424 while (cur->next != NULL) {
14425 cur = cur->next;
14426 if ((cur->type != XML_ENTITY_DECL) &&
14427 (cur->type != XML_DTD_NODE))
14428 goto next_node;
14429 }
14430
14431 do {
14432 cur = cur->parent;
14433 depth--;
14434 if ((cur == NULL) || (cur == limit))
14435 goto done;
14436 if (cur->type == XML_ELEMENT_NODE) {
14437 ret = xmlStreamPop(patstream);
14438 } else if ((eval_all_nodes) &&
14439 ((cur->type == XML_TEXT_NODE) ||
14440 (cur->type == XML_CDATA_SECTION_NODE) ||
14441 (cur->type == XML_COMMENT_NODE) ||
14442 (cur->type == XML_PI_NODE)))
14443 {
14444 ret = xmlStreamPop(patstream);
14445 }
14446 if (cur->next != NULL) {
14447 cur = cur->next;
14448 break;
14449 }
14450 } while (cur != NULL);
14451
14452 } while ((cur != NULL) && (depth >= 0));
14453
14454 done:
14455
14456 #if 0
14457 printf("stream eval: checked %d nodes selected %d\n",
14458 nb_nodes, retObj->nodesetval->nodeNr);
14459 #endif
14460
14461 if (patstream)
14462 xmlFreeStreamCtxt(patstream);
14463 return(0);
14464
14465 return_1:
14466 if (patstream)
14467 xmlFreeStreamCtxt(patstream);
14468 return(1);
14469 }
14470 #endif /* XPATH_STREAMING */
14471
14472 /**
14473 * xmlXPathRunEval:
14474 * @ctxt: the XPath parser context with the compiled expression
14475 * @toBool: evaluate to a boolean result
14476 *
14477 * Evaluate the Precompiled XPath expression in the given context.
14478 */
14479 static int
14480 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14481 {
14482 xmlXPathCompExprPtr comp;
14483
14484 if ((ctxt == NULL) || (ctxt->comp == NULL))
14485 return(-1);
14486
14487 if (ctxt->valueTab == NULL) {
14488 /* Allocate the value stack */
14489 ctxt->valueTab = (xmlXPathObjectPtr *)
14490 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14491 if (ctxt->valueTab == NULL) {
14492 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14493 xmlFree(ctxt);
14494 }
14495 ctxt->valueNr = 0;
14496 ctxt->valueMax = 10;
14497 ctxt->value = NULL;
14498 ctxt->valueFrame = 0;
14499 }
14500 #ifdef XPATH_STREAMING
14501 if (ctxt->comp->stream) {
14502 int res;
14503
14504 if (toBool) {
14505 /*
14506 * Evaluation to boolean result.
14507 */
14508 res = xmlXPathRunStreamEval(ctxt->context,
14509 ctxt->comp->stream, NULL, 1);
14510 if (res != -1)
14511 return(res);
14512 } else {
14513 xmlXPathObjectPtr resObj = NULL;
14514
14515 /*
14516 * Evaluation to a sequence.
14517 */
14518 res = xmlXPathRunStreamEval(ctxt->context,
14519 ctxt->comp->stream, &resObj, 0);
14520
14521 if ((res != -1) && (resObj != NULL)) {
14522 valuePush(ctxt, resObj);
14523 return(0);
14524 }
14525 if (resObj != NULL)
14526 xmlXPathReleaseObject(ctxt->context, resObj);
14527 }
14528 /*
14529 * QUESTION TODO: This falls back to normal XPath evaluation
14530 * if res == -1. Is this intended?
14531 */
14532 }
14533 #endif
14534 comp = ctxt->comp;
14535 if (comp->last < 0) {
14536 xmlGenericError(xmlGenericErrorContext,
14537 "xmlXPathRunEval: last is less than zero\n");
14538 return(-1);
14539 }
14540 if (toBool)
14541 return(xmlXPathCompOpEvalToBoolean(ctxt,
14542 &comp->steps[comp->last], 0));
14543 else
14544 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14545
14546 return(0);
14547 }
14548
14549 /************************************************************************
14550 * *
14551 * Public interfaces *
14552 * *
14553 ************************************************************************/
14554
14555 /**
14556 * xmlXPathEvalPredicate:
14557 * @ctxt: the XPath context
14558 * @res: the Predicate Expression evaluation result
14559 *
14560 * Evaluate a predicate result for the current node.
14561 * A PredicateExpr is evaluated by evaluating the Expr and converting
14562 * the result to a boolean. If the result is a number, the result will
14563 * be converted to true if the number is equal to the position of the
14564 * context node in the context node list (as returned by the position
14565 * function) and will be converted to false otherwise; if the result
14566 * is not a number, then the result will be converted as if by a call
14567 * to the boolean function.
14568 *
14569 * Returns 1 if predicate is true, 0 otherwise
14570 */
14571 int
14572 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14573 if ((ctxt == NULL) || (res == NULL)) return(0);
14574 switch (res->type) {
14575 case XPATH_BOOLEAN:
14576 return(res->boolval);
14577 case XPATH_NUMBER:
14578 return(res->floatval == ctxt->proximityPosition);
14579 case XPATH_NODESET:
14580 case XPATH_XSLT_TREE:
14581 if (res->nodesetval == NULL)
14582 return(0);
14583 return(res->nodesetval->nodeNr != 0);
14584 case XPATH_STRING:
14585 return((res->stringval != NULL) &&
14586 (xmlStrlen(res->stringval) != 0));
14587 default:
14588 STRANGE
14589 }
14590 return(0);
14591 }
14592
14593 /**
14594 * xmlXPathEvaluatePredicateResult:
14595 * @ctxt: the XPath Parser context
14596 * @res: the Predicate Expression evaluation result
14597 *
14598 * Evaluate a predicate result for the current node.
14599 * A PredicateExpr is evaluated by evaluating the Expr and converting
14600 * the result to a boolean. If the result is a number, the result will
14601 * be converted to true if the number is equal to the position of the
14602 * context node in the context node list (as returned by the position
14603 * function) and will be converted to false otherwise; if the result
14604 * is not a number, then the result will be converted as if by a call
14605 * to the boolean function.
14606 *
14607 * Returns 1 if predicate is true, 0 otherwise
14608 */
14609 int
14610 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14611 xmlXPathObjectPtr res) {
14612 if ((ctxt == NULL) || (res == NULL)) return(0);
14613 switch (res->type) {
14614 case XPATH_BOOLEAN:
14615 return(res->boolval);
14616 case XPATH_NUMBER:
14617 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14618 return((res->floatval == ctxt->context->proximityPosition) &&
14619 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14620 #else
14621 return(res->floatval == ctxt->context->proximityPosition);
14622 #endif
14623 case XPATH_NODESET:
14624 case XPATH_XSLT_TREE:
14625 if (res->nodesetval == NULL)
14626 return(0);
14627 return(res->nodesetval->nodeNr != 0);
14628 case XPATH_STRING:
14629 return((res->stringval != NULL) && (res->stringval[0] != 0));
14630 #ifdef LIBXML_XPTR_ENABLED
14631 case XPATH_LOCATIONSET:{
14632 xmlLocationSetPtr ptr = res->user;
14633 if (ptr == NULL)
14634 return(0);
14635 return (ptr->locNr != 0);
14636 }
14637 #endif
14638 default:
14639 STRANGE
14640 }
14641 return(0);
14642 }
14643
14644 #ifdef XPATH_STREAMING
14645 /**
14646 * xmlXPathTryStreamCompile:
14647 * @ctxt: an XPath context
14648 * @str: the XPath expression
14649 *
14650 * Try to compile the XPath expression as a streamable subset.
14651 *
14652 * Returns the compiled expression or NULL if failed to compile.
14653 */
14654 static xmlXPathCompExprPtr
14655 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14656 /*
14657 * Optimization: use streaming patterns when the XPath expression can
14658 * be compiled to a stream lookup
14659 */
14660 xmlPatternPtr stream;
14661 xmlXPathCompExprPtr comp;
14662 xmlDictPtr dict = NULL;
14663 const xmlChar **namespaces = NULL;
14664 xmlNsPtr ns;
14665 int i, j;
14666
14667 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14668 (!xmlStrchr(str, '@'))) {
14669 const xmlChar *tmp;
14670
14671 /*
14672 * We don't try to handle expressions using the verbose axis
14673 * specifiers ("::"), just the simplied form at this point.
14674 * Additionally, if there is no list of namespaces available and
14675 * there's a ":" in the expression, indicating a prefixed QName,
14676 * then we won't try to compile either. xmlPatterncompile() needs
14677 * to have a list of namespaces at compilation time in order to
14678 * compile prefixed name tests.
14679 */
14680 tmp = xmlStrchr(str, ':');
14681 if ((tmp != NULL) &&
14682 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14683 return(NULL);
14684
14685 if (ctxt != NULL) {
14686 dict = ctxt->dict;
14687 if (ctxt->nsNr > 0) {
14688 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14689 if (namespaces == NULL) {
14690 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14691 return(NULL);
14692 }
14693 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14694 ns = ctxt->namespaces[j];
14695 namespaces[i++] = ns->href;
14696 namespaces[i++] = ns->prefix;
14697 }
14698 namespaces[i++] = NULL;
14699 namespaces[i] = NULL;
14700 }
14701 }
14702
14703 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14704 &namespaces[0]);
14705 if (namespaces != NULL) {
14706 xmlFree((xmlChar **)namespaces);
14707 }
14708 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14709 comp = xmlXPathNewCompExpr();
14710 if (comp == NULL) {
14711 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14712 return(NULL);
14713 }
14714 comp->stream = stream;
14715 comp->dict = dict;
14716 if (comp->dict)
14717 xmlDictReference(comp->dict);
14718 return(comp);
14719 }
14720 xmlFreePattern(stream);
14721 }
14722 return(NULL);
14723 }
14724 #endif /* XPATH_STREAMING */
14725
14726 static void
14727 xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14728 {
14729 /*
14730 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14731 * internal representation.
14732 */
14733
14734 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14735 (op->ch1 != -1) &&
14736 (op->ch2 == -1 /* no predicate */))
14737 {
14738 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14739
14740 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14741 ((xmlXPathAxisVal) prevop->value ==
14742 AXIS_DESCENDANT_OR_SELF) &&
14743 (prevop->ch2 == -1) &&
14744 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14745 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14746 {
14747 /*
14748 * This is a "descendant-or-self::node()" without predicates.
14749 * Try to eliminate it.
14750 */
14751
14752 switch ((xmlXPathAxisVal) op->value) {
14753 case AXIS_CHILD:
14754 case AXIS_DESCENDANT:
14755 /*
14756 * Convert "descendant-or-self::node()/child::" or
14757 * "descendant-or-self::node()/descendant::" to
14758 * "descendant::"
14759 */
14760 op->ch1 = prevop->ch1;
14761 op->value = AXIS_DESCENDANT;
14762 break;
14763 case AXIS_SELF:
14764 case AXIS_DESCENDANT_OR_SELF:
14765 /*
14766 * Convert "descendant-or-self::node()/self::" or
14767 * "descendant-or-self::node()/descendant-or-self::" to
14768 * to "descendant-or-self::"
14769 */
14770 op->ch1 = prevop->ch1;
14771 op->value = AXIS_DESCENDANT_OR_SELF;
14772 break;
14773 default:
14774 break;
14775 }
14776 }
14777 }
14778
14779 /* OP_VALUE has invalid ch1. */
14780 if (op->op == XPATH_OP_VALUE)
14781 return;
14782
14783 /* Recurse */
14784 if (op->ch1 != -1)
14785 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
14786 if (op->ch2 != -1)
14787 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
14788 }
14789
14790 /**
14791 * xmlXPathCtxtCompile:
14792 * @ctxt: an XPath context
14793 * @str: the XPath expression
14794 *
14795 * Compile an XPath expression
14796 *
14797 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14798 * the caller has to free the object.
14799 */
14800 xmlXPathCompExprPtr
14801 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14802 xmlXPathParserContextPtr pctxt;
14803 xmlXPathCompExprPtr comp;
14804
14805 #ifdef XPATH_STREAMING
14806 comp = xmlXPathTryStreamCompile(ctxt, str);
14807 if (comp != NULL)
14808 return(comp);
14809 #endif
14810
14811 xmlXPathInit();
14812
14813 pctxt = xmlXPathNewParserContext(str, ctxt);
14814 if (pctxt == NULL)
14815 return NULL;
14816 xmlXPathCompileExpr(pctxt, 1);
14817
14818 if( pctxt->error != XPATH_EXPRESSION_OK )
14819 {
14820 xmlXPathFreeParserContext(pctxt);
14821 return(NULL);
14822 }
14823
14824 if (*pctxt->cur != 0) {
14825 /*
14826 * aleksey: in some cases this line prints *second* error message
14827 * (see bug #78858) and probably this should be fixed.
14828 * However, we are not sure that all error messages are printed
14829 * out in other places. It's not critical so we leave it as-is for now
14830 */
14831 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14832 comp = NULL;
14833 } else {
14834 comp = pctxt->comp;
14835 pctxt->comp = NULL;
14836 }
14837 xmlXPathFreeParserContext(pctxt);
14838
14839 if (comp != NULL) {
14840 comp->expr = xmlStrdup(str);
14841 #ifdef DEBUG_EVAL_COUNTS
14842 comp->string = xmlStrdup(str);
14843 comp->nb = 0;
14844 #endif
14845 if ((comp->nbStep > 1) && (comp->last >= 0)) {
14846 xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
14847 }
14848 }
14849 return(comp);
14850 }
14851
14852 /**
14853 * xmlXPathCompile:
14854 * @str: the XPath expression
14855 *
14856 * Compile an XPath expression
14857 *
14858 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14859 * the caller has to free the object.
14860 */
14861 xmlXPathCompExprPtr
14862 xmlXPathCompile(const xmlChar *str) {
14863 return(xmlXPathCtxtCompile(NULL, str));
14864 }
14865
14866 /**
14867 * xmlXPathCompiledEvalInternal:
14868 * @comp: the compiled XPath expression
14869 * @ctxt: the XPath context
14870 * @resObj: the resulting XPath object or NULL
14871 * @toBool: 1 if only a boolean result is requested
14872 *
14873 * Evaluate the Precompiled XPath expression in the given context.
14874 * The caller has to free @resObj.
14875 *
14876 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14877 * the caller has to free the object.
14878 */
14879 static int
14880 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14881 xmlXPathContextPtr ctxt,
14882 xmlXPathObjectPtr *resObjPtr,
14883 int toBool)
14884 {
14885 xmlXPathParserContextPtr pctxt;
14886 xmlXPathObjectPtr resObj;
14887 #ifndef LIBXML_THREAD_ENABLED
14888 static int reentance = 0;
14889 #endif
14890 int res;
14891
14892 CHECK_CTXT_NEG(ctxt)
14893
14894 if (comp == NULL)
14895 return(-1);
14896 xmlXPathInit();
14897
14898 #ifndef LIBXML_THREAD_ENABLED
14899 reentance++;
14900 if (reentance > 1)
14901 xmlXPathDisableOptimizer = 1;
14902 #endif
14903
14904 #ifdef DEBUG_EVAL_COUNTS
14905 comp->nb++;
14906 if ((comp->string != NULL) && (comp->nb > 100)) {
14907 fprintf(stderr, "100 x %s\n", comp->string);
14908 comp->nb = 0;
14909 }
14910 #endif
14911 pctxt = xmlXPathCompParserContext(comp, ctxt);
14912 res = xmlXPathRunEval(pctxt, toBool);
14913
14914 if (pctxt->error != XPATH_EXPRESSION_OK) {
14915 resObj = NULL;
14916 } else {
14917 resObj = valuePop(pctxt);
14918 if (resObj == NULL) {
14919 if (!toBool)
14920 xmlGenericError(xmlGenericErrorContext,
14921 "xmlXPathCompiledEval: No result on the stack.\n");
14922 } else if (pctxt->valueNr > 0) {
14923 xmlGenericError(xmlGenericErrorContext,
14924 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14925 pctxt->valueNr);
14926 }
14927 }
14928
14929 if (resObjPtr)
14930 *resObjPtr = resObj;
14931 else
14932 xmlXPathReleaseObject(ctxt, resObj);
14933
14934 pctxt->comp = NULL;
14935 xmlXPathFreeParserContext(pctxt);
14936 #ifndef LIBXML_THREAD_ENABLED
14937 reentance--;
14938 #endif
14939
14940 return(res);
14941 }
14942
14943 /**
14944 * xmlXPathCompiledEval:
14945 * @comp: the compiled XPath expression
14946 * @ctx: the XPath context
14947 *
14948 * Evaluate the Precompiled XPath expression in the given context.
14949 *
14950 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14951 * the caller has to free the object.
14952 */
14953 xmlXPathObjectPtr
14954 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14955 {
14956 xmlXPathObjectPtr res = NULL;
14957
14958 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14959 return(res);
14960 }
14961
14962 /**
14963 * xmlXPathCompiledEvalToBoolean:
14964 * @comp: the compiled XPath expression
14965 * @ctxt: the XPath context
14966 *
14967 * Applies the XPath boolean() function on the result of the given
14968 * compiled expression.
14969 *
14970 * Returns 1 if the expression evaluated to true, 0 if to false and
14971 * -1 in API and internal errors.
14972 */
14973 int
14974 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14975 xmlXPathContextPtr ctxt)
14976 {
14977 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14978 }
14979
14980 /**
14981 * xmlXPathEvalExpr:
14982 * @ctxt: the XPath Parser context
14983 *
14984 * Parse and evaluate an XPath expression in the given context,
14985 * then push the result on the context stack
14986 */
14987 void
14988 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14989 #ifdef XPATH_STREAMING
14990 xmlXPathCompExprPtr comp;
14991 #endif
14992
14993 if (ctxt == NULL) return;
14994
14995 #ifdef XPATH_STREAMING
14996 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14997 if (comp != NULL) {
14998 if (ctxt->comp != NULL)
14999 xmlXPathFreeCompExpr(ctxt->comp);
15000 ctxt->comp = comp;
15001 } else
15002 #endif
15003 {
15004 xmlXPathCompileExpr(ctxt, 1);
15005 CHECK_ERROR;
15006
15007 /* Check for trailing characters. */
15008 if (*ctxt->cur != 0)
15009 XP_ERROR(XPATH_EXPR_ERROR);
15010
15011 if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0))
15012 xmlXPathOptimizeExpression(ctxt->comp,
15013 &ctxt->comp->steps[ctxt->comp->last]);
15014 }
15015
15016 xmlXPathRunEval(ctxt, 0);
15017 }
15018
15019 /**
15020 * xmlXPathEval:
15021 * @str: the XPath expression
15022 * @ctx: the XPath context
15023 *
15024 * Evaluate the XPath Location Path in the given context.
15025 *
15026 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15027 * the caller has to free the object.
15028 */
15029 xmlXPathObjectPtr
15030 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
15031 xmlXPathParserContextPtr ctxt;
15032 xmlXPathObjectPtr res;
15033
15034 CHECK_CTXT(ctx)
15035
15036 xmlXPathInit();
15037
15038 ctxt = xmlXPathNewParserContext(str, ctx);
15039 if (ctxt == NULL)
15040 return NULL;
15041 xmlXPathEvalExpr(ctxt);
15042
15043 if (ctxt->error != XPATH_EXPRESSION_OK) {
15044 res = NULL;
15045 } else {
15046 res = valuePop(ctxt);
15047 if (res == NULL) {
15048 xmlGenericError(xmlGenericErrorContext,
15049 "xmlXPathCompiledEval: No result on the stack.\n");
15050 } else if (ctxt->valueNr > 0) {
15051 xmlGenericError(xmlGenericErrorContext,
15052 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
15053 ctxt->valueNr);
15054 }
15055 }
15056
15057 xmlXPathFreeParserContext(ctxt);
15058 return(res);
15059 }
15060
15061 /**
15062 * xmlXPathSetContextNode:
15063 * @node: the node to to use as the context node
15064 * @ctx: the XPath context
15065 *
15066 * Sets 'node' as the context node. The node must be in the same
15067 * document as that associated with the context.
15068 *
15069 * Returns -1 in case of error or 0 if successful
15070 */
15071 int
15072 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
15073 if ((node == NULL) || (ctx == NULL))
15074 return(-1);
15075
15076 if (node->doc == ctx->doc) {
15077 ctx->node = node;
15078 return(0);
15079 }
15080 return(-1);
15081 }
15082
15083 /**
15084 * xmlXPathNodeEval:
15085 * @node: the node to to use as the context node
15086 * @str: the XPath expression
15087 * @ctx: the XPath context
15088 *
15089 * Evaluate the XPath Location Path in the given context. The node 'node'
15090 * is set as the context node. The context node is not restored.
15091 *
15092 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15093 * the caller has to free the object.
15094 */
15095 xmlXPathObjectPtr
15096 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
15097 if (str == NULL)
15098 return(NULL);
15099 if (xmlXPathSetContextNode(node, ctx) < 0)
15100 return(NULL);
15101 return(xmlXPathEval(str, ctx));
15102 }
15103
15104 /**
15105 * xmlXPathEvalExpression:
15106 * @str: the XPath expression
15107 * @ctxt: the XPath context
15108 *
15109 * Alias for xmlXPathEval().
15110 *
15111 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15112 * the caller has to free the object.
15113 */
15114 xmlXPathObjectPtr
15115 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
15116 return(xmlXPathEval(str, ctxt));
15117 }
15118
15119 /************************************************************************
15120 * *
15121 * Extra functions not pertaining to the XPath spec *
15122 * *
15123 ************************************************************************/
15124 /**
15125 * xmlXPathEscapeUriFunction:
15126 * @ctxt: the XPath Parser context
15127 * @nargs: the number of arguments
15128 *
15129 * Implement the escape-uri() XPath function
15130 * string escape-uri(string $str, bool $escape-reserved)
15131 *
15132 * This function applies the URI escaping rules defined in section 2 of [RFC
15133 * 2396] to the string supplied as $uri-part, which typically represents all
15134 * or part of a URI. The effect of the function is to replace any special
15135 * character in the string by an escape sequence of the form %xx%yy...,
15136 * where xxyy... is the hexadecimal representation of the octets used to
15137 * represent the character in UTF-8.
15138 *
15139 * The set of characters that are escaped depends on the setting of the
15140 * boolean argument $escape-reserved.
15141 *
15142 * If $escape-reserved is true, all characters are escaped other than lower
15143 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15144 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15145 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15146 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15147 * A-F).
15148 *
15149 * If $escape-reserved is false, the behavior differs in that characters
15150 * referred to in [RFC 2396] as reserved characters are not escaped. These
15151 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
15152 *
15153 * [RFC 2396] does not define whether escaped URIs should use lower case or
15154 * upper case for hexadecimal digits. To ensure that escaped URIs can be
15155 * compared using string comparison functions, this function must always use
15156 * the upper-case letters A-F.
15157 *
15158 * Generally, $escape-reserved should be set to true when escaping a string
15159 * that is to form a single part of a URI, and to false when escaping an
15160 * entire URI or URI reference.
15161 *
15162 * In the case of non-ascii characters, the string is encoded according to
15163 * utf-8 and then converted according to RFC 2396.
15164 *
15165 * Examples
15166 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
15167 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15168 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15169 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15170 *
15171 */
15172 static void
15173 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15174 xmlXPathObjectPtr str;
15175 int escape_reserved;
15176 xmlBufPtr target;
15177 xmlChar *cptr;
15178 xmlChar escape[4];
15179
15180 CHECK_ARITY(2);
15181
15182 escape_reserved = xmlXPathPopBoolean(ctxt);
15183
15184 CAST_TO_STRING;
15185 str = valuePop(ctxt);
15186
15187 target = xmlBufCreate();
15188
15189 escape[0] = '%';
15190 escape[3] = 0;
15191
15192 if (target) {
15193 for (cptr = str->stringval; *cptr; cptr++) {
15194 if ((*cptr >= 'A' && *cptr <= 'Z') ||
15195 (*cptr >= 'a' && *cptr <= 'z') ||
15196 (*cptr >= '0' && *cptr <= '9') ||
15197 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
15198 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
15199 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
15200 (*cptr == '%' &&
15201 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15202 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15203 (cptr[1] >= '0' && cptr[1] <= '9')) &&
15204 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15205 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15206 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15207 (!escape_reserved &&
15208 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15209 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15210 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15211 *cptr == ','))) {
15212 xmlBufAdd(target, cptr, 1);
15213 } else {
15214 if ((*cptr >> 4) < 10)
15215 escape[1] = '0' + (*cptr >> 4);
15216 else
15217 escape[1] = 'A' - 10 + (*cptr >> 4);
15218 if ((*cptr & 0xF) < 10)
15219 escape[2] = '0' + (*cptr & 0xF);
15220 else
15221 escape[2] = 'A' - 10 + (*cptr & 0xF);
15222
15223 xmlBufAdd(target, &escape[0], 3);
15224 }
15225 }
15226 }
15227 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15228 xmlBufContent(target)));
15229 xmlBufFree(target);
15230 xmlXPathReleaseObject(ctxt->context, str);
15231 }
15232
15233 /**
15234 * xmlXPathRegisterAllFunctions:
15235 * @ctxt: the XPath context
15236 *
15237 * Registers all default XPath functions in this context
15238 */
15239 void
15240 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15241 {
15242 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15243 xmlXPathBooleanFunction);
15244 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15245 xmlXPathCeilingFunction);
15246 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15247 xmlXPathCountFunction);
15248 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15249 xmlXPathConcatFunction);
15250 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15251 xmlXPathContainsFunction);
15252 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15253 xmlXPathIdFunction);
15254 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15255 xmlXPathFalseFunction);
15256 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15257 xmlXPathFloorFunction);
15258 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15259 xmlXPathLastFunction);
15260 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15261 xmlXPathLangFunction);
15262 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15263 xmlXPathLocalNameFunction);
15264 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15265 xmlXPathNotFunction);
15266 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15267 xmlXPathNameFunction);
15268 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15269 xmlXPathNamespaceURIFunction);
15270 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15271 xmlXPathNormalizeFunction);
15272 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15273 xmlXPathNumberFunction);
15274 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15275 xmlXPathPositionFunction);
15276 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15277 xmlXPathRoundFunction);
15278 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15279 xmlXPathStringFunction);
15280 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15281 xmlXPathStringLengthFunction);
15282 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15283 xmlXPathStartsWithFunction);
15284 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15285 xmlXPathSubstringFunction);
15286 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15287 xmlXPathSubstringBeforeFunction);
15288 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15289 xmlXPathSubstringAfterFunction);
15290 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15291 xmlXPathSumFunction);
15292 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15293 xmlXPathTrueFunction);
15294 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15295 xmlXPathTranslateFunction);
15296
15297 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15298 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15299 xmlXPathEscapeUriFunction);
15300 }
15301
15302 #endif /* LIBXML_XPATH_ENABLED */
15303 #define bottom_xpath
15304 #include "elfgcchack.h"