[LWIP] Fix src/core/init.c a bit (#1620)
[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 *
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 INFINITY
481 #define INFINITY (DBL_MAX * DBL_MAX)
482 #endif
483
484 #ifndef NAN
485 #define NAN (INFINITY / INFINITY)
486 #endif
487
488 double xmlXPathNAN;
489 double xmlXPathPINF;
490 double xmlXPathNINF;
491
492 /**
493 * xmlXPathInit:
494 *
495 * Initialize the XPath environment
496 */
497 void
498 xmlXPathInit(void) {
499 xmlXPathNAN = NAN;
500 xmlXPathPINF = INFINITY;
501 xmlXPathNINF = -INFINITY;
502 }
503
504 /**
505 * xmlXPathIsNaN:
506 * @val: a double value
507 *
508 * Returns 1 if the value is a NaN, 0 otherwise
509 */
510 int
511 xmlXPathIsNaN(double val) {
512 #ifdef isnan
513 return isnan(val);
514 #else
515 return !(val == val);
516 #endif
517 }
518
519 /**
520 * xmlXPathIsInf:
521 * @val: a double value
522 *
523 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
524 */
525 int
526 xmlXPathIsInf(double val) {
527 #ifdef isinf
528 return isinf(val) ? (val > 0 ? 1 : -1) : 0;
529 #else
530 if (val >= INFINITY)
531 return 1;
532 if (val <= -INFINITY)
533 return -1;
534 return 0;
535 #endif
536 }
537
538 #endif /* SCHEMAS or XPATH */
539
540 #ifdef LIBXML_XPATH_ENABLED
541
542 /*
543 * TODO: when compatibility allows remove all "fake node libxslt" strings
544 * the test should just be name[0] = ' '
545 */
546 #ifdef DEBUG_XPATH_EXPRESSION
547 #define DEBUG_STEP
548 #define DEBUG_EXPR
549 #define DEBUG_EVAL_COUNTS
550 #endif
551
552 static xmlNs xmlXPathXMLNamespaceStruct = {
553 NULL,
554 XML_NAMESPACE_DECL,
555 XML_XML_NAMESPACE,
556 BAD_CAST "xml",
557 NULL,
558 NULL
559 };
560 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
561 #ifndef LIBXML_THREAD_ENABLED
562 /*
563 * Optimizer is disabled only when threaded apps are detected while
564 * the library ain't compiled for thread safety.
565 */
566 static int xmlXPathDisableOptimizer = 0;
567 #endif
568
569 /************************************************************************
570 * *
571 * Error handling routines *
572 * *
573 ************************************************************************/
574
575 /**
576 * XP_ERRORNULL:
577 * @X: the error code
578 *
579 * Macro to raise an XPath error and return NULL.
580 */
581 #define XP_ERRORNULL(X) \
582 { xmlXPathErr(ctxt, X); return(NULL); }
583
584 /*
585 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
586 */
587 static const char *xmlXPathErrorMessages[] = {
588 "Ok\n",
589 "Number encoding\n",
590 "Unfinished literal\n",
591 "Start of literal\n",
592 "Expected $ for variable reference\n",
593 "Undefined variable\n",
594 "Invalid predicate\n",
595 "Invalid expression\n",
596 "Missing closing curly brace\n",
597 "Unregistered function\n",
598 "Invalid operand\n",
599 "Invalid type\n",
600 "Invalid number of arguments\n",
601 "Invalid context size\n",
602 "Invalid context position\n",
603 "Memory allocation error\n",
604 "Syntax error\n",
605 "Resource error\n",
606 "Sub resource error\n",
607 "Undefined namespace prefix\n",
608 "Encoding error\n",
609 "Char out of XML range\n",
610 "Invalid or incomplete context\n",
611 "Stack usage error\n",
612 "Forbidden variable\n",
613 "?? Unknown error ??\n" /* Must be last in the list! */
614 };
615 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
616 sizeof(xmlXPathErrorMessages[0])) - 1)
617 /**
618 * xmlXPathErrMemory:
619 * @ctxt: an XPath context
620 * @extra: extra informations
621 *
622 * Handle a redefinition of attribute error
623 */
624 static void
625 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
626 {
627 if (ctxt != NULL) {
628 if (extra) {
629 xmlChar buf[200];
630
631 xmlStrPrintf(buf, 200,
632 "Memory allocation failed : %s\n",
633 extra);
634 ctxt->lastError.message = (char *) xmlStrdup(buf);
635 } else {
636 ctxt->lastError.message = (char *)
637 xmlStrdup(BAD_CAST "Memory allocation failed\n");
638 }
639 ctxt->lastError.domain = XML_FROM_XPATH;
640 ctxt->lastError.code = XML_ERR_NO_MEMORY;
641 if (ctxt->error != NULL)
642 ctxt->error(ctxt->userData, &ctxt->lastError);
643 } else {
644 if (extra)
645 __xmlRaiseError(NULL, NULL, NULL,
646 NULL, NULL, XML_FROM_XPATH,
647 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
648 extra, NULL, NULL, 0, 0,
649 "Memory allocation failed : %s\n", extra);
650 else
651 __xmlRaiseError(NULL, NULL, NULL,
652 NULL, NULL, XML_FROM_XPATH,
653 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
654 NULL, NULL, NULL, 0, 0,
655 "Memory allocation failed\n");
656 }
657 }
658
659 /**
660 * xmlXPathPErrMemory:
661 * @ctxt: an XPath parser context
662 * @extra: extra informations
663 *
664 * Handle a redefinition of attribute error
665 */
666 static void
667 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
668 {
669 if (ctxt == NULL)
670 xmlXPathErrMemory(NULL, extra);
671 else {
672 ctxt->error = XPATH_MEMORY_ERROR;
673 xmlXPathErrMemory(ctxt->context, extra);
674 }
675 }
676
677 /**
678 * xmlXPathErr:
679 * @ctxt: a XPath parser context
680 * @error: the error code
681 *
682 * Handle an XPath error
683 */
684 void
685 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
686 {
687 if ((error < 0) || (error > MAXERRNO))
688 error = MAXERRNO;
689 if (ctxt == NULL) {
690 __xmlRaiseError(NULL, NULL, NULL,
691 NULL, NULL, XML_FROM_XPATH,
692 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
693 XML_ERR_ERROR, NULL, 0,
694 NULL, NULL, NULL, 0, 0,
695 "%s", xmlXPathErrorMessages[error]);
696 return;
697 }
698 ctxt->error = error;
699 if (ctxt->context == NULL) {
700 __xmlRaiseError(NULL, NULL, NULL,
701 NULL, NULL, XML_FROM_XPATH,
702 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
703 XML_ERR_ERROR, NULL, 0,
704 (const char *) ctxt->base, NULL, NULL,
705 ctxt->cur - ctxt->base, 0,
706 "%s", xmlXPathErrorMessages[error]);
707 return;
708 }
709
710 /* cleanup current last error */
711 xmlResetError(&ctxt->context->lastError);
712
713 ctxt->context->lastError.domain = XML_FROM_XPATH;
714 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
715 XPATH_EXPRESSION_OK;
716 ctxt->context->lastError.level = XML_ERR_ERROR;
717 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
718 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
719 ctxt->context->lastError.node = ctxt->context->debugNode;
720 if (ctxt->context->error != NULL) {
721 ctxt->context->error(ctxt->context->userData,
722 &ctxt->context->lastError);
723 } else {
724 __xmlRaiseError(NULL, NULL, NULL,
725 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
726 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
727 XML_ERR_ERROR, NULL, 0,
728 (const char *) ctxt->base, NULL, NULL,
729 ctxt->cur - ctxt->base, 0,
730 "%s", xmlXPathErrorMessages[error]);
731 }
732
733 }
734
735 /**
736 * xmlXPatherror:
737 * @ctxt: the XPath Parser context
738 * @file: the file name
739 * @line: the line number
740 * @no: the error number
741 *
742 * Formats an error message.
743 */
744 void
745 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
746 int line ATTRIBUTE_UNUSED, int no) {
747 xmlXPathErr(ctxt, no);
748 }
749
750 /************************************************************************
751 * *
752 * Utilities *
753 * *
754 ************************************************************************/
755
756 /**
757 * xsltPointerList:
758 *
759 * Pointer-list for various purposes.
760 */
761 typedef struct _xmlPointerList xmlPointerList;
762 typedef xmlPointerList *xmlPointerListPtr;
763 struct _xmlPointerList {
764 void **items;
765 int number;
766 int size;
767 };
768 /*
769 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
770 * and here, we should make the functions public.
771 */
772 static int
773 xmlPointerListAddSize(xmlPointerListPtr list,
774 void *item,
775 int initialSize)
776 {
777 if (list->items == NULL) {
778 if (initialSize <= 0)
779 initialSize = 1;
780 list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
781 if (list->items == NULL) {
782 xmlXPathErrMemory(NULL,
783 "xmlPointerListCreate: allocating item\n");
784 return(-1);
785 }
786 list->number = 0;
787 list->size = initialSize;
788 } else if (list->size <= list->number) {
789 if (list->size > 50000000) {
790 xmlXPathErrMemory(NULL,
791 "xmlPointerListAddSize: re-allocating item\n");
792 return(-1);
793 }
794 list->size *= 2;
795 list->items = (void **) xmlRealloc(list->items,
796 list->size * sizeof(void *));
797 if (list->items == NULL) {
798 xmlXPathErrMemory(NULL,
799 "xmlPointerListAddSize: re-allocating item\n");
800 list->size = 0;
801 return(-1);
802 }
803 }
804 list->items[list->number++] = item;
805 return(0);
806 }
807
808 /**
809 * xsltPointerListCreate:
810 *
811 * Creates an xsltPointerList structure.
812 *
813 * Returns a xsltPointerList structure or NULL in case of an error.
814 */
815 static xmlPointerListPtr
816 xmlPointerListCreate(int initialSize)
817 {
818 xmlPointerListPtr ret;
819
820 ret = xmlMalloc(sizeof(xmlPointerList));
821 if (ret == NULL) {
822 xmlXPathErrMemory(NULL,
823 "xmlPointerListCreate: allocating item\n");
824 return (NULL);
825 }
826 memset(ret, 0, sizeof(xmlPointerList));
827 if (initialSize > 0) {
828 xmlPointerListAddSize(ret, NULL, initialSize);
829 ret->number = 0;
830 }
831 return (ret);
832 }
833
834 /**
835 * xsltPointerListFree:
836 *
837 * Frees the xsltPointerList structure. This does not free
838 * the content of the list.
839 */
840 static void
841 xmlPointerListFree(xmlPointerListPtr list)
842 {
843 if (list == NULL)
844 return;
845 if (list->items != NULL)
846 xmlFree(list->items);
847 xmlFree(list);
848 }
849
850 /************************************************************************
851 * *
852 * Parser Types *
853 * *
854 ************************************************************************/
855
856 /*
857 * Types are private:
858 */
859
860 typedef enum {
861 XPATH_OP_END=0,
862 XPATH_OP_AND,
863 XPATH_OP_OR,
864 XPATH_OP_EQUAL,
865 XPATH_OP_CMP,
866 XPATH_OP_PLUS,
867 XPATH_OP_MULT,
868 XPATH_OP_UNION,
869 XPATH_OP_ROOT,
870 XPATH_OP_NODE,
871 XPATH_OP_COLLECT,
872 XPATH_OP_VALUE, /* 11 */
873 XPATH_OP_VARIABLE,
874 XPATH_OP_FUNCTION,
875 XPATH_OP_ARG,
876 XPATH_OP_PREDICATE,
877 XPATH_OP_FILTER, /* 16 */
878 XPATH_OP_SORT /* 17 */
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_SORT:
1529 fprintf(output, "SORT"); break;
1530 case XPATH_OP_COLLECT: {
1531 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1532 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1533 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1534 const xmlChar *prefix = op->value4;
1535 const xmlChar *name = op->value5;
1536
1537 fprintf(output, "COLLECT ");
1538 switch (axis) {
1539 case AXIS_ANCESTOR:
1540 fprintf(output, " 'ancestors' "); break;
1541 case AXIS_ANCESTOR_OR_SELF:
1542 fprintf(output, " 'ancestors-or-self' "); break;
1543 case AXIS_ATTRIBUTE:
1544 fprintf(output, " 'attributes' "); break;
1545 case AXIS_CHILD:
1546 fprintf(output, " 'child' "); break;
1547 case AXIS_DESCENDANT:
1548 fprintf(output, " 'descendant' "); break;
1549 case AXIS_DESCENDANT_OR_SELF:
1550 fprintf(output, " 'descendant-or-self' "); break;
1551 case AXIS_FOLLOWING:
1552 fprintf(output, " 'following' "); break;
1553 case AXIS_FOLLOWING_SIBLING:
1554 fprintf(output, " 'following-siblings' "); break;
1555 case AXIS_NAMESPACE:
1556 fprintf(output, " 'namespace' "); break;
1557 case AXIS_PARENT:
1558 fprintf(output, " 'parent' "); break;
1559 case AXIS_PRECEDING:
1560 fprintf(output, " 'preceding' "); break;
1561 case AXIS_PRECEDING_SIBLING:
1562 fprintf(output, " 'preceding-sibling' "); break;
1563 case AXIS_SELF:
1564 fprintf(output, " 'self' "); break;
1565 }
1566 switch (test) {
1567 case NODE_TEST_NONE:
1568 fprintf(output, "'none' "); break;
1569 case NODE_TEST_TYPE:
1570 fprintf(output, "'type' "); break;
1571 case NODE_TEST_PI:
1572 fprintf(output, "'PI' "); break;
1573 case NODE_TEST_ALL:
1574 fprintf(output, "'all' "); break;
1575 case NODE_TEST_NS:
1576 fprintf(output, "'namespace' "); break;
1577 case NODE_TEST_NAME:
1578 fprintf(output, "'name' "); break;
1579 }
1580 switch (type) {
1581 case NODE_TYPE_NODE:
1582 fprintf(output, "'node' "); break;
1583 case NODE_TYPE_COMMENT:
1584 fprintf(output, "'comment' "); break;
1585 case NODE_TYPE_TEXT:
1586 fprintf(output, "'text' "); break;
1587 case NODE_TYPE_PI:
1588 fprintf(output, "'PI' "); break;
1589 }
1590 if (prefix != NULL)
1591 fprintf(output, "%s:", prefix);
1592 if (name != NULL)
1593 fprintf(output, "%s", (const char *) name);
1594 break;
1595
1596 }
1597 case XPATH_OP_VALUE: {
1598 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1599
1600 fprintf(output, "ELEM ");
1601 xmlXPathDebugDumpObject(output, object, 0);
1602 goto finish;
1603 }
1604 case XPATH_OP_VARIABLE: {
1605 const xmlChar *prefix = op->value5;
1606 const xmlChar *name = op->value4;
1607
1608 if (prefix != NULL)
1609 fprintf(output, "VARIABLE %s:%s", prefix, name);
1610 else
1611 fprintf(output, "VARIABLE %s", name);
1612 break;
1613 }
1614 case XPATH_OP_FUNCTION: {
1615 int nbargs = op->value;
1616 const xmlChar *prefix = op->value5;
1617 const xmlChar *name = op->value4;
1618
1619 if (prefix != NULL)
1620 fprintf(output, "FUNCTION %s:%s(%d args)",
1621 prefix, name, nbargs);
1622 else
1623 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1624 break;
1625 }
1626 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1627 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1628 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1629 #ifdef LIBXML_XPTR_ENABLED
1630 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1631 #endif
1632 default:
1633 fprintf(output, "UNKNOWN %d\n", op->op); return;
1634 }
1635 fprintf(output, "\n");
1636 finish:
1637 if (op->ch1 >= 0)
1638 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1639 if (op->ch2 >= 0)
1640 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1641 }
1642
1643 /**
1644 * xmlXPathDebugDumpCompExpr:
1645 * @output: the FILE * for the output
1646 * @comp: the precompiled XPath expression
1647 * @depth: the indentation level.
1648 *
1649 * Dumps the tree of the compiled XPath expression.
1650 */
1651 void
1652 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1653 int depth) {
1654 int i;
1655 char shift[100];
1656
1657 if ((output == NULL) || (comp == NULL)) return;
1658
1659 for (i = 0;((i < depth) && (i < 25));i++)
1660 shift[2 * i] = shift[2 * i + 1] = ' ';
1661 shift[2 * i] = shift[2 * i + 1] = 0;
1662
1663 fprintf(output, "%s", shift);
1664
1665 #ifdef XPATH_STREAMING
1666 if (comp->stream) {
1667 fprintf(output, "Streaming Expression\n");
1668 } else
1669 #endif
1670 {
1671 fprintf(output, "Compiled Expression : %d elements\n",
1672 comp->nbStep);
1673 i = comp->last;
1674 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1675 }
1676 }
1677
1678 #ifdef XP_DEBUG_OBJ_USAGE
1679
1680 /*
1681 * XPath object usage related debugging variables.
1682 */
1683 static int xmlXPathDebugObjCounterUndefined = 0;
1684 static int xmlXPathDebugObjCounterNodeset = 0;
1685 static int xmlXPathDebugObjCounterBool = 0;
1686 static int xmlXPathDebugObjCounterNumber = 0;
1687 static int xmlXPathDebugObjCounterString = 0;
1688 static int xmlXPathDebugObjCounterPoint = 0;
1689 static int xmlXPathDebugObjCounterRange = 0;
1690 static int xmlXPathDebugObjCounterLocset = 0;
1691 static int xmlXPathDebugObjCounterUsers = 0;
1692 static int xmlXPathDebugObjCounterXSLTTree = 0;
1693 static int xmlXPathDebugObjCounterAll = 0;
1694
1695 static int xmlXPathDebugObjTotalUndefined = 0;
1696 static int xmlXPathDebugObjTotalNodeset = 0;
1697 static int xmlXPathDebugObjTotalBool = 0;
1698 static int xmlXPathDebugObjTotalNumber = 0;
1699 static int xmlXPathDebugObjTotalString = 0;
1700 static int xmlXPathDebugObjTotalPoint = 0;
1701 static int xmlXPathDebugObjTotalRange = 0;
1702 static int xmlXPathDebugObjTotalLocset = 0;
1703 static int xmlXPathDebugObjTotalUsers = 0;
1704 static int xmlXPathDebugObjTotalXSLTTree = 0;
1705 static int xmlXPathDebugObjTotalAll = 0;
1706
1707 static int xmlXPathDebugObjMaxUndefined = 0;
1708 static int xmlXPathDebugObjMaxNodeset = 0;
1709 static int xmlXPathDebugObjMaxBool = 0;
1710 static int xmlXPathDebugObjMaxNumber = 0;
1711 static int xmlXPathDebugObjMaxString = 0;
1712 static int xmlXPathDebugObjMaxPoint = 0;
1713 static int xmlXPathDebugObjMaxRange = 0;
1714 static int xmlXPathDebugObjMaxLocset = 0;
1715 static int xmlXPathDebugObjMaxUsers = 0;
1716 static int xmlXPathDebugObjMaxXSLTTree = 0;
1717 static int xmlXPathDebugObjMaxAll = 0;
1718
1719 /* REVISIT TODO: Make this static when committing */
1720 static void
1721 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1722 {
1723 if (ctxt != NULL) {
1724 if (ctxt->cache != NULL) {
1725 xmlXPathContextCachePtr cache =
1726 (xmlXPathContextCachePtr) ctxt->cache;
1727
1728 cache->dbgCachedAll = 0;
1729 cache->dbgCachedNodeset = 0;
1730 cache->dbgCachedString = 0;
1731 cache->dbgCachedBool = 0;
1732 cache->dbgCachedNumber = 0;
1733 cache->dbgCachedPoint = 0;
1734 cache->dbgCachedRange = 0;
1735 cache->dbgCachedLocset = 0;
1736 cache->dbgCachedUsers = 0;
1737 cache->dbgCachedXSLTTree = 0;
1738 cache->dbgCachedUndefined = 0;
1739
1740 cache->dbgReusedAll = 0;
1741 cache->dbgReusedNodeset = 0;
1742 cache->dbgReusedString = 0;
1743 cache->dbgReusedBool = 0;
1744 cache->dbgReusedNumber = 0;
1745 cache->dbgReusedPoint = 0;
1746 cache->dbgReusedRange = 0;
1747 cache->dbgReusedLocset = 0;
1748 cache->dbgReusedUsers = 0;
1749 cache->dbgReusedXSLTTree = 0;
1750 cache->dbgReusedUndefined = 0;
1751 }
1752 }
1753
1754 xmlXPathDebugObjCounterUndefined = 0;
1755 xmlXPathDebugObjCounterNodeset = 0;
1756 xmlXPathDebugObjCounterBool = 0;
1757 xmlXPathDebugObjCounterNumber = 0;
1758 xmlXPathDebugObjCounterString = 0;
1759 xmlXPathDebugObjCounterPoint = 0;
1760 xmlXPathDebugObjCounterRange = 0;
1761 xmlXPathDebugObjCounterLocset = 0;
1762 xmlXPathDebugObjCounterUsers = 0;
1763 xmlXPathDebugObjCounterXSLTTree = 0;
1764 xmlXPathDebugObjCounterAll = 0;
1765
1766 xmlXPathDebugObjTotalUndefined = 0;
1767 xmlXPathDebugObjTotalNodeset = 0;
1768 xmlXPathDebugObjTotalBool = 0;
1769 xmlXPathDebugObjTotalNumber = 0;
1770 xmlXPathDebugObjTotalString = 0;
1771 xmlXPathDebugObjTotalPoint = 0;
1772 xmlXPathDebugObjTotalRange = 0;
1773 xmlXPathDebugObjTotalLocset = 0;
1774 xmlXPathDebugObjTotalUsers = 0;
1775 xmlXPathDebugObjTotalXSLTTree = 0;
1776 xmlXPathDebugObjTotalAll = 0;
1777
1778 xmlXPathDebugObjMaxUndefined = 0;
1779 xmlXPathDebugObjMaxNodeset = 0;
1780 xmlXPathDebugObjMaxBool = 0;
1781 xmlXPathDebugObjMaxNumber = 0;
1782 xmlXPathDebugObjMaxString = 0;
1783 xmlXPathDebugObjMaxPoint = 0;
1784 xmlXPathDebugObjMaxRange = 0;
1785 xmlXPathDebugObjMaxLocset = 0;
1786 xmlXPathDebugObjMaxUsers = 0;
1787 xmlXPathDebugObjMaxXSLTTree = 0;
1788 xmlXPathDebugObjMaxAll = 0;
1789
1790 }
1791
1792 static void
1793 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1794 xmlXPathObjectType objType)
1795 {
1796 int isCached = 0;
1797
1798 if (ctxt != NULL) {
1799 if (ctxt->cache != NULL) {
1800 xmlXPathContextCachePtr cache =
1801 (xmlXPathContextCachePtr) ctxt->cache;
1802
1803 isCached = 1;
1804
1805 cache->dbgReusedAll++;
1806 switch (objType) {
1807 case XPATH_UNDEFINED:
1808 cache->dbgReusedUndefined++;
1809 break;
1810 case XPATH_NODESET:
1811 cache->dbgReusedNodeset++;
1812 break;
1813 case XPATH_BOOLEAN:
1814 cache->dbgReusedBool++;
1815 break;
1816 case XPATH_NUMBER:
1817 cache->dbgReusedNumber++;
1818 break;
1819 case XPATH_STRING:
1820 cache->dbgReusedString++;
1821 break;
1822 case XPATH_POINT:
1823 cache->dbgReusedPoint++;
1824 break;
1825 case XPATH_RANGE:
1826 cache->dbgReusedRange++;
1827 break;
1828 case XPATH_LOCATIONSET:
1829 cache->dbgReusedLocset++;
1830 break;
1831 case XPATH_USERS:
1832 cache->dbgReusedUsers++;
1833 break;
1834 case XPATH_XSLT_TREE:
1835 cache->dbgReusedXSLTTree++;
1836 break;
1837 default:
1838 break;
1839 }
1840 }
1841 }
1842
1843 switch (objType) {
1844 case XPATH_UNDEFINED:
1845 if (! isCached)
1846 xmlXPathDebugObjTotalUndefined++;
1847 xmlXPathDebugObjCounterUndefined++;
1848 if (xmlXPathDebugObjCounterUndefined >
1849 xmlXPathDebugObjMaxUndefined)
1850 xmlXPathDebugObjMaxUndefined =
1851 xmlXPathDebugObjCounterUndefined;
1852 break;
1853 case XPATH_NODESET:
1854 if (! isCached)
1855 xmlXPathDebugObjTotalNodeset++;
1856 xmlXPathDebugObjCounterNodeset++;
1857 if (xmlXPathDebugObjCounterNodeset >
1858 xmlXPathDebugObjMaxNodeset)
1859 xmlXPathDebugObjMaxNodeset =
1860 xmlXPathDebugObjCounterNodeset;
1861 break;
1862 case XPATH_BOOLEAN:
1863 if (! isCached)
1864 xmlXPathDebugObjTotalBool++;
1865 xmlXPathDebugObjCounterBool++;
1866 if (xmlXPathDebugObjCounterBool >
1867 xmlXPathDebugObjMaxBool)
1868 xmlXPathDebugObjMaxBool =
1869 xmlXPathDebugObjCounterBool;
1870 break;
1871 case XPATH_NUMBER:
1872 if (! isCached)
1873 xmlXPathDebugObjTotalNumber++;
1874 xmlXPathDebugObjCounterNumber++;
1875 if (xmlXPathDebugObjCounterNumber >
1876 xmlXPathDebugObjMaxNumber)
1877 xmlXPathDebugObjMaxNumber =
1878 xmlXPathDebugObjCounterNumber;
1879 break;
1880 case XPATH_STRING:
1881 if (! isCached)
1882 xmlXPathDebugObjTotalString++;
1883 xmlXPathDebugObjCounterString++;
1884 if (xmlXPathDebugObjCounterString >
1885 xmlXPathDebugObjMaxString)
1886 xmlXPathDebugObjMaxString =
1887 xmlXPathDebugObjCounterString;
1888 break;
1889 case XPATH_POINT:
1890 if (! isCached)
1891 xmlXPathDebugObjTotalPoint++;
1892 xmlXPathDebugObjCounterPoint++;
1893 if (xmlXPathDebugObjCounterPoint >
1894 xmlXPathDebugObjMaxPoint)
1895 xmlXPathDebugObjMaxPoint =
1896 xmlXPathDebugObjCounterPoint;
1897 break;
1898 case XPATH_RANGE:
1899 if (! isCached)
1900 xmlXPathDebugObjTotalRange++;
1901 xmlXPathDebugObjCounterRange++;
1902 if (xmlXPathDebugObjCounterRange >
1903 xmlXPathDebugObjMaxRange)
1904 xmlXPathDebugObjMaxRange =
1905 xmlXPathDebugObjCounterRange;
1906 break;
1907 case XPATH_LOCATIONSET:
1908 if (! isCached)
1909 xmlXPathDebugObjTotalLocset++;
1910 xmlXPathDebugObjCounterLocset++;
1911 if (xmlXPathDebugObjCounterLocset >
1912 xmlXPathDebugObjMaxLocset)
1913 xmlXPathDebugObjMaxLocset =
1914 xmlXPathDebugObjCounterLocset;
1915 break;
1916 case XPATH_USERS:
1917 if (! isCached)
1918 xmlXPathDebugObjTotalUsers++;
1919 xmlXPathDebugObjCounterUsers++;
1920 if (xmlXPathDebugObjCounterUsers >
1921 xmlXPathDebugObjMaxUsers)
1922 xmlXPathDebugObjMaxUsers =
1923 xmlXPathDebugObjCounterUsers;
1924 break;
1925 case XPATH_XSLT_TREE:
1926 if (! isCached)
1927 xmlXPathDebugObjTotalXSLTTree++;
1928 xmlXPathDebugObjCounterXSLTTree++;
1929 if (xmlXPathDebugObjCounterXSLTTree >
1930 xmlXPathDebugObjMaxXSLTTree)
1931 xmlXPathDebugObjMaxXSLTTree =
1932 xmlXPathDebugObjCounterXSLTTree;
1933 break;
1934 default:
1935 break;
1936 }
1937 if (! isCached)
1938 xmlXPathDebugObjTotalAll++;
1939 xmlXPathDebugObjCounterAll++;
1940 if (xmlXPathDebugObjCounterAll >
1941 xmlXPathDebugObjMaxAll)
1942 xmlXPathDebugObjMaxAll =
1943 xmlXPathDebugObjCounterAll;
1944 }
1945
1946 static void
1947 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1948 xmlXPathObjectType objType)
1949 {
1950 int isCached = 0;
1951
1952 if (ctxt != NULL) {
1953 if (ctxt->cache != NULL) {
1954 xmlXPathContextCachePtr cache =
1955 (xmlXPathContextCachePtr) ctxt->cache;
1956
1957 isCached = 1;
1958
1959 cache->dbgCachedAll++;
1960 switch (objType) {
1961 case XPATH_UNDEFINED:
1962 cache->dbgCachedUndefined++;
1963 break;
1964 case XPATH_NODESET:
1965 cache->dbgCachedNodeset++;
1966 break;
1967 case XPATH_BOOLEAN:
1968 cache->dbgCachedBool++;
1969 break;
1970 case XPATH_NUMBER:
1971 cache->dbgCachedNumber++;
1972 break;
1973 case XPATH_STRING:
1974 cache->dbgCachedString++;
1975 break;
1976 case XPATH_POINT:
1977 cache->dbgCachedPoint++;
1978 break;
1979 case XPATH_RANGE:
1980 cache->dbgCachedRange++;
1981 break;
1982 case XPATH_LOCATIONSET:
1983 cache->dbgCachedLocset++;
1984 break;
1985 case XPATH_USERS:
1986 cache->dbgCachedUsers++;
1987 break;
1988 case XPATH_XSLT_TREE:
1989 cache->dbgCachedXSLTTree++;
1990 break;
1991 default:
1992 break;
1993 }
1994
1995 }
1996 }
1997 switch (objType) {
1998 case XPATH_UNDEFINED:
1999 xmlXPathDebugObjCounterUndefined--;
2000 break;
2001 case XPATH_NODESET:
2002 xmlXPathDebugObjCounterNodeset--;
2003 break;
2004 case XPATH_BOOLEAN:
2005 xmlXPathDebugObjCounterBool--;
2006 break;
2007 case XPATH_NUMBER:
2008 xmlXPathDebugObjCounterNumber--;
2009 break;
2010 case XPATH_STRING:
2011 xmlXPathDebugObjCounterString--;
2012 break;
2013 case XPATH_POINT:
2014 xmlXPathDebugObjCounterPoint--;
2015 break;
2016 case XPATH_RANGE:
2017 xmlXPathDebugObjCounterRange--;
2018 break;
2019 case XPATH_LOCATIONSET:
2020 xmlXPathDebugObjCounterLocset--;
2021 break;
2022 case XPATH_USERS:
2023 xmlXPathDebugObjCounterUsers--;
2024 break;
2025 case XPATH_XSLT_TREE:
2026 xmlXPathDebugObjCounterXSLTTree--;
2027 break;
2028 default:
2029 break;
2030 }
2031 xmlXPathDebugObjCounterAll--;
2032 }
2033
2034 /* REVISIT TODO: Make this static when committing */
2035 static void
2036 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2037 {
2038 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2039 reqXSLTTree, reqUndefined;
2040 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2041 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2042 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2043 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2044 int leftObjs = xmlXPathDebugObjCounterAll;
2045
2046 reqAll = xmlXPathDebugObjTotalAll;
2047 reqNodeset = xmlXPathDebugObjTotalNodeset;
2048 reqString = xmlXPathDebugObjTotalString;
2049 reqBool = xmlXPathDebugObjTotalBool;
2050 reqNumber = xmlXPathDebugObjTotalNumber;
2051 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2052 reqUndefined = xmlXPathDebugObjTotalUndefined;
2053
2054 printf("# XPath object usage:\n");
2055
2056 if (ctxt != NULL) {
2057 if (ctxt->cache != NULL) {
2058 xmlXPathContextCachePtr cache =
2059 (xmlXPathContextCachePtr) ctxt->cache;
2060
2061 reAll = cache->dbgReusedAll;
2062 reqAll += reAll;
2063 reNodeset = cache->dbgReusedNodeset;
2064 reqNodeset += reNodeset;
2065 reString = cache->dbgReusedString;
2066 reqString += reString;
2067 reBool = cache->dbgReusedBool;
2068 reqBool += reBool;
2069 reNumber = cache->dbgReusedNumber;
2070 reqNumber += reNumber;
2071 reXSLTTree = cache->dbgReusedXSLTTree;
2072 reqXSLTTree += reXSLTTree;
2073 reUndefined = cache->dbgReusedUndefined;
2074 reqUndefined += reUndefined;
2075
2076 caAll = cache->dbgCachedAll;
2077 caBool = cache->dbgCachedBool;
2078 caNodeset = cache->dbgCachedNodeset;
2079 caString = cache->dbgCachedString;
2080 caNumber = cache->dbgCachedNumber;
2081 caXSLTTree = cache->dbgCachedXSLTTree;
2082 caUndefined = cache->dbgCachedUndefined;
2083
2084 if (cache->nodesetObjs)
2085 leftObjs -= cache->nodesetObjs->number;
2086 if (cache->stringObjs)
2087 leftObjs -= cache->stringObjs->number;
2088 if (cache->booleanObjs)
2089 leftObjs -= cache->booleanObjs->number;
2090 if (cache->numberObjs)
2091 leftObjs -= cache->numberObjs->number;
2092 if (cache->miscObjs)
2093 leftObjs -= cache->miscObjs->number;
2094 }
2095 }
2096
2097 printf("# all\n");
2098 printf("# total : %d\n", reqAll);
2099 printf("# left : %d\n", leftObjs);
2100 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
2101 printf("# reused : %d\n", reAll);
2102 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
2103
2104 printf("# node-sets\n");
2105 printf("# total : %d\n", reqNodeset);
2106 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
2107 printf("# reused : %d\n", reNodeset);
2108 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
2109
2110 printf("# strings\n");
2111 printf("# total : %d\n", reqString);
2112 printf("# created: %d\n", xmlXPathDebugObjTotalString);
2113 printf("# reused : %d\n", reString);
2114 printf("# max : %d\n", xmlXPathDebugObjMaxString);
2115
2116 printf("# booleans\n");
2117 printf("# total : %d\n", reqBool);
2118 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
2119 printf("# reused : %d\n", reBool);
2120 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
2121
2122 printf("# numbers\n");
2123 printf("# total : %d\n", reqNumber);
2124 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
2125 printf("# reused : %d\n", reNumber);
2126 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
2127
2128 printf("# XSLT result tree fragments\n");
2129 printf("# total : %d\n", reqXSLTTree);
2130 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2131 printf("# reused : %d\n", reXSLTTree);
2132 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
2133
2134 printf("# undefined\n");
2135 printf("# total : %d\n", reqUndefined);
2136 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
2137 printf("# reused : %d\n", reUndefined);
2138 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
2139
2140 }
2141
2142 #endif /* XP_DEBUG_OBJ_USAGE */
2143
2144 #endif /* LIBXML_DEBUG_ENABLED */
2145
2146 /************************************************************************
2147 * *
2148 * XPath object caching *
2149 * *
2150 ************************************************************************/
2151
2152 /**
2153 * xmlXPathNewCache:
2154 *
2155 * Create a new object cache
2156 *
2157 * Returns the xmlXPathCache just allocated.
2158 */
2159 static xmlXPathContextCachePtr
2160 xmlXPathNewCache(void)
2161 {
2162 xmlXPathContextCachePtr ret;
2163
2164 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2165 if (ret == NULL) {
2166 xmlXPathErrMemory(NULL, "creating object cache\n");
2167 return(NULL);
2168 }
2169 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
2170 ret->maxNodeset = 100;
2171 ret->maxString = 100;
2172 ret->maxBoolean = 100;
2173 ret->maxNumber = 100;
2174 ret->maxMisc = 100;
2175 return(ret);
2176 }
2177
2178 static void
2179 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2180 {
2181 int i;
2182 xmlXPathObjectPtr obj;
2183
2184 if (list == NULL)
2185 return;
2186
2187 for (i = 0; i < list->number; i++) {
2188 obj = list->items[i];
2189 /*
2190 * Note that it is already assured that we don't need to
2191 * look out for namespace nodes in the node-set.
2192 */
2193 if (obj->nodesetval != NULL) {
2194 if (obj->nodesetval->nodeTab != NULL)
2195 xmlFree(obj->nodesetval->nodeTab);
2196 xmlFree(obj->nodesetval);
2197 }
2198 xmlFree(obj);
2199 #ifdef XP_DEBUG_OBJ_USAGE
2200 xmlXPathDebugObjCounterAll--;
2201 #endif
2202 }
2203 xmlPointerListFree(list);
2204 }
2205
2206 static void
2207 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2208 {
2209 if (cache == NULL)
2210 return;
2211 if (cache->nodesetObjs)
2212 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2213 if (cache->stringObjs)
2214 xmlXPathCacheFreeObjectList(cache->stringObjs);
2215 if (cache->booleanObjs)
2216 xmlXPathCacheFreeObjectList(cache->booleanObjs);
2217 if (cache->numberObjs)
2218 xmlXPathCacheFreeObjectList(cache->numberObjs);
2219 if (cache->miscObjs)
2220 xmlXPathCacheFreeObjectList(cache->miscObjs);
2221 xmlFree(cache);
2222 }
2223
2224 /**
2225 * xmlXPathContextSetCache:
2226 *
2227 * @ctxt: the XPath context
2228 * @active: enables/disables (creates/frees) the cache
2229 * @value: a value with semantics dependant on @options
2230 * @options: options (currently only the value 0 is used)
2231 *
2232 * Creates/frees an object cache on the XPath context.
2233 * If activates XPath objects (xmlXPathObject) will be cached internally
2234 * to be reused.
2235 * @options:
2236 * 0: This will set the XPath object caching:
2237 * @value:
2238 * This will set the maximum number of XPath objects
2239 * to be cached per slot
2240 * There are 5 slots for: node-set, string, number, boolean, and
2241 * misc objects. Use <0 for the default number (100).
2242 * Other values for @options have currently no effect.
2243 *
2244 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2245 */
2246 int
2247 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2248 int active,
2249 int value,
2250 int options)
2251 {
2252 if (ctxt == NULL)
2253 return(-1);
2254 if (active) {
2255 xmlXPathContextCachePtr cache;
2256
2257 if (ctxt->cache == NULL) {
2258 ctxt->cache = xmlXPathNewCache();
2259 if (ctxt->cache == NULL)
2260 return(-1);
2261 }
2262 cache = (xmlXPathContextCachePtr) ctxt->cache;
2263 if (options == 0) {
2264 if (value < 0)
2265 value = 100;
2266 cache->maxNodeset = value;
2267 cache->maxString = value;
2268 cache->maxNumber = value;
2269 cache->maxBoolean = value;
2270 cache->maxMisc = value;
2271 }
2272 } else if (ctxt->cache != NULL) {
2273 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2274 ctxt->cache = NULL;
2275 }
2276 return(0);
2277 }
2278
2279 /**
2280 * xmlXPathCacheWrapNodeSet:
2281 * @ctxt: the XPath context
2282 * @val: the NodePtr value
2283 *
2284 * This is the cached version of xmlXPathWrapNodeSet().
2285 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2286 *
2287 * Returns the created or reused object.
2288 */
2289 static xmlXPathObjectPtr
2290 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2291 {
2292 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2293 xmlXPathContextCachePtr cache =
2294 (xmlXPathContextCachePtr) ctxt->cache;
2295
2296 if ((cache->miscObjs != NULL) &&
2297 (cache->miscObjs->number != 0))
2298 {
2299 xmlXPathObjectPtr ret;
2300
2301 ret = (xmlXPathObjectPtr)
2302 cache->miscObjs->items[--cache->miscObjs->number];
2303 ret->type = XPATH_NODESET;
2304 ret->nodesetval = val;
2305 #ifdef XP_DEBUG_OBJ_USAGE
2306 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2307 #endif
2308 return(ret);
2309 }
2310 }
2311
2312 return(xmlXPathWrapNodeSet(val));
2313
2314 }
2315
2316 /**
2317 * xmlXPathCacheWrapString:
2318 * @ctxt: the XPath context
2319 * @val: the xmlChar * value
2320 *
2321 * This is the cached version of xmlXPathWrapString().
2322 * Wraps the @val string into an XPath object.
2323 *
2324 * Returns the created or reused object.
2325 */
2326 static xmlXPathObjectPtr
2327 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2328 {
2329 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2330 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2331
2332 if ((cache->stringObjs != NULL) &&
2333 (cache->stringObjs->number != 0))
2334 {
2335
2336 xmlXPathObjectPtr ret;
2337
2338 ret = (xmlXPathObjectPtr)
2339 cache->stringObjs->items[--cache->stringObjs->number];
2340 ret->type = XPATH_STRING;
2341 ret->stringval = val;
2342 #ifdef XP_DEBUG_OBJ_USAGE
2343 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2344 #endif
2345 return(ret);
2346 } else if ((cache->miscObjs != NULL) &&
2347 (cache->miscObjs->number != 0))
2348 {
2349 xmlXPathObjectPtr ret;
2350 /*
2351 * Fallback to misc-cache.
2352 */
2353 ret = (xmlXPathObjectPtr)
2354 cache->miscObjs->items[--cache->miscObjs->number];
2355
2356 ret->type = XPATH_STRING;
2357 ret->stringval = val;
2358 #ifdef XP_DEBUG_OBJ_USAGE
2359 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2360 #endif
2361 return(ret);
2362 }
2363 }
2364 return(xmlXPathWrapString(val));
2365 }
2366
2367 /**
2368 * xmlXPathCacheNewNodeSet:
2369 * @ctxt: the XPath context
2370 * @val: the NodePtr value
2371 *
2372 * This is the cached version of xmlXPathNewNodeSet().
2373 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2374 * it with the single Node @val
2375 *
2376 * Returns the created or reused object.
2377 */
2378 static xmlXPathObjectPtr
2379 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2380 {
2381 if ((ctxt != NULL) && (ctxt->cache)) {
2382 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2383
2384 if ((cache->nodesetObjs != NULL) &&
2385 (cache->nodesetObjs->number != 0))
2386 {
2387 xmlXPathObjectPtr ret;
2388 /*
2389 * Use the nodset-cache.
2390 */
2391 ret = (xmlXPathObjectPtr)
2392 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2393 ret->type = XPATH_NODESET;
2394 ret->boolval = 0;
2395 if (val) {
2396 if ((ret->nodesetval->nodeMax == 0) ||
2397 (val->type == XML_NAMESPACE_DECL))
2398 {
2399 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2400 } else {
2401 ret->nodesetval->nodeTab[0] = val;
2402 ret->nodesetval->nodeNr = 1;
2403 }
2404 }
2405 #ifdef XP_DEBUG_OBJ_USAGE
2406 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2407 #endif
2408 return(ret);
2409 } else if ((cache->miscObjs != NULL) &&
2410 (cache->miscObjs->number != 0))
2411 {
2412 xmlXPathObjectPtr ret;
2413 /*
2414 * Fallback to misc-cache.
2415 */
2416
2417 ret = (xmlXPathObjectPtr)
2418 cache->miscObjs->items[--cache->miscObjs->number];
2419
2420 ret->type = XPATH_NODESET;
2421 ret->boolval = 0;
2422 ret->nodesetval = xmlXPathNodeSetCreate(val);
2423 if (ret->nodesetval == NULL) {
2424 ctxt->lastError.domain = XML_FROM_XPATH;
2425 ctxt->lastError.code = XML_ERR_NO_MEMORY;
2426 return(NULL);
2427 }
2428 #ifdef XP_DEBUG_OBJ_USAGE
2429 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2430 #endif
2431 return(ret);
2432 }
2433 }
2434 return(xmlXPathNewNodeSet(val));
2435 }
2436
2437 /**
2438 * xmlXPathCacheNewCString:
2439 * @ctxt: the XPath context
2440 * @val: the char * value
2441 *
2442 * This is the cached version of xmlXPathNewCString().
2443 * Acquire an xmlXPathObjectPtr of type string and of value @val
2444 *
2445 * Returns the created or reused object.
2446 */
2447 static xmlXPathObjectPtr
2448 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2449 {
2450 if ((ctxt != NULL) && (ctxt->cache)) {
2451 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2452
2453 if ((cache->stringObjs != NULL) &&
2454 (cache->stringObjs->number != 0))
2455 {
2456 xmlXPathObjectPtr ret;
2457
2458 ret = (xmlXPathObjectPtr)
2459 cache->stringObjs->items[--cache->stringObjs->number];
2460
2461 ret->type = XPATH_STRING;
2462 ret->stringval = xmlStrdup(BAD_CAST val);
2463 #ifdef XP_DEBUG_OBJ_USAGE
2464 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2465 #endif
2466 return(ret);
2467 } else if ((cache->miscObjs != NULL) &&
2468 (cache->miscObjs->number != 0))
2469 {
2470 xmlXPathObjectPtr ret;
2471
2472 ret = (xmlXPathObjectPtr)
2473 cache->miscObjs->items[--cache->miscObjs->number];
2474
2475 ret->type = XPATH_STRING;
2476 ret->stringval = xmlStrdup(BAD_CAST val);
2477 #ifdef XP_DEBUG_OBJ_USAGE
2478 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2479 #endif
2480 return(ret);
2481 }
2482 }
2483 return(xmlXPathNewCString(val));
2484 }
2485
2486 /**
2487 * xmlXPathCacheNewString:
2488 * @ctxt: the XPath context
2489 * @val: the xmlChar * value
2490 *
2491 * This is the cached version of xmlXPathNewString().
2492 * Acquire an xmlXPathObjectPtr of type string and of value @val
2493 *
2494 * Returns the created or reused object.
2495 */
2496 static xmlXPathObjectPtr
2497 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2498 {
2499 if ((ctxt != NULL) && (ctxt->cache)) {
2500 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2501
2502 if ((cache->stringObjs != NULL) &&
2503 (cache->stringObjs->number != 0))
2504 {
2505 xmlXPathObjectPtr ret;
2506
2507 ret = (xmlXPathObjectPtr)
2508 cache->stringObjs->items[--cache->stringObjs->number];
2509 ret->type = XPATH_STRING;
2510 if (val != NULL)
2511 ret->stringval = xmlStrdup(val);
2512 else
2513 ret->stringval = xmlStrdup((const xmlChar *)"");
2514 #ifdef XP_DEBUG_OBJ_USAGE
2515 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2516 #endif
2517 return(ret);
2518 } else if ((cache->miscObjs != NULL) &&
2519 (cache->miscObjs->number != 0))
2520 {
2521 xmlXPathObjectPtr ret;
2522
2523 ret = (xmlXPathObjectPtr)
2524 cache->miscObjs->items[--cache->miscObjs->number];
2525
2526 ret->type = XPATH_STRING;
2527 if (val != NULL)
2528 ret->stringval = xmlStrdup(val);
2529 else
2530 ret->stringval = xmlStrdup((const xmlChar *)"");
2531 #ifdef XP_DEBUG_OBJ_USAGE
2532 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2533 #endif
2534 return(ret);
2535 }
2536 }
2537 return(xmlXPathNewString(val));
2538 }
2539
2540 /**
2541 * xmlXPathCacheNewBoolean:
2542 * @ctxt: the XPath context
2543 * @val: the boolean value
2544 *
2545 * This is the cached version of xmlXPathNewBoolean().
2546 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2547 *
2548 * Returns the created or reused object.
2549 */
2550 static xmlXPathObjectPtr
2551 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2552 {
2553 if ((ctxt != NULL) && (ctxt->cache)) {
2554 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2555
2556 if ((cache->booleanObjs != NULL) &&
2557 (cache->booleanObjs->number != 0))
2558 {
2559 xmlXPathObjectPtr ret;
2560
2561 ret = (xmlXPathObjectPtr)
2562 cache->booleanObjs->items[--cache->booleanObjs->number];
2563 ret->type = XPATH_BOOLEAN;
2564 ret->boolval = (val != 0);
2565 #ifdef XP_DEBUG_OBJ_USAGE
2566 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2567 #endif
2568 return(ret);
2569 } else if ((cache->miscObjs != NULL) &&
2570 (cache->miscObjs->number != 0))
2571 {
2572 xmlXPathObjectPtr ret;
2573
2574 ret = (xmlXPathObjectPtr)
2575 cache->miscObjs->items[--cache->miscObjs->number];
2576
2577 ret->type = XPATH_BOOLEAN;
2578 ret->boolval = (val != 0);
2579 #ifdef XP_DEBUG_OBJ_USAGE
2580 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2581 #endif
2582 return(ret);
2583 }
2584 }
2585 return(xmlXPathNewBoolean(val));
2586 }
2587
2588 /**
2589 * xmlXPathCacheNewFloat:
2590 * @ctxt: the XPath context
2591 * @val: the double value
2592 *
2593 * This is the cached version of xmlXPathNewFloat().
2594 * Acquires an xmlXPathObjectPtr of type double and of value @val
2595 *
2596 * Returns the created or reused object.
2597 */
2598 static xmlXPathObjectPtr
2599 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2600 {
2601 if ((ctxt != NULL) && (ctxt->cache)) {
2602 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2603
2604 if ((cache->numberObjs != NULL) &&
2605 (cache->numberObjs->number != 0))
2606 {
2607 xmlXPathObjectPtr ret;
2608
2609 ret = (xmlXPathObjectPtr)
2610 cache->numberObjs->items[--cache->numberObjs->number];
2611 ret->type = XPATH_NUMBER;
2612 ret->floatval = val;
2613 #ifdef XP_DEBUG_OBJ_USAGE
2614 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2615 #endif
2616 return(ret);
2617 } else if ((cache->miscObjs != NULL) &&
2618 (cache->miscObjs->number != 0))
2619 {
2620 xmlXPathObjectPtr ret;
2621
2622 ret = (xmlXPathObjectPtr)
2623 cache->miscObjs->items[--cache->miscObjs->number];
2624
2625 ret->type = XPATH_NUMBER;
2626 ret->floatval = val;
2627 #ifdef XP_DEBUG_OBJ_USAGE
2628 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2629 #endif
2630 return(ret);
2631 }
2632 }
2633 return(xmlXPathNewFloat(val));
2634 }
2635
2636 /**
2637 * xmlXPathCacheConvertString:
2638 * @ctxt: the XPath context
2639 * @val: an XPath object
2640 *
2641 * This is the cached version of xmlXPathConvertString().
2642 * Converts an existing object to its string() equivalent
2643 *
2644 * Returns a created or reused object, the old one is freed (cached)
2645 * (or the operation is done directly on @val)
2646 */
2647
2648 static xmlXPathObjectPtr
2649 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2650 xmlChar *res = NULL;
2651
2652 if (val == NULL)
2653 return(xmlXPathCacheNewCString(ctxt, ""));
2654
2655 switch (val->type) {
2656 case XPATH_UNDEFINED:
2657 #ifdef DEBUG_EXPR
2658 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2659 #endif
2660 break;
2661 case XPATH_NODESET:
2662 case XPATH_XSLT_TREE:
2663 res = xmlXPathCastNodeSetToString(val->nodesetval);
2664 break;
2665 case XPATH_STRING:
2666 return(val);
2667 case XPATH_BOOLEAN:
2668 res = xmlXPathCastBooleanToString(val->boolval);
2669 break;
2670 case XPATH_NUMBER:
2671 res = xmlXPathCastNumberToString(val->floatval);
2672 break;
2673 case XPATH_USERS:
2674 case XPATH_POINT:
2675 case XPATH_RANGE:
2676 case XPATH_LOCATIONSET:
2677 TODO;
2678 break;
2679 }
2680 xmlXPathReleaseObject(ctxt, val);
2681 if (res == NULL)
2682 return(xmlXPathCacheNewCString(ctxt, ""));
2683 return(xmlXPathCacheWrapString(ctxt, res));
2684 }
2685
2686 /**
2687 * xmlXPathCacheObjectCopy:
2688 * @ctxt: the XPath context
2689 * @val: the original object
2690 *
2691 * This is the cached version of xmlXPathObjectCopy().
2692 * Acquire a copy of a given object
2693 *
2694 * Returns a created or reused created object.
2695 */
2696 static xmlXPathObjectPtr
2697 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2698 {
2699 if (val == NULL)
2700 return(NULL);
2701
2702 if (XP_HAS_CACHE(ctxt)) {
2703 switch (val->type) {
2704 case XPATH_NODESET:
2705 return(xmlXPathCacheWrapNodeSet(ctxt,
2706 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2707 case XPATH_STRING:
2708 return(xmlXPathCacheNewString(ctxt, val->stringval));
2709 case XPATH_BOOLEAN:
2710 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2711 case XPATH_NUMBER:
2712 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2713 default:
2714 break;
2715 }
2716 }
2717 return(xmlXPathObjectCopy(val));
2718 }
2719
2720 /**
2721 * xmlXPathCacheConvertBoolean:
2722 * @ctxt: the XPath context
2723 * @val: an XPath object
2724 *
2725 * This is the cached version of xmlXPathConvertBoolean().
2726 * Converts an existing object to its boolean() equivalent
2727 *
2728 * Returns a created or reused object, the old one is freed (or the operation
2729 * is done directly on @val)
2730 */
2731 static xmlXPathObjectPtr
2732 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2733 xmlXPathObjectPtr ret;
2734
2735 if (val == NULL)
2736 return(xmlXPathCacheNewBoolean(ctxt, 0));
2737 if (val->type == XPATH_BOOLEAN)
2738 return(val);
2739 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2740 xmlXPathReleaseObject(ctxt, val);
2741 return(ret);
2742 }
2743
2744 /**
2745 * xmlXPathCacheConvertNumber:
2746 * @ctxt: the XPath context
2747 * @val: an XPath object
2748 *
2749 * This is the cached version of xmlXPathConvertNumber().
2750 * Converts an existing object to its number() equivalent
2751 *
2752 * Returns a created or reused object, the old one is freed (or the operation
2753 * is done directly on @val)
2754 */
2755 static xmlXPathObjectPtr
2756 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2757 xmlXPathObjectPtr ret;
2758
2759 if (val == NULL)
2760 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2761 if (val->type == XPATH_NUMBER)
2762 return(val);
2763 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2764 xmlXPathReleaseObject(ctxt, val);
2765 return(ret);
2766 }
2767
2768 /************************************************************************
2769 * *
2770 * Parser stacks related functions and macros *
2771 * *
2772 ************************************************************************/
2773
2774 /**
2775 * xmlXPathSetFrame:
2776 * @ctxt: an XPath parser context
2777 *
2778 * Set the callee evaluation frame
2779 *
2780 * Returns the previous frame value to be restored once done
2781 */
2782 static int
2783 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2784 int ret;
2785
2786 if (ctxt == NULL)
2787 return(0);
2788 ret = ctxt->valueFrame;
2789 ctxt->valueFrame = ctxt->valueNr;
2790 return(ret);
2791 }
2792
2793 /**
2794 * xmlXPathPopFrame:
2795 * @ctxt: an XPath parser context
2796 * @frame: the previous frame value
2797 *
2798 * Remove the callee evaluation frame
2799 */
2800 static void
2801 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2802 if (ctxt == NULL)
2803 return;
2804 if (ctxt->valueNr < ctxt->valueFrame) {
2805 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2806 }
2807 ctxt->valueFrame = frame;
2808 }
2809
2810 /**
2811 * valuePop:
2812 * @ctxt: an XPath evaluation context
2813 *
2814 * Pops the top XPath object from the value stack
2815 *
2816 * Returns the XPath object just removed
2817 */
2818 xmlXPathObjectPtr
2819 valuePop(xmlXPathParserContextPtr ctxt)
2820 {
2821 xmlXPathObjectPtr ret;
2822
2823 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2824 return (NULL);
2825
2826 if (ctxt->valueNr <= ctxt->valueFrame) {
2827 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2828 return (NULL);
2829 }
2830
2831 ctxt->valueNr--;
2832 if (ctxt->valueNr > 0)
2833 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2834 else
2835 ctxt->value = NULL;
2836 ret = ctxt->valueTab[ctxt->valueNr];
2837 ctxt->valueTab[ctxt->valueNr] = NULL;
2838 return (ret);
2839 }
2840 /**
2841 * valuePush:
2842 * @ctxt: an XPath evaluation context
2843 * @value: the XPath object
2844 *
2845 * Pushes a new XPath object on top of the value stack
2846 *
2847 * returns the number of items on the value stack
2848 */
2849 int
2850 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2851 {
2852 if ((ctxt == NULL) || (value == NULL)) return(-1);
2853 if (ctxt->valueNr >= ctxt->valueMax) {
2854 xmlXPathObjectPtr *tmp;
2855
2856 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2857 xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
2858 ctxt->error = XPATH_MEMORY_ERROR;
2859 return (0);
2860 }
2861 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2862 2 * ctxt->valueMax *
2863 sizeof(ctxt->valueTab[0]));
2864 if (tmp == NULL) {
2865 xmlXPathErrMemory(NULL, "pushing value\n");
2866 ctxt->error = XPATH_MEMORY_ERROR;
2867 return (0);
2868 }
2869 ctxt->valueMax *= 2;
2870 ctxt->valueTab = tmp;
2871 }
2872 ctxt->valueTab[ctxt->valueNr] = value;
2873 ctxt->value = value;
2874 return (ctxt->valueNr++);
2875 }
2876
2877 /**
2878 * xmlXPathPopBoolean:
2879 * @ctxt: an XPath parser context
2880 *
2881 * Pops a boolean from the stack, handling conversion if needed.
2882 * Check error with #xmlXPathCheckError.
2883 *
2884 * Returns the boolean
2885 */
2886 int
2887 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2888 xmlXPathObjectPtr obj;
2889 int ret;
2890
2891 obj = valuePop(ctxt);
2892 if (obj == NULL) {
2893 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2894 return(0);
2895 }
2896 if (obj->type != XPATH_BOOLEAN)
2897 ret = xmlXPathCastToBoolean(obj);
2898 else
2899 ret = obj->boolval;
2900 xmlXPathReleaseObject(ctxt->context, obj);
2901 return(ret);
2902 }
2903
2904 /**
2905 * xmlXPathPopNumber:
2906 * @ctxt: an XPath parser context
2907 *
2908 * Pops a number from the stack, handling conversion if needed.
2909 * Check error with #xmlXPathCheckError.
2910 *
2911 * Returns the number
2912 */
2913 double
2914 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2915 xmlXPathObjectPtr obj;
2916 double ret;
2917
2918 obj = valuePop(ctxt);
2919 if (obj == NULL) {
2920 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2921 return(0);
2922 }
2923 if (obj->type != XPATH_NUMBER)
2924 ret = xmlXPathCastToNumber(obj);
2925 else
2926 ret = obj->floatval;
2927 xmlXPathReleaseObject(ctxt->context, obj);
2928 return(ret);
2929 }
2930
2931 /**
2932 * xmlXPathPopString:
2933 * @ctxt: an XPath parser context
2934 *
2935 * Pops a string from the stack, handling conversion if needed.
2936 * Check error with #xmlXPathCheckError.
2937 *
2938 * Returns the string
2939 */
2940 xmlChar *
2941 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2942 xmlXPathObjectPtr obj;
2943 xmlChar * ret;
2944
2945 obj = valuePop(ctxt);
2946 if (obj == NULL) {
2947 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2948 return(NULL);
2949 }
2950 ret = xmlXPathCastToString(obj); /* this does required strdup */
2951 /* TODO: needs refactoring somewhere else */
2952 if (obj->stringval == ret)
2953 obj->stringval = NULL;
2954 xmlXPathReleaseObject(ctxt->context, obj);
2955 return(ret);
2956 }
2957
2958 /**
2959 * xmlXPathPopNodeSet:
2960 * @ctxt: an XPath parser context
2961 *
2962 * Pops a node-set from the stack, handling conversion if needed.
2963 * Check error with #xmlXPathCheckError.
2964 *
2965 * Returns the node-set
2966 */
2967 xmlNodeSetPtr
2968 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2969 xmlXPathObjectPtr obj;
2970 xmlNodeSetPtr ret;
2971
2972 if (ctxt == NULL) return(NULL);
2973 if (ctxt->value == NULL) {
2974 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2975 return(NULL);
2976 }
2977 if (!xmlXPathStackIsNodeSet(ctxt)) {
2978 xmlXPathSetTypeError(ctxt);
2979 return(NULL);
2980 }
2981 obj = valuePop(ctxt);
2982 ret = obj->nodesetval;
2983 #if 0
2984 /* to fix memory leak of not clearing obj->user */
2985 if (obj->boolval && obj->user != NULL)
2986 xmlFreeNodeList((xmlNodePtr) obj->user);
2987 #endif
2988 obj->nodesetval = NULL;
2989 xmlXPathReleaseObject(ctxt->context, obj);
2990 return(ret);
2991 }
2992
2993 /**
2994 * xmlXPathPopExternal:
2995 * @ctxt: an XPath parser context
2996 *
2997 * Pops an external object from the stack, handling conversion if needed.
2998 * Check error with #xmlXPathCheckError.
2999 *
3000 * Returns the object
3001 */
3002 void *
3003 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3004 xmlXPathObjectPtr obj;
3005 void * ret;
3006
3007 if ((ctxt == NULL) || (ctxt->value == NULL)) {
3008 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3009 return(NULL);
3010 }
3011 if (ctxt->value->type != XPATH_USERS) {
3012 xmlXPathSetTypeError(ctxt);
3013 return(NULL);
3014 }
3015 obj = valuePop(ctxt);
3016 ret = obj->user;
3017 obj->user = NULL;
3018 xmlXPathReleaseObject(ctxt->context, obj);
3019 return(ret);
3020 }
3021
3022 /*
3023 * Macros for accessing the content. Those should be used only by the parser,
3024 * and not exported.
3025 *
3026 * Dirty macros, i.e. one need to make assumption on the context to use them
3027 *
3028 * CUR_PTR return the current pointer to the xmlChar to be parsed.
3029 * CUR returns the current xmlChar value, i.e. a 8 bit value
3030 * in ISO-Latin or UTF-8.
3031 * This should be used internally by the parser
3032 * only to compare to ASCII values otherwise it would break when
3033 * running with UTF-8 encoding.
3034 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
3035 * to compare on ASCII based substring.
3036 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3037 * strings within the parser.
3038 * CURRENT Returns the current char value, with the full decoding of
3039 * UTF-8 if we are using this mode. It returns an int.
3040 * NEXT Skip to the next character, this does the proper decoding
3041 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
3042 * It returns the pointer to the current xmlChar.
3043 */
3044
3045 #define CUR (*ctxt->cur)
3046 #define SKIP(val) ctxt->cur += (val)
3047 #define NXT(val) ctxt->cur[(val)]
3048 #define CUR_PTR ctxt->cur
3049 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3050
3051 #define COPY_BUF(l,b,i,v) \
3052 if (l == 1) b[i++] = (xmlChar) v; \
3053 else i += xmlCopyChar(l,&b[i],v)
3054
3055 #define NEXTL(l) ctxt->cur += l
3056
3057 #define SKIP_BLANKS \
3058 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3059
3060 #define CURRENT (*ctxt->cur)
3061 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
3062
3063
3064 #ifndef DBL_DIG
3065 #define DBL_DIG 16
3066 #endif
3067 #ifndef DBL_EPSILON
3068 #define DBL_EPSILON 1E-9
3069 #endif
3070
3071 #define UPPER_DOUBLE 1E9
3072 #define LOWER_DOUBLE 1E-5
3073 #define LOWER_DOUBLE_EXP 5
3074
3075 #define INTEGER_DIGITS DBL_DIG
3076 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3077 #define EXPONENT_DIGITS (3 + 2)
3078
3079 /**
3080 * xmlXPathFormatNumber:
3081 * @number: number to format
3082 * @buffer: output buffer
3083 * @buffersize: size of output buffer
3084 *
3085 * Convert the number into a string representation.
3086 */
3087 static void
3088 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3089 {
3090 switch (xmlXPathIsInf(number)) {
3091 case 1:
3092 if (buffersize > (int)sizeof("Infinity"))
3093 snprintf(buffer, buffersize, "Infinity");
3094 break;
3095 case -1:
3096 if (buffersize > (int)sizeof("-Infinity"))
3097 snprintf(buffer, buffersize, "-Infinity");
3098 break;
3099 default:
3100 if (xmlXPathIsNaN(number)) {
3101 if (buffersize > (int)sizeof("NaN"))
3102 snprintf(buffer, buffersize, "NaN");
3103 } else if (number == 0) {
3104 /* Omit sign for negative zero. */
3105 snprintf(buffer, buffersize, "0");
3106 } else if ((number > INT_MIN) && (number < INT_MAX) &&
3107 (number == (int) number)) {
3108 char work[30];
3109 char *ptr, *cur;
3110 int value = (int) number;
3111
3112 ptr = &buffer[0];
3113 if (value == 0) {
3114 *ptr++ = '0';
3115 } else {
3116 snprintf(work, 29, "%d", value);
3117 cur = &work[0];
3118 while ((*cur) && (ptr - buffer < buffersize)) {
3119 *ptr++ = *cur++;
3120 }
3121 }
3122 if (ptr - buffer < buffersize) {
3123 *ptr = 0;
3124 } else if (buffersize > 0) {
3125 ptr--;
3126 *ptr = 0;
3127 }
3128 } else {
3129 /*
3130 For the dimension of work,
3131 DBL_DIG is number of significant digits
3132 EXPONENT is only needed for "scientific notation"
3133 3 is sign, decimal point, and terminating zero
3134 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3135 Note that this dimension is slightly (a few characters)
3136 larger than actually necessary.
3137 */
3138 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3139 int integer_place, fraction_place;
3140 char *ptr;
3141 char *after_fraction;
3142 double absolute_value;
3143 int size;
3144
3145 absolute_value = fabs(number);
3146
3147 /*
3148 * First choose format - scientific or regular floating point.
3149 * In either case, result is in work, and after_fraction points
3150 * just past the fractional part.
3151 */
3152 if ( ((absolute_value > UPPER_DOUBLE) ||
3153 (absolute_value < LOWER_DOUBLE)) &&
3154 (absolute_value != 0.0) ) {
3155 /* Use scientific notation */
3156 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3157 fraction_place = DBL_DIG - 1;
3158 size = snprintf(work, sizeof(work),"%*.*e",
3159 integer_place, fraction_place, number);
3160 while ((size > 0) && (work[size] != 'e')) size--;
3161
3162 }
3163 else {
3164 /* Use regular notation */
3165 if (absolute_value > 0.0) {
3166 integer_place = (int)log10(absolute_value);
3167 if (integer_place > 0)
3168 fraction_place = DBL_DIG - integer_place - 1;
3169 else
3170 fraction_place = DBL_DIG - integer_place;
3171 } else {
3172 fraction_place = 1;
3173 }
3174 size = snprintf(work, sizeof(work), "%0.*f",
3175 fraction_place, number);
3176 }
3177
3178 /* Remove leading spaces sometimes inserted by snprintf */
3179 while (work[0] == ' ') {
3180 for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3181 size--;
3182 }
3183
3184 /* Remove fractional trailing zeroes */
3185 after_fraction = work + size;
3186 ptr = after_fraction;
3187 while (*(--ptr) == '0')
3188 ;
3189 if (*ptr != '.')
3190 ptr++;
3191 while ((*ptr++ = *after_fraction++) != 0);
3192
3193 /* Finally copy result back to caller */
3194 size = strlen(work) + 1;
3195 if (size > buffersize) {
3196 work[buffersize - 1] = 0;
3197 size = buffersize;
3198 }
3199 memmove(buffer, work, size);
3200 }
3201 break;
3202 }
3203 }
3204
3205
3206 /************************************************************************
3207 * *
3208 * Routines to handle NodeSets *
3209 * *
3210 ************************************************************************/
3211
3212 /**
3213 * xmlXPathOrderDocElems:
3214 * @doc: an input document
3215 *
3216 * Call this routine to speed up XPath computation on static documents.
3217 * This stamps all the element nodes with the document order
3218 * Like for line information, the order is kept in the element->content
3219 * field, the value stored is actually - the node number (starting at -1)
3220 * to be able to differentiate from line numbers.
3221 *
3222 * Returns the number of elements found in the document or -1 in case
3223 * of error.
3224 */
3225 long
3226 xmlXPathOrderDocElems(xmlDocPtr doc) {
3227 ptrdiff_t count = 0;
3228 xmlNodePtr cur;
3229
3230 if (doc == NULL)
3231 return(-1);
3232 cur = doc->children;
3233 while (cur != NULL) {
3234 if (cur->type == XML_ELEMENT_NODE) {
3235 cur->content = (void *) (-(++count));
3236 if (cur->children != NULL) {
3237 cur = cur->children;
3238 continue;
3239 }
3240 }
3241 if (cur->next != NULL) {
3242 cur = cur->next;
3243 continue;
3244 }
3245 do {
3246 cur = cur->parent;
3247 if (cur == NULL)
3248 break;
3249 if (cur == (xmlNodePtr) doc) {
3250 cur = NULL;
3251 break;
3252 }
3253 if (cur->next != NULL) {
3254 cur = cur->next;
3255 break;
3256 }
3257 } while (cur != NULL);
3258 }
3259 return((long) count);
3260 }
3261
3262 /**
3263 * xmlXPathCmpNodes:
3264 * @node1: the first node
3265 * @node2: the second node
3266 *
3267 * Compare two nodes w.r.t document order
3268 *
3269 * Returns -2 in case of error 1 if first point < second point, 0 if
3270 * it's the same node, -1 otherwise
3271 */
3272 int
3273 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3274 int depth1, depth2;
3275 int attr1 = 0, attr2 = 0;
3276 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3277 xmlNodePtr cur, root;
3278
3279 if ((node1 == NULL) || (node2 == NULL))
3280 return(-2);
3281 /*
3282 * a couple of optimizations which will avoid computations in most cases
3283 */
3284 if (node1 == node2) /* trivial case */
3285 return(0);
3286 if (node1->type == XML_ATTRIBUTE_NODE) {
3287 attr1 = 1;
3288 attrNode1 = node1;
3289 node1 = node1->parent;
3290 }
3291 if (node2->type == XML_ATTRIBUTE_NODE) {
3292 attr2 = 1;
3293 attrNode2 = node2;
3294 node2 = node2->parent;
3295 }
3296 if (node1 == node2) {
3297 if (attr1 == attr2) {
3298 /* not required, but we keep attributes in order */
3299 if (attr1 != 0) {
3300 cur = attrNode2->prev;
3301 while (cur != NULL) {
3302 if (cur == attrNode1)
3303 return (1);
3304 cur = cur->prev;
3305 }
3306 return (-1);
3307 }
3308 return(0);
3309 }
3310 if (attr2 == 1)
3311 return(1);
3312 return(-1);
3313 }
3314 if ((node1->type == XML_NAMESPACE_DECL) ||
3315 (node2->type == XML_NAMESPACE_DECL))
3316 return(1);
3317 if (node1 == node2->prev)
3318 return(1);
3319 if (node1 == node2->next)
3320 return(-1);
3321
3322 /*
3323 * Speedup using document order if availble.
3324 */
3325 if ((node1->type == XML_ELEMENT_NODE) &&
3326 (node2->type == XML_ELEMENT_NODE) &&
3327 (0 > (ptrdiff_t) node1->content) &&
3328 (0 > (ptrdiff_t) node2->content) &&
3329 (node1->doc == node2->doc)) {
3330 ptrdiff_t l1, l2;
3331
3332 l1 = -((ptrdiff_t) node1->content);
3333 l2 = -((ptrdiff_t) node2->content);
3334 if (l1 < l2)
3335 return(1);
3336 if (l1 > l2)
3337 return(-1);
3338 }
3339
3340 /*
3341 * compute depth to root
3342 */
3343 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3344 if (cur->parent == node1)
3345 return(1);
3346 depth2++;
3347 }
3348 root = cur;
3349 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3350 if (cur->parent == node2)
3351 return(-1);
3352 depth1++;
3353 }
3354 /*
3355 * Distinct document (or distinct entities :-( ) case.
3356 */
3357 if (root != cur) {
3358 return(-2);
3359 }
3360 /*
3361 * get the nearest common ancestor.
3362 */
3363 while (depth1 > depth2) {
3364 depth1--;
3365 node1 = node1->parent;
3366 }
3367 while (depth2 > depth1) {
3368 depth2--;
3369 node2 = node2->parent;
3370 }
3371 while (node1->parent != node2->parent) {
3372 node1 = node1->parent;
3373 node2 = node2->parent;
3374 /* should not happen but just in case ... */
3375 if ((node1 == NULL) || (node2 == NULL))
3376 return(-2);
3377 }
3378 /*
3379 * Find who's first.
3380 */
3381 if (node1 == node2->prev)
3382 return(1);
3383 if (node1 == node2->next)
3384 return(-1);
3385 /*
3386 * Speedup using document order if availble.
3387 */
3388 if ((node1->type == XML_ELEMENT_NODE) &&
3389 (node2->type == XML_ELEMENT_NODE) &&
3390 (0 > (ptrdiff_t) node1->content) &&
3391 (0 > (ptrdiff_t) node2->content) &&
3392 (node1->doc == node2->doc)) {
3393 ptrdiff_t l1, l2;
3394
3395 l1 = -((ptrdiff_t) node1->content);
3396 l2 = -((ptrdiff_t) node2->content);
3397 if (l1 < l2)
3398 return(1);
3399 if (l1 > l2)
3400 return(-1);
3401 }
3402
3403 for (cur = node1->next;cur != NULL;cur = cur->next)
3404 if (cur == node2)
3405 return(1);
3406 return(-1); /* assume there is no sibling list corruption */
3407 }
3408
3409 /**
3410 * xmlXPathNodeSetSort:
3411 * @set: the node set
3412 *
3413 * Sort the node set in document order
3414 */
3415 void
3416 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3417 #ifndef WITH_TIM_SORT
3418 int i, j, incr, len;
3419 xmlNodePtr tmp;
3420 #endif
3421
3422 if (set == NULL)
3423 return;
3424
3425 #ifndef WITH_TIM_SORT
3426 /*
3427 * Use the old Shell's sort implementation to sort the node-set
3428 * Timsort ought to be quite faster
3429 */
3430 len = set->nodeNr;
3431 for (incr = len / 2; incr > 0; incr /= 2) {
3432 for (i = incr; i < len; i++) {
3433 j = i - incr;
3434 while (j >= 0) {
3435 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3436 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3437 set->nodeTab[j + incr]) == -1)
3438 #else
3439 if (xmlXPathCmpNodes(set->nodeTab[j],
3440 set->nodeTab[j + incr]) == -1)
3441 #endif
3442 {
3443 tmp = set->nodeTab[j];
3444 set->nodeTab[j] = set->nodeTab[j + incr];
3445 set->nodeTab[j + incr] = tmp;
3446 j -= incr;
3447 } else
3448 break;
3449 }
3450 }
3451 }
3452 #else /* WITH_TIM_SORT */
3453 libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3454 #endif /* WITH_TIM_SORT */
3455 }
3456
3457 #define XML_NODESET_DEFAULT 10
3458 /**
3459 * xmlXPathNodeSetDupNs:
3460 * @node: the parent node of the namespace XPath node
3461 * @ns: the libxml namespace declaration node.
3462 *
3463 * Namespace node in libxml don't match the XPath semantic. In a node set
3464 * the namespace nodes are duplicated and the next pointer is set to the
3465 * parent node in the XPath semantic.
3466 *
3467 * Returns the newly created object.
3468 */
3469 static xmlNodePtr
3470 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3471 xmlNsPtr cur;
3472
3473 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3474 return(NULL);
3475 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3476 return((xmlNodePtr) ns);
3477
3478 /*
3479 * Allocate a new Namespace and fill the fields.
3480 */
3481 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3482 if (cur == NULL) {
3483 xmlXPathErrMemory(NULL, "duplicating namespace\n");
3484 return(NULL);
3485 }
3486 memset(cur, 0, sizeof(xmlNs));
3487 cur->type = XML_NAMESPACE_DECL;
3488 if (ns->href != NULL)
3489 cur->href = xmlStrdup(ns->href);
3490 if (ns->prefix != NULL)
3491 cur->prefix = xmlStrdup(ns->prefix);
3492 cur->next = (xmlNsPtr) node;
3493 return((xmlNodePtr) cur);
3494 }
3495
3496 /**
3497 * xmlXPathNodeSetFreeNs:
3498 * @ns: the XPath namespace node found in a nodeset.
3499 *
3500 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3501 * the namespace nodes are duplicated and the next pointer is set to the
3502 * parent node in the XPath semantic. Check if such a node needs to be freed
3503 */
3504 void
3505 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3506 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3507 return;
3508
3509 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3510 if (ns->href != NULL)
3511 xmlFree((xmlChar *)ns->href);
3512 if (ns->prefix != NULL)
3513 xmlFree((xmlChar *)ns->prefix);
3514 xmlFree(ns);
3515 }
3516 }
3517
3518 /**
3519 * xmlXPathNodeSetCreate:
3520 * @val: an initial xmlNodePtr, or NULL
3521 *
3522 * Create a new xmlNodeSetPtr of type double and of value @val
3523 *
3524 * Returns the newly created object.
3525 */
3526 xmlNodeSetPtr
3527 xmlXPathNodeSetCreate(xmlNodePtr val) {
3528 xmlNodeSetPtr ret;
3529
3530 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3531 if (ret == NULL) {
3532 xmlXPathErrMemory(NULL, "creating nodeset\n");
3533 return(NULL);
3534 }
3535 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3536 if (val != NULL) {
3537 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3538 sizeof(xmlNodePtr));
3539 if (ret->nodeTab == NULL) {
3540 xmlXPathErrMemory(NULL, "creating nodeset\n");
3541 xmlFree(ret);
3542 return(NULL);
3543 }
3544 memset(ret->nodeTab, 0 ,
3545 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3546 ret->nodeMax = XML_NODESET_DEFAULT;
3547 if (val->type == XML_NAMESPACE_DECL) {
3548 xmlNsPtr ns = (xmlNsPtr) val;
3549
3550 ret->nodeTab[ret->nodeNr++] =
3551 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3552 } else
3553 ret->nodeTab[ret->nodeNr++] = val;
3554 }
3555 return(ret);
3556 }
3557
3558 /**
3559 * xmlXPathNodeSetCreateSize:
3560 * @size: the initial size of the set
3561 *
3562 * Create a new xmlNodeSetPtr of type double and of value @val
3563 *
3564 * Returns the newly created object.
3565 */
3566 static xmlNodeSetPtr
3567 xmlXPathNodeSetCreateSize(int size) {
3568 xmlNodeSetPtr ret;
3569
3570 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3571 if (ret == NULL) {
3572 xmlXPathErrMemory(NULL, "creating nodeset\n");
3573 return(NULL);
3574 }
3575 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3576 if (size < XML_NODESET_DEFAULT)
3577 size = XML_NODESET_DEFAULT;
3578 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3579 if (ret->nodeTab == NULL) {
3580 xmlXPathErrMemory(NULL, "creating nodeset\n");
3581 xmlFree(ret);
3582 return(NULL);
3583 }
3584 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3585 ret->nodeMax = size;
3586 return(ret);
3587 }
3588
3589 /**
3590 * xmlXPathNodeSetContains:
3591 * @cur: the node-set
3592 * @val: the node
3593 *
3594 * checks whether @cur contains @val
3595 *
3596 * Returns true (1) if @cur contains @val, false (0) otherwise
3597 */
3598 int
3599 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3600 int i;
3601
3602 if ((cur == NULL) || (val == NULL)) return(0);
3603 if (val->type == XML_NAMESPACE_DECL) {
3604 for (i = 0; i < cur->nodeNr; i++) {
3605 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3606 xmlNsPtr ns1, ns2;
3607
3608 ns1 = (xmlNsPtr) val;
3609 ns2 = (xmlNsPtr) cur->nodeTab[i];
3610 if (ns1 == ns2)
3611 return(1);
3612 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3613 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3614 return(1);
3615 }
3616 }
3617 } else {
3618 for (i = 0; i < cur->nodeNr; i++) {
3619 if (cur->nodeTab[i] == val)
3620 return(1);
3621 }
3622 }
3623 return(0);
3624 }
3625
3626 /**
3627 * xmlXPathNodeSetAddNs:
3628 * @cur: the initial node set
3629 * @node: the hosting node
3630 * @ns: a the namespace node
3631 *
3632 * add a new namespace node to an existing NodeSet
3633 *
3634 * Returns 0 in case of success and -1 in case of error
3635 */
3636 int
3637 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3638 int i;
3639
3640
3641 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3642 (ns->type != XML_NAMESPACE_DECL) ||
3643 (node->type != XML_ELEMENT_NODE))
3644 return(-1);
3645
3646 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3647 /*
3648 * prevent duplicates
3649 */
3650 for (i = 0;i < cur->nodeNr;i++) {
3651 if ((cur->nodeTab[i] != NULL) &&
3652 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3653 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3654 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3655 return(0);
3656 }
3657
3658 /*
3659 * grow the nodeTab if needed
3660 */
3661 if (cur->nodeMax == 0) {
3662 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3663 sizeof(xmlNodePtr));
3664 if (cur->nodeTab == NULL) {
3665 xmlXPathErrMemory(NULL, "growing nodeset\n");
3666 return(-1);
3667 }
3668 memset(cur->nodeTab, 0 ,
3669 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3670 cur->nodeMax = XML_NODESET_DEFAULT;
3671 } else if (cur->nodeNr == cur->nodeMax) {
3672 xmlNodePtr *temp;
3673
3674 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3675 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3676 return(-1);
3677 }
3678 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3679 sizeof(xmlNodePtr));
3680 if (temp == NULL) {
3681 xmlXPathErrMemory(NULL, "growing nodeset\n");
3682 return(-1);
3683 }
3684 cur->nodeMax *= 2;
3685 cur->nodeTab = temp;
3686 }
3687 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3688 return(0);
3689 }
3690
3691 /**
3692 * xmlXPathNodeSetAdd:
3693 * @cur: the initial node set
3694 * @val: a new xmlNodePtr
3695 *
3696 * add a new xmlNodePtr to an existing NodeSet
3697 *
3698 * Returns 0 in case of success, and -1 in case of error
3699 */
3700 int
3701 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3702 int i;
3703
3704 if ((cur == NULL) || (val == NULL)) return(-1);
3705
3706 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3707 /*
3708 * prevent duplicates
3709 */
3710 for (i = 0;i < cur->nodeNr;i++)
3711 if (cur->nodeTab[i] == val) return(0);
3712
3713 /*
3714 * grow the nodeTab if needed
3715 */
3716 if (cur->nodeMax == 0) {
3717 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3718 sizeof(xmlNodePtr));
3719 if (cur->nodeTab == NULL) {
3720 xmlXPathErrMemory(NULL, "growing nodeset\n");
3721 return(-1);
3722 }
3723 memset(cur->nodeTab, 0 ,
3724 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3725 cur->nodeMax = XML_NODESET_DEFAULT;
3726 } else if (cur->nodeNr == cur->nodeMax) {
3727 xmlNodePtr *temp;
3728
3729 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3730 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3731 return(-1);
3732 }
3733 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3734 sizeof(xmlNodePtr));
3735 if (temp == NULL) {
3736 xmlXPathErrMemory(NULL, "growing nodeset\n");
3737 return(-1);
3738 }
3739 cur->nodeMax *= 2;
3740 cur->nodeTab = temp;
3741 }
3742 if (val->type == XML_NAMESPACE_DECL) {
3743 xmlNsPtr ns = (xmlNsPtr) val;
3744
3745 cur->nodeTab[cur->nodeNr++] =
3746 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3747 } else
3748 cur->nodeTab[cur->nodeNr++] = val;
3749 return(0);
3750 }
3751
3752 /**
3753 * xmlXPathNodeSetAddUnique:
3754 * @cur: the initial node set
3755 * @val: a new xmlNodePtr
3756 *
3757 * add a new xmlNodePtr to an existing NodeSet, optimized version
3758 * when we are sure the node is not already in the set.
3759 *
3760 * Returns 0 in case of success and -1 in case of failure
3761 */
3762 int
3763 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3764 if ((cur == NULL) || (val == NULL)) return(-1);
3765
3766 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3767 /*
3768 * grow the nodeTab if needed
3769 */
3770 if (cur->nodeMax == 0) {
3771 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3772 sizeof(xmlNodePtr));
3773 if (cur->nodeTab == NULL) {
3774 xmlXPathErrMemory(NULL, "growing nodeset\n");
3775 return(-1);
3776 }
3777 memset(cur->nodeTab, 0 ,
3778 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3779 cur->nodeMax = XML_NODESET_DEFAULT;
3780 } else if (cur->nodeNr == cur->nodeMax) {
3781 xmlNodePtr *temp;
3782
3783 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3784 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3785 return(-1);
3786 }
3787 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3788 sizeof(xmlNodePtr));
3789 if (temp == NULL) {
3790 xmlXPathErrMemory(NULL, "growing nodeset\n");
3791 return(-1);
3792 }
3793 cur->nodeTab = temp;
3794 cur->nodeMax *= 2;
3795 }
3796 if (val->type == XML_NAMESPACE_DECL) {
3797 xmlNsPtr ns = (xmlNsPtr) val;
3798
3799 cur->nodeTab[cur->nodeNr++] =
3800 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3801 } else
3802 cur->nodeTab[cur->nodeNr++] = val;
3803 return(0);
3804 }
3805
3806 /**
3807 * xmlXPathNodeSetMerge:
3808 * @val1: the first NodeSet or NULL
3809 * @val2: the second NodeSet
3810 *
3811 * Merges two nodesets, all nodes from @val2 are added to @val1
3812 * if @val1 is NULL, a new set is created and copied from @val2
3813 *
3814 * Returns @val1 once extended or NULL in case of error.
3815 */
3816 xmlNodeSetPtr
3817 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3818 int i, j, initNr, skip;
3819 xmlNodePtr n1, n2;
3820
3821 if (val2 == NULL) return(val1);
3822 if (val1 == NULL) {
3823 val1 = xmlXPathNodeSetCreate(NULL);
3824 if (val1 == NULL)
3825 return (NULL);
3826 #if 0
3827 /*
3828 * TODO: The optimization won't work in every case, since
3829 * those nasty namespace nodes need to be added with
3830 * xmlXPathNodeSetDupNs() to the set; thus a pure
3831 * memcpy is not possible.
3832 * If there was a flag on the nodesetval, indicating that
3833 * some temporary nodes are in, that would be helpfull.
3834 */
3835 /*
3836 * Optimization: Create an equally sized node-set
3837 * and memcpy the content.
3838 */
3839 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3840 if (val1 == NULL)
3841 return(NULL);
3842 if (val2->nodeNr != 0) {
3843 if (val2->nodeNr == 1)
3844 *(val1->nodeTab) = *(val2->nodeTab);
3845 else {
3846 memcpy(val1->nodeTab, val2->nodeTab,
3847 val2->nodeNr * sizeof(xmlNodePtr));
3848 }
3849 val1->nodeNr = val2->nodeNr;
3850 }
3851 return(val1);
3852 #endif
3853 }
3854
3855 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3856 initNr = val1->nodeNr;
3857
3858 for (i = 0;i < val2->nodeNr;i++) {
3859 n2 = val2->nodeTab[i];
3860 /*
3861 * check against duplicates
3862 */
3863 skip = 0;
3864 for (j = 0; j < initNr; j++) {
3865 n1 = val1->nodeTab[j];
3866 if (n1 == n2) {
3867 skip = 1;
3868 break;
3869 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3870 (n2->type == XML_NAMESPACE_DECL)) {
3871 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3872 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3873 ((xmlNsPtr) n2)->prefix)))
3874 {
3875 skip = 1;
3876 break;
3877 }
3878 }
3879 }
3880 if (skip)
3881 continue;
3882
3883 /*
3884 * grow the nodeTab if needed
3885 */
3886 if (val1->nodeMax == 0) {
3887 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3888 sizeof(xmlNodePtr));
3889 if (val1->nodeTab == NULL) {
3890 xmlXPathErrMemory(NULL, "merging nodeset\n");
3891 return(NULL);
3892 }
3893 memset(val1->nodeTab, 0 ,
3894 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3895 val1->nodeMax = XML_NODESET_DEFAULT;
3896 } else if (val1->nodeNr == val1->nodeMax) {
3897 xmlNodePtr *temp;
3898
3899 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3900 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3901 return(NULL);
3902 }
3903 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3904 sizeof(xmlNodePtr));
3905 if (temp == NULL) {
3906 xmlXPathErrMemory(NULL, "merging nodeset\n");
3907 return(NULL);
3908 }
3909 val1->nodeTab = temp;
3910 val1->nodeMax *= 2;
3911 }
3912 if (n2->type == XML_NAMESPACE_DECL) {
3913 xmlNsPtr ns = (xmlNsPtr) n2;
3914
3915 val1->nodeTab[val1->nodeNr++] =
3916 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3917 } else
3918 val1->nodeTab[val1->nodeNr++] = n2;
3919 }
3920
3921 return(val1);
3922 }
3923
3924
3925 /**
3926 * xmlXPathNodeSetMergeAndClear:
3927 * @set1: the first NodeSet or NULL
3928 * @set2: the second NodeSet
3929 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3930 *
3931 * Merges two nodesets, all nodes from @set2 are added to @set1
3932 * if @set1 is NULL, a new set is created and copied from @set2.
3933 * Checks for duplicate nodes. Clears set2.
3934 *
3935 * Returns @set1 once extended or NULL in case of error.
3936 */
3937 static xmlNodeSetPtr
3938 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3939 int hasNullEntries)
3940 {
3941 if ((set1 == NULL) && (hasNullEntries == 0)) {
3942 /*
3943 * Note that doing a memcpy of the list, namespace nodes are
3944 * just assigned to set1, since set2 is cleared anyway.
3945 */
3946 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3947 if (set1 == NULL)
3948 return(NULL);
3949 if (set2->nodeNr != 0) {
3950 memcpy(set1->nodeTab, set2->nodeTab,
3951 set2->nodeNr * sizeof(xmlNodePtr));
3952 set1->nodeNr = set2->nodeNr;
3953 }
3954 } else {
3955 int i, j, initNbSet1;
3956 xmlNodePtr n1, n2;
3957
3958 if (set1 == NULL)
3959 set1 = xmlXPathNodeSetCreate(NULL);
3960 if (set1 == NULL)
3961 return (NULL);
3962
3963 initNbSet1 = set1->nodeNr;
3964 for (i = 0;i < set2->nodeNr;i++) {
3965 n2 = set2->nodeTab[i];
3966 /*
3967 * Skip NULLed entries.
3968 */
3969 if (n2 == NULL)
3970 continue;
3971 /*
3972 * Skip duplicates.
3973 */
3974 for (j = 0; j < initNbSet1; j++) {
3975 n1 = set1->nodeTab[j];
3976 if (n1 == n2) {
3977 goto skip_node;
3978 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3979 (n2->type == XML_NAMESPACE_DECL))
3980 {
3981 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3982 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3983 ((xmlNsPtr) n2)->prefix)))
3984 {
3985 /*
3986 * Free the namespace node.
3987 */
3988 set2->nodeTab[i] = NULL;
3989 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3990 goto skip_node;
3991 }
3992 }
3993 }
3994 /*
3995 * grow the nodeTab if needed
3996 */
3997 if (set1->nodeMax == 0) {
3998 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3999 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4000 if (set1->nodeTab == NULL) {
4001 xmlXPathErrMemory(NULL, "merging nodeset\n");
4002 return(NULL);
4003 }
4004 memset(set1->nodeTab, 0,
4005 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4006 set1->nodeMax = XML_NODESET_DEFAULT;
4007 } else if (set1->nodeNr >= set1->nodeMax) {
4008 xmlNodePtr *temp;
4009
4010 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4011 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4012 return(NULL);
4013 }
4014 temp = (xmlNodePtr *) xmlRealloc(
4015 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4016 if (temp == NULL) {
4017 xmlXPathErrMemory(NULL, "merging nodeset\n");
4018 return(NULL);
4019 }
4020 set1->nodeTab = temp;
4021 set1->nodeMax *= 2;
4022 }
4023 set1->nodeTab[set1->nodeNr++] = n2;
4024 skip_node:
4025 {}
4026 }
4027 }
4028 set2->nodeNr = 0;
4029 return(set1);
4030 }
4031
4032 /**
4033 * xmlXPathNodeSetMergeAndClearNoDupls:
4034 * @set1: the first NodeSet or NULL
4035 * @set2: the second NodeSet
4036 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
4037 *
4038 * Merges two nodesets, all nodes from @set2 are added to @set1
4039 * if @set1 is NULL, a new set is created and copied from @set2.
4040 * Doesn't chack for duplicate nodes. Clears set2.
4041 *
4042 * Returns @set1 once extended or NULL in case of error.
4043 */
4044 static xmlNodeSetPtr
4045 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
4046 int hasNullEntries)
4047 {
4048 if (set2 == NULL)
4049 return(set1);
4050 if ((set1 == NULL) && (hasNullEntries == 0)) {
4051 /*
4052 * Note that doing a memcpy of the list, namespace nodes are
4053 * just assigned to set1, since set2 is cleared anyway.
4054 */
4055 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
4056 if (set1 == NULL)
4057 return(NULL);
4058 if (set2->nodeNr != 0) {
4059 memcpy(set1->nodeTab, set2->nodeTab,
4060 set2->nodeNr * sizeof(xmlNodePtr));
4061 set1->nodeNr = set2->nodeNr;
4062 }
4063 } else {
4064 int i;
4065 xmlNodePtr n2;
4066
4067 if (set1 == NULL)
4068 set1 = xmlXPathNodeSetCreate(NULL);
4069 if (set1 == NULL)
4070 return (NULL);
4071
4072 for (i = 0;i < set2->nodeNr;i++) {
4073 n2 = set2->nodeTab[i];
4074 /*
4075 * Skip NULLed entries.
4076 */
4077 if (n2 == NULL)
4078 continue;
4079 if (set1->nodeMax == 0) {
4080 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4081 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4082 if (set1->nodeTab == NULL) {
4083 xmlXPathErrMemory(NULL, "merging nodeset\n");
4084 return(NULL);
4085 }
4086 memset(set1->nodeTab, 0,
4087 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4088 set1->nodeMax = XML_NODESET_DEFAULT;
4089 } else if (set1->nodeNr >= set1->nodeMax) {
4090 xmlNodePtr *temp;
4091
4092 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4093 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4094 return(NULL);
4095 }
4096 temp = (xmlNodePtr *) xmlRealloc(
4097 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4098 if (temp == NULL) {
4099 xmlXPathErrMemory(NULL, "merging nodeset\n");
4100 return(NULL);
4101 }
4102 set1->nodeTab = temp;
4103 set1->nodeMax *= 2;
4104 }
4105 set1->nodeTab[set1->nodeNr++] = n2;
4106 }
4107 }
4108 set2->nodeNr = 0;
4109 return(set1);
4110 }
4111
4112 /**
4113 * xmlXPathNodeSetDel:
4114 * @cur: the initial node set
4115 * @val: an xmlNodePtr
4116 *
4117 * Removes an xmlNodePtr from an existing NodeSet
4118 */
4119 void
4120 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4121 int i;
4122
4123 if (cur == NULL) return;
4124 if (val == NULL) return;
4125
4126 /*
4127 * find node in nodeTab
4128 */
4129 for (i = 0;i < cur->nodeNr;i++)
4130 if (cur->nodeTab[i] == val) break;
4131
4132 if (i >= cur->nodeNr) { /* not found */
4133 #ifdef DEBUG
4134 xmlGenericError(xmlGenericErrorContext,
4135 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4136 val->name);
4137 #endif
4138 return;
4139 }
4140 if ((cur->nodeTab[i] != NULL) &&
4141 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4142 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4143 cur->nodeNr--;
4144 for (;i < cur->nodeNr;i++)
4145 cur->nodeTab[i] = cur->nodeTab[i + 1];
4146 cur->nodeTab[cur->nodeNr] = NULL;
4147 }
4148
4149 /**
4150 * xmlXPathNodeSetRemove:
4151 * @cur: the initial node set
4152 * @val: the index to remove
4153 *
4154 * Removes an entry from an existing NodeSet list.
4155 */
4156 void
4157 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4158 if (cur == NULL) return;
4159 if (val >= cur->nodeNr) return;
4160 if ((cur->nodeTab[val] != NULL) &&
4161 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4162 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4163 cur->nodeNr--;
4164 for (;val < cur->nodeNr;val++)
4165 cur->nodeTab[val] = cur->nodeTab[val + 1];
4166 cur->nodeTab[cur->nodeNr] = NULL;
4167 }
4168
4169 /**
4170 * xmlXPathFreeNodeSet:
4171 * @obj: the xmlNodeSetPtr to free
4172 *
4173 * Free the NodeSet compound (not the actual nodes !).
4174 */
4175 void
4176 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4177 if (obj == NULL) return;
4178 if (obj->nodeTab != NULL) {
4179 int i;
4180
4181 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4182 for (i = 0;i < obj->nodeNr;i++)
4183 if ((obj->nodeTab[i] != NULL) &&
4184 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4185 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4186 xmlFree(obj->nodeTab);
4187 }
4188 xmlFree(obj);
4189 }
4190
4191 /**
4192 * xmlXPathNodeSetClearFromPos:
4193 * @set: the node set to be cleared
4194 * @pos: the start position to clear from
4195 *
4196 * Clears the list from temporary XPath objects (e.g. namespace nodes
4197 * are feed) starting with the entry at @pos, but does *not* free the list
4198 * itself. Sets the length of the list to @pos.
4199 */
4200 static void
4201 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4202 {
4203 if ((set == NULL) || (pos >= set->nodeNr))
4204 return;
4205 else if ((hasNsNodes)) {
4206 int i;
4207 xmlNodePtr node;
4208
4209 for (i = pos; i < set->nodeNr; i++) {
4210 node = set->nodeTab[i];
4211 if ((node != NULL) &&
4212 (node->type == XML_NAMESPACE_DECL))
4213 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4214 }
4215 }
4216 set->nodeNr = pos;
4217 }
4218
4219 /**
4220 * xmlXPathNodeSetClear:
4221 * @set: the node set to clear
4222 *
4223 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4224 * are feed), but does *not* free the list itself. Sets the length of the
4225 * list to 0.
4226 */
4227 static void
4228 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4229 {
4230 xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4231 }
4232
4233 /**
4234 * xmlXPathNodeSetKeepLast:
4235 * @set: the node set to be cleared
4236 *
4237 * Move the last node to the first position and clear temporary XPath objects
4238 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4239 * to 1.
4240 */
4241 static void
4242 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4243 {
4244 int i;
4245 xmlNodePtr node;
4246
4247 if ((set == NULL) || (set->nodeNr <= 1))
4248 return;
4249 for (i = 0; i < set->nodeNr - 1; i++) {
4250 node = set->nodeTab[i];
4251 if ((node != NULL) &&
4252 (node->type == XML_NAMESPACE_DECL))
4253 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4254 }
4255 set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4256 set->nodeNr = 1;
4257 }
4258
4259 /**
4260 * xmlXPathFreeValueTree:
4261 * @obj: the xmlNodeSetPtr to free
4262 *
4263 * Free the NodeSet compound and the actual tree, this is different
4264 * from xmlXPathFreeNodeSet()
4265 */
4266 static void
4267 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4268 int i;
4269
4270 if (obj == NULL) return;
4271
4272 if (obj->nodeTab != NULL) {
4273 for (i = 0;i < obj->nodeNr;i++) {
4274 if (obj->nodeTab[i] != NULL) {
4275 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4276 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4277 } else {
4278 xmlFreeNodeList(obj->nodeTab[i]);
4279 }
4280 }
4281 }
4282 xmlFree(obj->nodeTab);
4283 }
4284 xmlFree(obj);
4285 }
4286
4287 #if defined(DEBUG) || defined(DEBUG_STEP)
4288 /**
4289 * xmlGenericErrorContextNodeSet:
4290 * @output: a FILE * for the output
4291 * @obj: the xmlNodeSetPtr to display
4292 *
4293 * Quick display of a NodeSet
4294 */
4295 void
4296 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4297 int i;
4298
4299 if (output == NULL) output = xmlGenericErrorContext;
4300 if (obj == NULL) {
4301 fprintf(output, "NodeSet == NULL !\n");
4302 return;
4303 }
4304 if (obj->nodeNr == 0) {
4305 fprintf(output, "NodeSet is empty\n");
4306 return;
4307 }
4308 if (obj->nodeTab == NULL) {
4309 fprintf(output, " nodeTab == NULL !\n");
4310 return;
4311 }
4312 for (i = 0; i < obj->nodeNr; i++) {
4313 if (obj->nodeTab[i] == NULL) {
4314 fprintf(output, " NULL !\n");
4315 return;
4316 }
4317 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4318 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4319 fprintf(output, " /");
4320 else if (obj->nodeTab[i]->name == NULL)
4321 fprintf(output, " noname!");
4322 else fprintf(output, " %s", obj->nodeTab[i]->name);
4323 }
4324 fprintf(output, "\n");
4325 }
4326 #endif
4327
4328 /**
4329 * xmlXPathNewNodeSet:
4330 * @val: the NodePtr value
4331 *
4332 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4333 * it with the single Node @val
4334 *
4335 * Returns the newly created object.
4336 */
4337 xmlXPathObjectPtr
4338 xmlXPathNewNodeSet(xmlNodePtr val) {
4339 xmlXPathObjectPtr ret;
4340
4341 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4342 if (ret == NULL) {
4343 xmlXPathErrMemory(NULL, "creating nodeset\n");
4344 return(NULL);
4345 }
4346 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4347 ret->type = XPATH_NODESET;
4348 ret->boolval = 0;
4349 ret->nodesetval = xmlXPathNodeSetCreate(val);
4350 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4351 #ifdef XP_DEBUG_OBJ_USAGE
4352 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4353 #endif
4354 return(ret);
4355 }
4356
4357 /**
4358 * xmlXPathNewValueTree:
4359 * @val: the NodePtr value
4360 *
4361 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4362 * it with the tree root @val
4363 *
4364 * Returns the newly created object.
4365 */
4366 xmlXPathObjectPtr
4367 xmlXPathNewValueTree(xmlNodePtr val) {
4368 xmlXPathObjectPtr ret;
4369
4370 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4371 if (ret == NULL) {
4372 xmlXPathErrMemory(NULL, "creating result value tree\n");
4373 return(NULL);
4374 }
4375 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4376 ret->type = XPATH_XSLT_TREE;
4377 ret->boolval = 1;
4378 ret->user = (void *) val;
4379 ret->nodesetval = xmlXPathNodeSetCreate(val);
4380 #ifdef XP_DEBUG_OBJ_USAGE
4381 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4382 #endif
4383 return(ret);
4384 }
4385
4386 /**
4387 * xmlXPathNewNodeSetList:
4388 * @val: an existing NodeSet
4389 *
4390 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4391 * it with the Nodeset @val
4392 *
4393 * Returns the newly created object.
4394 */
4395 xmlXPathObjectPtr
4396 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4397 {
4398 xmlXPathObjectPtr ret;
4399 int i;
4400
4401 if (val == NULL)
4402 ret = NULL;
4403 else if (val->nodeTab == NULL)
4404 ret = xmlXPathNewNodeSet(NULL);
4405 else {
4406 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4407 if (ret) {
4408 for (i = 1; i < val->nodeNr; ++i) {
4409 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4410 < 0) break;
4411 }
4412 }
4413 }
4414
4415 return (ret);
4416 }
4417
4418 /**
4419 * xmlXPathWrapNodeSet:
4420 * @val: the NodePtr value
4421 *
4422 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4423 *
4424 * Returns the newly created object.
4425 */
4426 xmlXPathObjectPtr
4427 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4428 xmlXPathObjectPtr ret;
4429
4430 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4431 if (ret == NULL) {
4432 xmlXPathErrMemory(NULL, "creating node set object\n");
4433 return(NULL);
4434 }
4435 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4436 ret->type = XPATH_NODESET;
4437 ret->nodesetval = val;
4438 #ifdef XP_DEBUG_OBJ_USAGE
4439 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4440 #endif
4441 return(ret);
4442 }
4443
4444 /**
4445 * xmlXPathFreeNodeSetList:
4446 * @obj: an existing NodeSetList object
4447 *
4448 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4449 * the list contrary to xmlXPathFreeObject().
4450 */
4451 void
4452 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4453 if (obj == NULL) return;
4454 #ifdef XP_DEBUG_OBJ_USAGE
4455 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4456 #endif
4457 xmlFree(obj);
4458 }
4459
4460 /**
4461 * xmlXPathDifference:
4462 * @nodes1: a node-set
4463 * @nodes2: a node-set
4464 *
4465 * Implements the EXSLT - Sets difference() function:
4466 * node-set set:difference (node-set, node-set)
4467 *
4468 * Returns the difference between the two node sets, or nodes1 if
4469 * nodes2 is empty
4470 */
4471 xmlNodeSetPtr
4472 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4473 xmlNodeSetPtr ret;
4474 int i, l1;
4475 xmlNodePtr cur;
4476
4477 if (xmlXPathNodeSetIsEmpty(nodes2))
4478 return(nodes1);
4479
4480 ret = xmlXPathNodeSetCreate(NULL);
4481 if (xmlXPathNodeSetIsEmpty(nodes1))
4482 return(ret);
4483
4484 l1 = xmlXPathNodeSetGetLength(nodes1);
4485
4486 for (i = 0; i < l1; i++) {
4487 cur = xmlXPathNodeSetItem(nodes1, i);
4488 if (!xmlXPathNodeSetContains(nodes2, cur)) {
4489 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4490 break;
4491 }
4492 }
4493 return(ret);
4494 }
4495
4496 /**
4497 * xmlXPathIntersection:
4498 * @nodes1: a node-set
4499 * @nodes2: a node-set
4500 *
4501 * Implements the EXSLT - Sets intersection() function:
4502 * node-set set:intersection (node-set, node-set)
4503 *
4504 * Returns a node set comprising the nodes that are within both the
4505 * node sets passed as arguments
4506 */
4507 xmlNodeSetPtr
4508 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4509 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4510 int i, l1;
4511 xmlNodePtr cur;
4512
4513 if (ret == NULL)
4514 return(ret);
4515 if (xmlXPathNodeSetIsEmpty(nodes1))
4516 return(ret);
4517 if (xmlXPathNodeSetIsEmpty(nodes2))
4518 return(ret);
4519
4520 l1 = xmlXPathNodeSetGetLength(nodes1);
4521
4522 for (i = 0; i < l1; i++) {
4523 cur = xmlXPathNodeSetItem(nodes1, i);
4524 if (xmlXPathNodeSetContains(nodes2, cur)) {
4525 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4526 break;
4527 }
4528 }
4529 return(ret);
4530 }
4531
4532 /**
4533 * xmlXPathDistinctSorted:
4534 * @nodes: a node-set, sorted by document order
4535 *
4536 * Implements the EXSLT - Sets distinct() function:
4537 * node-set set:distinct (node-set)
4538 *
4539 * Returns a subset of the nodes contained in @nodes, or @nodes if
4540 * it is empty
4541 */
4542 xmlNodeSetPtr
4543 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4544 xmlNodeSetPtr ret;
4545 xmlHashTablePtr hash;
4546 int i, l;
4547 xmlChar * strval;
4548 xmlNodePtr cur;
4549
4550 if (xmlXPathNodeSetIsEmpty(nodes))
4551 return(nodes);
4552
4553 ret = xmlXPathNodeSetCreate(NULL);
4554 if (ret == NULL)
4555 return(ret);
4556 l = xmlXPathNodeSetGetLength(nodes);
4557 hash = xmlHashCreate (l);
4558 for (i = 0; i < l; i++) {
4559 cur = xmlXPathNodeSetItem(nodes, i);
4560 strval = xmlXPathCastNodeToString(cur);
4561 if (xmlHashLookup(hash, strval) == NULL) {
4562 xmlHashAddEntry(hash, strval, strval);
4563 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4564 break;
4565 } else {
4566 xmlFree(strval);
4567 }
4568 }
4569 xmlHashFree(hash, xmlHashDefaultDeallocator);
4570 return(ret);
4571 }
4572
4573 /**
4574 * xmlXPathDistinct:
4575 * @nodes: a node-set
4576 *
4577 * Implements the EXSLT - Sets distinct() function:
4578 * node-set set:distinct (node-set)
4579 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4580 * is called with the sorted node-set
4581 *
4582 * Returns a subset of the nodes contained in @nodes, or @nodes if
4583 * it is empty
4584 */
4585 xmlNodeSetPtr
4586 xmlXPathDistinct (xmlNodeSetPtr nodes) {
4587 if (xmlXPathNodeSetIsEmpty(nodes))
4588 return(nodes);
4589
4590 xmlXPathNodeSetSort(nodes);
4591 return(xmlXPathDistinctSorted(nodes));
4592 }
4593
4594 /**
4595 * xmlXPathHasSameNodes:
4596 * @nodes1: a node-set
4597 * @nodes2: a node-set
4598 *
4599 * Implements the EXSLT - Sets has-same-nodes function:
4600 * boolean set:has-same-node(node-set, node-set)
4601 *
4602 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4603 * otherwise
4604 */
4605 int
4606 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4607 int i, l;
4608 xmlNodePtr cur;
4609
4610 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4611 xmlXPathNodeSetIsEmpty(nodes2))
4612 return(0);
4613
4614 l = xmlXPathNodeSetGetLength(nodes1);
4615 for (i = 0; i < l; i++) {
4616 cur = xmlXPathNodeSetItem(nodes1, i);
4617 if (xmlXPathNodeSetContains(nodes2, cur))
4618 return(1);
4619 }
4620 return(0);
4621 }
4622
4623 /**
4624 * xmlXPathNodeLeadingSorted:
4625 * @nodes: a node-set, sorted by document order
4626 * @node: a node
4627 *
4628 * Implements the EXSLT - Sets leading() function:
4629 * node-set set:leading (node-set, node-set)
4630 *
4631 * Returns the nodes in @nodes that precede @node in document order,
4632 * @nodes if @node is NULL or an empty node-set if @nodes
4633 * doesn't contain @node
4634 */
4635 xmlNodeSetPtr
4636 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4637 int i, l;
4638 xmlNodePtr cur;
4639 xmlNodeSetPtr ret;
4640
4641 if (node == NULL)
4642 return(nodes);
4643
4644 ret = xmlXPathNodeSetCreate(NULL);
4645 if (ret == NULL)
4646 return(ret);
4647 if (xmlXPathNodeSetIsEmpty(nodes) ||
4648 (!xmlXPathNodeSetContains(nodes, node)))
4649 return(ret);
4650
4651 l = xmlXPathNodeSetGetLength(nodes);
4652 for (i = 0; i < l; i++) {
4653 cur = xmlXPathNodeSetItem(nodes, i);
4654 if (cur == node)
4655 break;
4656 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4657 break;
4658 }
4659 return(ret);
4660 }
4661
4662 /**
4663 * xmlXPathNodeLeading:
4664 * @nodes: a node-set
4665 * @node: a node
4666 *
4667 * Implements the EXSLT - Sets leading() function:
4668 * node-set set:leading (node-set, node-set)
4669 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4670 * is called.
4671 *
4672 * Returns the nodes in @nodes that precede @node in document order,
4673 * @nodes if @node is NULL or an empty node-set if @nodes
4674 * doesn't contain @node
4675 */
4676 xmlNodeSetPtr
4677 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4678 xmlXPathNodeSetSort(nodes);
4679 return(xmlXPathNodeLeadingSorted(nodes, node));
4680 }
4681
4682 /**
4683 * xmlXPathLeadingSorted:
4684 * @nodes1: a node-set, sorted by document order
4685 * @nodes2: a node-set, sorted by document order
4686 *
4687 * Implements the EXSLT - Sets leading() function:
4688 * node-set set:leading (node-set, node-set)
4689 *
4690 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4691 * in document order, @nodes1 if @nodes2 is NULL or empty or
4692 * an empty node-set if @nodes1 doesn't contain @nodes2
4693 */
4694 xmlNodeSetPtr
4695 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4696 if (xmlXPathNodeSetIsEmpty(nodes2))
4697 return(nodes1);
4698 return(xmlXPathNodeLeadingSorted(nodes1,
4699 xmlXPathNodeSetItem(nodes2, 1)));
4700 }
4701
4702 /**
4703 * xmlXPathLeading:
4704 * @nodes1: a node-set
4705 * @nodes2: a node-set
4706 *
4707 * Implements the EXSLT - Sets leading() function:
4708 * node-set set:leading (node-set, node-set)
4709 * @nodes1 and @nodes2 are sorted by document order, then
4710 * #exslSetsLeadingSorted is called.
4711 *
4712 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4713 * in document order, @nodes1 if @nodes2 is NULL or empty or
4714 * an empty node-set if @nodes1 doesn't contain @nodes2
4715 */
4716 xmlNodeSetPtr
4717 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4718 if (xmlXPathNodeSetIsEmpty(nodes2))
4719 return(nodes1);
4720 if (xmlXPathNodeSetIsEmpty(nodes1))
4721 return(xmlXPathNodeSetCreate(NULL));
4722 xmlXPathNodeSetSort(nodes1);
4723 xmlXPathNodeSetSort(nodes2);
4724 return(xmlXPathNodeLeadingSorted(nodes1,
4725 xmlXPathNodeSetItem(nodes2, 1)));
4726 }
4727
4728 /**
4729 * xmlXPathNodeTrailingSorted:
4730 * @nodes: a node-set, sorted by document order
4731 * @node: a node
4732 *
4733 * Implements the EXSLT - Sets trailing() function:
4734 * node-set set:trailing (node-set, node-set)
4735 *
4736 * Returns the nodes in @nodes that follow @node in document order,
4737 * @nodes if @node is NULL or an empty node-set if @nodes
4738 * doesn't contain @node
4739 */
4740 xmlNodeSetPtr
4741 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4742 int i, l;
4743 xmlNodePtr cur;
4744 xmlNodeSetPtr ret;
4745
4746 if (node == NULL)
4747 return(nodes);
4748
4749 ret = xmlXPathNodeSetCreate(NULL);
4750 if (ret == NULL)
4751 return(ret);
4752 if (xmlXPathNodeSetIsEmpty(nodes) ||
4753 (!xmlXPathNodeSetContains(nodes, node)))
4754 return(ret);
4755
4756 l = xmlXPathNodeSetGetLength(nodes);
4757 for (i = l - 1; i >= 0; i--) {
4758 cur = xmlXPathNodeSetItem(nodes, i);
4759 if (cur == node)
4760 break;
4761 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4762 break;
4763 }
4764 xmlXPathNodeSetSort(ret); /* bug 413451 */
4765 return(ret);
4766 }
4767
4768 /**
4769 * xmlXPathNodeTrailing:
4770 * @nodes: a node-set
4771 * @node: a node
4772 *
4773 * Implements the EXSLT - Sets trailing() function:
4774 * node-set set:trailing (node-set, node-set)
4775 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4776 * is called.
4777 *
4778 * Returns the nodes in @nodes that follow @node in document order,
4779 * @nodes if @node is NULL or an empty node-set if @nodes
4780 * doesn't contain @node
4781 */
4782 xmlNodeSetPtr
4783 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4784 xmlXPathNodeSetSort(nodes);
4785 return(xmlXPathNodeTrailingSorted(nodes, node));
4786 }
4787
4788 /**
4789 * xmlXPathTrailingSorted:
4790 * @nodes1: a node-set, sorted by document order
4791 * @nodes2: a node-set, sorted by document order
4792 *
4793 * Implements the EXSLT - Sets trailing() function:
4794 * node-set set:trailing (node-set, node-set)
4795 *
4796 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4797 * in document order, @nodes1 if @nodes2 is NULL or empty or
4798 * an empty node-set if @nodes1 doesn't contain @nodes2
4799 */
4800 xmlNodeSetPtr
4801 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4802 if (xmlXPathNodeSetIsEmpty(nodes2))
4803 return(nodes1);
4804 return(xmlXPathNodeTrailingSorted(nodes1,
4805 xmlXPathNodeSetItem(nodes2, 0)));
4806 }
4807
4808 /**
4809 * xmlXPathTrailing:
4810 * @nodes1: a node-set
4811 * @nodes2: a node-set
4812 *
4813 * Implements the EXSLT - Sets trailing() function:
4814 * node-set set:trailing (node-set, node-set)
4815 * @nodes1 and @nodes2 are sorted by document order, then
4816 * #xmlXPathTrailingSorted is called.
4817 *
4818 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4819 * in document order, @nodes1 if @nodes2 is NULL or empty or
4820 * an empty node-set if @nodes1 doesn't contain @nodes2
4821 */
4822 xmlNodeSetPtr
4823 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4824 if (xmlXPathNodeSetIsEmpty(nodes2))
4825 return(nodes1);
4826 if (xmlXPathNodeSetIsEmpty(nodes1))
4827 return(xmlXPathNodeSetCreate(NULL));
4828 xmlXPathNodeSetSort(nodes1);
4829 xmlXPathNodeSetSort(nodes2);
4830 return(xmlXPathNodeTrailingSorted(nodes1,
4831 xmlXPathNodeSetItem(nodes2, 0)));
4832 }
4833
4834 /************************************************************************
4835 * *
4836 * Routines to handle extra functions *
4837 * *
4838 ************************************************************************/
4839
4840 /**
4841 * xmlXPathRegisterFunc:
4842 * @ctxt: the XPath context
4843 * @name: the function name
4844 * @f: the function implementation or NULL
4845 *
4846 * Register a new function. If @f is NULL it unregisters the function
4847 *
4848 * Returns 0 in case of success, -1 in case of error
4849 */
4850 int
4851 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4852 xmlXPathFunction f) {
4853 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4854 }
4855
4856 /**
4857 * xmlXPathRegisterFuncNS:
4858 * @ctxt: the XPath context
4859 * @name: the function name
4860 * @ns_uri: the function namespace URI
4861 * @f: the function implementation or NULL
4862 *
4863 * Register a new function. If @f is NULL it unregisters the function
4864 *
4865 * Returns 0 in case of success, -1 in case of error
4866 */
4867 int
4868 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4869 const xmlChar *ns_uri, xmlXPathFunction f) {
4870 if (ctxt == NULL)
4871 return(-1);
4872 if (name == NULL)
4873 return(-1);
4874
4875 if (ctxt->funcHash == NULL)
4876 ctxt->funcHash = xmlHashCreate(0);
4877 if (ctxt->funcHash == NULL)
4878 return(-1);
4879 if (f == NULL)
4880 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4881 XML_IGNORE_PEDANTIC_WARNINGS
4882 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4883 XML_POP_WARNINGS
4884 }
4885
4886 /**
4887 * xmlXPathRegisterFuncLookup:
4888 * @ctxt: the XPath context
4889 * @f: the lookup function
4890 * @funcCtxt: the lookup data
4891 *
4892 * Registers an external mechanism to do function lookup.
4893 */
4894 void
4895 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4896 xmlXPathFuncLookupFunc f,
4897 void *funcCtxt) {
4898 if (ctxt == NULL)
4899 return;
4900 ctxt->funcLookupFunc = f;
4901 ctxt->funcLookupData = funcCtxt;
4902 }
4903
4904 /**
4905 * xmlXPathFunctionLookup:
4906 * @ctxt: the XPath context
4907 * @name: the function name
4908 *
4909 * Search in the Function array of the context for the given
4910 * function.
4911 *
4912 * Returns the xmlXPathFunction or NULL if not found
4913 */
4914 xmlXPathFunction
4915 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4916 if (ctxt == NULL)
4917 return (NULL);
4918
4919 if (ctxt->funcLookupFunc != NULL) {
4920 xmlXPathFunction ret;
4921 xmlXPathFuncLookupFunc f;
4922
4923 f = ctxt->funcLookupFunc;
4924 ret = f(ctxt->funcLookupData, name, NULL);
4925 if (ret != NULL)
4926 return(ret);
4927 }
4928 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4929 }
4930
4931 /**
4932 * xmlXPathFunctionLookupNS:
4933 * @ctxt: the XPath context
4934 * @name: the function name
4935 * @ns_uri: the function namespace URI
4936 *
4937 * Search in the Function array of the context for the given
4938 * function.
4939 *
4940 * Returns the xmlXPathFunction or NULL if not found
4941 */
4942 xmlXPathFunction
4943 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4944 const xmlChar *ns_uri) {
4945 xmlXPathFunction ret;
4946
4947 if (ctxt == NULL)
4948 return(NULL);
4949 if (name == NULL)
4950 return(NULL);
4951
4952 if (ctxt->funcLookupFunc != NULL) {
4953 xmlXPathFuncLookupFunc f;
4954
4955 f = ctxt->funcLookupFunc;
4956 ret = f(ctxt->funcLookupData, name, ns_uri);
4957 if (ret != NULL)
4958 return(ret);
4959 }
4960
4961 if (ctxt->funcHash == NULL)
4962 return(NULL);
4963
4964 XML_IGNORE_PEDANTIC_WARNINGS
4965 ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4966 XML_POP_WARNINGS
4967 return(ret);
4968 }
4969
4970 /**
4971 * xmlXPathRegisteredFuncsCleanup:
4972 * @ctxt: the XPath context
4973 *
4974 * Cleanup the XPath context data associated to registered functions
4975 */
4976 void
4977 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4978 if (ctxt == NULL)
4979 return;
4980
4981 xmlHashFree(ctxt->funcHash, NULL);
4982 ctxt->funcHash = NULL;
4983 }
4984
4985 /************************************************************************
4986 * *
4987 * Routines to handle Variables *
4988 * *
4989 ************************************************************************/
4990
4991 /**
4992 * xmlXPathRegisterVariable:
4993 * @ctxt: the XPath context
4994 * @name: the variable name
4995 * @value: the variable value or NULL
4996 *
4997 * Register a new variable value. If @value is NULL it unregisters
4998 * the variable
4999 *
5000 * Returns 0 in case of success, -1 in case of error
5001 */
5002 int
5003 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
5004 xmlXPathObjectPtr value) {
5005 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
5006 }
5007
5008 /**
5009 * xmlXPathRegisterVariableNS:
5010 * @ctxt: the XPath context
5011 * @name: the variable name
5012 * @ns_uri: the variable namespace URI
5013 * @value: the variable value or NULL
5014 *
5015 * Register a new variable value. If @value is NULL it unregisters
5016 * the variable
5017 *
5018 * Returns 0 in case of success, -1 in case of error
5019 */
5020 int
5021 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5022 const xmlChar *ns_uri,
5023 xmlXPathObjectPtr value) {
5024 if (ctxt == NULL)
5025 return(-1);
5026 if (name == NULL)
5027 return(-1);
5028
5029 if (ctxt->varHash == NULL)
5030 ctxt->varHash = xmlHashCreate(0);
5031 if (ctxt->varHash == NULL)
5032 return(-1);
5033 if (value == NULL)
5034 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5035 xmlXPathFreeObjectEntry));
5036 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5037 (void *) value, xmlXPathFreeObjectEntry));
5038 }
5039
5040 /**
5041 * xmlXPathRegisterVariableLookup:
5042 * @ctxt: the XPath context
5043 * @f: the lookup function
5044 * @data: the lookup data
5045 *
5046 * register an external mechanism to do variable lookup
5047 */
5048 void
5049 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5050 xmlXPathVariableLookupFunc f, void *data) {
5051 if (ctxt == NULL)
5052 return;
5053 ctxt->varLookupFunc = f;
5054 ctxt->varLookupData = data;
5055 }
5056
5057 /**
5058 * xmlXPathVariableLookup:
5059 * @ctxt: the XPath context
5060 * @name: the variable name
5061 *
5062 * Search in the Variable array of the context for the given
5063 * variable value.
5064 *
5065 * Returns a copy of the value or NULL if not found
5066 */
5067 xmlXPathObjectPtr
5068 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5069 if (ctxt == NULL)
5070 return(NULL);
5071
5072 if (ctxt->varLookupFunc != NULL) {
5073 xmlXPathObjectPtr ret;
5074
5075 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5076 (ctxt->varLookupData, name, NULL);
5077 return(ret);
5078 }
5079 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5080 }
5081
5082 /**
5083 * xmlXPathVariableLookupNS:
5084 * @ctxt: the XPath context
5085 * @name: the variable name
5086 * @ns_uri: the variable namespace URI
5087 *
5088 * Search in the Variable array of the context for the given
5089 * variable value.
5090 *
5091 * Returns the a copy of the value or NULL if not found
5092 */
5093 xmlXPathObjectPtr
5094 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5095 const xmlChar *ns_uri) {
5096 if (ctxt == NULL)
5097 return(NULL);
5098
5099 if (ctxt->varLookupFunc != NULL) {
5100 xmlXPathObjectPtr ret;
5101
5102 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5103 (ctxt->varLookupData, name, ns_uri);
5104 if (ret != NULL) return(ret);
5105 }
5106
5107 if (ctxt->varHash == NULL)
5108 return(NULL);
5109 if (name == NULL)
5110 return(NULL);
5111
5112 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5113 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5114 }
5115
5116 /**
5117 * xmlXPathRegisteredVariablesCleanup:
5118 * @ctxt: the XPath context
5119 *
5120 * Cleanup the XPath context data associated to registered variables
5121 */
5122 void
5123 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5124 if (ctxt == NULL)
5125 return;
5126
5127 xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
5128 ctxt->varHash = NULL;
5129 }
5130
5131 /**
5132 * xmlXPathRegisterNs:
5133 * @ctxt: the XPath context
5134 * @prefix: the namespace prefix cannot be NULL or empty string
5135 * @ns_uri: the namespace name
5136 *
5137 * Register a new namespace. If @ns_uri is NULL it unregisters
5138 * the namespace
5139 *
5140 * Returns 0 in case of success, -1 in case of error
5141 */
5142 int
5143 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5144 const xmlChar *ns_uri) {
5145 if (ctxt == NULL)
5146 return(-1);
5147 if (prefix == NULL)
5148 return(-1);
5149 if (prefix[0] == 0)
5150 return(-1);
5151
5152 if (ctxt->nsHash == NULL)
5153 ctxt->nsHash = xmlHashCreate(10);
5154 if (ctxt->nsHash == NULL)
5155 return(-1);
5156 if (ns_uri == NULL)
5157 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5158 xmlHashDefaultDeallocator));
5159 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5160 xmlHashDefaultDeallocator));
5161 }
5162
5163 /**
5164 * xmlXPathNsLookup:
5165 * @ctxt: the XPath context
5166 * @prefix: the namespace prefix value
5167 *
5168 * Search in the namespace declaration array of the context for the given
5169 * namespace name associated to the given prefix
5170 *
5171 * Returns the value or NULL if not found
5172 */
5173 const xmlChar *
5174 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5175 if (ctxt == NULL)
5176 return(NULL);
5177 if (prefix == NULL)
5178 return(NULL);
5179
5180 #ifdef XML_XML_NAMESPACE
5181 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5182 return(XML_XML_NAMESPACE);
5183 #endif
5184
5185 if (ctxt->namespaces != NULL) {
5186 int i;
5187
5188 for (i = 0;i < ctxt->nsNr;i++) {
5189 if ((ctxt->namespaces[i] != NULL) &&
5190 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5191 return(ctxt->namespaces[i]->href);
5192 }
5193 }
5194
5195 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5196 }
5197
5198 /**
5199 * xmlXPathRegisteredNsCleanup:
5200 * @ctxt: the XPath context
5201 *
5202 * Cleanup the XPath context data associated to registered variables
5203 */
5204 void
5205 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5206 if (ctxt == NULL)
5207 return;
5208
5209 xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
5210 ctxt->nsHash = NULL;
5211 }
5212
5213 /************************************************************************
5214 * *
5215 * Routines to handle Values *
5216 * *
5217 ************************************************************************/
5218
5219 /* Allocations are terrible, one needs to optimize all this !!! */
5220
5221 /**
5222 * xmlXPathNewFloat:
5223 * @val: the double value
5224 *
5225 * Create a new xmlXPathObjectPtr of type double and of value @val
5226 *
5227 * Returns the newly created object.
5228 */
5229 xmlXPathObjectPtr
5230 xmlXPathNewFloat(double val) {
5231 xmlXPathObjectPtr ret;
5232
5233 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5234 if (ret == NULL) {
5235 xmlXPathErrMemory(NULL, "creating float object\n");
5236 return(NULL);
5237 }
5238 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5239 ret->type = XPATH_NUMBER;
5240 ret->floatval = val;
5241 #ifdef XP_DEBUG_OBJ_USAGE
5242 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5243 #endif
5244 return(ret);
5245 }
5246
5247 /**
5248 * xmlXPathNewBoolean:
5249 * @val: the boolean value
5250 *
5251 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5252 *
5253 * Returns the newly created object.
5254 */
5255 xmlXPathObjectPtr
5256 xmlXPathNewBoolean(int val) {
5257 xmlXPathObjectPtr ret;
5258
5259 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5260 if (ret == NULL) {
5261 xmlXPathErrMemory(NULL, "creating boolean object\n");
5262 return(NULL);
5263 }
5264 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5265 ret->type = XPATH_BOOLEAN;
5266 ret->boolval = (val != 0);
5267 #ifdef XP_DEBUG_OBJ_USAGE
5268 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5269 #endif
5270 return(ret);
5271 }
5272
5273 /**
5274 * xmlXPathNewString:
5275 * @val: the xmlChar * value
5276 *
5277 * Create a new xmlXPathObjectPtr of type string and of value @val
5278 *
5279 * Returns the newly created object.
5280 */
5281 xmlXPathObjectPtr
5282 xmlXPathNewString(const xmlChar *val) {
5283 xmlXPathObjectPtr ret;
5284
5285 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5286 if (ret == NULL) {
5287 xmlXPathErrMemory(NULL, "creating string object\n");
5288 return(NULL);
5289 }
5290 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5291 ret->type = XPATH_STRING;
5292 if (val != NULL)
5293 ret->stringval = xmlStrdup(val);
5294 else
5295 ret->stringval = xmlStrdup((const xmlChar *)"");
5296 #ifdef XP_DEBUG_OBJ_USAGE
5297 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5298 #endif
5299 return(ret);
5300 }
5301
5302 /**
5303 * xmlXPathWrapString:
5304 * @val: the xmlChar * value
5305 *
5306 * Wraps the @val string into an XPath object.
5307 *
5308 * Returns the newly created object.
5309 */
5310 xmlXPathObjectPtr
5311 xmlXPathWrapString (xmlChar *val) {
5312 xmlXPathObjectPtr ret;
5313
5314 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5315 if (ret == NULL) {
5316 xmlXPathErrMemory(NULL, "creating string object\n");
5317 return(NULL);
5318 }
5319 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5320 ret->type = XPATH_STRING;
5321 ret->stringval = val;
5322 #ifdef XP_DEBUG_OBJ_USAGE
5323 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5324 #endif
5325 return(ret);
5326 }
5327
5328 /**
5329 * xmlXPathNewCString:
5330 * @val: the char * value
5331 *
5332 * Create a new xmlXPathObjectPtr of type string and of value @val
5333 *
5334 * Returns the newly created object.
5335 */
5336 xmlXPathObjectPtr
5337 xmlXPathNewCString(const char *val) {
5338 xmlXPathObjectPtr ret;
5339
5340 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5341 if (ret == NULL) {
5342 xmlXPathErrMemory(NULL, "creating string object\n");
5343 return(NULL);
5344 }
5345 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5346 ret->type = XPATH_STRING;
5347 ret->stringval = xmlStrdup(BAD_CAST val);
5348 #ifdef XP_DEBUG_OBJ_USAGE
5349 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5350 #endif
5351 return(ret);
5352 }
5353
5354 /**
5355 * xmlXPathWrapCString:
5356 * @val: the char * value
5357 *
5358 * Wraps a string into an XPath object.
5359 *
5360 * Returns the newly created object.
5361 */
5362 xmlXPathObjectPtr
5363 xmlXPathWrapCString (char * val) {
5364 return(xmlXPathWrapString((xmlChar *)(val)));
5365 }
5366
5367 /**
5368 * xmlXPathWrapExternal:
5369 * @val: the user data
5370 *
5371 * Wraps the @val data into an XPath object.
5372 *
5373 * Returns the newly created object.
5374 */
5375 xmlXPathObjectPtr
5376 xmlXPathWrapExternal (void *val) {
5377 xmlXPathObjectPtr ret;
5378
5379 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5380 if (ret == NULL) {
5381 xmlXPathErrMemory(NULL, "creating user object\n");
5382 return(NULL);
5383 }
5384 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5385 ret->type = XPATH_USERS;
5386 ret->user = val;
5387 #ifdef XP_DEBUG_OBJ_USAGE
5388 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5389 #endif
5390 return(ret);
5391 }
5392
5393 /**
5394 * xmlXPathObjectCopy:
5395 * @val: the original object
5396 *
5397 * allocate a new copy of a given object
5398 *
5399 * Returns the newly created object.
5400 */
5401 xmlXPathObjectPtr
5402 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5403 xmlXPathObjectPtr ret;
5404
5405 if (val == NULL)
5406 return(NULL);
5407
5408 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5409 if (ret == NULL) {
5410 xmlXPathErrMemory(NULL, "copying object\n");
5411 return(NULL);
5412 }
5413 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5414 #ifdef XP_DEBUG_OBJ_USAGE
5415 xmlXPathDebugObjUsageRequested(NULL, val->type);
5416 #endif
5417 switch (val->type) {
5418 case XPATH_BOOLEAN:
5419 case XPATH_NUMBER:
5420 case XPATH_POINT:
5421 case XPATH_RANGE:
5422 break;
5423 case XPATH_STRING:
5424 ret->stringval = xmlStrdup(val->stringval);
5425 break;
5426 case XPATH_XSLT_TREE:
5427 #if 0
5428 /*
5429 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5430 this previous handling is no longer correct, and can cause some serious
5431 problems (ref. bug 145547)
5432 */
5433 if ((val->nodesetval != NULL) &&
5434 (val->nodesetval->nodeTab != NULL)) {
5435 xmlNodePtr cur, tmp;
5436 xmlDocPtr top;
5437
5438 ret->boolval = 1;
5439 top = xmlNewDoc(NULL);
5440 top->name = (char *)
5441 xmlStrdup(val->nodesetval->nodeTab[0]->name);
5442 ret->user = top;
5443 if (top != NULL) {
5444 top->doc = top;
5445 cur = val->nodesetval->nodeTab[0]->children;
5446 while (cur != NULL) {
5447 tmp = xmlDocCopyNode(cur, top, 1);
5448 xmlAddChild((xmlNodePtr) top, tmp);
5449 cur = cur->next;
5450 }
5451 }
5452
5453 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5454 } else
5455 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5456 /* Deallocate the copied tree value */
5457 break;
5458 #endif
5459 case XPATH_NODESET:
5460 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5461 /* Do not deallocate the copied tree value */
5462 ret->boolval = 0;
5463 break;
5464 case XPATH_LOCATIONSET:
5465 #ifdef LIBXML_XPTR_ENABLED
5466 {
5467 xmlLocationSetPtr loc = val->user;
5468 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5469 break;
5470 }
5471 #endif
5472 case XPATH_USERS:
5473 ret->user = val->user;
5474 break;
5475 case XPATH_UNDEFINED:
5476 xmlGenericError(xmlGenericErrorContext,
5477 "xmlXPathObjectCopy: unsupported type %d\n",
5478 val->type);
5479 break;
5480 }
5481 return(ret);
5482 }
5483
5484 /**
5485 * xmlXPathFreeObject:
5486 * @obj: the object to free
5487 *
5488 * Free up an xmlXPathObjectPtr object.
5489 */
5490 void
5491 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5492 if (obj == NULL) return;
5493 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5494 if (obj->boolval) {
5495 #if 0
5496 if (obj->user != NULL) {
5497 xmlXPathFreeNodeSet(obj->nodesetval);
5498 xmlFreeNodeList((xmlNodePtr) obj->user);
5499 } else
5500 #endif
5501 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5502 if (obj->nodesetval != NULL)
5503 xmlXPathFreeValueTree(obj->nodesetval);
5504 } else {
5505 if (obj->nodesetval != NULL)
5506 xmlXPathFreeNodeSet(obj->nodesetval);
5507 }
5508 #ifdef LIBXML_XPTR_ENABLED
5509 } else if (obj->type == XPATH_LOCATIONSET) {
5510 if (obj->user != NULL)
5511 xmlXPtrFreeLocationSet(obj->user);
5512 #endif
5513 } else if (obj->type == XPATH_STRING) {
5514 if (obj->stringval != NULL)
5515 xmlFree(obj->stringval);
5516 }
5517 #ifdef XP_DEBUG_OBJ_USAGE
5518 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5519 #endif
5520 xmlFree(obj);
5521 }
5522
5523 static void
5524 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
5525 xmlXPathFreeObject((xmlXPathObjectPtr) obj);
5526 }
5527
5528 /**
5529 * xmlXPathReleaseObject:
5530 * @obj: the xmlXPathObjectPtr to free or to cache
5531 *
5532 * Depending on the state of the cache this frees the given
5533 * XPath object or stores it in the cache.
5534 */
5535 static void
5536 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5537 {
5538 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5539 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5540 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5541
5542 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5543
5544 if (obj == NULL)
5545 return;
5546 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5547 xmlXPathFreeObject(obj);
5548 } else {
5549 xmlXPathContextCachePtr cache =
5550 (xmlXPathContextCachePtr) ctxt->cache;
5551
5552 switch (obj->type) {
5553 case XPATH_NODESET:
5554 case XPATH_XSLT_TREE:
5555 if (obj->nodesetval != NULL) {
5556 if (obj->boolval) {
5557 /*
5558 * It looks like the @boolval is used for
5559 * evaluation if this an XSLT Result Tree Fragment.
5560 * TODO: Check if this assumption is correct.
5561 */
5562 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5563 xmlXPathFreeValueTree(obj->nodesetval);
5564 obj->nodesetval = NULL;
5565 } else if ((obj->nodesetval->nodeMax <= 40) &&
5566 (XP_CACHE_WANTS(cache->nodesetObjs,
5567 cache->maxNodeset)))
5568 {
5569 XP_CACHE_ADD(cache->nodesetObjs, obj);
5570 goto obj_cached;
5571 } else {
5572 xmlXPathFreeNodeSet(obj->nodesetval);
5573 obj->nodesetval = NULL;
5574 }
5575 }
5576 break;
5577 case XPATH_STRING:
5578 if (obj->stringval != NULL)
5579 xmlFree(obj->stringval);
5580
5581 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5582 XP_CACHE_ADD(cache->stringObjs, obj);
5583 goto obj_cached;
5584 }
5585 break;
5586 case XPATH_BOOLEAN:
5587 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5588 XP_CACHE_ADD(cache->booleanObjs, obj);
5589 goto obj_cached;
5590 }
5591 break;
5592 case XPATH_NUMBER:
5593 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5594 XP_CACHE_ADD(cache->numberObjs, obj);
5595 goto obj_cached;
5596 }
5597 break;
5598 #ifdef LIBXML_XPTR_ENABLED
5599 case XPATH_LOCATIONSET:
5600 if (obj->user != NULL) {
5601 xmlXPtrFreeLocationSet(obj->user);
5602 }
5603 goto free_obj;
5604 #endif
5605 default:
5606 goto free_obj;
5607 }
5608
5609 /*
5610 * Fallback to adding to the misc-objects slot.
5611 */
5612 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5613 XP_CACHE_ADD(cache->miscObjs, obj);
5614 } else
5615 goto free_obj;
5616
5617 obj_cached:
5618
5619 #ifdef XP_DEBUG_OBJ_USAGE
5620 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5621 #endif
5622
5623 if (obj->nodesetval != NULL) {
5624 xmlNodeSetPtr tmpset = obj->nodesetval;
5625
5626 /*
5627 * TODO: Due to those nasty ns-nodes, we need to traverse
5628 * the list and free the ns-nodes.
5629 * URGENT TODO: Check if it's actually slowing things down.
5630 * Maybe we shouldn't try to preserve the list.
5631 */
5632 if (tmpset->nodeNr > 1) {
5633 int i;
5634 xmlNodePtr node;
5635
5636 for (i = 0; i < tmpset->nodeNr; i++) {
5637 node = tmpset->nodeTab[i];
5638 if ((node != NULL) &&
5639 (node->type == XML_NAMESPACE_DECL))
5640 {
5641 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5642 }
5643 }
5644 } else if (tmpset->nodeNr == 1) {
5645 if ((tmpset->nodeTab[0] != NULL) &&
5646 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5647 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5648 }
5649 tmpset->nodeNr = 0;
5650 memset(obj, 0, sizeof(xmlXPathObject));
5651 obj->nodesetval = tmpset;
5652 } else
5653 memset(obj, 0, sizeof(xmlXPathObject));
5654
5655 return;
5656
5657 free_obj:
5658 /*
5659 * Cache is full; free the object.
5660 */
5661 if (obj->nodesetval != NULL)
5662 xmlXPathFreeNodeSet(obj->nodesetval);
5663 #ifdef XP_DEBUG_OBJ_USAGE
5664 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5665 #endif
5666 xmlFree(obj);
5667 }
5668 return;
5669 }
5670
5671
5672 /************************************************************************
5673 * *
5674 * Type Casting Routines *
5675 * *
5676 ************************************************************************/
5677
5678 /**
5679 * xmlXPathCastBooleanToString:
5680 * @val: a boolean
5681 *
5682 * Converts a boolean to its string value.
5683 *
5684 * Returns a newly allocated string.
5685 */
5686 xmlChar *
5687 xmlXPathCastBooleanToString (int val) {
5688 xmlChar *ret;
5689 if (val)
5690 ret = xmlStrdup((const xmlChar *) "true");
5691 else
5692 ret = xmlStrdup((const xmlChar *) "false");
5693 return(ret);
5694 }
5695
5696 /**
5697 * xmlXPathCastNumberToString:
5698 * @val: a number
5699 *
5700 * Converts a number to its string value.
5701 *
5702 * Returns a newly allocated string.
5703 */
5704 xmlChar *
5705 xmlXPathCastNumberToString (double val) {
5706 xmlChar *ret;
5707 switch (xmlXPathIsInf(val)) {
5708 case 1:
5709 ret = xmlStrdup((const xmlChar *) "Infinity");
5710 break;
5711 case -1:
5712 ret = xmlStrdup((const xmlChar *) "-Infinity");
5713 break;
5714 default:
5715 if (xmlXPathIsNaN(val)) {
5716 ret = xmlStrdup((const xmlChar *) "NaN");
5717 } else if (val == 0) {
5718 /* Omit sign for negative zero. */
5719 ret = xmlStrdup((const xmlChar *) "0");
5720 } else {
5721 /* could be improved */
5722 char buf[100];
5723 xmlXPathFormatNumber(val, buf, 99);
5724 buf[99] = 0;
5725 ret = xmlStrdup((const xmlChar *) buf);
5726 }
5727 }
5728 return(ret);
5729 }
5730
5731 /**
5732 * xmlXPathCastNodeToString:
5733 * @node: a node
5734 *
5735 * Converts a node to its string value.
5736 *
5737 * Returns a newly allocated string.
5738 */
5739 xmlChar *
5740 xmlXPathCastNodeToString (xmlNodePtr node) {
5741 xmlChar *ret;
5742 if ((ret = xmlNodeGetContent(node)) == NULL)
5743 ret = xmlStrdup((const xmlChar *) "");
5744 return(ret);
5745 }
5746
5747 /**
5748 * xmlXPathCastNodeSetToString:
5749 * @ns: a node-set
5750 *
5751 * Converts a node-set to its string value.
5752 *
5753 * Returns a newly allocated string.
5754 */
5755 xmlChar *
5756 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5757 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5758 return(xmlStrdup((const xmlChar *) ""));
5759
5760 if (ns->nodeNr > 1)
5761 xmlXPathNodeSetSort(ns);
5762 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5763 }
5764
5765 /**
5766 * xmlXPathCastToString:
5767 * @val: an XPath object
5768 *
5769 * Converts an existing object to its string() equivalent
5770 *
5771 * Returns the allocated string value of the object, NULL in case of error.
5772 * It's up to the caller to free the string memory with xmlFree().
5773 */
5774 xmlChar *
5775 xmlXPathCastToString(xmlXPathObjectPtr val) {
5776 xmlChar *ret = NULL;
5777
5778 if (val == NULL)
5779 return(xmlStrdup((const xmlChar *) ""));
5780 switch (val->type) {
5781 case XPATH_UNDEFINED:
5782 #ifdef DEBUG_EXPR
5783 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5784 #endif
5785 ret = xmlStrdup((const xmlChar *) "");
5786 break;
5787 case XPATH_NODESET:
5788 case XPATH_XSLT_TREE:
5789 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5790 break;
5791 case XPATH_STRING:
5792 return(xmlStrdup(val->stringval));
5793 case XPATH_BOOLEAN:
5794 ret = xmlXPathCastBooleanToString(val->boolval);
5795 break;
5796 case XPATH_NUMBER: {
5797 ret = xmlXPathCastNumberToString(val->floatval);
5798 break;
5799 }
5800 case XPATH_USERS:
5801 case XPATH_POINT:
5802 case XPATH_RANGE:
5803 case XPATH_LOCATIONSET:
5804 TODO
5805 ret = xmlStrdup((const xmlChar *) "");
5806 break;
5807 }
5808 return(ret);
5809 }
5810
5811 /**
5812 * xmlXPathConvertString:
5813 * @val: an XPath object
5814 *
5815 * Converts an existing object to its string() equivalent
5816 *
5817 * Returns the new object, the old one is freed (or the operation
5818 * is done directly on @val)
5819 */
5820 xmlXPathObjectPtr
5821 xmlXPathConvertString(xmlXPathObjectPtr val) {
5822 xmlChar *res = NULL;
5823
5824 if (val == NULL)
5825 return(xmlXPathNewCString(""));
5826
5827 switch (val->type) {
5828 case XPATH_UNDEFINED:
5829 #ifdef DEBUG_EXPR
5830 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5831 #endif
5832 break;
5833 case XPATH_NODESET:
5834 case XPATH_XSLT_TREE:
5835 res = xmlXPathCastNodeSetToString(val->nodesetval);
5836 break;
5837 case XPATH_STRING:
5838 return(val);
5839 case XPATH_BOOLEAN:
5840 res = xmlXPathCastBooleanToString(val->boolval);
5841 break;
5842 case XPATH_NUMBER:
5843 res = xmlXPathCastNumberToString(val->floatval);
5844 break;
5845 case XPATH_USERS:
5846 case XPATH_POINT:
5847 case XPATH_RANGE:
5848 case XPATH_LOCATIONSET:
5849 TODO;
5850 break;
5851 }
5852 xmlXPathFreeObject(val);
5853 if (res == NULL)
5854 return(xmlXPathNewCString(""));
5855 return(xmlXPathWrapString(res));
5856 }
5857
5858 /**
5859 * xmlXPathCastBooleanToNumber:
5860 * @val: a boolean
5861 *
5862 * Converts a boolean to its number value
5863 *
5864 * Returns the number value
5865 */
5866 double
5867 xmlXPathCastBooleanToNumber(int val) {
5868 if (val)
5869 return(1.0);
5870 return(0.0);
5871 }
5872
5873 /**
5874 * xmlXPathCastStringToNumber:
5875 * @val: a string
5876 *
5877 * Converts a string to its number value
5878 *
5879 * Returns the number value
5880 */
5881 double
5882 xmlXPathCastStringToNumber(const xmlChar * val) {
5883 return(xmlXPathStringEvalNumber(val));
5884 }
5885
5886 /**
5887 * xmlXPathCastNodeToNumber:
5888 * @node: a node
5889 *
5890 * Converts a node to its number value
5891 *
5892 * Returns the number value
5893 */
5894 double
5895 xmlXPathCastNodeToNumber (xmlNodePtr node) {
5896 xmlChar *strval;
5897 double ret;
5898
5899 if (node == NULL)
5900 return(NAN);
5901 strval = xmlXPathCastNodeToString(node);
5902 if (strval == NULL)
5903 return(NAN);
5904 ret = xmlXPathCastStringToNumber(strval);
5905 xmlFree(strval);
5906
5907 return(ret);
5908 }
5909
5910 /**
5911 * xmlXPathCastNodeSetToNumber:
5912 * @ns: a node-set
5913 *
5914 * Converts a node-set to its number value
5915 *
5916 * Returns the number value
5917 */
5918 double
5919 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5920 xmlChar *str;
5921 double ret;
5922
5923 if (ns == NULL)
5924 return(NAN);
5925 str = xmlXPathCastNodeSetToString(ns);
5926 ret = xmlXPathCastStringToNumber(str);
5927 xmlFree(str);
5928 return(ret);
5929 }
5930
5931 /**
5932 * xmlXPathCastToNumber:
5933 * @val: an XPath object
5934 *
5935 * Converts an XPath object to its number value
5936 *
5937 * Returns the number value
5938 */
5939 double
5940 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5941 double ret = 0.0;
5942
5943 if (val == NULL)
5944 return(NAN);
5945 switch (val->type) {
5946 case XPATH_UNDEFINED:
5947 #ifdef DEGUB_EXPR
5948 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5949 #endif
5950 ret = NAN;
5951 break;
5952 case XPATH_NODESET:
5953 case XPATH_XSLT_TREE:
5954 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5955 break;
5956 case XPATH_STRING:
5957 ret = xmlXPathCastStringToNumber(val->stringval);
5958 break;
5959 case XPATH_NUMBER:
5960 ret = val->floatval;
5961 break;
5962 case XPATH_BOOLEAN:
5963 ret = xmlXPathCastBooleanToNumber(val->boolval);
5964 break;
5965 case XPATH_USERS:
5966 case XPATH_POINT:
5967 case XPATH_RANGE:
5968 case XPATH_LOCATIONSET:
5969 TODO;
5970 ret = NAN;
5971 break;
5972 }
5973 return(ret);
5974 }
5975
5976 /**
5977 * xmlXPathConvertNumber:
5978 * @val: an XPath object
5979 *
5980 * Converts an existing object to its number() equivalent
5981 *
5982 * Returns the new object, the old one is freed (or the operation
5983 * is done directly on @val)
5984 */
5985 xmlXPathObjectPtr
5986 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5987 xmlXPathObjectPtr ret;
5988
5989 if (val == NULL)
5990 return(xmlXPathNewFloat(0.0));
5991 if (val->type == XPATH_NUMBER)
5992 return(val);
5993 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5994 xmlXPathFreeObject(val);
5995 return(ret);
5996 }
5997
5998 /**
5999 * xmlXPathCastNumberToBoolean:
6000 * @val: a number
6001 *
6002 * Converts a number to its boolean value
6003 *
6004 * Returns the boolean value
6005 */
6006 int
6007 xmlXPathCastNumberToBoolean (double val) {
6008 if (xmlXPathIsNaN(val) || (val == 0.0))
6009 return(0);
6010 return(1);
6011 }
6012
6013 /**
6014 * xmlXPathCastStringToBoolean:
6015 * @val: a string
6016 *
6017 * Converts a string to its boolean value
6018 *
6019 * Returns the boolean value
6020 */
6021 int
6022 xmlXPathCastStringToBoolean (const xmlChar *val) {
6023 if ((val == NULL) || (xmlStrlen(val) == 0))
6024 return(0);
6025 return(1);
6026 }
6027
6028 /**
6029 * xmlXPathCastNodeSetToBoolean:
6030 * @ns: a node-set
6031 *
6032 * Converts a node-set to its boolean value
6033 *
6034 * Returns the boolean value
6035 */
6036 int
6037 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6038 if ((ns == NULL) || (ns->nodeNr == 0))
6039 return(0);
6040 return(1);
6041 }
6042
6043 /**
6044 * xmlXPathCastToBoolean:
6045 * @val: an XPath object
6046 *
6047 * Converts an XPath object to its boolean value
6048 *
6049 * Returns the boolean value
6050 */
6051 int
6052 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6053 int ret = 0;
6054
6055 if (val == NULL)
6056 return(0);
6057 switch (val->type) {
6058 case XPATH_UNDEFINED:
6059 #ifdef DEBUG_EXPR
6060 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6061 #endif
6062 ret = 0;
6063 break;
6064 case XPATH_NODESET:
6065 case XPATH_XSLT_TREE:
6066 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6067 break;
6068 case XPATH_STRING:
6069 ret = xmlXPathCastStringToBoolean(val->stringval);
6070 break;
6071 case XPATH_NUMBER:
6072 ret = xmlXPathCastNumberToBoolean(val->floatval);
6073 break;
6074 case XPATH_BOOLEAN:
6075 ret = val->boolval;
6076 break;
6077 case XPATH_USERS:
6078 case XPATH_POINT:
6079 case XPATH_RANGE:
6080 case XPATH_LOCATIONSET:
6081 TODO;
6082 ret = 0;
6083 break;
6084 }
6085 return(ret);
6086 }
6087
6088
6089 /**
6090 * xmlXPathConvertBoolean:
6091 * @val: an XPath object
6092 *
6093 * Converts an existing object to its boolean() equivalent
6094 *
6095 * Returns the new object, the old one is freed (or the operation
6096 * is done directly on @val)
6097 */
6098 xmlXPathObjectPtr
6099 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6100 xmlXPathObjectPtr ret;
6101
6102 if (val == NULL)
6103 return(xmlXPathNewBoolean(0));
6104 if (val->type == XPATH_BOOLEAN)
6105 return(val);
6106 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6107 xmlXPathFreeObject(val);
6108 return(ret);
6109 }
6110
6111 /************************************************************************
6112 * *
6113 * Routines to handle XPath contexts *
6114 * *
6115 ************************************************************************/
6116
6117 /**
6118 * xmlXPathNewContext:
6119 * @doc: the XML document
6120 *
6121 * Create a new xmlXPathContext
6122 *
6123 * Returns the xmlXPathContext just allocated. The caller will need to free it.
6124 */
6125 xmlXPathContextPtr
6126 xmlXPathNewContext(xmlDocPtr doc) {
6127 xmlXPathContextPtr ret;
6128
6129 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6130 if (ret == NULL) {
6131 xmlXPathErrMemory(NULL, "creating context\n");
6132 return(NULL);
6133 }
6134 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6135 ret->doc = doc;
6136 ret->node = NULL;
6137
6138 ret->varHash = NULL;
6139
6140 ret->nb_types = 0;
6141 ret->max_types = 0;
6142 ret->types = NULL;
6143
6144 ret->funcHash = xmlHashCreate(0);
6145
6146 ret->nb_axis = 0;
6147 ret->max_axis = 0;
6148 ret->axis = NULL;
6149
6150 ret->nsHash = NULL;
6151 ret->user = NULL;
6152
6153 ret->contextSize = -1;
6154 ret->proximityPosition = -1;
6155
6156 #ifdef XP_DEFAULT_CACHE_ON
6157 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6158 xmlXPathFreeContext(ret);
6159 return(NULL);
6160 }
6161 #endif
6162
6163 xmlXPathRegisterAllFunctions(ret);
6164
6165 return(ret);
6166 }
6167
6168 /**
6169 * xmlXPathFreeContext:
6170 * @ctxt: the context to free
6171 *
6172 * Free up an xmlXPathContext
6173 */
6174 void
6175 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6176 if (ctxt == NULL) return;
6177
6178 if (ctxt->cache != NULL)
6179 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6180 xmlXPathRegisteredNsCleanup(ctxt);
6181 xmlXPathRegisteredFuncsCleanup(ctxt);
6182 xmlXPathRegisteredVariablesCleanup(ctxt);
6183 xmlResetError(&ctxt->lastError);
6184 xmlFree(ctxt);
6185 }
6186
6187 /************************************************************************
6188 * *
6189 * Routines to handle XPath parser contexts *
6190 * *
6191 ************************************************************************/
6192
6193 #define CHECK_CTXT(ctxt) \
6194 if (ctxt == NULL) { \
6195 __xmlRaiseError(NULL, NULL, NULL, \
6196 NULL, NULL, XML_FROM_XPATH, \
6197 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6198 __FILE__, __LINE__, \
6199 NULL, NULL, NULL, 0, 0, \
6200 "NULL context pointer\n"); \
6201 return(NULL); \
6202 } \
6203
6204 #define CHECK_CTXT_NEG(ctxt) \
6205 if (ctxt == NULL) { \
6206 __xmlRaiseError(NULL, NULL, NULL, \
6207 NULL, NULL, XML_FROM_XPATH, \
6208 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6209 __FILE__, __LINE__, \
6210 NULL, NULL, NULL, 0, 0, \
6211 "NULL context pointer\n"); \
6212 return(-1); \
6213 } \
6214
6215
6216 #define CHECK_CONTEXT(ctxt) \
6217 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
6218 (ctxt->doc->children == NULL)) { \
6219 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
6220 return(NULL); \
6221 }
6222
6223
6224 /**
6225 * xmlXPathNewParserContext:
6226 * @str: the XPath expression
6227 * @ctxt: the XPath context
6228 *
6229 * Create a new xmlXPathParserContext
6230 *
6231 * Returns the xmlXPathParserContext just allocated.
6232 */
6233 xmlXPathParserContextPtr
6234 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6235 xmlXPathParserContextPtr ret;
6236
6237 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6238 if (ret == NULL) {
6239 xmlXPathErrMemory(ctxt, "creating parser context\n");
6240 return(NULL);
6241 }
6242 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6243 ret->cur = ret->base = str;
6244 ret->context = ctxt;
6245
6246 ret->comp = xmlXPathNewCompExpr();
6247 if (ret->comp == NULL) {
6248 xmlFree(ret->valueTab);
6249 xmlFree(ret);
6250 return(NULL);
6251 }
6252 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6253 ret->comp->dict = ctxt->dict;
6254 xmlDictReference(ret->comp->dict);
6255 }
6256
6257 return(ret);
6258 }
6259
6260 /**
6261 * xmlXPathCompParserContext:
6262 * @comp: the XPath compiled expression
6263 * @ctxt: the XPath context
6264 *
6265 * Create a new xmlXPathParserContext when processing a compiled expression
6266 *
6267 * Returns the xmlXPathParserContext just allocated.
6268 */
6269 static xmlXPathParserContextPtr
6270 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6271 xmlXPathParserContextPtr ret;
6272
6273 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6274 if (ret == NULL) {
6275 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6276 return(NULL);
6277 }
6278 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6279
6280 /* Allocate the value stack */
6281 ret->valueTab = (xmlXPathObjectPtr *)
6282 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6283 if (ret->valueTab == NULL) {
6284 xmlFree(ret);
6285 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6286 return(NULL);
6287 }
6288 ret->valueNr = 0;
6289 ret->valueMax = 10;
6290 ret->value = NULL;
6291 ret->valueFrame = 0;
6292
6293 ret->context = ctxt;
6294 ret->comp = comp;
6295
6296 return(ret);
6297 }
6298
6299 /**
6300 * xmlXPathFreeParserContext:
6301 * @ctxt: the context to free
6302 *
6303 * Free up an xmlXPathParserContext
6304 */
6305 void
6306 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6307 int i;
6308
6309 if (ctxt->valueTab != NULL) {
6310 for (i = 0; i < ctxt->valueNr; i++) {
6311 if (ctxt->context)
6312 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6313 else
6314 xmlXPathFreeObject(ctxt->valueTab[i]);
6315 }
6316 xmlFree(ctxt->valueTab);
6317 }
6318 if (ctxt->comp != NULL) {
6319 #ifdef XPATH_STREAMING
6320 if (ctxt->comp->stream != NULL) {
6321 xmlFreePatternList(ctxt->comp->stream);
6322 ctxt->comp->stream = NULL;
6323 }
6324 #endif
6325 xmlXPathFreeCompExpr(ctxt->comp);
6326 }
6327 xmlFree(ctxt);
6328 }
6329
6330 /************************************************************************
6331 * *
6332 * The implicit core function library *
6333 * *
6334 ************************************************************************/
6335
6336 /**
6337 * xmlXPathNodeValHash:
6338 * @node: a node pointer
6339 *
6340 * Function computing the beginning of the string value of the node,
6341 * used to speed up comparisons
6342 *
6343 * Returns an int usable as a hash
6344 */
6345 static unsigned int
6346 xmlXPathNodeValHash(xmlNodePtr node) {
6347 int len = 2;
6348 const xmlChar * string = NULL;
6349 xmlNodePtr tmp = NULL;
6350 unsigned int ret = 0;
6351
6352 if (node == NULL)
6353 return(0);
6354
6355 if (node->type == XML_DOCUMENT_NODE) {
6356 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6357 if (tmp == NULL)
6358 node = node->children;
6359 else
6360 node = tmp;
6361
6362 if (node == NULL)
6363 return(0);
6364 }
6365
6366 switch (node->type) {
6367 case XML_COMMENT_NODE:
6368 case XML_PI_NODE:
6369 case XML_CDATA_SECTION_NODE:
6370 case XML_TEXT_NODE:
6371 string = node->content;
6372 if (string == NULL)
6373 return(0);
6374 if (string[0] == 0)
6375 return(0);
6376 return(((unsigned int) string[0]) +
6377 (((unsigned int) string[1]) << 8));
6378 case XML_NAMESPACE_DECL:
6379 string = ((xmlNsPtr)node)->href;
6380 if (string == NULL)
6381 return(0);
6382 if (string[0] == 0)
6383 return(0);
6384 return(((unsigned int) string[0]) +
6385 (((unsigned int) string[1]) << 8));
6386 case XML_ATTRIBUTE_NODE:
6387 tmp = ((xmlAttrPtr) node)->children;
6388 break;
6389 case XML_ELEMENT_NODE:
6390 tmp = node->children;
6391 break;
6392 default:
6393 return(0);
6394 }
6395 while (tmp != NULL) {
6396 switch (tmp->type) {
6397 case XML_CDATA_SECTION_NODE:
6398 case XML_TEXT_NODE:
6399 string = tmp->content;
6400 break;
6401 default:
6402 string = NULL;
6403 break;
6404 }
6405 if ((string != NULL) && (string[0] != 0)) {
6406 if (len == 1) {
6407 return(ret + (((unsigned int) string[0]) << 8));
6408 }
6409 if (string[1] == 0) {
6410 len = 1;
6411 ret = (unsigned int) string[0];
6412 } else {
6413 return(((unsigned int) string[0]) +
6414 (((unsigned int) string[1]) << 8));
6415 }
6416 }
6417 /*
6418 * Skip to next node
6419 */
6420 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6421 if (tmp->children->type != XML_ENTITY_DECL) {
6422 tmp = tmp->children;
6423 continue;
6424 }
6425 }
6426 if (tmp == node)
6427 break;
6428
6429 if (tmp->next != NULL) {
6430 tmp = tmp->next;
6431 continue;
6432 }
6433
6434 do {
6435 tmp = tmp->parent;
6436 if (tmp == NULL)
6437 break;
6438 if (tmp == node) {
6439 tmp = NULL;
6440 break;
6441 }
6442 if (tmp->next != NULL) {
6443 tmp = tmp->next;
6444 break;
6445 }
6446 } while (tmp != NULL);
6447 }
6448 return(ret);
6449 }
6450
6451 /**
6452 * xmlXPathStringHash:
6453 * @string: a string
6454 *
6455 * Function computing the beginning of the string value of the node,
6456 * used to speed up comparisons
6457 *
6458 * Returns an int usable as a hash
6459 */
6460 static unsigned int
6461 xmlXPathStringHash(const xmlChar * string) {
6462 if (string == NULL)
6463 return((unsigned int) 0);
6464 if (string[0] == 0)
6465 return(0);
6466 return(((unsigned int) string[0]) +
6467 (((unsigned int) string[1]) << 8));
6468 }
6469
6470 /**
6471 * xmlXPathCompareNodeSetFloat:
6472 * @ctxt: the XPath Parser context
6473 * @inf: less than (1) or greater than (0)
6474 * @strict: is the comparison strict
6475 * @arg: the node set
6476 * @f: the value
6477 *
6478 * Implement the compare operation between a nodeset and a number
6479 * @ns < @val (1, 1, ...
6480 * @ns <= @val (1, 0, ...
6481 * @ns > @val (0, 1, ...
6482 * @ns >= @val (0, 0, ...
6483 *
6484 * If one object to be compared is a node-set and the other is a number,
6485 * then the comparison will be true if and only if there is a node in the
6486 * node-set such that the result of performing the comparison on the number
6487 * to be compared and on the result of converting the string-value of that
6488 * node to a number using the number function is true.
6489 *
6490 * Returns 0 or 1 depending on the results of the test.
6491 */
6492 static int
6493 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6494 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6495 int i, ret = 0;
6496 xmlNodeSetPtr ns;
6497 xmlChar *str2;
6498
6499 if ((f == NULL) || (arg == NULL) ||
6500 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6501 xmlXPathReleaseObject(ctxt->context, arg);
6502 xmlXPathReleaseObject(ctxt->context, f);
6503 return(0);
6504 }
6505 ns = arg->nodesetval;
6506 if (ns != NULL) {
6507 for (i = 0;i < ns->nodeNr;i++) {
6508 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6509 if (str2 != NULL) {
6510 valuePush(ctxt,
6511 xmlXPathCacheNewString(ctxt->context, str2));
6512 xmlFree(str2);
6513 xmlXPathNumberFunction(ctxt, 1);
6514 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6515 ret = xmlXPathCompareValues(ctxt, inf, strict);
6516 if (ret)
6517 break;
6518 }
6519 }
6520 }
6521 xmlXPathReleaseObject(ctxt->context, arg);
6522 xmlXPathReleaseObject(ctxt->context, f);
6523 return(ret);
6524 }
6525
6526 /**
6527 * xmlXPathCompareNodeSetString:
6528 * @ctxt: the XPath Parser context
6529 * @inf: less than (1) or greater than (0)
6530 * @strict: is the comparison strict
6531 * @arg: the node set
6532 * @s: the value
6533 *
6534 * Implement the compare operation between a nodeset and a string
6535 * @ns < @val (1, 1, ...
6536 * @ns <= @val (1, 0, ...
6537 * @ns > @val (0, 1, ...
6538 * @ns >= @val (0, 0, ...
6539 *
6540 * If one object to be compared is a node-set and the other is a string,
6541 * then the comparison will be true if and only if there is a node in
6542 * the node-set such that the result of performing the comparison on the
6543 * string-value of the node and the other string is true.
6544 *
6545 * Returns 0 or 1 depending on the results of the test.
6546 */
6547 static int
6548 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6549 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6550 int i, ret = 0;
6551 xmlNodeSetPtr ns;
6552 xmlChar *str2;
6553
6554 if ((s == NULL) || (arg == NULL) ||
6555 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6556 xmlXPathReleaseObject(ctxt->context, arg);
6557 xmlXPathReleaseObject(ctxt->context, s);
6558 return(0);
6559 }
6560 ns = arg->nodesetval;
6561 if (ns != NULL) {
6562 for (i = 0;i < ns->nodeNr;i++) {
6563 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6564 if (str2 != NULL) {
6565 valuePush(ctxt,
6566 xmlXPathCacheNewString(ctxt->context, str2));
6567 xmlFree(str2);
6568 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6569 ret = xmlXPathCompareValues(ctxt, inf, strict);
6570 if (ret)
6571 break;
6572 }
6573 }
6574 }
6575 xmlXPathReleaseObject(ctxt->context, arg);
6576 xmlXPathReleaseObject(ctxt->context, s);
6577 return(ret);
6578 }
6579
6580 /**
6581 * xmlXPathCompareNodeSets:
6582 * @inf: less than (1) or greater than (0)
6583 * @strict: is the comparison strict
6584 * @arg1: the first node set object
6585 * @arg2: the second node set object
6586 *
6587 * Implement the compare operation on nodesets:
6588 *
6589 * If both objects to be compared are node-sets, then the comparison
6590 * will be true if and only if there is a node in the first node-set
6591 * and a node in the second node-set such that the result of performing
6592 * the comparison on the string-values of the two nodes is true.
6593 * ....
6594 * When neither object to be compared is a node-set and the operator
6595 * is <=, <, >= or >, then the objects are compared by converting both
6596 * objects to numbers and comparing the numbers according to IEEE 754.
6597 * ....
6598 * The number function converts its argument to a number as follows:
6599 * - a string that consists of optional whitespace followed by an
6600 * optional minus sign followed by a Number followed by whitespace
6601 * is converted to the IEEE 754 number that is nearest (according
6602 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6603 * represented by the string; any other string is converted to NaN
6604 *
6605 * Conclusion all nodes need to be converted first to their string value
6606 * and then the comparison must be done when possible
6607 */
6608 static int
6609 xmlXPathCompareNodeSets(int inf, int strict,
6610 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6611 int i, j, init = 0;
6612 double val1;
6613 double *values2;
6614 int ret = 0;
6615 xmlNodeSetPtr ns1;
6616 xmlNodeSetPtr ns2;
6617
6618 if ((arg1 == NULL) ||
6619 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6620 xmlXPathFreeObject(arg2);
6621 return(0);
6622 }
6623 if ((arg2 == NULL) ||
6624 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6625 xmlXPathFreeObject(arg1);
6626 xmlXPathFreeObject(arg2);
6627 return(0);
6628 }
6629
6630 ns1 = arg1->nodesetval;
6631 ns2 = arg2->nodesetval;
6632
6633 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6634 xmlXPathFreeObject(arg1);
6635 xmlXPathFreeObject(arg2);
6636 return(0);
6637 }
6638 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6639 xmlXPathFreeObject(arg1);
6640 xmlXPathFreeObject(arg2);
6641 return(0);
6642 }
6643
6644 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6645 if (values2 == NULL) {
6646 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6647 xmlXPathFreeObject(arg1);
6648 xmlXPathFreeObject(arg2);
6649 return(0);
6650 }
6651 for (i = 0;i < ns1->nodeNr;i++) {
6652 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6653 if (xmlXPathIsNaN(val1))
6654 continue;
6655 for (j = 0;j < ns2->nodeNr;j++) {
6656 if (init == 0) {
6657 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6658 }
6659 if (xmlXPathIsNaN(values2[j]))
6660 continue;
6661 if (inf && strict)
6662 ret = (val1 < values2[j]);
6663 else 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 if (ret)
6670 break;
6671 }
6672 if (ret)
6673 break;
6674 init = 1;
6675 }
6676 xmlFree(values2);
6677 xmlXPathFreeObject(arg1);
6678 xmlXPathFreeObject(arg2);
6679 return(ret);
6680 }
6681
6682 /**
6683 * xmlXPathCompareNodeSetValue:
6684 * @ctxt: the XPath Parser context
6685 * @inf: less than (1) or greater than (0)
6686 * @strict: is the comparison strict
6687 * @arg: the node set
6688 * @val: the value
6689 *
6690 * Implement the compare operation between a nodeset and a value
6691 * @ns < @val (1, 1, ...
6692 * @ns <= @val (1, 0, ...
6693 * @ns > @val (0, 1, ...
6694 * @ns >= @val (0, 0, ...
6695 *
6696 * If one object to be compared is a node-set and the other is a boolean,
6697 * then the comparison will be true if and only if the result of performing
6698 * the comparison on the boolean and on the result of converting
6699 * the node-set to a boolean using the boolean function is true.
6700 *
6701 * Returns 0 or 1 depending on the results of the test.
6702 */
6703 static int
6704 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6705 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6706 if ((val == NULL) || (arg == NULL) ||
6707 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6708 return(0);
6709
6710 switch(val->type) {
6711 case XPATH_NUMBER:
6712 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6713 case XPATH_NODESET:
6714 case XPATH_XSLT_TREE:
6715 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6716 case XPATH_STRING:
6717 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6718 case XPATH_BOOLEAN:
6719 valuePush(ctxt, arg);
6720 xmlXPathBooleanFunction(ctxt, 1);
6721 valuePush(ctxt, val);
6722 return(xmlXPathCompareValues(ctxt, inf, strict));
6723 default:
6724 xmlGenericError(xmlGenericErrorContext,
6725 "xmlXPathCompareNodeSetValue: Can't compare node set "
6726 "and object of type %d\n",
6727 val->type);
6728 xmlXPathReleaseObject(ctxt->context, arg);
6729 xmlXPathReleaseObject(ctxt->context, val);
6730 XP_ERROR0(XPATH_INVALID_TYPE);
6731 }
6732 return(0);
6733 }
6734
6735 /**
6736 * xmlXPathEqualNodeSetString:
6737 * @arg: the nodeset object argument
6738 * @str: the string to compare to.
6739 * @neq: flag to show whether for '=' (0) or '!=' (1)
6740 *
6741 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6742 * If one object to be compared is a node-set and the other is a string,
6743 * then the comparison will be true if and only if there is a node in
6744 * the node-set such that the result of performing the comparison on the
6745 * string-value of the node and the other string is true.
6746 *
6747 * Returns 0 or 1 depending on the results of the test.
6748 */
6749 static int
6750 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6751 {
6752 int i;
6753 xmlNodeSetPtr ns;
6754 xmlChar *str2;
6755 unsigned int hash;
6756
6757 if ((str == NULL) || (arg == NULL) ||
6758 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6759 return (0);
6760 ns = arg->nodesetval;
6761 /*
6762 * A NULL nodeset compared with a string is always false
6763 * (since there is no node equal, and no node not equal)
6764 */
6765 if ((ns == NULL) || (ns->nodeNr <= 0) )
6766 return (0);
6767 hash = xmlXPathStringHash(str);
6768 for (i = 0; i < ns->nodeNr; i++) {
6769 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6770 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6771 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6772 xmlFree(str2);
6773 if (neq)
6774 continue;
6775 return (1);
6776 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6777 if (neq)
6778 continue;
6779 return (1);
6780 } else if (neq) {
6781 if (str2 != NULL)
6782 xmlFree(str2);
6783 return (1);
6784 }
6785 if (str2 != NULL)
6786 xmlFree(str2);
6787 } else if (neq)
6788 return (1);
6789 }
6790 return (0);
6791 }
6792
6793 /**
6794 * xmlXPathEqualNodeSetFloat:
6795 * @arg: the nodeset object argument
6796 * @f: the float to compare to
6797 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
6798 *
6799 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6800 * If one object to be compared is a node-set and the other is a number,
6801 * then the comparison will be true if and only if there is a node in
6802 * the node-set such that the result of performing the comparison on the
6803 * number to be compared and on the result of converting the string-value
6804 * of that node to a number using the number function is true.
6805 *
6806 * Returns 0 or 1 depending on the results of the test.
6807 */
6808 static int
6809 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6810 xmlXPathObjectPtr arg, double f, int neq) {
6811 int i, ret=0;
6812 xmlNodeSetPtr ns;
6813 xmlChar *str2;
6814 xmlXPathObjectPtr val;
6815 double v;
6816
6817 if ((arg == NULL) ||
6818 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6819 return(0);
6820
6821 ns = arg->nodesetval;
6822 if (ns != NULL) {
6823 for (i=0;i<ns->nodeNr;i++) {
6824 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6825 if (str2 != NULL) {
6826 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6827 xmlFree(str2);
6828 xmlXPathNumberFunction(ctxt, 1);
6829 val = valuePop(ctxt);
6830 v = val->floatval;
6831 xmlXPathReleaseObject(ctxt->context, val);
6832 if (!xmlXPathIsNaN(v)) {
6833 if ((!neq) && (v==f)) {
6834 ret = 1;
6835 break;
6836 } else if ((neq) && (v!=f)) {
6837 ret = 1;
6838 break;
6839 }
6840 } else { /* NaN is unequal to any value */
6841 if (neq)
6842 ret = 1;
6843 }
6844 }
6845 }
6846 }
6847
6848 return(ret);
6849 }
6850
6851
6852 /**
6853 * xmlXPathEqualNodeSets:
6854 * @arg1: first nodeset object argument
6855 * @arg2: second nodeset object argument
6856 * @neq: flag to show whether to test '=' (0) or '!=' (1)
6857 *
6858 * Implement the equal / not equal operation on XPath nodesets:
6859 * @arg1 == @arg2 or @arg1 != @arg2
6860 * If both objects to be compared are node-sets, then the comparison
6861 * will be true if and only if there is a node in the first node-set and
6862 * a node in the second node-set such that the result of performing the
6863 * comparison on the string-values of the two nodes is true.
6864 *
6865 * (needless to say, this is a costly operation)
6866 *
6867 * Returns 0 or 1 depending on the results of the test.
6868 */
6869 static int
6870 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6871 int i, j;
6872 unsigned int *hashs1;
6873 unsigned int *hashs2;
6874 xmlChar **values1;
6875 xmlChar **values2;
6876 int ret = 0;
6877 xmlNodeSetPtr ns1;
6878 xmlNodeSetPtr ns2;
6879
6880 if ((arg1 == NULL) ||
6881 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6882 return(0);
6883 if ((arg2 == NULL) ||
6884 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6885 return(0);
6886
6887 ns1 = arg1->nodesetval;
6888 ns2 = arg2->nodesetval;
6889
6890 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6891 return(0);
6892 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6893 return(0);
6894
6895 /*
6896 * for equal, check if there is a node pertaining to both sets
6897 */
6898 if (neq == 0)
6899 for (i = 0;i < ns1->nodeNr;i++)
6900 for (j = 0;j < ns2->nodeNr;j++)
6901 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6902 return(1);
6903
6904 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6905 if (values1 == NULL) {
6906 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6907 return(0);
6908 }
6909 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6910 if (hashs1 == NULL) {
6911 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6912 xmlFree(values1);
6913 return(0);
6914 }
6915 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6916 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6917 if (values2 == NULL) {
6918 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6919 xmlFree(hashs1);
6920 xmlFree(values1);
6921 return(0);
6922 }
6923 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6924 if (hashs2 == NULL) {
6925 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6926 xmlFree(hashs1);
6927 xmlFree(values1);
6928 xmlFree(values2);
6929 return(0);
6930 }
6931 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6932 for (i = 0;i < ns1->nodeNr;i++) {
6933 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6934 for (j = 0;j < ns2->nodeNr;j++) {
6935 if (i == 0)
6936 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6937 if (hashs1[i] != hashs2[j]) {
6938 if (neq) {
6939 ret = 1;
6940 break;
6941 }
6942 }
6943 else {
6944 if (values1[i] == NULL)
6945 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6946 if (values2[j] == NULL)
6947 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6948 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6949 if (ret)
6950 break;
6951 }
6952 }
6953 if (ret)
6954 break;
6955 }
6956 for (i = 0;i < ns1->nodeNr;i++)
6957 if (values1[i] != NULL)
6958 xmlFree(values1[i]);
6959 for (j = 0;j < ns2->nodeNr;j++)
6960 if (values2[j] != NULL)
6961 xmlFree(values2[j]);
6962 xmlFree(values1);
6963 xmlFree(values2);
6964 xmlFree(hashs1);
6965 xmlFree(hashs2);
6966 return(ret);
6967 }
6968
6969 static int
6970 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6971 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6972 int ret = 0;
6973 /*
6974 *At this point we are assured neither arg1 nor arg2
6975 *is a nodeset, so we can just pick the appropriate routine.
6976 */
6977 switch (arg1->type) {
6978 case XPATH_UNDEFINED:
6979 #ifdef DEBUG_EXPR
6980 xmlGenericError(xmlGenericErrorContext,
6981 "Equal: undefined\n");
6982 #endif
6983 break;
6984 case XPATH_BOOLEAN:
6985 switch (arg2->type) {
6986 case XPATH_UNDEFINED:
6987 #ifdef DEBUG_EXPR
6988 xmlGenericError(xmlGenericErrorContext,
6989 "Equal: undefined\n");
6990 #endif
6991 break;
6992 case XPATH_BOOLEAN:
6993 #ifdef DEBUG_EXPR
6994 xmlGenericError(xmlGenericErrorContext,
6995 "Equal: %d boolean %d \n",
6996 arg1->boolval, arg2->boolval);
6997 #endif
6998 ret = (arg1->boolval == arg2->boolval);
6999 break;
7000 case XPATH_NUMBER:
7001 ret = (arg1->boolval ==
7002 xmlXPathCastNumberToBoolean(arg2->floatval));
7003 break;
7004 case XPATH_STRING:
7005 if ((arg2->stringval == NULL) ||
7006 (arg2->stringval[0] == 0)) ret = 0;
7007 else
7008 ret = 1;
7009 ret = (arg1->boolval == ret);
7010 break;
7011 case XPATH_USERS:
7012 case XPATH_POINT:
7013 case XPATH_RANGE:
7014 case XPATH_LOCATIONSET:
7015 TODO
7016 break;
7017 case XPATH_NODESET:
7018 case XPATH_XSLT_TREE:
7019 break;
7020 }
7021 break;
7022 case XPATH_NUMBER:
7023 switch (arg2->type) {
7024 case XPATH_UNDEFINED:
7025 #ifdef DEBUG_EXPR
7026 xmlGenericError(xmlGenericErrorContext,
7027 "Equal: undefined\n");
7028 #endif
7029 break;
7030 case XPATH_BOOLEAN:
7031 ret = (arg2->boolval==
7032 xmlXPathCastNumberToBoolean(arg1->floatval));
7033 break;
7034 case XPATH_STRING:
7035 valuePush(ctxt, arg2);
7036 xmlXPathNumberFunction(ctxt, 1);
7037 arg2 = valuePop(ctxt);
7038 /* Falls through. */
7039 case XPATH_NUMBER:
7040 /* Hand check NaN and Infinity equalities */
7041 if (xmlXPathIsNaN(arg1->floatval) ||
7042 xmlXPathIsNaN(arg2->floatval)) {
7043 ret = 0;
7044 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7045 if (xmlXPathIsInf(arg2->floatval) == 1)
7046 ret = 1;
7047 else
7048 ret = 0;
7049 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7050 if (xmlXPathIsInf(arg2->floatval) == -1)
7051 ret = 1;
7052 else
7053 ret = 0;
7054 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7055 if (xmlXPathIsInf(arg1->floatval) == 1)
7056 ret = 1;
7057 else
7058 ret = 0;
7059 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7060 if (xmlXPathIsInf(arg1->floatval) == -1)
7061 ret = 1;
7062 else
7063 ret = 0;
7064 } else {
7065 ret = (arg1->floatval == arg2->floatval);
7066 }
7067 break;
7068 case XPATH_USERS:
7069 case XPATH_POINT:
7070 case XPATH_RANGE:
7071 case XPATH_LOCATIONSET:
7072 TODO
7073 break;
7074 case XPATH_NODESET:
7075 case XPATH_XSLT_TREE:
7076 break;
7077 }
7078 break;
7079 case XPATH_STRING:
7080 switch (arg2->type) {
7081 case XPATH_UNDEFINED:
7082 #ifdef DEBUG_EXPR
7083 xmlGenericError(xmlGenericErrorContext,
7084 "Equal: undefined\n");
7085 #endif
7086 break;
7087 case XPATH_BOOLEAN:
7088 if ((arg1->stringval == NULL) ||
7089 (arg1->stringval[0] == 0)) ret = 0;
7090 else
7091 ret = 1;
7092 ret = (arg2->boolval == ret);
7093 break;
7094 case XPATH_STRING:
7095 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7096 break;
7097 case XPATH_NUMBER:
7098 valuePush(ctxt, arg1);
7099 xmlXPathNumberFunction(ctxt, 1);
7100 arg1 = valuePop(ctxt);
7101 /* Hand check NaN and Infinity equalities */
7102 if (xmlXPathIsNaN(arg1->floatval) ||
7103 xmlXPathIsNaN(arg2->floatval)) {
7104 ret = 0;
7105 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7106 if (xmlXPathIsInf(arg2->floatval) == 1)
7107 ret = 1;
7108 else
7109 ret = 0;
7110 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7111 if (xmlXPathIsInf(arg2->floatval) == -1)
7112 ret = 1;
7113 else
7114 ret = 0;
7115 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7116 if (xmlXPathIsInf(arg1->floatval) == 1)
7117 ret = 1;
7118 else
7119 ret = 0;
7120 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7121 if (xmlXPathIsInf(arg1->floatval) == -1)
7122 ret = 1;
7123 else
7124 ret = 0;
7125 } else {
7126 ret = (arg1->floatval == arg2->floatval);
7127 }
7128 break;
7129 case XPATH_USERS:
7130 case XPATH_POINT:
7131 case XPATH_RANGE:
7132 case XPATH_LOCATIONSET:
7133 TODO
7134 break;
7135 case XPATH_NODESET:
7136 case XPATH_XSLT_TREE:
7137 break;
7138 }
7139 break;
7140 case XPATH_USERS:
7141 case XPATH_POINT:
7142 case XPATH_RANGE:
7143 case XPATH_LOCATIONSET:
7144 TODO
7145 break;
7146 case XPATH_NODESET:
7147 case XPATH_XSLT_TREE:
7148 break;
7149 }
7150 xmlXPathReleaseObject(ctxt->context, arg1);
7151 xmlXPathReleaseObject(ctxt->context, arg2);
7152 return(ret);
7153 }
7154
7155 /**
7156 * xmlXPathEqualValues:
7157 * @ctxt: the XPath Parser context
7158 *
7159 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7160 *
7161 * Returns 0 or 1 depending on the results of the test.
7162 */
7163 int
7164 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7165 xmlXPathObjectPtr arg1, arg2, argtmp;
7166 int ret = 0;
7167
7168 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7169 arg2 = valuePop(ctxt);
7170 arg1 = valuePop(ctxt);
7171 if ((arg1 == NULL) || (arg2 == NULL)) {
7172 if (arg1 != NULL)
7173 xmlXPathReleaseObject(ctxt->context, arg1);
7174 else
7175 xmlXPathReleaseObject(ctxt->context, arg2);
7176 XP_ERROR0(XPATH_INVALID_OPERAND);
7177 }
7178
7179 if (arg1 == arg2) {
7180 #ifdef DEBUG_EXPR
7181 xmlGenericError(xmlGenericErrorContext,
7182 "Equal: by pointer\n");
7183 #endif
7184 xmlXPathFreeObject(arg1);
7185 return(1);
7186 }
7187
7188 /*
7189 *If either argument is a nodeset, it's a 'special case'
7190 */
7191 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7192 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7193 /*
7194 *Hack it to assure arg1 is the nodeset
7195 */
7196 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7197 argtmp = arg2;
7198 arg2 = arg1;
7199 arg1 = argtmp;
7200 }
7201 switch (arg2->type) {
7202 case XPATH_UNDEFINED:
7203 #ifdef DEBUG_EXPR
7204 xmlGenericError(xmlGenericErrorContext,
7205 "Equal: undefined\n");
7206 #endif
7207 break;
7208 case XPATH_NODESET:
7209 case XPATH_XSLT_TREE:
7210 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7211 break;
7212 case XPATH_BOOLEAN:
7213 if ((arg1->nodesetval == NULL) ||
7214 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7215 else
7216 ret = 1;
7217 ret = (ret == arg2->boolval);
7218 break;
7219 case XPATH_NUMBER:
7220 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7221 break;
7222 case XPATH_STRING:
7223 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7224 break;
7225 case XPATH_USERS:
7226 case XPATH_POINT:
7227 case XPATH_RANGE:
7228 case XPATH_LOCATIONSET:
7229 TODO
7230 break;
7231 }
7232 xmlXPathReleaseObject(ctxt->context, arg1);
7233 xmlXPathReleaseObject(ctxt->context, arg2);
7234 return(ret);
7235 }
7236
7237 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7238 }
7239
7240 /**
7241 * xmlXPathNotEqualValues:
7242 * @ctxt: the XPath Parser context
7243 *
7244 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7245 *
7246 * Returns 0 or 1 depending on the results of the test.
7247 */
7248 int
7249 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7250 xmlXPathObjectPtr arg1, arg2, argtmp;
7251 int ret = 0;
7252
7253 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7254 arg2 = valuePop(ctxt);
7255 arg1 = valuePop(ctxt);
7256 if ((arg1 == NULL) || (arg2 == NULL)) {
7257 if (arg1 != NULL)
7258 xmlXPathReleaseObject(ctxt->context, arg1);
7259 else
7260 xmlXPathReleaseObject(ctxt->context, arg2);
7261 XP_ERROR0(XPATH_INVALID_OPERAND);
7262 }
7263
7264 if (arg1 == arg2) {
7265 #ifdef DEBUG_EXPR
7266 xmlGenericError(xmlGenericErrorContext,
7267 "NotEqual: by pointer\n");
7268 #endif
7269 xmlXPathReleaseObject(ctxt->context, arg1);
7270 return(0);
7271 }
7272
7273 /*
7274 *If either argument is a nodeset, it's a 'special case'
7275 */
7276 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7277 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7278 /*
7279 *Hack it to assure arg1 is the nodeset
7280 */
7281 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7282 argtmp = arg2;
7283 arg2 = arg1;
7284 arg1 = argtmp;
7285 }
7286 switch (arg2->type) {
7287 case XPATH_UNDEFINED:
7288 #ifdef DEBUG_EXPR
7289 xmlGenericError(xmlGenericErrorContext,
7290 "NotEqual: undefined\n");
7291 #endif
7292 break;
7293 case XPATH_NODESET:
7294 case XPATH_XSLT_TREE:
7295 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7296 break;
7297 case XPATH_BOOLEAN:
7298 if ((arg1->nodesetval == NULL) ||
7299 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7300 else
7301 ret = 1;
7302 ret = (ret != arg2->boolval);
7303 break;
7304 case XPATH_NUMBER:
7305 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7306 break;
7307 case XPATH_STRING:
7308 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7309 break;
7310 case XPATH_USERS:
7311 case XPATH_POINT:
7312 case XPATH_RANGE:
7313 case XPATH_LOCATIONSET:
7314 TODO
7315 break;
7316 }
7317 xmlXPathReleaseObject(ctxt->context, arg1);
7318 xmlXPathReleaseObject(ctxt->context, arg2);
7319 return(ret);
7320 }
7321
7322 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7323 }
7324
7325 /**
7326 * xmlXPathCompareValues:
7327 * @ctxt: the XPath Parser context
7328 * @inf: less than (1) or greater than (0)
7329 * @strict: is the comparison strict
7330 *
7331 * Implement the compare operation on XPath objects:
7332 * @arg1 < @arg2 (1, 1, ...
7333 * @arg1 <= @arg2 (1, 0, ...
7334 * @arg1 > @arg2 (0, 1, ...
7335 * @arg1 >= @arg2 (0, 0, ...
7336 *
7337 * When neither object to be compared is a node-set and the operator is
7338 * <=, <, >=, >, then the objects are compared by converted both objects
7339 * to numbers and comparing the numbers according to IEEE 754. The <
7340 * comparison will be true if and only if the first number is less than the
7341 * second number. The <= comparison will be true if and only if the first
7342 * number is less than or equal to the second number. The > comparison
7343 * will be true if and only if the first number is greater than the second
7344 * number. The >= comparison will be true if and only if the first number
7345 * is greater than or equal to the second number.
7346 *
7347 * Returns 1 if the comparison succeeded, 0 if it failed
7348 */
7349 int
7350 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7351 int ret = 0, arg1i = 0, arg2i = 0;
7352 xmlXPathObjectPtr arg1, arg2;
7353
7354 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7355 arg2 = valuePop(ctxt);
7356 arg1 = valuePop(ctxt);
7357 if ((arg1 == NULL) || (arg2 == NULL)) {
7358 if (arg1 != NULL)
7359 xmlXPathReleaseObject(ctxt->context, arg1);
7360 else
7361 xmlXPathReleaseObject(ctxt->context, arg2);
7362 XP_ERROR0(XPATH_INVALID_OPERAND);
7363 }
7364
7365 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7366 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7367 /*
7368 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7369 * are not freed from within this routine; they will be freed from the
7370 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7371 */
7372 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7373 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7374 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7375 } else {
7376 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7377 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7378 arg1, arg2);
7379 } else {
7380 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7381 arg2, arg1);
7382 }
7383 }
7384 return(ret);
7385 }
7386
7387 if (arg1->type != XPATH_NUMBER) {
7388 valuePush(ctxt, arg1);
7389 xmlXPathNumberFunction(ctxt, 1);
7390 arg1 = valuePop(ctxt);
7391 }
7392 if (arg1->type != XPATH_NUMBER) {
7393 xmlXPathFreeObject(arg1);
7394 xmlXPathFreeObject(arg2);
7395 XP_ERROR0(XPATH_INVALID_OPERAND);
7396 }
7397 if (arg2->type != XPATH_NUMBER) {
7398 valuePush(ctxt, arg2);
7399 xmlXPathNumberFunction(ctxt, 1);
7400 arg2 = valuePop(ctxt);
7401 }
7402 if (arg2->type != XPATH_NUMBER) {
7403 xmlXPathReleaseObject(ctxt->context, arg1);
7404 xmlXPathReleaseObject(ctxt->context, arg2);
7405 XP_ERROR0(XPATH_INVALID_OPERAND);
7406 }
7407 /*
7408 * Add tests for infinity and nan
7409 * => feedback on 3.4 for Inf and NaN
7410 */
7411 /* Hand check NaN and Infinity comparisons */
7412 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7413 ret=0;
7414 } else {
7415 arg1i=xmlXPathIsInf(arg1->floatval);
7416 arg2i=xmlXPathIsInf(arg2->floatval);
7417 if (inf && strict) {
7418 if ((arg1i == -1 && arg2i != -1) ||
7419 (arg2i == 1 && arg1i != 1)) {
7420 ret = 1;
7421 } else if (arg1i == 0 && arg2i == 0) {
7422 ret = (arg1->floatval < arg2->floatval);
7423 } else {
7424 ret = 0;
7425 }
7426 }
7427 else if (inf && !strict) {
7428 if (arg1i == -1 || arg2i == 1) {
7429 ret = 1;
7430 } else if (arg1i == 0 && arg2i == 0) {
7431 ret = (arg1->floatval <= arg2->floatval);
7432 } else {
7433 ret = 0;
7434 }
7435 }
7436 else if (!inf && strict) {
7437 if ((arg1i == 1 && arg2i != 1) ||
7438 (arg2i == -1 && arg1i != -1)) {
7439 ret = 1;
7440 } else if (arg1i == 0 && arg2i == 0) {
7441 ret = (arg1->floatval > arg2->floatval);
7442 } else {
7443 ret = 0;
7444 }
7445 }
7446 else if (!inf && !strict) {
7447 if (arg1i == 1 || arg2i == -1) {
7448 ret = 1;
7449 } else if (arg1i == 0 && arg2i == 0) {
7450 ret = (arg1->floatval >= arg2->floatval);
7451 } else {
7452 ret = 0;
7453 }
7454 }
7455 }
7456 xmlXPathReleaseObject(ctxt->context, arg1);
7457 xmlXPathReleaseObject(ctxt->context, arg2);
7458 return(ret);
7459 }
7460
7461 /**
7462 * xmlXPathValueFlipSign:
7463 * @ctxt: the XPath Parser context
7464 *
7465 * Implement the unary - operation on an XPath object
7466 * The numeric operators convert their operands to numbers as if
7467 * by calling the number function.
7468 */
7469 void
7470 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7471 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7472 CAST_TO_NUMBER;
7473 CHECK_TYPE(XPATH_NUMBER);
7474 ctxt->value->floatval = -ctxt->value->floatval;
7475 }
7476
7477 /**
7478 * xmlXPathAddValues:
7479 * @ctxt: the XPath Parser context
7480 *
7481 * Implement the add operation on XPath objects:
7482 * The numeric operators convert their operands to numbers as if
7483 * by calling the number function.
7484 */
7485 void
7486 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7487 xmlXPathObjectPtr arg;
7488 double val;
7489
7490 arg = valuePop(ctxt);
7491 if (arg == NULL)
7492 XP_ERROR(XPATH_INVALID_OPERAND);
7493 val = xmlXPathCastToNumber(arg);
7494 xmlXPathReleaseObject(ctxt->context, arg);
7495 CAST_TO_NUMBER;
7496 CHECK_TYPE(XPATH_NUMBER);
7497 ctxt->value->floatval += val;
7498 }
7499
7500 /**
7501 * xmlXPathSubValues:
7502 * @ctxt: the XPath Parser context
7503 *
7504 * Implement the subtraction operation on XPath objects:
7505 * The numeric operators convert their operands to numbers as if
7506 * by calling the number function.
7507 */
7508 void
7509 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7510 xmlXPathObjectPtr arg;
7511 double val;
7512
7513 arg = valuePop(ctxt);
7514 if (arg == NULL)
7515 XP_ERROR(XPATH_INVALID_OPERAND);
7516 val = xmlXPathCastToNumber(arg);
7517 xmlXPathReleaseObject(ctxt->context, arg);
7518 CAST_TO_NUMBER;
7519 CHECK_TYPE(XPATH_NUMBER);
7520 ctxt->value->floatval -= val;
7521 }
7522
7523 /**
7524 * xmlXPathMultValues:
7525 * @ctxt: the XPath Parser context
7526 *
7527 * Implement the multiply operation on XPath objects:
7528 * The numeric operators convert their operands to numbers as if
7529 * by calling the number function.
7530 */
7531 void
7532 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7533 xmlXPathObjectPtr arg;
7534 double val;
7535
7536 arg = valuePop(ctxt);
7537 if (arg == NULL)
7538 XP_ERROR(XPATH_INVALID_OPERAND);
7539 val = xmlXPathCastToNumber(arg);
7540 xmlXPathReleaseObject(ctxt->context, arg);
7541 CAST_TO_NUMBER;
7542 CHECK_TYPE(XPATH_NUMBER);
7543 ctxt->value->floatval *= val;
7544 }
7545
7546 /**
7547 * xmlXPathDivValues:
7548 * @ctxt: the XPath Parser context
7549 *
7550 * Implement the div operation on XPath objects @arg1 / @arg2:
7551 * The numeric operators convert their operands to numbers as if
7552 * by calling the number function.
7553 */
7554 void
7555 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7556 xmlXPathObjectPtr arg;
7557 double val;
7558
7559 arg = valuePop(ctxt);
7560 if (arg == NULL)
7561 XP_ERROR(XPATH_INVALID_OPERAND);
7562 val = xmlXPathCastToNumber(arg);
7563 xmlXPathReleaseObject(ctxt->context, arg);
7564 CAST_TO_NUMBER;
7565 CHECK_TYPE(XPATH_NUMBER);
7566 ctxt->value->floatval /= val;
7567 }
7568
7569 /**
7570 * xmlXPathModValues:
7571 * @ctxt: the XPath Parser context
7572 *
7573 * Implement the mod operation on XPath objects: @arg1 / @arg2
7574 * The numeric operators convert their operands to numbers as if
7575 * by calling the number function.
7576 */
7577 void
7578 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7579 xmlXPathObjectPtr arg;
7580 double arg1, arg2;
7581
7582 arg = valuePop(ctxt);
7583 if (arg == NULL)
7584 XP_ERROR(XPATH_INVALID_OPERAND);
7585 arg2 = xmlXPathCastToNumber(arg);
7586 xmlXPathReleaseObject(ctxt->context, arg);
7587 CAST_TO_NUMBER;
7588 CHECK_TYPE(XPATH_NUMBER);
7589 arg1 = ctxt->value->floatval;
7590 if (arg2 == 0)
7591 ctxt->value->floatval = NAN;
7592 else {
7593 ctxt->value->floatval = fmod(arg1, arg2);
7594 }
7595 }
7596
7597 /************************************************************************
7598 * *
7599 * The traversal functions *
7600 * *
7601 ************************************************************************/
7602
7603 /*
7604 * A traversal function enumerates nodes along an axis.
7605 * Initially it must be called with NULL, and it indicates
7606 * termination on the axis by returning NULL.
7607 */
7608 typedef xmlNodePtr (*xmlXPathTraversalFunction)
7609 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7610
7611 /*
7612 * xmlXPathTraversalFunctionExt:
7613 * A traversal function enumerates nodes along an axis.
7614 * Initially it must be called with NULL, and it indicates
7615 * termination on the axis by returning NULL.
7616 * The context node of the traversal is specified via @contextNode.
7617 */
7618 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7619 (xmlNodePtr cur, xmlNodePtr contextNode);
7620
7621 /*
7622 * xmlXPathNodeSetMergeFunction:
7623 * Used for merging node sets in xmlXPathCollectAndTest().
7624 */
7625 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7626 (xmlNodeSetPtr, xmlNodeSetPtr, int);
7627
7628
7629 /**
7630 * xmlXPathNextSelf:
7631 * @ctxt: the XPath Parser context
7632 * @cur: the current node in the traversal
7633 *
7634 * Traversal function for the "self" direction
7635 * The self axis contains just the context node itself
7636 *
7637 * Returns the next element following that axis
7638 */
7639 xmlNodePtr
7640 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7641 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7642 if (cur == NULL)
7643 return(ctxt->context->node);
7644 return(NULL);
7645 }
7646
7647 /**
7648 * xmlXPathNextChild:
7649 * @ctxt: the XPath Parser context
7650 * @cur: the current node in the traversal
7651 *
7652 * Traversal function for the "child" direction
7653 * The child axis contains the children of the context node in document order.
7654 *
7655 * Returns the next element following that axis
7656 */
7657 xmlNodePtr
7658 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7659 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7660 if (cur == NULL) {
7661 if (ctxt->context->node == NULL) return(NULL);
7662 switch (ctxt->context->node->type) {
7663 case XML_ELEMENT_NODE:
7664 case XML_TEXT_NODE:
7665 case XML_CDATA_SECTION_NODE:
7666 case XML_ENTITY_REF_NODE:
7667 case XML_ENTITY_NODE:
7668 case XML_PI_NODE:
7669 case XML_COMMENT_NODE:
7670 case XML_NOTATION_NODE:
7671 case XML_DTD_NODE:
7672 return(ctxt->context->node->children);
7673 case XML_DOCUMENT_NODE:
7674 case XML_DOCUMENT_TYPE_NODE:
7675 case XML_DOCUMENT_FRAG_NODE:
7676 case XML_HTML_DOCUMENT_NODE:
7677 #ifdef LIBXML_DOCB_ENABLED
7678 case XML_DOCB_DOCUMENT_NODE:
7679 #endif
7680 return(((xmlDocPtr) ctxt->context->node)->children);
7681 case XML_ELEMENT_DECL:
7682 case XML_ATTRIBUTE_DECL:
7683 case XML_ENTITY_DECL:
7684 case XML_ATTRIBUTE_NODE:
7685 case XML_NAMESPACE_DECL:
7686 case XML_XINCLUDE_START:
7687 case XML_XINCLUDE_END:
7688 return(NULL);
7689 }
7690 return(NULL);
7691 }
7692 if ((cur->type == XML_DOCUMENT_NODE) ||
7693 (cur->type == XML_HTML_DOCUMENT_NODE))
7694 return(NULL);
7695 return(cur->next);
7696 }
7697
7698 /**
7699 * xmlXPathNextChildElement:
7700 * @ctxt: the XPath Parser context
7701 * @cur: the current node in the traversal
7702 *
7703 * Traversal function for the "child" direction and nodes of type element.
7704 * The child axis contains the children of the context node in document order.
7705 *
7706 * Returns the next element following that axis
7707 */
7708 static xmlNodePtr
7709 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7710 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7711 if (cur == NULL) {
7712 cur = ctxt->context->node;
7713 if (cur == NULL) return(NULL);
7714 /*
7715 * Get the first element child.
7716 */
7717 switch (cur->type) {
7718 case XML_ELEMENT_NODE:
7719 case XML_DOCUMENT_FRAG_NODE:
7720 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7721 case XML_ENTITY_NODE:
7722 cur = cur->children;
7723 if (cur != NULL) {
7724 if (cur->type == XML_ELEMENT_NODE)
7725 return(cur);
7726 do {
7727 cur = cur->next;
7728 } while ((cur != NULL) &&
7729 (cur->type != XML_ELEMENT_NODE));
7730 return(cur);
7731 }
7732 return(NULL);
7733 case XML_DOCUMENT_NODE:
7734 case XML_HTML_DOCUMENT_NODE:
7735 #ifdef LIBXML_DOCB_ENABLED
7736 case XML_DOCB_DOCUMENT_NODE:
7737 #endif
7738 return(xmlDocGetRootElement((xmlDocPtr) cur));
7739 default:
7740 return(NULL);
7741 }
7742 return(NULL);
7743 }
7744 /*
7745 * Get the next sibling element node.
7746 */
7747 switch (cur->type) {
7748 case XML_ELEMENT_NODE:
7749 case XML_TEXT_NODE:
7750 case XML_ENTITY_REF_NODE:
7751 case XML_ENTITY_NODE:
7752 case XML_CDATA_SECTION_NODE:
7753 case XML_PI_NODE:
7754 case XML_COMMENT_NODE:
7755 case XML_XINCLUDE_END:
7756 break;
7757 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7758 default:
7759 return(NULL);
7760 }
7761 if (cur->next != NULL) {
7762 if (cur->next->type == XML_ELEMENT_NODE)
7763 return(cur->next);
7764 cur = cur->next;
7765 do {
7766 cur = cur->next;
7767 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7768 return(cur);
7769 }
7770 return(NULL);
7771 }
7772
7773 #if 0
7774 /**
7775 * xmlXPathNextDescendantOrSelfElemParent:
7776 * @ctxt: the XPath Parser context
7777 * @cur: the current node in the traversal
7778 *
7779 * Traversal function for the "descendant-or-self" axis.
7780 * Additionally it returns only nodes which can be parents of
7781 * element nodes.
7782 *
7783 *
7784 * Returns the next element following that axis
7785 */
7786 static xmlNodePtr
7787 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7788 xmlNodePtr contextNode)
7789 {
7790 if (cur == NULL) {
7791 if (contextNode == NULL)
7792 return(NULL);
7793 switch (contextNode->type) {
7794 case XML_ELEMENT_NODE:
7795 case XML_XINCLUDE_START:
7796 case XML_DOCUMENT_FRAG_NODE:
7797 case XML_DOCUMENT_NODE:
7798 #ifdef LIBXML_DOCB_ENABLED
7799 case XML_DOCB_DOCUMENT_NODE:
7800 #endif
7801 case XML_HTML_DOCUMENT_NODE:
7802 return(contextNode);
7803 default:
7804 return(NULL);
7805 }
7806 return(NULL);
7807 } else {
7808 xmlNodePtr start = cur;
7809
7810 while (cur != NULL) {
7811 switch (cur->type) {
7812 case XML_ELEMENT_NODE:
7813 /* TODO: OK to have XInclude here? */
7814 case XML_XINCLUDE_START:
7815 case XML_DOCUMENT_FRAG_NODE:
7816 if (cur != start)
7817 return(cur);
7818 if (cur->children != NULL) {
7819 cur = cur->children;
7820 continue;
7821 }
7822 break;
7823 /* Not sure if we need those here. */
7824 case XML_DOCUMENT_NODE:
7825 #ifdef LIBXML_DOCB_ENABLED
7826 case XML_DOCB_DOCUMENT_NODE:
7827 #endif
7828 case XML_HTML_DOCUMENT_NODE:
7829 if (cur != start)
7830 return(cur);
7831 return(xmlDocGetRootElement((xmlDocPtr) cur));
7832 default:
7833 break;
7834 }
7835
7836 next_sibling:
7837 if ((cur == NULL) || (cur == contextNode))
7838 return(NULL);
7839 if (cur->next != NULL) {
7840 cur = cur->next;
7841 } else {
7842 cur = cur->parent;
7843 goto next_sibling;
7844 }
7845 }
7846 }
7847 return(NULL);
7848 }
7849 #endif
7850
7851 /**
7852 * xmlXPathNextDescendant:
7853 * @ctxt: the XPath Parser context
7854 * @cur: the current node in the traversal
7855 *
7856 * Traversal function for the "descendant" direction
7857 * the descendant axis contains the descendants of the context node in document
7858 * order; a descendant is a child or a child of a child and so on.
7859 *
7860 * Returns the next element following that axis
7861 */
7862 xmlNodePtr
7863 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7864 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7865 if (cur == NULL) {
7866 if (ctxt->context->node == NULL)
7867 return(NULL);
7868 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7869 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7870 return(NULL);
7871
7872 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7873 return(ctxt->context->doc->children);
7874 return(ctxt->context->node->children);
7875 }
7876
7877 if (cur->type == XML_NAMESPACE_DECL)
7878 return(NULL);
7879 if (cur->children != NULL) {
7880 /*
7881 * Do not descend on entities declarations
7882 */
7883 if (cur->children->type != XML_ENTITY_DECL) {
7884 cur = cur->children;
7885 /*
7886 * Skip DTDs
7887 */
7888 if (cur->type != XML_DTD_NODE)
7889 return(cur);
7890 }
7891 }
7892
7893 if (cur == ctxt->context->node) return(NULL);
7894
7895 while (cur->next != NULL) {
7896 cur = cur->next;
7897 if ((cur->type != XML_ENTITY_DECL) &&
7898 (cur->type != XML_DTD_NODE))
7899 return(cur);
7900 }
7901
7902 do {
7903 cur = cur->parent;
7904 if (cur == NULL) break;
7905 if (cur == ctxt->context->node) return(NULL);
7906 if (cur->next != NULL) {
7907 cur = cur->next;
7908 return(cur);
7909 }
7910 } while (cur != NULL);
7911 return(cur);
7912 }
7913
7914 /**
7915 * xmlXPathNextDescendantOrSelf:
7916 * @ctxt: the XPath Parser context
7917 * @cur: the current node in the traversal
7918 *
7919 * Traversal function for the "descendant-or-self" direction
7920 * the descendant-or-self axis contains the context node and the descendants
7921 * of the context node in document order; thus the context node is the first
7922 * node on the axis, and the first child of the context node is the second node
7923 * on the axis
7924 *
7925 * Returns the next element following that axis
7926 */
7927 xmlNodePtr
7928 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7929 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7930 if (cur == NULL)
7931 return(ctxt->context->node);
7932
7933 if (ctxt->context->node == NULL)
7934 return(NULL);
7935 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7936 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7937 return(NULL);
7938
7939 return(xmlXPathNextDescendant(ctxt, cur));
7940 }
7941
7942 /**
7943 * xmlXPathNextParent:
7944 * @ctxt: the XPath Parser context
7945 * @cur: the current node in the traversal
7946 *
7947 * Traversal function for the "parent" direction
7948 * The parent axis contains the parent of the context node, if there is one.
7949 *
7950 * Returns the next element following that axis
7951 */
7952 xmlNodePtr
7953 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7954 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7955 /*
7956 * the parent of an attribute or namespace node is the element
7957 * to which the attribute or namespace node is attached
7958 * Namespace handling !!!
7959 */
7960 if (cur == NULL) {
7961 if (ctxt->context->node == NULL) return(NULL);
7962 switch (ctxt->context->node->type) {
7963 case XML_ELEMENT_NODE:
7964 case XML_TEXT_NODE:
7965 case XML_CDATA_SECTION_NODE:
7966 case XML_ENTITY_REF_NODE:
7967 case XML_ENTITY_NODE:
7968 case XML_PI_NODE:
7969 case XML_COMMENT_NODE:
7970 case XML_NOTATION_NODE:
7971 case XML_DTD_NODE:
7972 case XML_ELEMENT_DECL:
7973 case XML_ATTRIBUTE_DECL:
7974 case XML_XINCLUDE_START:
7975 case XML_XINCLUDE_END:
7976 case XML_ENTITY_DECL:
7977 if (ctxt->context->node->parent == NULL)
7978 return((xmlNodePtr) ctxt->context->doc);
7979 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7980 ((ctxt->context->node->parent->name[0] == ' ') ||
7981 (xmlStrEqual(ctxt->context->node->parent->name,
7982 BAD_CAST "fake node libxslt"))))
7983 return(NULL);
7984 return(ctxt->context->node->parent);
7985 case XML_ATTRIBUTE_NODE: {
7986 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7987
7988 return(att->parent);
7989 }
7990 case XML_DOCUMENT_NODE:
7991 case XML_DOCUMENT_TYPE_NODE:
7992 case XML_DOCUMENT_FRAG_NODE:
7993 case XML_HTML_DOCUMENT_NODE:
7994 #ifdef LIBXML_DOCB_ENABLED
7995 case XML_DOCB_DOCUMENT_NODE:
7996 #endif
7997 return(NULL);
7998 case XML_NAMESPACE_DECL: {
7999 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8000
8001 if ((ns->next != NULL) &&
8002 (ns->next->type != XML_NAMESPACE_DECL))
8003 return((xmlNodePtr) ns->next);
8004 return(NULL);
8005 }
8006 }
8007 }
8008 return(NULL);
8009 }
8010
8011 /**
8012 * xmlXPathNextAncestor:
8013 * @ctxt: the XPath Parser context
8014 * @cur: the current node in the traversal
8015 *
8016 * Traversal function for the "ancestor" direction
8017 * the ancestor axis contains the ancestors of the context node; the ancestors
8018 * of the context node consist of the parent of context node and the parent's
8019 * parent and so on; the nodes are ordered in reverse document order; thus the
8020 * parent is the first node on the axis, and the parent's parent is the second
8021 * node on the axis
8022 *
8023 * Returns the next element following that axis
8024 */
8025 xmlNodePtr
8026 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8027 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8028 /*
8029 * the parent of an attribute or namespace node is the element
8030 * to which the attribute or namespace node is attached
8031 * !!!!!!!!!!!!!
8032 */
8033 if (cur == NULL) {
8034 if (ctxt->context->node == NULL) return(NULL);
8035 switch (ctxt->context->node->type) {
8036 case XML_ELEMENT_NODE:
8037 case XML_TEXT_NODE:
8038 case XML_CDATA_SECTION_NODE:
8039 case XML_ENTITY_REF_NODE:
8040 case XML_ENTITY_NODE:
8041 case XML_PI_NODE:
8042 case XML_COMMENT_NODE:
8043 case XML_DTD_NODE:
8044 case XML_ELEMENT_DECL:
8045 case XML_ATTRIBUTE_DECL:
8046 case XML_ENTITY_DECL:
8047 case XML_NOTATION_NODE:
8048 case XML_XINCLUDE_START:
8049 case XML_XINCLUDE_END:
8050 if (ctxt->context->node->parent == NULL)
8051 return((xmlNodePtr) ctxt->context->doc);
8052 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8053 ((ctxt->context->node->parent->name[0] == ' ') ||
8054 (xmlStrEqual(ctxt->context->node->parent->name,
8055 BAD_CAST "fake node libxslt"))))
8056 return(NULL);
8057 return(ctxt->context->node->parent);
8058 case XML_ATTRIBUTE_NODE: {
8059 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8060
8061 return(tmp->parent);
8062 }
8063 case XML_DOCUMENT_NODE:
8064 case XML_DOCUMENT_TYPE_NODE:
8065 case XML_DOCUMENT_FRAG_NODE:
8066 case XML_HTML_DOCUMENT_NODE:
8067 #ifdef LIBXML_DOCB_ENABLED
8068 case XML_DOCB_DOCUMENT_NODE:
8069 #endif
8070 return(NULL);
8071 case XML_NAMESPACE_DECL: {
8072 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8073
8074 if ((ns->next != NULL) &&
8075 (ns->next->type != XML_NAMESPACE_DECL))
8076 return((xmlNodePtr) ns->next);
8077 /* Bad, how did that namespace end up here ? */
8078 return(NULL);
8079 }
8080 }
8081 return(NULL);
8082 }
8083 if (cur == ctxt->context->doc->children)
8084 return((xmlNodePtr) ctxt->context->doc);
8085 if (cur == (xmlNodePtr) ctxt->context->doc)
8086 return(NULL);
8087 switch (cur->type) {
8088 case XML_ELEMENT_NODE:
8089 case XML_TEXT_NODE:
8090 case XML_CDATA_SECTION_NODE:
8091 case XML_ENTITY_REF_NODE:
8092 case XML_ENTITY_NODE:
8093 case XML_PI_NODE:
8094 case XML_COMMENT_NODE:
8095 case XML_NOTATION_NODE:
8096 case XML_DTD_NODE:
8097 case XML_ELEMENT_DECL:
8098 case XML_ATTRIBUTE_DECL:
8099 case XML_ENTITY_DECL:
8100 case XML_XINCLUDE_START:
8101 case XML_XINCLUDE_END:
8102 if (cur->parent == NULL)
8103 return(NULL);
8104 if ((cur->parent->type == XML_ELEMENT_NODE) &&
8105 ((cur->parent->name[0] == ' ') ||
8106 (xmlStrEqual(cur->parent->name,
8107 BAD_CAST "fake node libxslt"))))
8108 return(NULL);
8109 return(cur->parent);
8110 case XML_ATTRIBUTE_NODE: {
8111 xmlAttrPtr att = (xmlAttrPtr) cur;
8112
8113 return(att->parent);
8114 }
8115 case XML_NAMESPACE_DECL: {
8116 xmlNsPtr ns = (xmlNsPtr) cur;
8117
8118 if ((ns->next != NULL) &&
8119 (ns->next->type != XML_NAMESPACE_DECL))
8120 return((xmlNodePtr) ns->next);
8121 /* Bad, how did that namespace end up here ? */
8122 return(NULL);
8123 }
8124 case XML_DOCUMENT_NODE:
8125 case XML_DOCUMENT_TYPE_NODE:
8126 case XML_DOCUMENT_FRAG_NODE:
8127 case XML_HTML_DOCUMENT_NODE:
8128 #ifdef LIBXML_DOCB_ENABLED
8129 case XML_DOCB_DOCUMENT_NODE:
8130 #endif
8131 return(NULL);
8132 }
8133 return(NULL);
8134 }
8135
8136 /**
8137 * xmlXPathNextAncestorOrSelf:
8138 * @ctxt: the XPath Parser context
8139 * @cur: the current node in the traversal
8140 *
8141 * Traversal function for the "ancestor-or-self" direction
8142 * he ancestor-or-self axis contains the context node and ancestors of
8143 * the context node in reverse document order; thus the context node is
8144 * the first node on the axis, and the context node's parent the second;
8145 * parent here is defined the same as with the parent axis.
8146 *
8147 * Returns the next element following that axis
8148 */
8149 xmlNodePtr
8150 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8151 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8152 if (cur == NULL)
8153 return(ctxt->context->node);
8154 return(xmlXPathNextAncestor(ctxt, cur));
8155 }
8156
8157 /**
8158 * xmlXPathNextFollowingSibling:
8159 * @ctxt: the XPath Parser context
8160 * @cur: the current node in the traversal
8161 *
8162 * Traversal function for the "following-sibling" direction
8163 * The following-sibling axis contains the following siblings of the context
8164 * node in document order.
8165 *
8166 * Returns the next element following that axis
8167 */
8168 xmlNodePtr
8169 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8170 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8171 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8172 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8173 return(NULL);
8174 if (cur == (xmlNodePtr) ctxt->context->doc)
8175 return(NULL);
8176 if (cur == NULL)
8177 return(ctxt->context->node->next);
8178 return(cur->next);
8179 }
8180
8181 /**
8182 * xmlXPathNextPrecedingSibling:
8183 * @ctxt: the XPath Parser context
8184 * @cur: the current node in the traversal
8185 *
8186 * Traversal function for the "preceding-sibling" direction
8187 * The preceding-sibling axis contains the preceding siblings of the context
8188 * node in reverse document order; the first preceding sibling is first on the
8189 * axis; the sibling preceding that node is the second on the axis and so on.
8190 *
8191 * Returns the next element following that axis
8192 */
8193 xmlNodePtr
8194 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8195 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8196 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8197 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8198 return(NULL);
8199 if (cur == (xmlNodePtr) ctxt->context->doc)
8200 return(NULL);
8201 if (cur == NULL)
8202 return(ctxt->context->node->prev);
8203 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8204 cur = cur->prev;
8205 if (cur == NULL)
8206 return(ctxt->context->node->prev);
8207 }
8208 return(cur->prev);
8209 }
8210
8211 /**
8212 * xmlXPathNextFollowing:
8213 * @ctxt: the XPath Parser context
8214 * @cur: the current node in the traversal
8215 *
8216 * Traversal function for the "following" direction
8217 * The following axis contains all nodes in the same document as the context
8218 * node that are after the context node in document order, excluding any
8219 * descendants and excluding attribute nodes and namespace nodes; the nodes
8220 * are ordered in document order
8221 *
8222 * Returns the next element following that axis
8223 */
8224 xmlNodePtr
8225 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8226 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8227 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
8228 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8229 return(cur->children);
8230
8231 if (cur == NULL) {
8232 cur = ctxt->context->node;
8233 if (cur->type == XML_ATTRIBUTE_NODE) {
8234 cur = cur->parent;
8235 } else if (cur->type == XML_NAMESPACE_DECL) {
8236 xmlNsPtr ns = (xmlNsPtr) cur;
8237
8238 if ((ns->next == NULL) ||
8239 (ns->next->type == XML_NAMESPACE_DECL))
8240 return (NULL);
8241 cur = (xmlNodePtr) ns->next;
8242 }
8243 }
8244 if (cur == NULL) return(NULL) ; /* ERROR */
8245 if (cur->next != NULL) return(cur->next) ;
8246 do {
8247 cur = cur->parent;
8248 if (cur == NULL) break;
8249 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8250 if (cur->next != NULL) return(cur->next);
8251 } while (cur != NULL);
8252 return(cur);
8253 }
8254
8255 /*
8256 * xmlXPathIsAncestor:
8257 * @ancestor: the ancestor node
8258 * @node: the current node
8259 *
8260 * Check that @ancestor is a @node's ancestor
8261 *
8262 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8263 */
8264 static int
8265 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8266 if ((ancestor == NULL) || (node == NULL)) return(0);
8267 if (node->type == XML_NAMESPACE_DECL)
8268 return(0);
8269 if (ancestor->type == XML_NAMESPACE_DECL)
8270 return(0);
8271 /* nodes need to be in the same document */
8272 if (ancestor->doc != node->doc) return(0);
8273 /* avoid searching if ancestor or node is the root node */
8274 if (ancestor == (xmlNodePtr) node->doc) return(1);
8275 if (node == (xmlNodePtr) ancestor->doc) return(0);
8276 while (node->parent != NULL) {
8277 if (node->parent == ancestor)
8278 return(1);
8279 node = node->parent;
8280 }
8281 return(0);
8282 }
8283
8284 /**
8285 * xmlXPathNextPreceding:
8286 * @ctxt: the XPath Parser context
8287 * @cur: the current node in the traversal
8288 *
8289 * Traversal function for the "preceding" direction
8290 * the preceding axis contains all nodes in the same document as the context
8291 * node that are before the context node in document order, excluding any
8292 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8293 * ordered in reverse document order
8294 *
8295 * Returns the next element following that axis
8296 */
8297 xmlNodePtr
8298 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8299 {
8300 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8301 if (cur == NULL) {
8302 cur = ctxt->context->node;
8303 if (cur->type == XML_ATTRIBUTE_NODE) {
8304 cur = cur->parent;
8305 } else if (cur->type == XML_NAMESPACE_DECL) {
8306 xmlNsPtr ns = (xmlNsPtr) cur;
8307
8308 if ((ns->next == NULL) ||
8309 (ns->next->type == XML_NAMESPACE_DECL))
8310 return (NULL);
8311 cur = (xmlNodePtr) ns->next;
8312 }
8313 }
8314 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8315 return (NULL);
8316 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8317 cur = cur->prev;
8318 do {
8319 if (cur->prev != NULL) {
8320 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8321 return (cur);
8322 }
8323
8324 cur = cur->parent;
8325 if (cur == NULL)
8326 return (NULL);
8327 if (cur == ctxt->context->doc->children)
8328 return (NULL);
8329 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8330 return (cur);
8331 }
8332
8333 /**
8334 * xmlXPathNextPrecedingInternal:
8335 * @ctxt: the XPath Parser context
8336 * @cur: the current node in the traversal
8337 *
8338 * Traversal function for the "preceding" direction
8339 * the preceding axis contains all nodes in the same document as the context
8340 * node that are before the context node in document order, excluding any
8341 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8342 * ordered in reverse document order
8343 * This is a faster implementation but internal only since it requires a
8344 * state kept in the parser context: ctxt->ancestor.
8345 *
8346 * Returns the next element following that axis
8347 */
8348 static xmlNodePtr
8349 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8350 xmlNodePtr cur)
8351 {
8352 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8353 if (cur == NULL) {
8354 cur = ctxt->context->node;
8355 if (cur == NULL)
8356 return (NULL);
8357 if (cur->type == XML_ATTRIBUTE_NODE) {
8358 cur = cur->parent;
8359 } else if (cur->type == XML_NAMESPACE_DECL) {
8360 xmlNsPtr ns = (xmlNsPtr) cur;
8361
8362 if ((ns->next == NULL) ||
8363 (ns->next->type == XML_NAMESPACE_DECL))
8364 return (NULL);
8365 cur = (xmlNodePtr) ns->next;
8366 }
8367 ctxt->ancestor = cur->parent;
8368 }
8369 if (cur->type == XML_NAMESPACE_DECL)
8370 return(NULL);
8371 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8372 cur = cur->prev;
8373 while (cur->prev == NULL) {
8374 cur = cur->parent;
8375 if (cur == NULL)
8376 return (NULL);
8377 if (cur == ctxt->context->doc->children)
8378 return (NULL);
8379 if (cur != ctxt->ancestor)
8380 return (cur);
8381 ctxt->ancestor = cur->parent;
8382 }
8383 cur = cur->prev;
8384 while (cur->last != NULL)
8385 cur = cur->last;
8386 return (cur);
8387 }
8388
8389 /**
8390 * xmlXPathNextNamespace:
8391 * @ctxt: the XPath Parser context
8392 * @cur: the current attribute in the traversal
8393 *
8394 * Traversal function for the "namespace" direction
8395 * the namespace axis contains the namespace nodes of the context node;
8396 * the order of nodes on this axis is implementation-defined; the axis will
8397 * be empty unless the context node is an element
8398 *
8399 * We keep the XML namespace node at the end of the list.
8400 *
8401 * Returns the next element following that axis
8402 */
8403 xmlNodePtr
8404 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8405 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8406 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8407 if (cur == NULL) {
8408 if (ctxt->context->tmpNsList != NULL)
8409 xmlFree(ctxt->context->tmpNsList);
8410 ctxt->context->tmpNsList =
8411 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8412 ctxt->context->tmpNsNr = 0;
8413 if (ctxt->context->tmpNsList != NULL) {
8414 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8415 ctxt->context->tmpNsNr++;
8416 }
8417 }
8418 return((xmlNodePtr) xmlXPathXMLNamespace);
8419 }
8420 if (ctxt->context->tmpNsNr > 0) {
8421 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8422 } else {
8423 if (ctxt->context->tmpNsList != NULL)
8424 xmlFree(ctxt->context->tmpNsList);
8425 ctxt->context->tmpNsList = NULL;
8426 return(NULL);
8427 }
8428 }
8429
8430 /**
8431 * xmlXPathNextAttribute:
8432 * @ctxt: the XPath Parser context
8433 * @cur: the current attribute in the traversal
8434 *
8435 * Traversal function for the "attribute" direction
8436 * TODO: support DTD inherited default attributes
8437 *
8438 * Returns the next element following that axis
8439 */
8440 xmlNodePtr
8441 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8442 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8443 if (ctxt->context->node == NULL)
8444 return(NULL);
8445 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8446 return(NULL);
8447 if (cur == NULL) {
8448 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8449 return(NULL);
8450 return((xmlNodePtr)ctxt->context->node->properties);
8451 }
8452 return((xmlNodePtr)cur->next);
8453 }
8454
8455 /************************************************************************
8456 * *
8457 * NodeTest Functions *
8458 * *
8459 ************************************************************************/
8460
8461 #define IS_FUNCTION 200
8462
8463
8464 /************************************************************************
8465 * *
8466 * Implicit tree core function library *
8467 * *
8468 ************************************************************************/
8469
8470 /**
8471 * xmlXPathRoot:
8472 * @ctxt: the XPath Parser context
8473 *
8474 * Initialize the context to the root of the document
8475 */
8476 void
8477 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8478 if ((ctxt == NULL) || (ctxt->context == NULL))
8479 return;
8480 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8481 (xmlNodePtr) ctxt->context->doc));
8482 }
8483
8484 /************************************************************************
8485 * *
8486 * The explicit core function library *
8487 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8488 * *
8489 ************************************************************************/
8490
8491
8492 /**
8493 * xmlXPathLastFunction:
8494 * @ctxt: the XPath Parser context
8495 * @nargs: the number of arguments
8496 *
8497 * Implement the last() XPath function
8498 * number last()
8499 * The last function returns the number of nodes in the context node list.
8500 */
8501 void
8502 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8503 CHECK_ARITY(0);
8504 if (ctxt->context->contextSize >= 0) {
8505 valuePush(ctxt,
8506 xmlXPathCacheNewFloat(ctxt->context,
8507 (double) ctxt->context->contextSize));
8508 #ifdef DEBUG_EXPR
8509 xmlGenericError(xmlGenericErrorContext,
8510 "last() : %d\n", ctxt->context->contextSize);
8511 #endif
8512 } else {
8513 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8514 }
8515 }
8516
8517 /**
8518 * xmlXPathPositionFunction:
8519 * @ctxt: the XPath Parser context
8520 * @nargs: the number of arguments
8521 *
8522 * Implement the position() XPath function
8523 * number position()
8524 * The position function returns the position of the context node in the
8525 * context node list. The first position is 1, and so the last position
8526 * will be equal to last().
8527 */
8528 void
8529 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8530 CHECK_ARITY(0);
8531 if (ctxt->context->proximityPosition >= 0) {
8532 valuePush(ctxt,
8533 xmlXPathCacheNewFloat(ctxt->context,
8534 (double) ctxt->context->proximityPosition));
8535 #ifdef DEBUG_EXPR
8536 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8537 ctxt->context->proximityPosition);
8538 #endif
8539 } else {
8540 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8541 }
8542 }
8543
8544 /**
8545 * xmlXPathCountFunction:
8546 * @ctxt: the XPath Parser context
8547 * @nargs: the number of arguments
8548 *
8549 * Implement the count() XPath function
8550 * number count(node-set)
8551 */
8552 void
8553 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8554 xmlXPathObjectPtr cur;
8555
8556 CHECK_ARITY(1);
8557 if ((ctxt->value == NULL) ||
8558 ((ctxt->value->type != XPATH_NODESET) &&
8559 (ctxt->value->type != XPATH_XSLT_TREE)))
8560 XP_ERROR(XPATH_INVALID_TYPE);
8561 cur = valuePop(ctxt);
8562
8563 if ((cur == NULL) || (cur->nodesetval == NULL))
8564 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8565 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8566 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8567 (double) cur->nodesetval->nodeNr));
8568 } else {
8569 if ((cur->nodesetval->nodeNr != 1) ||
8570 (cur->nodesetval->nodeTab == NULL)) {
8571 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8572 } else {
8573 xmlNodePtr tmp;
8574 int i = 0;
8575
8576 tmp = cur->nodesetval->nodeTab[0];
8577 if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
8578 tmp = tmp->children;
8579 while (tmp != NULL) {
8580 tmp = tmp->next;
8581 i++;
8582 }
8583 }
8584 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8585 }
8586 }
8587 xmlXPathReleaseObject(ctxt->context, cur);
8588 }
8589
8590 /**
8591 * xmlXPathGetElementsByIds:
8592 * @doc: the document
8593 * @ids: a whitespace separated list of IDs
8594 *
8595 * Selects elements by their unique ID.
8596 *
8597 * Returns a node-set of selected elements.
8598 */
8599 static xmlNodeSetPtr
8600 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8601 xmlNodeSetPtr ret;
8602 const xmlChar *cur = ids;
8603 xmlChar *ID;
8604 xmlAttrPtr attr;
8605 xmlNodePtr elem = NULL;
8606
8607 if (ids == NULL) return(NULL);
8608
8609 ret = xmlXPathNodeSetCreate(NULL);
8610 if (ret == NULL)
8611 return(ret);
8612
8613 while (IS_BLANK_CH(*cur)) cur++;
8614 while (*cur != 0) {
8615 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8616 cur++;
8617
8618 ID = xmlStrndup(ids, cur - ids);
8619 if (ID != NULL) {
8620 /*
8621 * We used to check the fact that the value passed
8622 * was an NCName, but this generated much troubles for
8623 * me and Aleksey Sanin, people blatantly violated that
8624 * constaint, like Visa3D spec.
8625 * if (xmlValidateNCName(ID, 1) == 0)
8626 */
8627 attr = xmlGetID(doc, ID);
8628 if (attr != NULL) {
8629 if (attr->type == XML_ATTRIBUTE_NODE)
8630 elem = attr->parent;
8631 else if (attr->type == XML_ELEMENT_NODE)
8632 elem = (xmlNodePtr) attr;
8633 else
8634 elem = NULL;
8635 if (elem != NULL)
8636 xmlXPathNodeSetAdd(ret, elem);
8637 }
8638 xmlFree(ID);
8639 }
8640
8641 while (IS_BLANK_CH(*cur)) cur++;
8642 ids = cur;
8643 }
8644 return(ret);
8645 }
8646
8647 /**
8648 * xmlXPathIdFunction:
8649 * @ctxt: the XPath Parser context
8650 * @nargs: the number of arguments
8651 *
8652 * Implement the id() XPath function
8653 * node-set id(object)
8654 * The id function selects elements by their unique ID
8655 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8656 * then the result is the union of the result of applying id to the
8657 * string value of each of the nodes in the argument node-set. When the
8658 * argument to id is of any other type, the argument is converted to a
8659 * string as if by a call to the string function; the string is split
8660 * into a whitespace-separated list of tokens (whitespace is any sequence
8661 * of characters matching the production S); the result is a node-set
8662 * containing the elements in the same document as the context node that
8663 * have a unique ID equal to any of the tokens in the list.
8664 */
8665 void
8666 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8667 xmlChar *tokens;
8668 xmlNodeSetPtr ret;
8669 xmlXPathObjectPtr obj;
8670
8671 CHECK_ARITY(1);
8672 obj = valuePop(ctxt);
8673 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8674 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8675 xmlNodeSetPtr ns;
8676 int i;
8677
8678 ret = xmlXPathNodeSetCreate(NULL);
8679 /*
8680 * FIXME -- in an out-of-memory condition this will behave badly.
8681 * The solution is not clear -- we already popped an item from
8682 * ctxt, so the object is in a corrupt state.
8683 */
8684
8685 if (obj->nodesetval != NULL) {
8686 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8687 tokens =
8688 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8689 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8690 ret = xmlXPathNodeSetMerge(ret, ns);
8691 xmlXPathFreeNodeSet(ns);
8692 if (tokens != NULL)
8693 xmlFree(tokens);
8694 }
8695 }
8696 xmlXPathReleaseObject(ctxt->context, obj);
8697 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8698 return;
8699 }
8700 obj = xmlXPathCacheConvertString(ctxt->context, obj);
8701 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8702 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8703 xmlXPathReleaseObject(ctxt->context, obj);
8704 return;
8705 }
8706
8707 /**
8708 * xmlXPathLocalNameFunction:
8709 * @ctxt: the XPath Parser context
8710 * @nargs: the number of arguments
8711 *
8712 * Implement the local-name() XPath function
8713 * string local-name(node-set?)
8714 * The local-name function returns a string containing the local part
8715 * of the name of the node in the argument node-set that is first in
8716 * document order. If the node-set is empty or the first node has no
8717 * name, an empty string is returned. If the argument is omitted it
8718 * defaults to the context node.
8719 */
8720 void
8721 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8722 xmlXPathObjectPtr cur;
8723
8724 if (ctxt == NULL) return;
8725
8726 if (nargs == 0) {
8727 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8728 ctxt->context->node));
8729 nargs = 1;
8730 }
8731
8732 CHECK_ARITY(1);
8733 if ((ctxt->value == NULL) ||
8734 ((ctxt->value->type != XPATH_NODESET) &&
8735 (ctxt->value->type != XPATH_XSLT_TREE)))
8736 XP_ERROR(XPATH_INVALID_TYPE);
8737 cur = valuePop(ctxt);
8738
8739 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8740 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8741 } else {
8742 int i = 0; /* Should be first in document order !!!!! */
8743 switch (cur->nodesetval->nodeTab[i]->type) {
8744 case XML_ELEMENT_NODE:
8745 case XML_ATTRIBUTE_NODE:
8746 case XML_PI_NODE:
8747 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8748 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8749 else
8750 valuePush(ctxt,
8751 xmlXPathCacheNewString(ctxt->context,
8752 cur->nodesetval->nodeTab[i]->name));
8753 break;
8754 case XML_NAMESPACE_DECL:
8755 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8756 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8757 break;
8758 default:
8759 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8760 }
8761 }
8762 xmlXPathReleaseObject(ctxt->context, cur);
8763 }
8764
8765 /**
8766 * xmlXPathNamespaceURIFunction:
8767 * @ctxt: the XPath Parser context
8768 * @nargs: the number of arguments
8769 *
8770 * Implement the namespace-uri() XPath function
8771 * string namespace-uri(node-set?)
8772 * The namespace-uri function returns a string containing the
8773 * namespace URI of the expanded name of the node in the argument
8774 * node-set that is first in document order. If the node-set is empty,
8775 * the first node has no name, or the expanded name has no namespace
8776 * URI, an empty string is returned. If the argument is omitted it
8777 * defaults to the context node.
8778 */
8779 void
8780 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8781 xmlXPathObjectPtr cur;
8782
8783 if (ctxt == NULL) return;
8784
8785 if (nargs == 0) {
8786 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8787 ctxt->context->node));
8788 nargs = 1;
8789 }
8790 CHECK_ARITY(1);
8791 if ((ctxt->value == NULL) ||
8792 ((ctxt->value->type != XPATH_NODESET) &&
8793 (ctxt->value->type != XPATH_XSLT_TREE)))
8794 XP_ERROR(XPATH_INVALID_TYPE);
8795 cur = valuePop(ctxt);
8796
8797 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8798 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8799 } else {
8800 int i = 0; /* Should be first in document order !!!!! */
8801 switch (cur->nodesetval->nodeTab[i]->type) {
8802 case XML_ELEMENT_NODE:
8803 case XML_ATTRIBUTE_NODE:
8804 if (cur->nodesetval->nodeTab[i]->ns == NULL)
8805 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8806 else
8807 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8808 cur->nodesetval->nodeTab[i]->ns->href));
8809 break;
8810 default:
8811 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8812 }
8813 }
8814 xmlXPathReleaseObject(ctxt->context, cur);
8815 }
8816
8817 /**
8818 * xmlXPathNameFunction:
8819 * @ctxt: the XPath Parser context
8820 * @nargs: the number of arguments
8821 *
8822 * Implement the name() XPath function
8823 * string name(node-set?)
8824 * The name function returns a string containing a QName representing
8825 * the name of the node in the argument node-set that is first in document
8826 * order. The QName must represent the name with respect to the namespace
8827 * declarations in effect on the node whose name is being represented.
8828 * Typically, this will be the form in which the name occurred in the XML
8829 * source. This need not be the case if there are namespace declarations
8830 * in effect on the node that associate multiple prefixes with the same
8831 * namespace. However, an implementation may include information about
8832 * the original prefix in its representation of nodes; in this case, an
8833 * implementation can ensure that the returned string is always the same
8834 * as the QName used in the XML source. If the argument it omitted it
8835 * defaults to the context node.
8836 * Libxml keep the original prefix so the "real qualified name" used is
8837 * returned.
8838 */
8839 static void
8840 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8841 {
8842 xmlXPathObjectPtr cur;
8843
8844 if (nargs == 0) {
8845 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8846 ctxt->context->node));
8847 nargs = 1;
8848 }
8849
8850 CHECK_ARITY(1);
8851 if ((ctxt->value == NULL) ||
8852 ((ctxt->value->type != XPATH_NODESET) &&
8853 (ctxt->value->type != XPATH_XSLT_TREE)))
8854 XP_ERROR(XPATH_INVALID_TYPE);
8855 cur = valuePop(ctxt);
8856
8857 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8858 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8859 } else {
8860 int i = 0; /* Should be first in document order !!!!! */
8861
8862 switch (cur->nodesetval->nodeTab[i]->type) {
8863 case XML_ELEMENT_NODE:
8864 case XML_ATTRIBUTE_NODE:
8865 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8866 valuePush(ctxt,
8867 xmlXPathCacheNewCString(ctxt->context, ""));
8868 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8869 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8870 valuePush(ctxt,
8871 xmlXPathCacheNewString(ctxt->context,
8872 cur->nodesetval->nodeTab[i]->name));
8873 } else {
8874 xmlChar *fullname;
8875
8876 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8877 cur->nodesetval->nodeTab[i]->ns->prefix,
8878 NULL, 0);
8879 if (fullname == cur->nodesetval->nodeTab[i]->name)
8880 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8881 if (fullname == NULL) {
8882 XP_ERROR(XPATH_MEMORY_ERROR);
8883 }
8884 valuePush(ctxt, xmlXPathCacheWrapString(
8885 ctxt->context, fullname));
8886 }
8887 break;
8888 default:
8889 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8890 cur->nodesetval->nodeTab[i]));
8891 xmlXPathLocalNameFunction(ctxt, 1);
8892 }
8893 }
8894 xmlXPathReleaseObject(ctxt->context, cur);
8895 }
8896
8897
8898 /**
8899 * xmlXPathStringFunction:
8900 * @ctxt: the XPath Parser context
8901 * @nargs: the number of arguments
8902 *
8903 * Implement the string() XPath function
8904 * string string(object?)
8905 * The string function converts an object to a string as follows:
8906 * - A node-set is converted to a string by returning the value of
8907 * the node in the node-set that is first in document order.
8908 * If the node-set is empty, an empty string is returned.
8909 * - A number is converted to a string as follows
8910 * + NaN is converted to the string NaN
8911 * + positive zero is converted to the string 0
8912 * + negative zero is converted to the string 0
8913 * + positive infinity is converted to the string Infinity
8914 * + negative infinity is converted to the string -Infinity
8915 * + if the number is an integer, the number is represented in
8916 * decimal form as a Number with no decimal point and no leading
8917 * zeros, preceded by a minus sign (-) if the number is negative
8918 * + otherwise, the number is represented in decimal form as a
8919 * Number including a decimal point with at least one digit
8920 * before the decimal point and at least one digit after the
8921 * decimal point, preceded by a minus sign (-) if the number
8922 * is negative; there must be no leading zeros before the decimal
8923 * point apart possibly from the one required digit immediately
8924 * before the decimal point; beyond the one required digit
8925 * after the decimal point there must be as many, but only as
8926 * many, more digits as are needed to uniquely distinguish the
8927 * number from all other IEEE 754 numeric values.
8928 * - The boolean false value is converted to the string false.
8929 * The boolean true value is converted to the string true.
8930 *
8931 * If the argument is omitted, it defaults to a node-set with the
8932 * context node as its only member.
8933 */
8934 void
8935 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8936 xmlXPathObjectPtr cur;
8937
8938 if (ctxt == NULL) return;
8939 if (nargs == 0) {
8940 valuePush(ctxt,
8941 xmlXPathCacheWrapString(ctxt->context,
8942 xmlXPathCastNodeToString(ctxt->context->node)));
8943 return;
8944 }
8945
8946 CHECK_ARITY(1);
8947 cur = valuePop(ctxt);
8948 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8949 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8950 }
8951
8952 /**
8953 * xmlXPathStringLengthFunction:
8954 * @ctxt: the XPath Parser context
8955 * @nargs: the number of arguments
8956 *
8957 * Implement the string-length() XPath function
8958 * number string-length(string?)
8959 * The string-length returns the number of characters in the string
8960 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8961 * the context node converted to a string, in other words the value
8962 * of the context node.
8963 */
8964 void
8965 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8966 xmlXPathObjectPtr cur;
8967
8968 if (nargs == 0) {
8969 if ((ctxt == NULL) || (ctxt->context == NULL))
8970 return;
8971 if (ctxt->context->node == NULL) {
8972 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8973 } else {
8974 xmlChar *content;
8975
8976 content = xmlXPathCastNodeToString(ctxt->context->node);
8977 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8978 xmlUTF8Strlen(content)));
8979 xmlFree(content);
8980 }
8981 return;
8982 }
8983 CHECK_ARITY(1);
8984 CAST_TO_STRING;
8985 CHECK_TYPE(XPATH_STRING);
8986 cur = valuePop(ctxt);
8987 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8988 xmlUTF8Strlen(cur->stringval)));
8989 xmlXPathReleaseObject(ctxt->context, cur);
8990 }
8991
8992 /**
8993 * xmlXPathConcatFunction:
8994 * @ctxt: the XPath Parser context
8995 * @nargs: the number of arguments
8996 *
8997 * Implement the concat() XPath function
8998 * string concat(string, string, string*)
8999 * The concat function returns the concatenation of its arguments.
9000 */
9001 void
9002 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9003 xmlXPathObjectPtr cur, newobj;
9004 xmlChar *tmp;
9005
9006 if (ctxt == NULL) return;
9007 if (nargs < 2) {
9008 CHECK_ARITY(2);
9009 }
9010
9011 CAST_TO_STRING;
9012 cur = valuePop(ctxt);
9013 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
9014 xmlXPathReleaseObject(ctxt->context, cur);
9015 return;
9016 }
9017 nargs--;
9018
9019 while (nargs > 0) {
9020 CAST_TO_STRING;
9021 newobj = valuePop(ctxt);
9022 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
9023 xmlXPathReleaseObject(ctxt->context, newobj);
9024 xmlXPathReleaseObject(ctxt->context, cur);
9025 XP_ERROR(XPATH_INVALID_TYPE);
9026 }
9027 tmp = xmlStrcat(newobj->stringval, cur->stringval);
9028 newobj->stringval = cur->stringval;
9029 cur->stringval = tmp;
9030 xmlXPathReleaseObject(ctxt->context, newobj);
9031 nargs--;
9032 }
9033 valuePush(ctxt, cur);
9034 }
9035
9036 /**
9037 * xmlXPathContainsFunction:
9038 * @ctxt: the XPath Parser context
9039 * @nargs: the number of arguments
9040 *
9041 * Implement the contains() XPath function
9042 * boolean contains(string, string)
9043 * The contains function returns true if the first argument string
9044 * contains the second argument string, and otherwise returns false.
9045 */
9046 void
9047 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9048 xmlXPathObjectPtr hay, needle;
9049
9050 CHECK_ARITY(2);
9051 CAST_TO_STRING;
9052 CHECK_TYPE(XPATH_STRING);
9053 needle = valuePop(ctxt);
9054 CAST_TO_STRING;
9055 hay = valuePop(ctxt);
9056
9057 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9058 xmlXPathReleaseObject(ctxt->context, hay);
9059 xmlXPathReleaseObject(ctxt->context, needle);
9060 XP_ERROR(XPATH_INVALID_TYPE);
9061 }
9062 if (xmlStrstr(hay->stringval, needle->stringval))
9063 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9064 else
9065 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9066 xmlXPathReleaseObject(ctxt->context, hay);
9067 xmlXPathReleaseObject(ctxt->context, needle);
9068 }
9069
9070 /**
9071 * xmlXPathStartsWithFunction:
9072 * @ctxt: the XPath Parser context
9073 * @nargs: the number of arguments
9074 *
9075 * Implement the starts-with() XPath function
9076 * boolean starts-with(string, string)
9077 * The starts-with function returns true if the first argument string
9078 * starts with the second argument string, and otherwise returns false.
9079 */
9080 void
9081 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9082 xmlXPathObjectPtr hay, needle;
9083 int n;
9084
9085 CHECK_ARITY(2);
9086 CAST_TO_STRING;
9087 CHECK_TYPE(XPATH_STRING);
9088 needle = valuePop(ctxt);
9089 CAST_TO_STRING;
9090 hay = valuePop(ctxt);
9091
9092 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9093 xmlXPathReleaseObject(ctxt->context, hay);
9094 xmlXPathReleaseObject(ctxt->context, needle);
9095 XP_ERROR(XPATH_INVALID_TYPE);
9096 }
9097 n = xmlStrlen(needle->stringval);
9098 if (xmlStrncmp(hay->stringval, needle->stringval, n))
9099 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9100 else
9101 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9102 xmlXPathReleaseObject(ctxt->context, hay);
9103 xmlXPathReleaseObject(ctxt->context, needle);
9104 }
9105
9106 /**
9107 * xmlXPathSubstringFunction:
9108 * @ctxt: the XPath Parser context
9109 * @nargs: the number of arguments
9110 *
9111 * Implement the substring() XPath function
9112 * string substring(string, number, number?)
9113 * The substring function returns the substring of the first argument
9114 * starting at the position specified in the second argument with
9115 * length specified in the third argument. For example,
9116 * substring("12345",2,3) returns "234". If the third argument is not
9117 * specified, it returns the substring starting at the position specified
9118 * in the second argument and continuing to the end of the string. For
9119 * example, substring("12345",2) returns "2345". More precisely, each
9120 * character in the string (see [3.6 Strings]) is considered to have a
9121 * numeric position: the position of the first character is 1, the position
9122 * of the second character is 2 and so on. The returned substring contains
9123 * those characters for which the position of the character is greater than
9124 * or equal to the second argument and, if the third argument is specified,
9125 * less than the sum of the second and third arguments; the comparisons
9126 * and addition used for the above follow the standard IEEE 754 rules. Thus:
9127 * - substring("12345", 1.5, 2.6) returns "234"
9128 * - substring("12345", 0, 3) returns "12"
9129 * - substring("12345", 0 div 0, 3) returns ""
9130 * - substring("12345", 1, 0 div 0) returns ""
9131 * - substring("12345", -42, 1 div 0) returns "12345"
9132 * - substring("12345", -1 div 0, 1 div 0) returns ""
9133 */
9134 void
9135 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9136 xmlXPathObjectPtr str, start, len;
9137 double le=0, in;
9138 int i, l, m;
9139 xmlChar *ret;
9140
9141 if (nargs < 2) {
9142 CHECK_ARITY(2);
9143 }
9144 if (nargs > 3) {
9145 CHECK_ARITY(3);
9146 }
9147 /*
9148 * take care of possible last (position) argument
9149 */
9150 if (nargs == 3) {
9151 CAST_TO_NUMBER;
9152 CHECK_TYPE(XPATH_NUMBER);
9153 len = valuePop(ctxt);
9154 le = len->floatval;
9155 xmlXPathReleaseObject(ctxt->context, len);
9156 }
9157
9158 CAST_TO_NUMBER;
9159 CHECK_TYPE(XPATH_NUMBER);
9160 start = valuePop(ctxt);
9161 in = start->floatval;
9162 xmlXPathReleaseObject(ctxt->context, start);
9163 CAST_TO_STRING;
9164 CHECK_TYPE(XPATH_STRING);
9165 str = valuePop(ctxt);
9166 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
9167
9168 /*
9169 * If last pos not present, calculate last position
9170 */
9171 if (nargs != 3) {
9172 le = (double)m;
9173 if (in < 1.0)
9174 in = 1.0;
9175 }
9176
9177 /* Need to check for the special cases where either
9178 * the index is NaN, the length is NaN, or both
9179 * arguments are infinity (relying on Inf + -Inf = NaN)
9180 */
9181 if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
9182 /*
9183 * To meet the requirements of the spec, the arguments
9184 * must be converted to integer format before
9185 * initial index calculations are done
9186 *
9187 * First we go to integer form, rounding up
9188 * and checking for special cases
9189 */
9190 i = (int) in;
9191 if (((double)i)+0.5 <= in) i++;
9192
9193 if (xmlXPathIsInf(le) == 1) {
9194 l = m;
9195 if (i < 1)
9196 i = 1;
9197 }
9198 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9199 l = 0;
9200 else {
9201 l = (int) le;
9202 if (((double)l)+0.5 <= le) l++;
9203 }
9204
9205 /* Now we normalize inidices */
9206 i -= 1;
9207 l += i;
9208 if (i < 0)
9209 i = 0;
9210 if (l > m)
9211 l = m;
9212
9213 /* number of chars to copy */
9214 l -= i;
9215
9216 ret = xmlUTF8Strsub(str->stringval, i, l);
9217 }
9218 else {
9219 ret = NULL;
9220 }
9221 if (ret == NULL)
9222 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9223 else {
9224 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9225 xmlFree(ret);
9226 }
9227 xmlXPathReleaseObject(ctxt->context, str);
9228 }
9229
9230 /**
9231 * xmlXPathSubstringBeforeFunction:
9232 * @ctxt: the XPath Parser context
9233 * @nargs: the number of arguments
9234 *
9235 * Implement the substring-before() XPath function
9236 * string substring-before(string, string)
9237 * The substring-before function returns the substring of the first
9238 * argument string that precedes the first occurrence of the second
9239 * argument string in the first argument string, or the empty string
9240 * if the first argument string does not contain the second argument
9241 * string. For example, substring-before("1999/04/01","/") returns 1999.
9242 */
9243 void
9244 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9245 xmlXPathObjectPtr str;
9246 xmlXPathObjectPtr find;
9247 xmlBufPtr target;
9248 const xmlChar *point;
9249 int offset;
9250
9251 CHECK_ARITY(2);
9252 CAST_TO_STRING;
9253 find = valuePop(ctxt);
9254 CAST_TO_STRING;
9255 str = valuePop(ctxt);
9256
9257 target = xmlBufCreate();
9258 if (target) {
9259 point = xmlStrstr(str->stringval, find->stringval);
9260 if (point) {
9261 offset = (int)(point - str->stringval);
9262 xmlBufAdd(target, str->stringval, offset);
9263 }
9264 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9265 xmlBufContent(target)));
9266 xmlBufFree(target);
9267 }
9268 xmlXPathReleaseObject(ctxt->context, str);
9269 xmlXPathReleaseObject(ctxt->context, find);
9270 }
9271
9272 /**
9273 * xmlXPathSubstringAfterFunction:
9274 * @ctxt: the XPath Parser context
9275 * @nargs: the number of arguments
9276 *
9277 * Implement the substring-after() XPath function
9278 * string substring-after(string, string)
9279 * The substring-after function returns the substring of the first
9280 * argument string that follows the first occurrence of the second
9281 * argument string in the first argument string, or the empty stringi
9282 * if the first argument string does not contain the second argument
9283 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9284 * and substring-after("1999/04/01","19") returns 99/04/01.
9285 */
9286 void
9287 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9288 xmlXPathObjectPtr str;
9289 xmlXPathObjectPtr find;
9290 xmlBufPtr target;
9291 const xmlChar *point;
9292 int offset;
9293
9294 CHECK_ARITY(2);
9295 CAST_TO_STRING;
9296 find = valuePop(ctxt);
9297 CAST_TO_STRING;
9298 str = valuePop(ctxt);
9299
9300 target = xmlBufCreate();
9301 if (target) {
9302 point = xmlStrstr(str->stringval, find->stringval);
9303 if (point) {
9304 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9305 xmlBufAdd(target, &str->stringval[offset],
9306 xmlStrlen(str->stringval) - offset);
9307 }
9308 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9309 xmlBufContent(target)));
9310 xmlBufFree(target);
9311 }
9312 xmlXPathReleaseObject(ctxt->context, str);
9313 xmlXPathReleaseObject(ctxt->context, find);
9314 }
9315
9316 /**
9317 * xmlXPathNormalizeFunction:
9318 * @ctxt: the XPath Parser context
9319 * @nargs: the number of arguments
9320 *
9321 * Implement the normalize-space() XPath function
9322 * string normalize-space(string?)
9323 * The normalize-space function returns the argument string with white
9324 * space normalized by stripping leading and trailing whitespace
9325 * and replacing sequences of whitespace characters by a single
9326 * space. Whitespace characters are the same allowed by the S production
9327 * in XML. If the argument is omitted, it defaults to the context
9328 * node converted to a string, in other words the value of the context node.
9329 */
9330 void
9331 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9332 xmlXPathObjectPtr obj = NULL;
9333 xmlChar *source = NULL;
9334 xmlBufPtr target;
9335 xmlChar blank;
9336
9337 if (ctxt == NULL) return;
9338 if (nargs == 0) {
9339 /* Use current context node */
9340 valuePush(ctxt,
9341 xmlXPathCacheWrapString(ctxt->context,
9342 xmlXPathCastNodeToString(ctxt->context->node)));
9343 nargs = 1;
9344 }
9345
9346 CHECK_ARITY(1);
9347 CAST_TO_STRING;
9348 CHECK_TYPE(XPATH_STRING);
9349 obj = valuePop(ctxt);
9350 source = obj->stringval;
9351
9352 target = xmlBufCreate();
9353 if (target && source) {
9354
9355 /* Skip leading whitespaces */
9356 while (IS_BLANK_CH(*source))
9357 source++;
9358
9359 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9360 blank = 0;
9361 while (*source) {
9362 if (IS_BLANK_CH(*source)) {
9363 blank = 0x20;
9364 } else {
9365 if (blank) {
9366 xmlBufAdd(target, &blank, 1);
9367 blank = 0;
9368 }
9369 xmlBufAdd(target, source, 1);
9370 }
9371 source++;
9372 }
9373 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9374 xmlBufContent(target)));
9375 xmlBufFree(target);
9376 }
9377 xmlXPathReleaseObject(ctxt->context, obj);
9378 }
9379
9380 /**
9381 * xmlXPathTranslateFunction:
9382 * @ctxt: the XPath Parser context
9383 * @nargs: the number of arguments
9384 *
9385 * Implement the translate() XPath function
9386 * string translate(string, string, string)
9387 * The translate function returns the first argument string with
9388 * occurrences of characters in the second argument string replaced
9389 * by the character at the corresponding position in the third argument
9390 * string. For example, translate("bar","abc","ABC") returns the string
9391 * BAr. If there is a character in the second argument string with no
9392 * character at a corresponding position in the third argument string
9393 * (because the second argument string is longer than the third argument
9394 * string), then occurrences of that character in the first argument
9395 * string are removed. For example, translate("--aaa--","abc-","ABC")
9396 * returns "AAA". If a character occurs more than once in second
9397 * argument string, then the first occurrence determines the replacement
9398 * character. If the third argument string is longer than the second
9399 * argument string, then excess characters are ignored.
9400 */
9401 void
9402 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9403 xmlXPathObjectPtr str;
9404 xmlXPathObjectPtr from;
9405 xmlXPathObjectPtr to;
9406 xmlBufPtr target;
9407 int offset, max;
9408 xmlChar ch;
9409 const xmlChar *point;
9410 xmlChar *cptr;
9411
9412 CHECK_ARITY(3);
9413
9414 CAST_TO_STRING;
9415 to = valuePop(ctxt);
9416 CAST_TO_STRING;
9417 from = valuePop(ctxt);
9418 CAST_TO_STRING;
9419 str = valuePop(ctxt);
9420
9421 target = xmlBufCreate();
9422 if (target) {
9423 max = xmlUTF8Strlen(to->stringval);
9424 for (cptr = str->stringval; (ch=*cptr); ) {
9425 offset = xmlUTF8Strloc(from->stringval, cptr);
9426 if (offset >= 0) {
9427 if (offset < max) {
9428 point = xmlUTF8Strpos(to->stringval, offset);
9429 if (point)
9430 xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9431 }
9432 } else
9433 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9434
9435 /* Step to next character in input */
9436 cptr++;
9437 if ( ch & 0x80 ) {
9438 /* if not simple ascii, verify proper format */
9439 if ( (ch & 0xc0) != 0xc0 ) {
9440 xmlGenericError(xmlGenericErrorContext,
9441 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9442 /* not asserting an XPath error is probably better */
9443 break;
9444 }
9445 /* then skip over remaining bytes for this char */
9446 while ( (ch <<= 1) & 0x80 )
9447 if ( (*cptr++ & 0xc0) != 0x80 ) {
9448 xmlGenericError(xmlGenericErrorContext,
9449 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9450 /* not asserting an XPath error is probably better */
9451 break;
9452 }
9453 if (ch & 0x80) /* must have had error encountered */
9454 break;
9455 }
9456 }
9457 }
9458 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9459 xmlBufContent(target)));
9460 xmlBufFree(target);
9461 xmlXPathReleaseObject(ctxt->context, str);
9462 xmlXPathReleaseObject(ctxt->context, from);
9463 xmlXPathReleaseObject(ctxt->context, to);
9464 }
9465
9466 /**
9467 * xmlXPathBooleanFunction:
9468 * @ctxt: the XPath Parser context
9469 * @nargs: the number of arguments
9470 *
9471 * Implement the boolean() XPath function
9472 * boolean boolean(object)
9473 * The boolean function converts its argument to a boolean as follows:
9474 * - a number is true if and only if it is neither positive or
9475 * negative zero nor NaN
9476 * - a node-set is true if and only if it is non-empty
9477 * - a string is true if and only if its length is non-zero
9478 */
9479 void
9480 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9481 xmlXPathObjectPtr cur;
9482
9483 CHECK_ARITY(1);
9484 cur = valuePop(ctxt);
9485 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9486 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9487 valuePush(ctxt, cur);
9488 }
9489
9490 /**
9491 * xmlXPathNotFunction:
9492 * @ctxt: the XPath Parser context
9493 * @nargs: the number of arguments
9494 *
9495 * Implement the not() XPath function
9496 * boolean not(boolean)
9497 * The not function returns true if its argument is false,
9498 * and false otherwise.
9499 */
9500 void
9501 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9502 CHECK_ARITY(1);
9503 CAST_TO_BOOLEAN;
9504 CHECK_TYPE(XPATH_BOOLEAN);
9505 ctxt->value->boolval = ! ctxt->value->boolval;
9506 }
9507
9508 /**
9509 * xmlXPathTrueFunction:
9510 * @ctxt: the XPath Parser context
9511 * @nargs: the number of arguments
9512 *
9513 * Implement the true() XPath function
9514 * boolean true()
9515 */
9516 void
9517 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9518 CHECK_ARITY(0);
9519 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9520 }
9521
9522 /**
9523 * xmlXPathFalseFunction:
9524 * @ctxt: the XPath Parser context
9525 * @nargs: the number of arguments
9526 *
9527 * Implement the false() XPath function
9528 * boolean false()
9529 */
9530 void
9531 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9532 CHECK_ARITY(0);
9533 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9534 }
9535
9536 /**
9537 * xmlXPathLangFunction:
9538 * @ctxt: the XPath Parser context
9539 * @nargs: the number of arguments
9540 *
9541 * Implement the lang() XPath function
9542 * boolean lang(string)
9543 * The lang function returns true or false depending on whether the
9544 * language of the context node as specified by xml:lang attributes
9545 * is the same as or is a sublanguage of the language specified by
9546 * the argument string. The language of the context node is determined
9547 * by the value of the xml:lang attribute on the context node, or, if
9548 * the context node has no xml:lang attribute, by the value of the
9549 * xml:lang attribute on the nearest ancestor of the context node that
9550 * has an xml:lang attribute. If there is no such attribute, then lang
9551 * returns false. If there is such an attribute, then lang returns
9552 * true if the attribute value is equal to the argument ignoring case,
9553 * or if there is some suffix starting with - such that the attribute
9554 * value is equal to the argument ignoring that suffix of the attribute
9555 * value and ignoring case.
9556 */
9557 void
9558 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9559 xmlXPathObjectPtr val = NULL;
9560 const xmlChar *theLang = NULL;
9561 const xmlChar *lang;
9562 int ret = 0;
9563 int i;
9564
9565 CHECK_ARITY(1);
9566 CAST_TO_STRING;
9567 CHECK_TYPE(XPATH_STRING);
9568 val = valuePop(ctxt);
9569 lang = val->stringval;
9570 theLang = xmlNodeGetLang(ctxt->context->node);
9571 if ((theLang != NULL) && (lang != NULL)) {
9572 for (i = 0;lang[i] != 0;i++)
9573 if (toupper(lang[i]) != toupper(theLang[i]))
9574 goto not_equal;
9575 if ((theLang[i] == 0) || (theLang[i] == '-'))
9576 ret = 1;
9577 }
9578 not_equal:
9579 if (theLang != NULL)
9580 xmlFree((void *)theLang);
9581
9582 xmlXPathReleaseObject(ctxt->context, val);
9583 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9584 }
9585
9586 /**
9587 * xmlXPathNumberFunction:
9588 * @ctxt: the XPath Parser context
9589 * @nargs: the number of arguments
9590 *
9591 * Implement the number() XPath function
9592 * number number(object?)
9593 */
9594 void
9595 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9596 xmlXPathObjectPtr cur;
9597 double res;
9598
9599 if (ctxt == NULL) return;
9600 if (nargs == 0) {
9601 if (ctxt->context->node == NULL) {
9602 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9603 } else {
9604 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9605
9606 res = xmlXPathStringEvalNumber(content);
9607 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9608 xmlFree(content);
9609 }
9610 return;
9611 }
9612
9613 CHECK_ARITY(1);
9614 cur = valuePop(ctxt);
9615 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9616 }
9617
9618 /**
9619 * xmlXPathSumFunction:
9620 * @ctxt: the XPath Parser context
9621 * @nargs: the number of arguments
9622 *
9623 * Implement the sum() XPath function
9624 * number sum(node-set)
9625 * The sum function returns the sum of the values of the nodes in
9626 * the argument node-set.
9627 */
9628 void
9629 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9630 xmlXPathObjectPtr cur;
9631 int i;
9632 double res = 0.0;
9633
9634 CHECK_ARITY(1);
9635 if ((ctxt->value == NULL) ||
9636 ((ctxt->value->type != XPATH_NODESET) &&
9637 (ctxt->value->type != XPATH_XSLT_TREE)))
9638 XP_ERROR(XPATH_INVALID_TYPE);
9639 cur = valuePop(ctxt);
9640
9641 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9642 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9643 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9644 }
9645 }
9646 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9647 xmlXPathReleaseObject(ctxt->context, cur);
9648 }
9649
9650 /**
9651 * xmlXPathFloorFunction:
9652 * @ctxt: the XPath Parser context
9653 * @nargs: the number of arguments
9654 *
9655 * Implement the floor() XPath function
9656 * number floor(number)
9657 * The floor function returns the largest (closest to positive infinity)
9658 * number that is not greater than the argument and that is an integer.
9659 */
9660 void
9661 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9662 CHECK_ARITY(1);
9663 CAST_TO_NUMBER;
9664 CHECK_TYPE(XPATH_NUMBER);
9665
9666 ctxt->value->floatval = floor(ctxt->value->floatval);
9667 }
9668
9669 /**
9670 * xmlXPathCeilingFunction:
9671 * @ctxt: the XPath Parser context
9672 * @nargs: the number of arguments
9673 *
9674 * Implement the ceiling() XPath function
9675 * number ceiling(number)
9676 * The ceiling function returns the smallest (closest to negative infinity)
9677 * number that is not less than the argument and that is an integer.
9678 */
9679 void
9680 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9681 CHECK_ARITY(1);
9682 CAST_TO_NUMBER;
9683 CHECK_TYPE(XPATH_NUMBER);
9684
9685 ctxt->value->floatval = ceil(ctxt->value->floatval);
9686 }
9687
9688 /**
9689 * xmlXPathRoundFunction:
9690 * @ctxt: the XPath Parser context
9691 * @nargs: the number of arguments
9692 *
9693 * Implement the round() XPath function
9694 * number round(number)
9695 * The round function returns the number that is closest to the
9696 * argument and that is an integer. If there are two such numbers,
9697 * then the one that is closest to positive infinity is returned.
9698 */
9699 void
9700 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9701 double f;
9702
9703 CHECK_ARITY(1);
9704 CAST_TO_NUMBER;
9705 CHECK_TYPE(XPATH_NUMBER);
9706
9707 f = ctxt->value->floatval;
9708
9709 if ((f >= -0.5) && (f < 0.5)) {
9710 /* Handles negative zero. */
9711 ctxt->value->floatval *= 0.0;
9712 }
9713 else {
9714 double rounded = floor(f);
9715 if (f - rounded >= 0.5)
9716 rounded += 1.0;
9717 ctxt->value->floatval = rounded;
9718 }
9719 }
9720
9721 /************************************************************************
9722 * *
9723 * The Parser *
9724 * *
9725 ************************************************************************/
9726
9727 /*
9728 * a few forward declarations since we use a recursive call based
9729 * implementation.
9730 */
9731 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9732 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9733 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9734 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9735 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9736 int qualified);
9737
9738 /**
9739 * xmlXPathCurrentChar:
9740 * @ctxt: the XPath parser context
9741 * @cur: pointer to the beginning of the char
9742 * @len: pointer to the length of the char read
9743 *
9744 * The current char value, if using UTF-8 this may actually span multiple
9745 * bytes in the input buffer.
9746 *
9747 * Returns the current char value and its length
9748 */
9749
9750 static int
9751 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9752 unsigned char c;
9753 unsigned int val;
9754 const xmlChar *cur;
9755
9756 if (ctxt == NULL)
9757 return(0);
9758 cur = ctxt->cur;
9759
9760 /*
9761 * We are supposed to handle UTF8, check it's valid
9762 * From rfc2044: encoding of the Unicode values on UTF-8:
9763 *
9764 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9765 * 0000 0000-0000 007F 0xxxxxxx
9766 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
9767 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
9768 *
9769 * Check for the 0x110000 limit too
9770 */
9771 c = *cur;
9772 if (c & 0x80) {
9773 if ((cur[1] & 0xc0) != 0x80)
9774 goto encoding_error;
9775 if ((c & 0xe0) == 0xe0) {
9776
9777 if ((cur[2] & 0xc0) != 0x80)
9778 goto encoding_error;
9779 if ((c & 0xf0) == 0xf0) {
9780 if (((c & 0xf8) != 0xf0) ||
9781 ((cur[3] & 0xc0) != 0x80))
9782 goto encoding_error;
9783 /* 4-byte code */
9784 *len = 4;
9785 val = (cur[0] & 0x7) << 18;
9786 val |= (cur[1] & 0x3f) << 12;
9787 val |= (cur[2] & 0x3f) << 6;
9788 val |= cur[3] & 0x3f;
9789 } else {
9790 /* 3-byte code */
9791 *len = 3;
9792 val = (cur[0] & 0xf) << 12;
9793 val |= (cur[1] & 0x3f) << 6;
9794 val |= cur[2] & 0x3f;
9795 }
9796 } else {
9797 /* 2-byte code */
9798 *len = 2;
9799 val = (cur[0] & 0x1f) << 6;
9800 val |= cur[1] & 0x3f;
9801 }
9802 if (!IS_CHAR(val)) {
9803 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9804 }
9805 return(val);
9806 } else {
9807 /* 1-byte code */
9808 *len = 1;
9809 return((int) *cur);
9810 }
9811 encoding_error:
9812 /*
9813 * If we detect an UTF8 error that probably means that the
9814 * input encoding didn't get properly advertised in the
9815 * declaration header. Report the error and switch the encoding
9816 * to ISO-Latin-1 (if you don't like this policy, just declare the
9817 * encoding !)
9818 */
9819 *len = 0;
9820 XP_ERROR0(XPATH_ENCODING_ERROR);
9821 }
9822
9823 /**
9824 * xmlXPathParseNCName:
9825 * @ctxt: the XPath Parser context
9826 *
9827 * parse an XML namespace non qualified name.
9828 *
9829 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9830 *
9831 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9832 * CombiningChar | Extender
9833 *
9834 * Returns the namespace name or NULL
9835 */
9836
9837 xmlChar *
9838 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9839 const xmlChar *in;
9840 xmlChar *ret;
9841 int count = 0;
9842
9843 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9844 /*
9845 * Accelerator for simple ASCII names
9846 */
9847 in = ctxt->cur;
9848 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9849 ((*in >= 0x41) && (*in <= 0x5A)) ||
9850 (*in == '_')) {
9851 in++;
9852 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9853 ((*in >= 0x41) && (*in <= 0x5A)) ||
9854 ((*in >= 0x30) && (*in <= 0x39)) ||
9855 (*in == '_') || (*in == '.') ||
9856 (*in == '-'))
9857 in++;
9858 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9859 (*in == '[') || (*in == ']') || (*in == ':') ||
9860 (*in == '@') || (*in == '*')) {
9861 count = in - ctxt->cur;
9862 if (count == 0)
9863 return(NULL);
9864 ret = xmlStrndup(ctxt->cur, count);
9865 ctxt->cur = in;
9866 return(ret);
9867 }
9868 }
9869 return(xmlXPathParseNameComplex(ctxt, 0));
9870 }
9871
9872
9873 /**
9874 * xmlXPathParseQName:
9875 * @ctxt: the XPath Parser context
9876 * @prefix: a xmlChar **
9877 *
9878 * parse an XML qualified name
9879 *
9880 * [NS 5] QName ::= (Prefix ':')? LocalPart
9881 *
9882 * [NS 6] Prefix ::= NCName
9883 *
9884 * [NS 7] LocalPart ::= NCName
9885 *
9886 * Returns the function returns the local part, and prefix is updated
9887 * to get the Prefix if any.
9888 */
9889
9890 static xmlChar *
9891 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9892 xmlChar *ret = NULL;
9893
9894 *prefix = NULL;
9895 ret = xmlXPathParseNCName(ctxt);
9896 if (ret && CUR == ':') {
9897 *prefix = ret;
9898 NEXT;
9899 ret = xmlXPathParseNCName(ctxt);
9900 }
9901 return(ret);
9902 }
9903
9904 /**
9905 * xmlXPathParseName:
9906 * @ctxt: the XPath Parser context
9907 *
9908 * parse an XML name
9909 *
9910 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9911 * CombiningChar | Extender
9912 *
9913 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9914 *
9915 * Returns the namespace name or NULL
9916 */
9917
9918 xmlChar *
9919 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9920 const xmlChar *in;
9921 xmlChar *ret;
9922 size_t count = 0;
9923
9924 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9925 /*
9926 * Accelerator for simple ASCII names
9927 */
9928 in = ctxt->cur;
9929 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9930 ((*in >= 0x41) && (*in <= 0x5A)) ||
9931 (*in == '_') || (*in == ':')) {
9932 in++;
9933 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9934 ((*in >= 0x41) && (*in <= 0x5A)) ||
9935 ((*in >= 0x30) && (*in <= 0x39)) ||
9936 (*in == '_') || (*in == '-') ||
9937 (*in == ':') || (*in == '.'))
9938 in++;
9939 if ((*in > 0) && (*in < 0x80)) {
9940 count = in - ctxt->cur;
9941 if (count > XML_MAX_NAME_LENGTH) {
9942 ctxt->cur = in;
9943 XP_ERRORNULL(XPATH_EXPR_ERROR);
9944 }
9945 ret = xmlStrndup(ctxt->cur, count);
9946 ctxt->cur = in;
9947 return(ret);
9948 }
9949 }
9950 return(xmlXPathParseNameComplex(ctxt, 1));
9951 }
9952
9953 static xmlChar *
9954 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9955 xmlChar buf[XML_MAX_NAMELEN + 5];
9956 int len = 0, l;
9957 int c;
9958
9959 /*
9960 * Handler for more complex cases
9961 */
9962 c = CUR_CHAR(l);
9963 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9964 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9965 (c == '*') || /* accelerators */
9966 (!IS_LETTER(c) && (c != '_') &&
9967 ((!qualified) || (c != ':')))) {
9968 return(NULL);
9969 }
9970
9971 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9972 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9973 (c == '.') || (c == '-') ||
9974 (c == '_') || ((qualified) && (c == ':')) ||
9975 (IS_COMBINING(c)) ||
9976 (IS_EXTENDER(c)))) {
9977 COPY_BUF(l,buf,len,c);
9978 NEXTL(l);
9979 c = CUR_CHAR(l);
9980 if (len >= XML_MAX_NAMELEN) {
9981 /*
9982 * Okay someone managed to make a huge name, so he's ready to pay
9983 * for the processing speed.
9984 */
9985 xmlChar *buffer;
9986 int max = len * 2;
9987
9988 if (len > XML_MAX_NAME_LENGTH) {
9989 XP_ERRORNULL(XPATH_EXPR_ERROR);
9990 }
9991 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
9992 if (buffer == NULL) {
9993 XP_ERRORNULL(XPATH_MEMORY_ERROR);
9994 }
9995 memcpy(buffer, buf, len);
9996 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9997 (c == '.') || (c == '-') ||
9998 (c == '_') || ((qualified) && (c == ':')) ||
9999 (IS_COMBINING(c)) ||
10000 (IS_EXTENDER(c))) {
10001 if (len + 10 > max) {
10002 if (max > XML_MAX_NAME_LENGTH) {
10003 XP_ERRORNULL(XPATH_EXPR_ERROR);
10004 }
10005 max *= 2;
10006 buffer = (xmlChar *) xmlRealloc(buffer,
10007 max * sizeof(xmlChar));
10008 if (buffer == NULL) {
10009 XP_ERRORNULL(XPATH_MEMORY_ERROR);
10010 }
10011 }
10012 COPY_BUF(l,buffer,len,c);
10013 NEXTL(l);
10014 c = CUR_CHAR(l);
10015 }
10016 buffer[len] = 0;
10017 return(buffer);
10018 }
10019 }
10020 if (len == 0)
10021 return(NULL);
10022 return(xmlStrndup(buf, len));
10023 }
10024
10025 #define MAX_FRAC 20
10026
10027 /**
10028 * xmlXPathStringEvalNumber:
10029 * @str: A string to scan
10030 *
10031 * [30a] Float ::= Number ('e' Digits?)?
10032 *
10033 * [30] Number ::= Digits ('.' Digits?)?
10034 * | '.' Digits
10035 * [31] Digits ::= [0-9]+
10036 *
10037 * Compile a Number in the string
10038 * In complement of the Number expression, this function also handles
10039 * negative values : '-' Number.
10040 *
10041 * Returns the double value.
10042 */
10043 double
10044 xmlXPathStringEvalNumber(const xmlChar *str) {
10045 const xmlChar *cur = str;
10046 double ret;
10047 int ok = 0;
10048 int isneg = 0;
10049 int exponent = 0;
10050 int is_exponent_negative = 0;
10051 #ifdef __GNUC__
10052 unsigned long tmp = 0;
10053 double temp;
10054 #endif
10055 if (cur == NULL) return(0);
10056 while (IS_BLANK_CH(*cur)) cur++;
10057 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10058 return(NAN);
10059 }
10060 if (*cur == '-') {
10061 isneg = 1;
10062 cur++;
10063 }
10064
10065 #ifdef __GNUC__
10066 /*
10067 * tmp/temp is a workaround against a gcc compiler bug
10068 * http://veillard.com/gcc.bug
10069 */
10070 ret = 0;
10071 while ((*cur >= '0') && (*cur <= '9')) {
10072 ret = ret * 10;
10073 tmp = (*cur - '0');
10074 ok = 1;
10075 cur++;
10076 temp = (double) tmp;
10077 ret = ret + temp;
10078 }
10079 #else
10080 ret = 0;
10081 while ((*cur >= '0') && (*cur <= '9')) {
10082 ret = ret * 10 + (*cur - '0');
10083 ok = 1;
10084 cur++;
10085 }
10086 #endif
10087
10088 if (*cur == '.') {
10089 int v, frac = 0, max;
10090 double fraction = 0;
10091
10092 cur++;
10093 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10094 return(NAN);
10095 }
10096 while (*cur == '0') {
10097 frac = frac + 1;
10098 cur++;
10099 }
10100 max = frac + MAX_FRAC;
10101 while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
10102 v = (*cur - '0');
10103 fraction = fraction * 10 + v;
10104 frac = frac + 1;
10105 cur++;
10106 }
10107 fraction /= pow(10.0, frac);
10108 ret = ret + fraction;
10109 while ((*cur >= '0') && (*cur <= '9'))
10110 cur++;
10111 }
10112 if ((*cur == 'e') || (*cur == 'E')) {
10113 cur++;
10114 if (*cur == '-') {
10115 is_exponent_negative = 1;
10116 cur++;
10117 } else if (*cur == '+') {
10118 cur++;
10119 }
10120 while ((*cur >= '0') && (*cur <= '9')) {
10121 if (exponent < 1000000)
10122 exponent = exponent * 10 + (*cur - '0');
10123 cur++;
10124 }
10125 }
10126 while (IS_BLANK_CH(*cur)) cur++;
10127 if (*cur != 0) return(NAN);
10128 if (isneg) ret = -ret;
10129 if (is_exponent_negative) exponent = -exponent;
10130 ret *= pow(10.0, (double)exponent);
10131 return(ret);
10132 }
10133
10134 /**
10135 * xmlXPathCompNumber:
10136 * @ctxt: the XPath Parser context
10137 *
10138 * [30] Number ::= Digits ('.' Digits?)?
10139 * | '.' Digits
10140 * [31] Digits ::= [0-9]+
10141 *
10142 * Compile a Number, then push it on the stack
10143 *
10144 */
10145 static void
10146 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10147 {
10148 double ret = 0.0;
10149 int ok = 0;
10150 int exponent = 0;
10151 int is_exponent_negative = 0;
10152 #ifdef __GNUC__
10153 unsigned long tmp = 0;
10154 double temp;
10155 #endif
10156
10157 CHECK_ERROR;
10158 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10159 XP_ERROR(XPATH_NUMBER_ERROR);
10160 }
10161 #ifdef __GNUC__
10162 /*
10163 * tmp/temp is a workaround against a gcc compiler bug
10164 * http://veillard.com/gcc.bug
10165 */
10166 ret = 0;
10167 while ((CUR >= '0') && (CUR <= '9')) {
10168 ret = ret * 10;
10169 tmp = (CUR - '0');
10170 ok = 1;
10171 NEXT;
10172 temp = (double) tmp;
10173 ret = ret + temp;
10174 }
10175 #else
10176 ret = 0;
10177 while ((CUR >= '0') && (CUR <= '9')) {
10178 ret = ret * 10 + (CUR - '0');
10179 ok = 1;
10180 NEXT;
10181 }
10182 #endif
10183 if (CUR == '.') {
10184 int v, frac = 0, max;
10185 double fraction = 0;
10186
10187 NEXT;
10188 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10189 XP_ERROR(XPATH_NUMBER_ERROR);
10190 }
10191 while (CUR == '0') {
10192 frac = frac + 1;
10193 NEXT;
10194 }
10195 max = frac + MAX_FRAC;
10196 while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
10197 v = (CUR - '0');
10198 fraction = fraction * 10 + v;
10199 frac = frac + 1;
10200 NEXT;
10201 }
10202 fraction /= pow(10.0, frac);
10203 ret = ret + fraction;
10204 while ((CUR >= '0') && (CUR <= '9'))
10205 NEXT;
10206 }
10207 if ((CUR == 'e') || (CUR == 'E')) {
10208 NEXT;
10209 if (CUR == '-') {
10210 is_exponent_negative = 1;
10211 NEXT;
10212 } else if (CUR == '+') {
10213 NEXT;
10214 }
10215 while ((CUR >= '0') && (CUR <= '9')) {
10216 if (exponent < 1000000)
10217 exponent = exponent * 10 + (CUR - '0');
10218 NEXT;
10219 }
10220 if (is_exponent_negative)
10221 exponent = -exponent;
10222 ret *= pow(10.0, (double) exponent);
10223 }
10224 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10225 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10226 }
10227
10228 /**
10229 * xmlXPathParseLiteral:
10230 * @ctxt: the XPath Parser context
10231 *
10232 * Parse a Literal
10233 *
10234 * [29] Literal ::= '"' [^"]* '"'
10235 * | "'" [^']* "'"
10236 *
10237 * Returns the value found or NULL in case of error
10238 */
10239 static xmlChar *
10240 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10241 const xmlChar *q;
10242 xmlChar *ret = NULL;
10243
10244 if (CUR == '"') {
10245 NEXT;
10246 q = CUR_PTR;
10247 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10248 NEXT;
10249 if (!IS_CHAR_CH(CUR)) {
10250 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10251 } else {
10252 ret = xmlStrndup(q, CUR_PTR - q);
10253 NEXT;
10254 }
10255 } else if (CUR == '\'') {
10256 NEXT;
10257 q = CUR_PTR;
10258 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10259 NEXT;
10260 if (!IS_CHAR_CH(CUR)) {
10261 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10262 } else {
10263 ret = xmlStrndup(q, CUR_PTR - q);
10264 NEXT;
10265 }
10266 } else {
10267 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10268 }
10269 return(ret);
10270 }
10271
10272 /**
10273 * xmlXPathCompLiteral:
10274 * @ctxt: the XPath Parser context
10275 *
10276 * Parse a Literal and push it on the stack.
10277 *
10278 * [29] Literal ::= '"' [^"]* '"'
10279 * | "'" [^']* "'"
10280 *
10281 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10282 */
10283 static void
10284 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10285 const xmlChar *q;
10286 xmlChar *ret = NULL;
10287
10288 if (CUR == '"') {
10289 NEXT;
10290 q = CUR_PTR;
10291 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10292 NEXT;
10293 if (!IS_CHAR_CH(CUR)) {
10294 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10295 } else {
10296 ret = xmlStrndup(q, CUR_PTR - q);
10297 NEXT;
10298 }
10299 } else if (CUR == '\'') {
10300 NEXT;
10301 q = CUR_PTR;
10302 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10303 NEXT;
10304 if (!IS_CHAR_CH(CUR)) {
10305 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10306 } else {
10307 ret = xmlStrndup(q, CUR_PTR - q);
10308 NEXT;
10309 }
10310 } else {
10311 XP_ERROR(XPATH_START_LITERAL_ERROR);
10312 }
10313 if (ret == NULL) return;
10314 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10315 xmlXPathCacheNewString(ctxt->context, ret), NULL);
10316 xmlFree(ret);
10317 }
10318
10319 /**
10320 * xmlXPathCompVariableReference:
10321 * @ctxt: the XPath Parser context
10322 *
10323 * Parse a VariableReference, evaluate it and push it on the stack.
10324 *
10325 * The variable bindings consist of a mapping from variable names
10326 * to variable values. The value of a variable is an object, which can be
10327 * of any of the types that are possible for the value of an expression,
10328 * and may also be of additional types not specified here.
10329 *
10330 * Early evaluation is possible since:
10331 * The variable bindings [...] used to evaluate a subexpression are
10332 * always the same as those used to evaluate the containing expression.
10333 *
10334 * [36] VariableReference ::= '$' QName
10335 */
10336 static void
10337 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10338 xmlChar *name;
10339 xmlChar *prefix;
10340
10341 SKIP_BLANKS;
10342 if (CUR != '$') {
10343 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10344 }
10345 NEXT;
10346 name = xmlXPathParseQName(ctxt, &prefix);
10347 if (name == NULL) {
10348 xmlFree(prefix);
10349 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10350 }
10351 ctxt->comp->last = -1;
10352 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10353 name, prefix);
10354 SKIP_BLANKS;
10355 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10356 XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10357 }
10358 }
10359
10360 /**
10361 * xmlXPathIsNodeType:
10362 * @name: a name string
10363 *
10364 * Is the name given a NodeType one.
10365 *
10366 * [38] NodeType ::= 'comment'
10367 * | 'text'
10368 * | 'processing-instruction'
10369 * | 'node'
10370 *
10371 * Returns 1 if true 0 otherwise
10372 */
10373 int
10374 xmlXPathIsNodeType(const xmlChar *name) {
10375 if (name == NULL)
10376 return(0);
10377
10378 if (xmlStrEqual(name, BAD_CAST "node"))
10379 return(1);
10380 if (xmlStrEqual(name, BAD_CAST "text"))
10381 return(1);
10382 if (xmlStrEqual(name, BAD_CAST "comment"))
10383 return(1);
10384 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10385 return(1);
10386 return(0);
10387 }
10388
10389 /**
10390 * xmlXPathCompFunctionCall:
10391 * @ctxt: the XPath Parser context
10392 *
10393 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10394 * [17] Argument ::= Expr
10395 *
10396 * Compile a function call, the evaluation of all arguments are
10397 * pushed on the stack
10398 */
10399 static void
10400 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10401 xmlChar *name;
10402 xmlChar *prefix;
10403 int nbargs = 0;
10404 int sort = 1;
10405
10406 name = xmlXPathParseQName(ctxt, &prefix);
10407 if (name == NULL) {
10408 xmlFree(prefix);
10409 XP_ERROR(XPATH_EXPR_ERROR);
10410 }
10411 SKIP_BLANKS;
10412 #ifdef DEBUG_EXPR
10413 if (prefix == NULL)
10414 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10415 name);
10416 else
10417 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10418 prefix, name);
10419 #endif
10420
10421 if (CUR != '(') {
10422 xmlFree(name);
10423 xmlFree(prefix);
10424 XP_ERROR(XPATH_EXPR_ERROR);
10425 }
10426 NEXT;
10427 SKIP_BLANKS;
10428
10429 /*
10430 * Optimization for count(): we don't need the node-set to be sorted.
10431 */
10432 if ((prefix == NULL) && (name[0] == 'c') &&
10433 xmlStrEqual(name, BAD_CAST "count"))
10434 {
10435 sort = 0;
10436 }
10437 ctxt->comp->last = -1;
10438 if (CUR != ')') {
10439 while (CUR != 0) {
10440 int op1 = ctxt->comp->last;
10441 ctxt->comp->last = -1;
10442 xmlXPathCompileExpr(ctxt, sort);
10443 if (ctxt->error != XPATH_EXPRESSION_OK) {
10444 xmlFree(name);
10445 xmlFree(prefix);
10446 return;
10447 }
10448 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10449 nbargs++;
10450 if (CUR == ')') break;
10451 if (CUR != ',') {
10452 xmlFree(name);
10453 xmlFree(prefix);
10454 XP_ERROR(XPATH_EXPR_ERROR);
10455 }
10456 NEXT;
10457 SKIP_BLANKS;
10458 }
10459 }
10460 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10461 name, prefix);
10462 NEXT;
10463 SKIP_BLANKS;
10464 }
10465
10466 /**
10467 * xmlXPathCompPrimaryExpr:
10468 * @ctxt: the XPath Parser context
10469 *
10470 * [15] PrimaryExpr ::= VariableReference
10471 * | '(' Expr ')'
10472 * | Literal
10473 * | Number
10474 * | FunctionCall
10475 *
10476 * Compile a primary expression.
10477 */
10478 static void
10479 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10480 SKIP_BLANKS;
10481 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10482 else if (CUR == '(') {
10483 NEXT;
10484 SKIP_BLANKS;
10485 xmlXPathCompileExpr(ctxt, 1);
10486 CHECK_ERROR;
10487 if (CUR != ')') {
10488 XP_ERROR(XPATH_EXPR_ERROR);
10489 }
10490 NEXT;
10491 SKIP_BLANKS;
10492 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10493 xmlXPathCompNumber(ctxt);
10494 } else if ((CUR == '\'') || (CUR == '"')) {
10495 xmlXPathCompLiteral(ctxt);
10496 } else {
10497 xmlXPathCompFunctionCall(ctxt);
10498 }
10499 SKIP_BLANKS;
10500 }
10501
10502 /**
10503 * xmlXPathCompFilterExpr:
10504 * @ctxt: the XPath Parser context
10505 *
10506 * [20] FilterExpr ::= PrimaryExpr
10507 * | FilterExpr Predicate
10508 *
10509 * Compile a filter expression.
10510 * Square brackets are used to filter expressions in the same way that
10511 * they are used in location paths. It is an error if the expression to
10512 * be filtered does not evaluate to a node-set. The context node list
10513 * used for evaluating the expression in square brackets is the node-set
10514 * to be filtered listed in document order.
10515 */
10516
10517 static void
10518 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10519 xmlXPathCompPrimaryExpr(ctxt);
10520 CHECK_ERROR;
10521 SKIP_BLANKS;
10522
10523 while (CUR == '[') {
10524 xmlXPathCompPredicate(ctxt, 1);
10525 SKIP_BLANKS;
10526 }
10527
10528
10529 }
10530
10531 /**
10532 * xmlXPathScanName:
10533 * @ctxt: the XPath Parser context
10534 *
10535 * Trickery: parse an XML name but without consuming the input flow
10536 * Needed to avoid insanity in the parser state.
10537 *
10538 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10539 * CombiningChar | Extender
10540 *
10541 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10542 *
10543 * [6] Names ::= Name (S Name)*
10544 *
10545 * Returns the Name parsed or NULL
10546 */
10547
10548 static xmlChar *
10549 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10550 int len = 0, l;
10551 int c;
10552 const xmlChar *cur;
10553 xmlChar *ret;
10554
10555 cur = ctxt->cur;
10556
10557 c = CUR_CHAR(l);
10558 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10559 (!IS_LETTER(c) && (c != '_') &&
10560 (c != ':'))) {
10561 return(NULL);
10562 }
10563
10564 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10565 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10566 (c == '.') || (c == '-') ||
10567 (c == '_') || (c == ':') ||
10568 (IS_COMBINING(c)) ||
10569 (IS_EXTENDER(c)))) {
10570 len += l;
10571 NEXTL(l);
10572 c = CUR_CHAR(l);
10573 }
10574 ret = xmlStrndup(cur, ctxt->cur - cur);
10575 ctxt->cur = cur;
10576 return(ret);
10577 }
10578
10579 /**
10580 * xmlXPathCompPathExpr:
10581 * @ctxt: the XPath Parser context
10582 *
10583 * [19] PathExpr ::= LocationPath
10584 * | FilterExpr
10585 * | FilterExpr '/' RelativeLocationPath
10586 * | FilterExpr '//' RelativeLocationPath
10587 *
10588 * Compile a path expression.
10589 * The / operator and // operators combine an arbitrary expression
10590 * and a relative location path. It is an error if the expression
10591 * does not evaluate to a node-set.
10592 * The / operator does composition in the same way as when / is
10593 * used in a location path. As in location paths, // is short for
10594 * /descendant-or-self::node()/.
10595 */
10596
10597 static void
10598 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10599 int lc = 1; /* Should we branch to LocationPath ? */
10600 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10601
10602 SKIP_BLANKS;
10603 if ((CUR == '$') || (CUR == '(') ||
10604 (IS_ASCII_DIGIT(CUR)) ||
10605 (CUR == '\'') || (CUR == '"') ||
10606 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10607 lc = 0;
10608 } else if (CUR == '*') {
10609 /* relative or absolute location path */
10610 lc = 1;
10611 } else if (CUR == '/') {
10612 /* relative or absolute location path */
10613 lc = 1;
10614 } else if (CUR == '@') {
10615 /* relative abbreviated attribute location path */
10616 lc = 1;
10617 } else if (CUR == '.') {
10618 /* relative abbreviated attribute location path */
10619 lc = 1;
10620 } else {
10621 /*
10622 * Problem is finding if we have a name here whether it's:
10623 * - a nodetype
10624 * - a function call in which case it's followed by '('
10625 * - an axis in which case it's followed by ':'
10626 * - a element name
10627 * We do an a priori analysis here rather than having to
10628 * maintain parsed token content through the recursive function
10629 * calls. This looks uglier but makes the code easier to
10630 * read/write/debug.
10631 */
10632 SKIP_BLANKS;
10633 name = xmlXPathScanName(ctxt);
10634 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10635 #ifdef DEBUG_STEP
10636 xmlGenericError(xmlGenericErrorContext,
10637 "PathExpr: Axis\n");
10638 #endif
10639 lc = 1;
10640 xmlFree(name);
10641 } else if (name != NULL) {
10642 int len =xmlStrlen(name);
10643
10644
10645 while (NXT(len) != 0) {
10646 if (NXT(len) == '/') {
10647 /* element name */
10648 #ifdef DEBUG_STEP
10649 xmlGenericError(xmlGenericErrorContext,
10650 "PathExpr: AbbrRelLocation\n");
10651 #endif
10652 lc = 1;
10653 break;
10654 } else if (IS_BLANK_CH(NXT(len))) {
10655 /* ignore blanks */
10656 ;
10657 } else if (NXT(len) == ':') {
10658 #ifdef DEBUG_STEP
10659 xmlGenericError(xmlGenericErrorContext,
10660 "PathExpr: AbbrRelLocation\n");
10661 #endif
10662 lc = 1;
10663 break;
10664 } else if ((NXT(len) == '(')) {
10665 /* Node Type or Function */
10666 if (xmlXPathIsNodeType(name)) {
10667 #ifdef DEBUG_STEP
10668 xmlGenericError(xmlGenericErrorContext,
10669 "PathExpr: Type search\n");
10670 #endif
10671 lc = 1;
10672 #ifdef LIBXML_XPTR_ENABLED
10673 } else if (ctxt->xptr &&
10674 xmlStrEqual(name, BAD_CAST "range-to")) {
10675 lc = 1;
10676 #endif
10677 } else {
10678 #ifdef DEBUG_STEP
10679 xmlGenericError(xmlGenericErrorContext,
10680 "PathExpr: function call\n");
10681 #endif
10682 lc = 0;
10683 }
10684 break;
10685 } else if ((NXT(len) == '[')) {
10686 /* element name */
10687 #ifdef DEBUG_STEP
10688 xmlGenericError(xmlGenericErrorContext,
10689 "PathExpr: AbbrRelLocation\n");
10690 #endif
10691 lc = 1;
10692 break;
10693 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10694 (NXT(len) == '=')) {
10695 lc = 1;
10696 break;
10697 } else {
10698 lc = 1;
10699 break;
10700 }
10701 len++;
10702 }
10703 if (NXT(len) == 0) {
10704 #ifdef DEBUG_STEP
10705 xmlGenericError(xmlGenericErrorContext,
10706 "PathExpr: AbbrRelLocation\n");
10707 #endif
10708 /* element name */
10709 lc = 1;
10710 }
10711 xmlFree(name);
10712 } else {
10713 /* make sure all cases are covered explicitly */
10714 XP_ERROR(XPATH_EXPR_ERROR);
10715 }
10716 }
10717
10718 if (lc) {
10719 if (CUR == '/') {
10720 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10721 } else {
10722 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10723 }
10724 xmlXPathCompLocationPath(ctxt);
10725 } else {
10726 xmlXPathCompFilterExpr(ctxt);
10727 CHECK_ERROR;
10728 if ((CUR == '/') && (NXT(1) == '/')) {
10729 SKIP(2);
10730 SKIP_BLANKS;
10731
10732 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10733 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10734
10735 xmlXPathCompRelativeLocationPath(ctxt);
10736 } else if (CUR == '/') {
10737 xmlXPathCompRelativeLocationPath(ctxt);
10738 }
10739 }
10740 SKIP_BLANKS;
10741 }
10742
10743 /**
10744 * xmlXPathCompUnionExpr:
10745 * @ctxt: the XPath Parser context
10746 *
10747 * [18] UnionExpr ::= PathExpr
10748 * | UnionExpr '|' PathExpr
10749 *
10750 * Compile an union expression.
10751 */
10752
10753 static void
10754 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10755 xmlXPathCompPathExpr(ctxt);
10756 CHECK_ERROR;
10757 SKIP_BLANKS;
10758 while (CUR == '|') {
10759 int op1 = ctxt->comp->last;
10760 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10761
10762 NEXT;
10763 SKIP_BLANKS;
10764 xmlXPathCompPathExpr(ctxt);
10765
10766 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10767
10768 SKIP_BLANKS;
10769 }
10770 }
10771
10772 /**
10773 * xmlXPathCompUnaryExpr:
10774 * @ctxt: the XPath Parser context
10775 *
10776 * [27] UnaryExpr ::= UnionExpr
10777 * | '-' UnaryExpr
10778 *
10779 * Compile an unary expression.
10780 */
10781
10782 static void
10783 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10784 int minus = 0;
10785 int found = 0;
10786
10787 SKIP_BLANKS;
10788 while (CUR == '-') {
10789 minus = 1 - minus;
10790 found = 1;
10791 NEXT;
10792 SKIP_BLANKS;
10793 }
10794
10795 xmlXPathCompUnionExpr(ctxt);
10796 CHECK_ERROR;
10797 if (found) {
10798 if (minus)
10799 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10800 else
10801 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10802 }
10803 }
10804
10805 /**
10806 * xmlXPathCompMultiplicativeExpr:
10807 * @ctxt: the XPath Parser context
10808 *
10809 * [26] MultiplicativeExpr ::= UnaryExpr
10810 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10811 * | MultiplicativeExpr 'div' UnaryExpr
10812 * | MultiplicativeExpr 'mod' UnaryExpr
10813 * [34] MultiplyOperator ::= '*'
10814 *
10815 * Compile an Additive expression.
10816 */
10817
10818 static void
10819 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10820 xmlXPathCompUnaryExpr(ctxt);
10821 CHECK_ERROR;
10822 SKIP_BLANKS;
10823 while ((CUR == '*') ||
10824 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10825 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10826 int op = -1;
10827 int op1 = ctxt->comp->last;
10828
10829 if (CUR == '*') {
10830 op = 0;
10831 NEXT;
10832 } else if (CUR == 'd') {
10833 op = 1;
10834 SKIP(3);
10835 } else if (CUR == 'm') {
10836 op = 2;
10837 SKIP(3);
10838 }
10839 SKIP_BLANKS;
10840 xmlXPathCompUnaryExpr(ctxt);
10841 CHECK_ERROR;
10842 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10843 SKIP_BLANKS;
10844 }
10845 }
10846
10847 /**
10848 * xmlXPathCompAdditiveExpr:
10849 * @ctxt: the XPath Parser context
10850 *
10851 * [25] AdditiveExpr ::= MultiplicativeExpr
10852 * | AdditiveExpr '+' MultiplicativeExpr
10853 * | AdditiveExpr '-' MultiplicativeExpr
10854 *
10855 * Compile an Additive expression.
10856 */
10857
10858 static void
10859 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10860
10861 xmlXPathCompMultiplicativeExpr(ctxt);
10862 CHECK_ERROR;
10863 SKIP_BLANKS;
10864 while ((CUR == '+') || (CUR == '-')) {
10865 int plus;
10866 int op1 = ctxt->comp->last;
10867
10868 if (CUR == '+') plus = 1;
10869 else plus = 0;
10870 NEXT;
10871 SKIP_BLANKS;
10872 xmlXPathCompMultiplicativeExpr(ctxt);
10873 CHECK_ERROR;
10874 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10875 SKIP_BLANKS;
10876 }
10877 }
10878
10879 /**
10880 * xmlXPathCompRelationalExpr:
10881 * @ctxt: the XPath Parser context
10882 *
10883 * [24] RelationalExpr ::= AdditiveExpr
10884 * | RelationalExpr '<' AdditiveExpr
10885 * | RelationalExpr '>' AdditiveExpr
10886 * | RelationalExpr '<=' AdditiveExpr
10887 * | RelationalExpr '>=' AdditiveExpr
10888 *
10889 * A <= B > C is allowed ? Answer from James, yes with
10890 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10891 * which is basically what got implemented.
10892 *
10893 * Compile a Relational expression, then push the result
10894 * on the stack
10895 */
10896
10897 static void
10898 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10899 xmlXPathCompAdditiveExpr(ctxt);
10900 CHECK_ERROR;
10901 SKIP_BLANKS;
10902 while ((CUR == '<') ||
10903 (CUR == '>') ||
10904 ((CUR == '<') && (NXT(1) == '=')) ||
10905 ((CUR == '>') && (NXT(1) == '='))) {
10906 int inf, strict;
10907 int op1 = ctxt->comp->last;
10908
10909 if (CUR == '<') inf = 1;
10910 else inf = 0;
10911 if (NXT(1) == '=') strict = 0;
10912 else strict = 1;
10913 NEXT;
10914 if (!strict) NEXT;
10915 SKIP_BLANKS;
10916 xmlXPathCompAdditiveExpr(ctxt);
10917 CHECK_ERROR;
10918 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10919 SKIP_BLANKS;
10920 }
10921 }
10922
10923 /**
10924 * xmlXPathCompEqualityExpr:
10925 * @ctxt: the XPath Parser context
10926 *
10927 * [23] EqualityExpr ::= RelationalExpr
10928 * | EqualityExpr '=' RelationalExpr
10929 * | EqualityExpr '!=' RelationalExpr
10930 *
10931 * A != B != C is allowed ? Answer from James, yes with
10932 * (RelationalExpr = RelationalExpr) = RelationalExpr
10933 * (RelationalExpr != RelationalExpr) != RelationalExpr
10934 * which is basically what got implemented.
10935 *
10936 * Compile an Equality expression.
10937 *
10938 */
10939 static void
10940 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10941 xmlXPathCompRelationalExpr(ctxt);
10942 CHECK_ERROR;
10943 SKIP_BLANKS;
10944 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10945 int eq;
10946 int op1 = ctxt->comp->last;
10947
10948 if (CUR == '=') eq = 1;
10949 else eq = 0;
10950 NEXT;
10951 if (!eq) NEXT;
10952 SKIP_BLANKS;
10953 xmlXPathCompRelationalExpr(ctxt);
10954 CHECK_ERROR;
10955 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10956 SKIP_BLANKS;
10957 }
10958 }
10959
10960 /**
10961 * xmlXPathCompAndExpr:
10962 * @ctxt: the XPath Parser context
10963 *
10964 * [22] AndExpr ::= EqualityExpr
10965 * | AndExpr 'and' EqualityExpr
10966 *
10967 * Compile an AND expression.
10968 *
10969 */
10970 static void
10971 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10972 xmlXPathCompEqualityExpr(ctxt);
10973 CHECK_ERROR;
10974 SKIP_BLANKS;
10975 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10976 int op1 = ctxt->comp->last;
10977 SKIP(3);
10978 SKIP_BLANKS;
10979 xmlXPathCompEqualityExpr(ctxt);
10980 CHECK_ERROR;
10981 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10982 SKIP_BLANKS;
10983 }
10984 }
10985
10986 /**
10987 * xmlXPathCompileExpr:
10988 * @ctxt: the XPath Parser context
10989 *
10990 * [14] Expr ::= OrExpr
10991 * [21] OrExpr ::= AndExpr
10992 * | OrExpr 'or' AndExpr
10993 *
10994 * Parse and compile an expression
10995 */
10996 static void
10997 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10998 xmlXPathCompAndExpr(ctxt);
10999 CHECK_ERROR;
11000 SKIP_BLANKS;
11001 while ((CUR == 'o') && (NXT(1) == 'r')) {
11002 int op1 = ctxt->comp->last;
11003 SKIP(2);
11004 SKIP_BLANKS;
11005 xmlXPathCompAndExpr(ctxt);
11006 CHECK_ERROR;
11007 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
11008 SKIP_BLANKS;
11009 }
11010 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
11011 /* more ops could be optimized too */
11012 /*
11013 * This is the main place to eliminate sorting for
11014 * operations which don't require a sorted node-set.
11015 * E.g. count().
11016 */
11017 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
11018 }
11019 }
11020
11021 /**
11022 * xmlXPathCompPredicate:
11023 * @ctxt: the XPath Parser context
11024 * @filter: act as a filter
11025 *
11026 * [8] Predicate ::= '[' PredicateExpr ']'
11027 * [9] PredicateExpr ::= Expr
11028 *
11029 * Compile a predicate expression
11030 */
11031 static void
11032 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
11033 int op1 = ctxt->comp->last;
11034
11035 SKIP_BLANKS;
11036 if (CUR != '[') {
11037 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11038 }
11039 NEXT;
11040 SKIP_BLANKS;
11041
11042 ctxt->comp->last = -1;
11043 /*
11044 * This call to xmlXPathCompileExpr() will deactivate sorting
11045 * of the predicate result.
11046 * TODO: Sorting is still activated for filters, since I'm not
11047 * sure if needed. Normally sorting should not be needed, since
11048 * a filter can only diminish the number of items in a sequence,
11049 * but won't change its order; so if the initial sequence is sorted,
11050 * subsequent sorting is not needed.
11051 */
11052 if (! filter)
11053 xmlXPathCompileExpr(ctxt, 0);
11054 else
11055 xmlXPathCompileExpr(ctxt, 1);
11056 CHECK_ERROR;
11057
11058 if (CUR != ']') {
11059 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11060 }
11061
11062 if (filter)
11063 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11064 else
11065 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11066
11067 NEXT;
11068 SKIP_BLANKS;
11069 }
11070
11071 /**
11072 * xmlXPathCompNodeTest:
11073 * @ctxt: the XPath Parser context
11074 * @test: pointer to a xmlXPathTestVal
11075 * @type: pointer to a xmlXPathTypeVal
11076 * @prefix: placeholder for a possible name prefix
11077 *
11078 * [7] NodeTest ::= NameTest
11079 * | NodeType '(' ')'
11080 * | 'processing-instruction' '(' Literal ')'
11081 *
11082 * [37] NameTest ::= '*'
11083 * | NCName ':' '*'
11084 * | QName
11085 * [38] NodeType ::= 'comment'
11086 * | 'text'
11087 * | 'processing-instruction'
11088 * | 'node'
11089 *
11090 * Returns the name found and updates @test, @type and @prefix appropriately
11091 */
11092 static xmlChar *
11093 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11094 xmlXPathTypeVal *type, const xmlChar **prefix,
11095 xmlChar *name) {
11096 int blanks;
11097
11098 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11099 STRANGE;
11100 return(NULL);
11101 }
11102 *type = (xmlXPathTypeVal) 0;
11103 *test = (xmlXPathTestVal) 0;
11104 *prefix = NULL;
11105 SKIP_BLANKS;
11106
11107 if ((name == NULL) && (CUR == '*')) {
11108 /*
11109 * All elements
11110 */
11111 NEXT;
11112 *test = NODE_TEST_ALL;
11113 return(NULL);
11114 }
11115
11116 if (name == NULL)
11117 name = xmlXPathParseNCName(ctxt);
11118 if (name == NULL) {
11119 XP_ERRORNULL(XPATH_EXPR_ERROR);
11120 }
11121
11122 blanks = IS_BLANK_CH(CUR);
11123 SKIP_BLANKS;
11124 if (CUR == '(') {
11125 NEXT;
11126 /*
11127 * NodeType or PI search
11128 */
11129 if (xmlStrEqual(name, BAD_CAST "comment"))
11130 *type = NODE_TYPE_COMMENT;
11131 else if (xmlStrEqual(name, BAD_CAST "node"))
11132 *type = NODE_TYPE_NODE;
11133 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11134 *type = NODE_TYPE_PI;
11135 else if (xmlStrEqual(name, BAD_CAST "text"))
11136 *type = NODE_TYPE_TEXT;
11137 else {
11138 if (name != NULL)
11139 xmlFree(name);
11140 XP_ERRORNULL(XPATH_EXPR_ERROR);
11141 }
11142
11143 *test = NODE_TEST_TYPE;
11144
11145 SKIP_BLANKS;
11146 if (*type == NODE_TYPE_PI) {
11147 /*
11148 * Specific case: search a PI by name.
11149 */
11150 if (name != NULL)
11151 xmlFree(name);
11152 name = NULL;
11153 if (CUR != ')') {
11154 name = xmlXPathParseLiteral(ctxt);
11155 CHECK_ERROR NULL;
11156 *test = NODE_TEST_PI;
11157 SKIP_BLANKS;
11158 }
11159 }
11160 if (CUR != ')') {
11161 if (name != NULL)
11162 xmlFree(name);
11163 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11164 }
11165 NEXT;
11166 return(name);
11167 }
11168 *test = NODE_TEST_NAME;
11169 if ((!blanks) && (CUR == ':')) {
11170 NEXT;
11171
11172 /*
11173 * Since currently the parser context don't have a
11174 * namespace list associated:
11175 * The namespace name for this prefix can be computed
11176 * only at evaluation time. The compilation is done
11177 * outside of any context.
11178 */
11179 #if 0
11180 *prefix = xmlXPathNsLookup(ctxt->context, name);
11181 if (name != NULL)
11182 xmlFree(name);
11183 if (*prefix == NULL) {
11184 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11185 }
11186 #else
11187 *prefix = name;
11188 #endif
11189
11190 if (CUR == '*') {
11191 /*
11192 * All elements
11193 */
11194 NEXT;
11195 *test = NODE_TEST_ALL;
11196 return(NULL);
11197 }
11198
11199 name = xmlXPathParseNCName(ctxt);
11200 if (name == NULL) {
11201 XP_ERRORNULL(XPATH_EXPR_ERROR);
11202 }
11203 }
11204 return(name);
11205 }
11206
11207 /**
11208 * xmlXPathIsAxisName:
11209 * @name: a preparsed name token
11210 *
11211 * [6] AxisName ::= 'ancestor'
11212 * | 'ancestor-or-self'
11213 * | 'attribute'
11214 * | 'child'
11215 * | 'descendant'
11216 * | 'descendant-or-self'
11217 * | 'following'
11218 * | 'following-sibling'
11219 * | 'namespace'
11220 * | 'parent'
11221 * | 'preceding'
11222 * | 'preceding-sibling'
11223 * | 'self'
11224 *
11225 * Returns the axis or 0
11226 */
11227 static xmlXPathAxisVal
11228 xmlXPathIsAxisName(const xmlChar *name) {
11229 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11230 switch (name[0]) {
11231 case 'a':
11232 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11233 ret = AXIS_ANCESTOR;
11234 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11235 ret = AXIS_ANCESTOR_OR_SELF;
11236 if (xmlStrEqual(name, BAD_CAST "attribute"))
11237 ret = AXIS_ATTRIBUTE;
11238 break;
11239 case 'c':
11240 if (xmlStrEqual(name, BAD_CAST "child"))
11241 ret = AXIS_CHILD;
11242 break;
11243 case 'd':
11244 if (xmlStrEqual(name, BAD_CAST "descendant"))
11245 ret = AXIS_DESCENDANT;
11246 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11247 ret = AXIS_DESCENDANT_OR_SELF;
11248 break;
11249 case 'f':
11250 if (xmlStrEqual(name, BAD_CAST "following"))
11251 ret = AXIS_FOLLOWING;
11252 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11253 ret = AXIS_FOLLOWING_SIBLING;
11254 break;
11255 case 'n':
11256 if (xmlStrEqual(name, BAD_CAST "namespace"))
11257 ret = AXIS_NAMESPACE;
11258 break;
11259 case 'p':
11260 if (xmlStrEqual(name, BAD_CAST "parent"))
11261 ret = AXIS_PARENT;
11262 if (xmlStrEqual(name, BAD_CAST "preceding"))
11263 ret = AXIS_PRECEDING;
11264 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11265 ret = AXIS_PRECEDING_SIBLING;
11266 break;
11267 case 's':
11268 if (xmlStrEqual(name, BAD_CAST "self"))
11269 ret = AXIS_SELF;
11270 break;
11271 }
11272 return(ret);
11273 }
11274
11275 /**
11276 * xmlXPathCompStep:
11277 * @ctxt: the XPath Parser context
11278 *
11279 * [4] Step ::= AxisSpecifier NodeTest Predicate*
11280 * | AbbreviatedStep
11281 *
11282 * [12] AbbreviatedStep ::= '.' | '..'
11283 *
11284 * [5] AxisSpecifier ::= AxisName '::'
11285 * | AbbreviatedAxisSpecifier
11286 *
11287 * [13] AbbreviatedAxisSpecifier ::= '@'?
11288 *
11289 * Modified for XPtr range support as:
11290 *
11291 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11292 * | AbbreviatedStep
11293 * | 'range-to' '(' Expr ')' Predicate*
11294 *
11295 * Compile one step in a Location Path
11296 * A location step of . is short for self::node(). This is
11297 * particularly useful in conjunction with //. For example, the
11298 * location path .//para is short for
11299 * self::node()/descendant-or-self::node()/child::para
11300 * and so will select all para descendant elements of the context
11301 * node.
11302 * Similarly, a location step of .. is short for parent::node().
11303 * For example, ../title is short for parent::node()/child::title
11304 * and so will select the title children of the parent of the context
11305 * node.
11306 */
11307 static void
11308 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11309 #ifdef LIBXML_XPTR_ENABLED
11310 int rangeto = 0;
11311 int op2 = -1;
11312 #endif
11313
11314 SKIP_BLANKS;
11315 if ((CUR == '.') && (NXT(1) == '.')) {
11316 SKIP(2);
11317 SKIP_BLANKS;
11318 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11319 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11320 } else if (CUR == '.') {
11321 NEXT;
11322 SKIP_BLANKS;
11323 } else {
11324 xmlChar *name = NULL;
11325 const xmlChar *prefix = NULL;
11326 xmlXPathTestVal test = (xmlXPathTestVal) 0;
11327 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11328 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11329 int op1;
11330
11331 /*
11332 * The modification needed for XPointer change to the production
11333 */
11334 #ifdef LIBXML_XPTR_ENABLED
11335 if (ctxt->xptr) {
11336 name = xmlXPathParseNCName(ctxt);
11337 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11338 op2 = ctxt->comp->last;
11339 xmlFree(name);
11340 SKIP_BLANKS;
11341 if (CUR != '(') {
11342 XP_ERROR(XPATH_EXPR_ERROR);
11343 }
11344 NEXT;
11345 SKIP_BLANKS;
11346
11347 xmlXPathCompileExpr(ctxt, 1);
11348 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11349 CHECK_ERROR;
11350
11351 SKIP_BLANKS;
11352 if (CUR != ')') {
11353 XP_ERROR(XPATH_EXPR_ERROR);
11354 }
11355 NEXT;
11356 rangeto = 1;
11357 goto eval_predicates;
11358 }
11359 }
11360 #endif
11361 if (CUR == '*') {
11362 axis = AXIS_CHILD;
11363 } else {
11364 if (name == NULL)
11365 name = xmlXPathParseNCName(ctxt);
11366 if (name != NULL) {
11367 axis = xmlXPathIsAxisName(name);
11368 if (axis != 0) {
11369 SKIP_BLANKS;
11370 if ((CUR == ':') && (NXT(1) == ':')) {
11371 SKIP(2);
11372 xmlFree(name);
11373 name = NULL;
11374 } else {
11375 /* an element name can conflict with an axis one :-\ */
11376 axis = AXIS_CHILD;
11377 }
11378 } else {
11379 axis = AXIS_CHILD;
11380 }
11381 } else if (CUR == '@') {
11382 NEXT;
11383 axis = AXIS_ATTRIBUTE;
11384 } else {
11385 axis = AXIS_CHILD;
11386 }
11387 }
11388
11389 if (ctxt->error != XPATH_EXPRESSION_OK) {
11390 xmlFree(name);
11391 return;
11392 }
11393
11394 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11395 if (test == 0)
11396 return;
11397
11398 if ((prefix != NULL) && (ctxt->context != NULL) &&
11399 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11400 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11401 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11402 }
11403 }
11404 #ifdef DEBUG_STEP
11405 xmlGenericError(xmlGenericErrorContext,
11406 "Basis : computing new set\n");
11407 #endif
11408
11409 #ifdef DEBUG_STEP
11410 xmlGenericError(xmlGenericErrorContext, "Basis : ");
11411 if (ctxt->value == NULL)
11412 xmlGenericError(xmlGenericErrorContext, "no value\n");
11413 else if (ctxt->value->nodesetval == NULL)
11414 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11415 else
11416 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11417 #endif
11418
11419 #ifdef LIBXML_XPTR_ENABLED
11420 eval_predicates:
11421 #endif
11422 op1 = ctxt->comp->last;
11423 ctxt->comp->last = -1;
11424
11425 SKIP_BLANKS;
11426 while (CUR == '[') {
11427 xmlXPathCompPredicate(ctxt, 0);
11428 }
11429
11430 #ifdef LIBXML_XPTR_ENABLED
11431 if (rangeto) {
11432 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11433 } else
11434 #endif
11435 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11436 test, type, (void *)prefix, (void *)name);
11437
11438 }
11439 #ifdef DEBUG_STEP
11440 xmlGenericError(xmlGenericErrorContext, "Step : ");
11441 if (ctxt->value == NULL)
11442 xmlGenericError(xmlGenericErrorContext, "no value\n");
11443 else if (ctxt->value->nodesetval == NULL)
11444 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11445 else
11446 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11447 ctxt->value->nodesetval);
11448 #endif
11449 }
11450
11451 /**
11452 * xmlXPathCompRelativeLocationPath:
11453 * @ctxt: the XPath Parser context
11454 *
11455 * [3] RelativeLocationPath ::= Step
11456 * | RelativeLocationPath '/' Step
11457 * | AbbreviatedRelativeLocationPath
11458 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
11459 *
11460 * Compile a relative location path.
11461 */
11462 static void
11463 xmlXPathCompRelativeLocationPath
11464 (xmlXPathParserContextPtr ctxt) {
11465 SKIP_BLANKS;
11466 if ((CUR == '/') && (NXT(1) == '/')) {
11467 SKIP(2);
11468 SKIP_BLANKS;
11469 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11470 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11471 } else if (CUR == '/') {
11472 NEXT;
11473 SKIP_BLANKS;
11474 }
11475 xmlXPathCompStep(ctxt);
11476 CHECK_ERROR;
11477 SKIP_BLANKS;
11478 while (CUR == '/') {
11479 if ((CUR == '/') && (NXT(1) == '/')) {
11480 SKIP(2);
11481 SKIP_BLANKS;
11482 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11483 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11484 xmlXPathCompStep(ctxt);
11485 } else if (CUR == '/') {
11486 NEXT;
11487 SKIP_BLANKS;
11488 xmlXPathCompStep(ctxt);
11489 }
11490 SKIP_BLANKS;
11491 }
11492 }
11493
11494 /**
11495 * xmlXPathCompLocationPath:
11496 * @ctxt: the XPath Parser context
11497 *
11498 * [1] LocationPath ::= RelativeLocationPath
11499 * | AbsoluteLocationPath
11500 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
11501 * | AbbreviatedAbsoluteLocationPath
11502 * [10] AbbreviatedAbsoluteLocationPath ::=
11503 * '//' RelativeLocationPath
11504 *
11505 * Compile a location path
11506 *
11507 * // is short for /descendant-or-self::node()/. For example,
11508 * //para is short for /descendant-or-self::node()/child::para and
11509 * so will select any para element in the document (even a para element
11510 * that is a document element will be selected by //para since the
11511 * document element node is a child of the root node); div//para is
11512 * short for div/descendant-or-self::node()/child::para and so will
11513 * select all para descendants of div children.
11514 */
11515 static void
11516 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11517 SKIP_BLANKS;
11518 if (CUR != '/') {
11519 xmlXPathCompRelativeLocationPath(ctxt);
11520 } else {
11521 while (CUR == '/') {
11522 if ((CUR == '/') && (NXT(1) == '/')) {
11523 SKIP(2);
11524 SKIP_BLANKS;
11525 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11526 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11527 xmlXPathCompRelativeLocationPath(ctxt);
11528 } else if (CUR == '/') {
11529 NEXT;
11530 SKIP_BLANKS;
11531 if ((CUR != 0 ) &&
11532 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11533 (CUR == '@') || (CUR == '*')))
11534 xmlXPathCompRelativeLocationPath(ctxt);
11535 }
11536 CHECK_ERROR;
11537 }
11538 }
11539 }
11540
11541 /************************************************************************
11542 * *
11543 * XPath precompiled expression evaluation *
11544 * *
11545 ************************************************************************/
11546
11547 static int
11548 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11549
11550 #ifdef DEBUG_STEP
11551 static void
11552 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11553 int nbNodes)
11554 {
11555 xmlGenericError(xmlGenericErrorContext, "new step : ");
11556 switch (op->value) {
11557 case AXIS_ANCESTOR:
11558 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11559 break;
11560 case AXIS_ANCESTOR_OR_SELF:
11561 xmlGenericError(xmlGenericErrorContext,
11562 "axis 'ancestors-or-self' ");
11563 break;
11564 case AXIS_ATTRIBUTE:
11565 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11566 break;
11567 case AXIS_CHILD:
11568 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11569 break;
11570 case AXIS_DESCENDANT:
11571 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11572 break;
11573 case AXIS_DESCENDANT_OR_SELF:
11574 xmlGenericError(xmlGenericErrorContext,
11575 "axis 'descendant-or-self' ");
11576 break;
11577 case AXIS_FOLLOWING:
11578 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11579 break;
11580 case AXIS_FOLLOWING_SIBLING:
11581 xmlGenericError(xmlGenericErrorContext,
11582 "axis 'following-siblings' ");
11583 break;
11584 case AXIS_NAMESPACE:
11585 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11586 break;
11587 case AXIS_PARENT:
11588 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11589 break;
11590 case AXIS_PRECEDING:
11591 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11592 break;
11593 case AXIS_PRECEDING_SIBLING:
11594 xmlGenericError(xmlGenericErrorContext,
11595 "axis 'preceding-sibling' ");
11596 break;
11597 case AXIS_SELF:
11598 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11599 break;
11600 }
11601 xmlGenericError(xmlGenericErrorContext,
11602 " context contains %d nodes\n", nbNodes);
11603 switch (op->value2) {
11604 case NODE_TEST_NONE:
11605 xmlGenericError(xmlGenericErrorContext,
11606 " searching for none !!!\n");
11607 break;
11608 case NODE_TEST_TYPE:
11609 xmlGenericError(xmlGenericErrorContext,
11610 " searching for type %d\n", op->value3);
11611 break;
11612 case NODE_TEST_PI:
11613 xmlGenericError(xmlGenericErrorContext,
11614 " searching for PI !!!\n");
11615 break;
11616 case NODE_TEST_ALL:
11617 xmlGenericError(xmlGenericErrorContext,
11618 " searching for *\n");
11619 break;
11620 case NODE_TEST_NS:
11621 xmlGenericError(xmlGenericErrorContext,
11622 " searching for namespace %s\n",
11623 op->value5);
11624 break;
11625 case NODE_TEST_NAME:
11626 xmlGenericError(xmlGenericErrorContext,
11627 " searching for name %s\n", op->value5);
11628 if (op->value4)
11629 xmlGenericError(xmlGenericErrorContext,
11630 " with namespace %s\n", op->value4);
11631 break;
11632 }
11633 xmlGenericError(xmlGenericErrorContext, "Testing : ");
11634 }
11635 #endif /* DEBUG_STEP */
11636
11637 static int
11638 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11639 xmlXPathStepOpPtr op,
11640 xmlNodeSetPtr set,
11641 int contextSize,
11642 int hasNsNodes)
11643 {
11644 if (op->ch1 != -1) {
11645 xmlXPathCompExprPtr comp = ctxt->comp;
11646 /*
11647 * Process inner predicates first.
11648 */
11649 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11650 /*
11651 * TODO: raise an internal error.
11652 */
11653 }
11654 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11655 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11656 CHECK_ERROR0;
11657 if (contextSize <= 0)
11658 return(0);
11659 }
11660 if (op->ch2 != -1) {
11661 xmlXPathContextPtr xpctxt = ctxt->context;
11662 xmlNodePtr contextNode, oldContextNode;
11663 xmlDocPtr oldContextDoc;
11664 int oldcs, oldpp;
11665 int i, res, contextPos = 0, newContextSize;
11666 xmlXPathStepOpPtr exprOp;
11667 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11668
11669 #ifdef LIBXML_XPTR_ENABLED
11670 /*
11671 * URGENT TODO: Check the following:
11672 * We don't expect location sets if evaluating prediates, right?
11673 * Only filters should expect location sets, right?
11674 */
11675 #endif
11676 /*
11677 * SPEC XPath 1.0:
11678 * "For each node in the node-set to be filtered, the
11679 * PredicateExpr is evaluated with that node as the
11680 * context node, with the number of nodes in the
11681 * node-set as the context size, and with the proximity
11682 * position of the node in the node-set with respect to
11683 * the axis as the context position;"
11684 * @oldset is the node-set" to be filtered.
11685 *
11686 * SPEC XPath 1.0:
11687 * "only predicates change the context position and
11688 * context size (see [2.4 Predicates])."
11689 * Example:
11690 * node-set context pos
11691 * nA 1
11692 * nB 2
11693 * nC 3
11694 * After applying predicate [position() > 1] :
11695 * node-set context pos
11696 * nB 1
11697 * nC 2
11698 */
11699 oldContextNode = xpctxt->node;
11700 oldContextDoc = xpctxt->doc;
11701 oldcs = xpctxt->contextSize;
11702 oldpp = xpctxt->proximityPosition;
11703 /*
11704 * Get the expression of this predicate.
11705 */
11706 exprOp = &ctxt->comp->steps[op->ch2];
11707 newContextSize = 0;
11708 for (i = 0; i < set->nodeNr; i++) {
11709 if (set->nodeTab[i] == NULL)
11710 continue;
11711
11712 contextNode = set->nodeTab[i];
11713 xpctxt->node = contextNode;
11714 xpctxt->contextSize = contextSize;
11715 xpctxt->proximityPosition = ++contextPos;
11716
11717 /*
11718 * Also set the xpath document in case things like
11719 * key() are evaluated in the predicate.
11720 */
11721 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11722 (contextNode->doc != NULL))
11723 xpctxt->doc = contextNode->doc;
11724 /*
11725 * Evaluate the predicate expression with 1 context node
11726 * at a time; this node is packaged into a node set; this
11727 * node set is handed over to the evaluation mechanism.
11728 */
11729 if (contextObj == NULL)
11730 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11731 else {
11732 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11733 contextNode) < 0) {
11734 ctxt->error = XPATH_MEMORY_ERROR;
11735 goto evaluation_exit;
11736 }
11737 }
11738
11739 valuePush(ctxt, contextObj);
11740
11741 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11742
11743 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11744 xmlXPathNodeSetClear(set, hasNsNodes);
11745 newContextSize = 0;
11746 goto evaluation_exit;
11747 }
11748
11749 if (res != 0) {
11750 newContextSize++;
11751 } else {
11752 /*
11753 * Remove the entry from the initial node set.
11754 */
11755 set->nodeTab[i] = NULL;
11756 if (contextNode->type == XML_NAMESPACE_DECL)
11757 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11758 }
11759 if (ctxt->value == contextObj) {
11760 /*
11761 * Don't free the temporary XPath object holding the
11762 * context node, in order to avoid massive recreation
11763 * inside this loop.
11764 */
11765 valuePop(ctxt);
11766 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11767 } else {
11768 /*
11769 * TODO: The object was lost in the evaluation machinery.
11770 * Can this happen? Maybe in internal-error cases.
11771 */
11772 contextObj = NULL;
11773 }
11774 }
11775
11776 if (contextObj != NULL) {
11777 if (ctxt->value == contextObj)
11778 valuePop(ctxt);
11779 xmlXPathReleaseObject(xpctxt, contextObj);
11780 }
11781 evaluation_exit:
11782 if (exprRes != NULL)
11783 xmlXPathReleaseObject(ctxt->context, exprRes);
11784 /*
11785 * Reset/invalidate the context.
11786 */
11787 xpctxt->node = oldContextNode;
11788 xpctxt->doc = oldContextDoc;
11789 xpctxt->contextSize = oldcs;
11790 xpctxt->proximityPosition = oldpp;
11791 return(newContextSize);
11792 }
11793 return(contextSize);
11794 }
11795
11796 static int
11797 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11798 xmlXPathStepOpPtr op,
11799 xmlNodeSetPtr set,
11800 int contextSize,
11801 int minPos,
11802 int maxPos,
11803 int hasNsNodes)
11804 {
11805 if (op->ch1 != -1) {
11806 xmlXPathCompExprPtr comp = ctxt->comp;
11807 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11808 /*
11809 * TODO: raise an internal error.
11810 */
11811 }
11812 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11813 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11814 CHECK_ERROR0;
11815 if (contextSize <= 0)
11816 return(0);
11817 }
11818 /*
11819 * Check if the node set contains a sufficient number of nodes for
11820 * the requested range.
11821 */
11822 if (contextSize < minPos) {
11823 xmlXPathNodeSetClear(set, hasNsNodes);
11824 return(0);
11825 }
11826 if (op->ch2 == -1) {
11827 /*
11828 * TODO: Can this ever happen?
11829 */
11830 return (contextSize);
11831 } else {
11832 xmlDocPtr oldContextDoc;
11833 int oldcs, oldpp;
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 oldcs = xpctxt->contextSize;
11855 oldpp = xpctxt->proximityPosition;
11856 /*
11857 * Get the expression of this predicate.
11858 */
11859 exprOp = &ctxt->comp->steps[op->ch2];
11860 for (i = 0; i < set->nodeNr; i++) {
11861 xmlXPathObjectPtr tmp;
11862
11863 if (set->nodeTab[i] == NULL)
11864 continue;
11865
11866 contextNode = set->nodeTab[i];
11867 xpctxt->node = contextNode;
11868 xpctxt->contextSize = contextSize;
11869 xpctxt->proximityPosition = ++contextPos;
11870
11871 /*
11872 * Initialize the new set.
11873 * Also set the xpath document in case things like
11874 * key() evaluation are attempted on the predicate
11875 */
11876 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11877 (contextNode->doc != NULL))
11878 xpctxt->doc = contextNode->doc;
11879 /*
11880 * Evaluate the predicate expression with 1 context node
11881 * at a time; this node is packaged into a node set; this
11882 * node set is handed over to the evaluation mechanism.
11883 */
11884 if (contextObj == NULL)
11885 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11886 else {
11887 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11888 contextNode) < 0) {
11889 ctxt->error = XPATH_MEMORY_ERROR;
11890 goto evaluation_exit;
11891 }
11892 }
11893
11894 valuePush(ctxt, contextObj);
11895 frame = xmlXPathSetFrame(ctxt);
11896 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11897 xmlXPathPopFrame(ctxt, frame);
11898 tmp = valuePop(ctxt);
11899
11900 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11901 while (tmp != contextObj) {
11902 /*
11903 * Free up the result
11904 * then pop off contextObj, which will be freed later
11905 */
11906 xmlXPathReleaseObject(xpctxt, tmp);
11907 tmp = valuePop(ctxt);
11908 }
11909 goto evaluation_error;
11910 }
11911 /* push the result back onto the stack */
11912 valuePush(ctxt, tmp);
11913
11914 if (res)
11915 pos++;
11916
11917 if (res && (pos >= minPos) && (pos <= maxPos)) {
11918 /*
11919 * Fits in the requested range.
11920 */
11921 newContextSize++;
11922 if (minPos == maxPos) {
11923 /*
11924 * Only 1 node was requested.
11925 */
11926 if (contextNode->type == XML_NAMESPACE_DECL) {
11927 /*
11928 * As always: take care of those nasty
11929 * namespace nodes.
11930 */
11931 set->nodeTab[i] = NULL;
11932 }
11933 xmlXPathNodeSetClear(set, hasNsNodes);
11934 set->nodeNr = 1;
11935 set->nodeTab[0] = contextNode;
11936 goto evaluation_exit;
11937 }
11938 if (pos == maxPos) {
11939 /*
11940 * We are done.
11941 */
11942 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11943 goto evaluation_exit;
11944 }
11945 } else {
11946 /*
11947 * Remove the entry from the initial node set.
11948 */
11949 set->nodeTab[i] = NULL;
11950 if (contextNode->type == XML_NAMESPACE_DECL)
11951 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11952 }
11953 if (exprRes != NULL) {
11954 xmlXPathReleaseObject(ctxt->context, exprRes);
11955 exprRes = NULL;
11956 }
11957 if (ctxt->value == contextObj) {
11958 /*
11959 * Don't free the temporary XPath object holding the
11960 * context node, in order to avoid massive recreation
11961 * inside this loop.
11962 */
11963 valuePop(ctxt);
11964 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11965 } else {
11966 /*
11967 * The object was lost in the evaluation machinery.
11968 * Can this happen? Maybe in case of internal-errors.
11969 */
11970 contextObj = NULL;
11971 }
11972 }
11973 goto evaluation_exit;
11974
11975 evaluation_error:
11976 xmlXPathNodeSetClear(set, hasNsNodes);
11977 newContextSize = 0;
11978
11979 evaluation_exit:
11980 if (contextObj != NULL) {
11981 if (ctxt->value == contextObj)
11982 valuePop(ctxt);
11983 xmlXPathReleaseObject(xpctxt, contextObj);
11984 }
11985 if (exprRes != NULL)
11986 xmlXPathReleaseObject(ctxt->context, exprRes);
11987 /*
11988 * Reset/invalidate the context.
11989 */
11990 xpctxt->node = oldContextNode;
11991 xpctxt->doc = oldContextDoc;
11992 xpctxt->contextSize = oldcs;
11993 xpctxt->proximityPosition = oldpp;
11994 return(newContextSize);
11995 }
11996 return(contextSize);
11997 }
11998
11999 static int
12000 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
12001 xmlXPathStepOpPtr op,
12002 int *maxPos)
12003 {
12004
12005 xmlXPathStepOpPtr exprOp;
12006
12007 /*
12008 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
12009 */
12010
12011 /*
12012 * If not -1, then ch1 will point to:
12013 * 1) For predicates (XPATH_OP_PREDICATE):
12014 * - an inner predicate operator
12015 * 2) For filters (XPATH_OP_FILTER):
12016 * - an inner filter operater OR
12017 * - an expression selecting the node set.
12018 * E.g. "key('a', 'b')" or "(//foo | //bar)".
12019 */
12020 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
12021 return(0);
12022
12023 if (op->ch2 != -1) {
12024 exprOp = &ctxt->comp->steps[op->ch2];
12025 } else
12026 return(0);
12027
12028 if ((exprOp != NULL) &&
12029 (exprOp->op == XPATH_OP_VALUE) &&
12030 (exprOp->value4 != NULL) &&
12031 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
12032 {
12033 double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
12034
12035 /*
12036 * We have a "[n]" predicate here.
12037 * TODO: Unfortunately this simplistic test here is not
12038 * able to detect a position() predicate in compound
12039 * expressions like "[@attr = 'a" and position() = 1],
12040 * and even not the usage of position() in
12041 * "[position() = 1]"; thus - obviously - a position-range,
12042 * like it "[position() < 5]", is also not detected.
12043 * Maybe we could rewrite the AST to ease the optimization.
12044 */
12045
12046 if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
12047 *maxPos = (int) floatval;
12048 if (floatval == (double) *maxPos)
12049 return(1);
12050 }
12051 }
12052 return(0);
12053 }
12054
12055 static int
12056 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
12057 xmlXPathStepOpPtr op,
12058 xmlNodePtr * first, xmlNodePtr * last,
12059 int toBool)
12060 {
12061
12062 #define XP_TEST_HIT \
12063 if (hasAxisRange != 0) { \
12064 if (++pos == maxPos) { \
12065 if (addNode(seq, cur) < 0) \
12066 ctxt->error = XPATH_MEMORY_ERROR; \
12067 goto axis_range_end; } \
12068 } else { \
12069 if (addNode(seq, cur) < 0) \
12070 ctxt->error = XPATH_MEMORY_ERROR; \
12071 if (breakOnFirstHit) goto first_hit; }
12072
12073 #define XP_TEST_HIT_NS \
12074 if (hasAxisRange != 0) { \
12075 if (++pos == maxPos) { \
12076 hasNsNodes = 1; \
12077 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12078 ctxt->error = XPATH_MEMORY_ERROR; \
12079 goto axis_range_end; } \
12080 } else { \
12081 hasNsNodes = 1; \
12082 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12083 ctxt->error = XPATH_MEMORY_ERROR; \
12084 if (breakOnFirstHit) goto first_hit; }
12085
12086 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
12087 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12088 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12089 const xmlChar *prefix = op->value4;
12090 const xmlChar *name = op->value5;
12091 const xmlChar *URI = NULL;
12092
12093 #ifdef DEBUG_STEP
12094 int nbMatches = 0, prevMatches = 0;
12095 #endif
12096 int total = 0, hasNsNodes = 0;
12097 /* The popped object holding the context nodes */
12098 xmlXPathObjectPtr obj;
12099 /* The set of context nodes for the node tests */
12100 xmlNodeSetPtr contextSeq;
12101 int contextIdx;
12102 xmlNodePtr contextNode;
12103 /* The final resulting node set wrt to all context nodes */
12104 xmlNodeSetPtr outSeq;
12105 /*
12106 * The temporary resulting node set wrt 1 context node.
12107 * Used to feed predicate evaluation.
12108 */
12109 xmlNodeSetPtr seq;
12110 xmlNodePtr cur;
12111 /* First predicate operator */
12112 xmlXPathStepOpPtr predOp;
12113 int maxPos; /* The requested position() (when a "[n]" predicate) */
12114 int hasPredicateRange, hasAxisRange, pos, size, newSize;
12115 int breakOnFirstHit;
12116
12117 xmlXPathTraversalFunction next = NULL;
12118 int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12119 xmlXPathNodeSetMergeFunction mergeAndClear;
12120 xmlNodePtr oldContextNode;
12121 xmlXPathContextPtr xpctxt = ctxt->context;
12122
12123
12124 CHECK_TYPE0(XPATH_NODESET);
12125 obj = valuePop(ctxt);
12126 /*
12127 * Setup namespaces.
12128 */
12129 if (prefix != NULL) {
12130 URI = xmlXPathNsLookup(xpctxt, prefix);
12131 if (URI == NULL) {
12132 xmlXPathReleaseObject(xpctxt, obj);
12133 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12134 }
12135 }
12136 /*
12137 * Setup axis.
12138 *
12139 * MAYBE FUTURE TODO: merging optimizations:
12140 * - If the nodes to be traversed wrt to the initial nodes and
12141 * the current axis cannot overlap, then we could avoid searching
12142 * for duplicates during the merge.
12143 * But the question is how/when to evaluate if they cannot overlap.
12144 * Example: if we know that for two initial nodes, the one is
12145 * not in the ancestor-or-self axis of the other, then we could safely
12146 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12147 * the descendant-or-self axis.
12148 */
12149 mergeAndClear = xmlXPathNodeSetMergeAndClear;
12150 switch (axis) {
12151 case AXIS_ANCESTOR:
12152 first = NULL;
12153 next = xmlXPathNextAncestor;
12154 break;
12155 case AXIS_ANCESTOR_OR_SELF:
12156 first = NULL;
12157 next = xmlXPathNextAncestorOrSelf;
12158 break;
12159 case AXIS_ATTRIBUTE:
12160 first = NULL;
12161 last = NULL;
12162 next = xmlXPathNextAttribute;
12163 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12164 break;
12165 case AXIS_CHILD:
12166 last = NULL;
12167 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12168 (type == NODE_TYPE_NODE))
12169 {
12170 /*
12171 * Optimization if an element node type is 'element'.
12172 */
12173 next = xmlXPathNextChildElement;
12174 } else
12175 next = xmlXPathNextChild;
12176 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12177 break;
12178 case AXIS_DESCENDANT:
12179 last = NULL;
12180 next = xmlXPathNextDescendant;
12181 break;
12182 case AXIS_DESCENDANT_OR_SELF:
12183 last = NULL;
12184 next = xmlXPathNextDescendantOrSelf;
12185 break;
12186 case AXIS_FOLLOWING:
12187 last = NULL;
12188 next = xmlXPathNextFollowing;
12189 break;
12190 case AXIS_FOLLOWING_SIBLING:
12191 last = NULL;
12192 next = xmlXPathNextFollowingSibling;
12193 break;
12194 case AXIS_NAMESPACE:
12195 first = NULL;
12196 last = NULL;
12197 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12198 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12199 break;
12200 case AXIS_PARENT:
12201 first = NULL;
12202 next = xmlXPathNextParent;
12203 break;
12204 case AXIS_PRECEDING:
12205 first = NULL;
12206 next = xmlXPathNextPrecedingInternal;
12207 break;
12208 case AXIS_PRECEDING_SIBLING:
12209 first = NULL;
12210 next = xmlXPathNextPrecedingSibling;
12211 break;
12212 case AXIS_SELF:
12213 first = NULL;
12214 last = NULL;
12215 next = xmlXPathNextSelf;
12216 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12217 break;
12218 }
12219
12220 #ifdef DEBUG_STEP
12221 xmlXPathDebugDumpStepAxis(op,
12222 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12223 #endif
12224
12225 if (next == NULL) {
12226 xmlXPathReleaseObject(xpctxt, obj);
12227 return(0);
12228 }
12229 contextSeq = obj->nodesetval;
12230 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12231 xmlXPathReleaseObject(xpctxt, obj);
12232 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12233 return(0);
12234 }
12235 /*
12236 * Predicate optimization ---------------------------------------------
12237 * If this step has a last predicate, which contains a position(),
12238 * then we'll optimize (although not exactly "position()", but only
12239 * the short-hand form, i.e., "[n]".
12240 *
12241 * Example - expression "/foo[parent::bar][1]":
12242 *
12243 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12244 * ROOT -- op->ch1
12245 * PREDICATE -- op->ch2 (predOp)
12246 * PREDICATE -- predOp->ch1 = [parent::bar]
12247 * SORT
12248 * COLLECT 'parent' 'name' 'node' bar
12249 * NODE
12250 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12251 *
12252 */
12253 maxPos = 0;
12254 predOp = NULL;
12255 hasPredicateRange = 0;
12256 hasAxisRange = 0;
12257 if (op->ch2 != -1) {
12258 /*
12259 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12260 */
12261 predOp = &ctxt->comp->steps[op->ch2];
12262 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12263 if (predOp->ch1 != -1) {
12264 /*
12265 * Use the next inner predicate operator.
12266 */
12267 predOp = &ctxt->comp->steps[predOp->ch1];
12268 hasPredicateRange = 1;
12269 } else {
12270 /*
12271 * There's no other predicate than the [n] predicate.
12272 */
12273 predOp = NULL;
12274 hasAxisRange = 1;
12275 }
12276 }
12277 }
12278 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12279 /*
12280 * Axis traversal -----------------------------------------------------
12281 */
12282 /*
12283 * 2.3 Node Tests
12284 * - For the attribute axis, the principal node type is attribute.
12285 * - For the namespace axis, the principal node type is namespace.
12286 * - For other axes, the principal node type is element.
12287 *
12288 * A node test * is true for any node of the
12289 * principal node type. For example, child::* will
12290 * select all element children of the context node
12291 */
12292 oldContextNode = xpctxt->node;
12293 addNode = xmlXPathNodeSetAddUnique;
12294 outSeq = NULL;
12295 seq = NULL;
12296 contextNode = NULL;
12297 contextIdx = 0;
12298
12299
12300 while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12301 (ctxt->error == XPATH_EXPRESSION_OK)) {
12302 xpctxt->node = contextSeq->nodeTab[contextIdx++];
12303
12304 if (seq == NULL) {
12305 seq = xmlXPathNodeSetCreate(NULL);
12306 if (seq == NULL) {
12307 total = 0;
12308 goto error;
12309 }
12310 }
12311 /*
12312 * Traverse the axis and test the nodes.
12313 */
12314 pos = 0;
12315 cur = NULL;
12316 hasNsNodes = 0;
12317 do {
12318 cur = next(ctxt, cur);
12319 if (cur == NULL)
12320 break;
12321
12322 /*
12323 * QUESTION TODO: What does the "first" and "last" stuff do?
12324 */
12325 if ((first != NULL) && (*first != NULL)) {
12326 if (*first == cur)
12327 break;
12328 if (((total % 256) == 0) &&
12329 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12330 (xmlXPathCmpNodesExt(*first, cur) >= 0))
12331 #else
12332 (xmlXPathCmpNodes(*first, cur) >= 0))
12333 #endif
12334 {
12335 break;
12336 }
12337 }
12338 if ((last != NULL) && (*last != NULL)) {
12339 if (*last == cur)
12340 break;
12341 if (((total % 256) == 0) &&
12342 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12343 (xmlXPathCmpNodesExt(cur, *last) >= 0))
12344 #else
12345 (xmlXPathCmpNodes(cur, *last) >= 0))
12346 #endif
12347 {
12348 break;
12349 }
12350 }
12351
12352 total++;
12353
12354 #ifdef DEBUG_STEP
12355 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12356 #endif
12357
12358 switch (test) {
12359 case NODE_TEST_NONE:
12360 total = 0;
12361 STRANGE
12362 goto error;
12363 case NODE_TEST_TYPE:
12364 if (type == NODE_TYPE_NODE) {
12365 switch (cur->type) {
12366 case XML_DOCUMENT_NODE:
12367 case XML_HTML_DOCUMENT_NODE:
12368 #ifdef LIBXML_DOCB_ENABLED
12369 case XML_DOCB_DOCUMENT_NODE:
12370 #endif
12371 case XML_ELEMENT_NODE:
12372 case XML_ATTRIBUTE_NODE:
12373 case XML_PI_NODE:
12374 case XML_COMMENT_NODE:
12375 case XML_CDATA_SECTION_NODE:
12376 case XML_TEXT_NODE:
12377 XP_TEST_HIT
12378 break;
12379 case XML_NAMESPACE_DECL: {
12380 if (axis == AXIS_NAMESPACE) {
12381 XP_TEST_HIT_NS
12382 } else {
12383 hasNsNodes = 1;
12384 XP_TEST_HIT
12385 }
12386 break;
12387 }
12388 default:
12389 break;
12390 }
12391 } else if (cur->type == (xmlElementType) type) {
12392 if (cur->type == XML_NAMESPACE_DECL)
12393 XP_TEST_HIT_NS
12394 else
12395 XP_TEST_HIT
12396 } else if ((type == NODE_TYPE_TEXT) &&
12397 (cur->type == XML_CDATA_SECTION_NODE))
12398 {
12399 XP_TEST_HIT
12400 }
12401 break;
12402 case NODE_TEST_PI:
12403 if ((cur->type == XML_PI_NODE) &&
12404 ((name == NULL) || xmlStrEqual(name, cur->name)))
12405 {
12406 XP_TEST_HIT
12407 }
12408 break;
12409 case NODE_TEST_ALL:
12410 if (axis == AXIS_ATTRIBUTE) {
12411 if (cur->type == XML_ATTRIBUTE_NODE)
12412 {
12413 if (prefix == NULL)
12414 {
12415 XP_TEST_HIT
12416 } else if ((cur->ns != NULL) &&
12417 (xmlStrEqual(URI, cur->ns->href)))
12418 {
12419 XP_TEST_HIT
12420 }
12421 }
12422 } else if (axis == AXIS_NAMESPACE) {
12423 if (cur->type == XML_NAMESPACE_DECL)
12424 {
12425 XP_TEST_HIT_NS
12426 }
12427 } else {
12428 if (cur->type == XML_ELEMENT_NODE) {
12429 if (prefix == NULL)
12430 {
12431 XP_TEST_HIT
12432
12433 } else if ((cur->ns != NULL) &&
12434 (xmlStrEqual(URI, cur->ns->href)))
12435 {
12436 XP_TEST_HIT
12437 }
12438 }
12439 }
12440 break;
12441 case NODE_TEST_NS:{
12442 TODO;
12443 break;
12444 }
12445 case NODE_TEST_NAME:
12446 if (axis == AXIS_ATTRIBUTE) {
12447 if (cur->type != XML_ATTRIBUTE_NODE)
12448 break;
12449 } else if (axis == AXIS_NAMESPACE) {
12450 if (cur->type != XML_NAMESPACE_DECL)
12451 break;
12452 } else {
12453 if (cur->type != XML_ELEMENT_NODE)
12454 break;
12455 }
12456 switch (cur->type) {
12457 case XML_ELEMENT_NODE:
12458 if (xmlStrEqual(name, cur->name)) {
12459 if (prefix == NULL) {
12460 if (cur->ns == NULL)
12461 {
12462 XP_TEST_HIT
12463 }
12464 } else {
12465 if ((cur->ns != NULL) &&
12466 (xmlStrEqual(URI, cur->ns->href)))
12467 {
12468 XP_TEST_HIT
12469 }
12470 }
12471 }
12472 break;
12473 case XML_ATTRIBUTE_NODE:{
12474 xmlAttrPtr attr = (xmlAttrPtr) cur;
12475
12476 if (xmlStrEqual(name, attr->name)) {
12477 if (prefix == NULL) {
12478 if ((attr->ns == NULL) ||
12479 (attr->ns->prefix == NULL))
12480 {
12481 XP_TEST_HIT
12482 }
12483 } else {
12484 if ((attr->ns != NULL) &&
12485 (xmlStrEqual(URI,
12486 attr->ns->href)))
12487 {
12488 XP_TEST_HIT
12489 }
12490 }
12491 }
12492 break;
12493 }
12494 case XML_NAMESPACE_DECL:
12495 if (cur->type == XML_NAMESPACE_DECL) {
12496 xmlNsPtr ns = (xmlNsPtr) cur;
12497
12498 if ((ns->prefix != NULL) && (name != NULL)
12499 && (xmlStrEqual(ns->prefix, name)))
12500 {
12501 XP_TEST_HIT_NS
12502 }
12503 }
12504 break;
12505 default:
12506 break;
12507 }
12508 break;
12509 } /* switch(test) */
12510 } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12511
12512 goto apply_predicates;
12513
12514 axis_range_end: /* ----------------------------------------------------- */
12515 /*
12516 * We have a "/foo[n]", and position() = n was reached.
12517 * Note that we can have as well "/foo/::parent::foo[1]", so
12518 * a duplicate-aware merge is still needed.
12519 * Merge with the result.
12520 */
12521 if (outSeq == NULL) {
12522 outSeq = seq;
12523 seq = NULL;
12524 } else
12525 outSeq = mergeAndClear(outSeq, seq, 0);
12526 /*
12527 * Break if only a true/false result was requested.
12528 */
12529 if (toBool)
12530 break;
12531 continue;
12532
12533 first_hit: /* ---------------------------------------------------------- */
12534 /*
12535 * Break if only a true/false result was requested and
12536 * no predicates existed and a node test succeeded.
12537 */
12538 if (outSeq == NULL) {
12539 outSeq = seq;
12540 seq = NULL;
12541 } else
12542 outSeq = mergeAndClear(outSeq, seq, 0);
12543 break;
12544
12545 #ifdef DEBUG_STEP
12546 if (seq != NULL)
12547 nbMatches += seq->nodeNr;
12548 #endif
12549
12550 apply_predicates: /* --------------------------------------------------- */
12551 if (ctxt->error != XPATH_EXPRESSION_OK)
12552 goto error;
12553
12554 /*
12555 * Apply predicates.
12556 */
12557 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12558 /*
12559 * E.g. when we have a "/foo[some expression][n]".
12560 */
12561 /*
12562 * QUESTION TODO: The old predicate evaluation took into
12563 * account location-sets.
12564 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12565 * Do we expect such a set here?
12566 * All what I learned now from the evaluation semantics
12567 * does not indicate that a location-set will be processed
12568 * here, so this looks OK.
12569 */
12570 /*
12571 * Iterate over all predicates, starting with the outermost
12572 * predicate.
12573 * TODO: Problem: we cannot execute the inner predicates first
12574 * since we cannot go back *up* the operator tree!
12575 * Options we have:
12576 * 1) Use of recursive functions (like is it currently done
12577 * via xmlXPathCompOpEval())
12578 * 2) Add a predicate evaluation information stack to the
12579 * context struct
12580 * 3) Change the way the operators are linked; we need a
12581 * "parent" field on xmlXPathStepOp
12582 *
12583 * For the moment, I'll try to solve this with a recursive
12584 * function: xmlXPathCompOpEvalPredicate().
12585 */
12586 size = seq->nodeNr;
12587 if (hasPredicateRange != 0)
12588 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12589 predOp, seq, size, maxPos, maxPos, hasNsNodes);
12590 else
12591 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12592 predOp, seq, size, hasNsNodes);
12593
12594 if (ctxt->error != XPATH_EXPRESSION_OK) {
12595 total = 0;
12596 goto error;
12597 }
12598 /*
12599 * Add the filtered set of nodes to the result node set.
12600 */
12601 if (newSize == 0) {
12602 /*
12603 * The predicates filtered all nodes out.
12604 */
12605 xmlXPathNodeSetClear(seq, hasNsNodes);
12606 } else if (seq->nodeNr > 0) {
12607 /*
12608 * Add to result set.
12609 */
12610 if (outSeq == NULL) {
12611 if (size != newSize) {
12612 /*
12613 * We need to merge and clear here, since
12614 * the sequence will contained NULLed entries.
12615 */
12616 outSeq = mergeAndClear(NULL, seq, 1);
12617 } else {
12618 outSeq = seq;
12619 seq = NULL;
12620 }
12621 } else
12622 outSeq = mergeAndClear(outSeq, seq,
12623 (size != newSize) ? 1: 0);
12624 /*
12625 * Break if only a true/false result was requested.
12626 */
12627 if (toBool)
12628 break;
12629 }
12630 } else if (seq->nodeNr > 0) {
12631 /*
12632 * Add to result set.
12633 */
12634 if (outSeq == NULL) {
12635 outSeq = seq;
12636 seq = NULL;
12637 } else {
12638 outSeq = mergeAndClear(outSeq, seq, 0);
12639 }
12640 }
12641 }
12642
12643 error:
12644 if ((obj->boolval) && (obj->user != NULL)) {
12645 /*
12646 * QUESTION TODO: What does this do and why?
12647 * TODO: Do we have to do this also for the "error"
12648 * cleanup further down?
12649 */
12650 ctxt->value->boolval = 1;
12651 ctxt->value->user = obj->user;
12652 obj->user = NULL;
12653 obj->boolval = 0;
12654 }
12655 xmlXPathReleaseObject(xpctxt, obj);
12656
12657 /*
12658 * Ensure we return at least an emtpy set.
12659 */
12660 if (outSeq == NULL) {
12661 if ((seq != NULL) && (seq->nodeNr == 0))
12662 outSeq = seq;
12663 else
12664 outSeq = xmlXPathNodeSetCreate(NULL);
12665 /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12666 }
12667 if ((seq != NULL) && (seq != outSeq)) {
12668 xmlXPathFreeNodeSet(seq);
12669 }
12670 /*
12671 * Hand over the result. Better to push the set also in
12672 * case of errors.
12673 */
12674 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12675 /*
12676 * Reset the context node.
12677 */
12678 xpctxt->node = oldContextNode;
12679 /*
12680 * When traversing the namespace axis in "toBool" mode, it's
12681 * possible that tmpNsList wasn't freed.
12682 */
12683 if (xpctxt->tmpNsList != NULL) {
12684 xmlFree(xpctxt->tmpNsList);
12685 xpctxt->tmpNsList = NULL;
12686 }
12687
12688 #ifdef DEBUG_STEP
12689 xmlGenericError(xmlGenericErrorContext,
12690 "\nExamined %d nodes, found %d nodes at that step\n",
12691 total, nbMatches);
12692 #endif
12693
12694 return(total);
12695 }
12696
12697 static int
12698 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12699 xmlXPathStepOpPtr op, xmlNodePtr * first);
12700
12701 /**
12702 * xmlXPathCompOpEvalFirst:
12703 * @ctxt: the XPath parser context with the compiled expression
12704 * @op: an XPath compiled operation
12705 * @first: the first elem found so far
12706 *
12707 * Evaluate the Precompiled XPath operation searching only the first
12708 * element in document order
12709 *
12710 * Returns the number of examined objects.
12711 */
12712 static int
12713 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12714 xmlXPathStepOpPtr op, xmlNodePtr * first)
12715 {
12716 int total = 0, cur;
12717 xmlXPathCompExprPtr comp;
12718 xmlXPathObjectPtr arg1, arg2;
12719
12720 CHECK_ERROR0;
12721 comp = ctxt->comp;
12722 switch (op->op) {
12723 case XPATH_OP_END:
12724 return (0);
12725 case XPATH_OP_UNION:
12726 total =
12727 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12728 first);
12729 CHECK_ERROR0;
12730 if ((ctxt->value != NULL)
12731 && (ctxt->value->type == XPATH_NODESET)
12732 && (ctxt->value->nodesetval != NULL)
12733 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12734 /*
12735 * limit tree traversing to first node in the result
12736 */
12737 /*
12738 * OPTIMIZE TODO: This implicitely sorts
12739 * the result, even if not needed. E.g. if the argument
12740 * of the count() function, no sorting is needed.
12741 * OPTIMIZE TODO: How do we know if the node-list wasn't
12742 * aready sorted?
12743 */
12744 if (ctxt->value->nodesetval->nodeNr > 1)
12745 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12746 *first = ctxt->value->nodesetval->nodeTab[0];
12747 }
12748 cur =
12749 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12750 first);
12751 CHECK_ERROR0;
12752
12753 arg2 = valuePop(ctxt);
12754 arg1 = valuePop(ctxt);
12755 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12756 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12757 xmlXPathReleaseObject(ctxt->context, arg1);
12758 xmlXPathReleaseObject(ctxt->context, arg2);
12759 XP_ERROR0(XPATH_INVALID_TYPE);
12760 }
12761
12762 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12763 arg2->nodesetval);
12764 valuePush(ctxt, arg1);
12765 xmlXPathReleaseObject(ctxt->context, arg2);
12766 /* optimizer */
12767 if (total > cur)
12768 xmlXPathCompSwap(op);
12769 return (total + cur);
12770 case XPATH_OP_ROOT:
12771 xmlXPathRoot(ctxt);
12772 return (0);
12773 case XPATH_OP_NODE:
12774 if (op->ch1 != -1)
12775 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12776 CHECK_ERROR0;
12777 if (op->ch2 != -1)
12778 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12779 CHECK_ERROR0;
12780 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12781 ctxt->context->node));
12782 return (total);
12783 case XPATH_OP_COLLECT:{
12784 if (op->ch1 == -1)
12785 return (total);
12786
12787 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12788 CHECK_ERROR0;
12789
12790 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12791 return (total);
12792 }
12793 case XPATH_OP_VALUE:
12794 valuePush(ctxt,
12795 xmlXPathCacheObjectCopy(ctxt->context,
12796 (xmlXPathObjectPtr) op->value4));
12797 return (0);
12798 case XPATH_OP_SORT:
12799 if (op->ch1 != -1)
12800 total +=
12801 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12802 first);
12803 CHECK_ERROR0;
12804 if ((ctxt->value != NULL)
12805 && (ctxt->value->type == XPATH_NODESET)
12806 && (ctxt->value->nodesetval != NULL)
12807 && (ctxt->value->nodesetval->nodeNr > 1))
12808 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12809 return (total);
12810 #ifdef XP_OPTIMIZED_FILTER_FIRST
12811 case XPATH_OP_FILTER:
12812 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12813 return (total);
12814 #endif
12815 default:
12816 return (xmlXPathCompOpEval(ctxt, op));
12817 }
12818 }
12819
12820 /**
12821 * xmlXPathCompOpEvalLast:
12822 * @ctxt: the XPath parser context with the compiled expression
12823 * @op: an XPath compiled operation
12824 * @last: the last elem found so far
12825 *
12826 * Evaluate the Precompiled XPath operation searching only the last
12827 * element in document order
12828 *
12829 * Returns the number of nodes traversed
12830 */
12831 static int
12832 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12833 xmlNodePtr * last)
12834 {
12835 int total = 0, cur;
12836 xmlXPathCompExprPtr comp;
12837 xmlXPathObjectPtr arg1, arg2;
12838
12839 CHECK_ERROR0;
12840 comp = ctxt->comp;
12841 switch (op->op) {
12842 case XPATH_OP_END:
12843 return (0);
12844 case XPATH_OP_UNION:
12845 total =
12846 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12847 CHECK_ERROR0;
12848 if ((ctxt->value != NULL)
12849 && (ctxt->value->type == XPATH_NODESET)
12850 && (ctxt->value->nodesetval != NULL)
12851 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12852 /*
12853 * limit tree traversing to first node in the result
12854 */
12855 if (ctxt->value->nodesetval->nodeNr > 1)
12856 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12857 *last =
12858 ctxt->value->nodesetval->nodeTab[ctxt->value->
12859 nodesetval->nodeNr -
12860 1];
12861 }
12862 cur =
12863 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12864 CHECK_ERROR0;
12865 if ((ctxt->value != NULL)
12866 && (ctxt->value->type == XPATH_NODESET)
12867 && (ctxt->value->nodesetval != NULL)
12868 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12869 }
12870
12871 arg2 = valuePop(ctxt);
12872 arg1 = valuePop(ctxt);
12873 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12874 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12875 xmlXPathReleaseObject(ctxt->context, arg1);
12876 xmlXPathReleaseObject(ctxt->context, arg2);
12877 XP_ERROR0(XPATH_INVALID_TYPE);
12878 }
12879
12880 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12881 arg2->nodesetval);
12882 valuePush(ctxt, arg1);
12883 xmlXPathReleaseObject(ctxt->context, arg2);
12884 /* optimizer */
12885 if (total > cur)
12886 xmlXPathCompSwap(op);
12887 return (total + cur);
12888 case XPATH_OP_ROOT:
12889 xmlXPathRoot(ctxt);
12890 return (0);
12891 case XPATH_OP_NODE:
12892 if (op->ch1 != -1)
12893 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12894 CHECK_ERROR0;
12895 if (op->ch2 != -1)
12896 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12897 CHECK_ERROR0;
12898 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12899 ctxt->context->node));
12900 return (total);
12901 case XPATH_OP_COLLECT:{
12902 if (op->ch1 == -1)
12903 return (0);
12904
12905 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12906 CHECK_ERROR0;
12907
12908 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12909 return (total);
12910 }
12911 case XPATH_OP_VALUE:
12912 valuePush(ctxt,
12913 xmlXPathCacheObjectCopy(ctxt->context,
12914 (xmlXPathObjectPtr) op->value4));
12915 return (0);
12916 case XPATH_OP_SORT:
12917 if (op->ch1 != -1)
12918 total +=
12919 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12920 last);
12921 CHECK_ERROR0;
12922 if ((ctxt->value != NULL)
12923 && (ctxt->value->type == XPATH_NODESET)
12924 && (ctxt->value->nodesetval != NULL)
12925 && (ctxt->value->nodesetval->nodeNr > 1))
12926 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12927 return (total);
12928 default:
12929 return (xmlXPathCompOpEval(ctxt, op));
12930 }
12931 }
12932
12933 #ifdef XP_OPTIMIZED_FILTER_FIRST
12934 static int
12935 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12936 xmlXPathStepOpPtr op, xmlNodePtr * first)
12937 {
12938 int total = 0;
12939 xmlXPathCompExprPtr comp;
12940 xmlXPathObjectPtr res;
12941 xmlXPathObjectPtr obj;
12942 xmlNodeSetPtr oldset;
12943 xmlNodePtr oldnode;
12944 xmlDocPtr oldDoc;
12945 int oldcs, oldpp;
12946 int i;
12947
12948 CHECK_ERROR0;
12949 comp = ctxt->comp;
12950 /*
12951 * Optimization for ()[last()] selection i.e. the last elem
12952 */
12953 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12954 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12955 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12956 int f = comp->steps[op->ch2].ch1;
12957
12958 if ((f != -1) &&
12959 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12960 (comp->steps[f].value5 == NULL) &&
12961 (comp->steps[f].value == 0) &&
12962 (comp->steps[f].value4 != NULL) &&
12963 (xmlStrEqual
12964 (comp->steps[f].value4, BAD_CAST "last"))) {
12965 xmlNodePtr last = NULL;
12966
12967 total +=
12968 xmlXPathCompOpEvalLast(ctxt,
12969 &comp->steps[op->ch1],
12970 &last);
12971 CHECK_ERROR0;
12972 /*
12973 * The nodeset should be in document order,
12974 * Keep only the last value
12975 */
12976 if ((ctxt->value != NULL) &&
12977 (ctxt->value->type == XPATH_NODESET) &&
12978 (ctxt->value->nodesetval != NULL) &&
12979 (ctxt->value->nodesetval->nodeTab != NULL) &&
12980 (ctxt->value->nodesetval->nodeNr > 1)) {
12981 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12982 *first = *(ctxt->value->nodesetval->nodeTab);
12983 }
12984 return (total);
12985 }
12986 }
12987
12988 if (op->ch1 != -1)
12989 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12990 CHECK_ERROR0;
12991 if (op->ch2 == -1)
12992 return (total);
12993 if (ctxt->value == NULL)
12994 return (total);
12995
12996 #ifdef LIBXML_XPTR_ENABLED
12997 /*
12998 * Hum are we filtering the result of an XPointer expression
12999 */
13000 if (ctxt->value->type == XPATH_LOCATIONSET) {
13001 xmlXPathObjectPtr tmp = NULL;
13002 xmlLocationSetPtr newlocset = NULL;
13003 xmlLocationSetPtr oldlocset;
13004
13005 /*
13006 * Extract the old locset, and then evaluate the result of the
13007 * expression for all the element in the locset. use it to grow
13008 * up a new locset.
13009 */
13010 CHECK_TYPE0(XPATH_LOCATIONSET);
13011
13012 if ((ctxt->value->user == NULL) ||
13013 (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
13014 return (total);
13015
13016 obj = valuePop(ctxt);
13017 oldlocset = obj->user;
13018 oldnode = ctxt->context->node;
13019 oldcs = ctxt->context->contextSize;
13020 oldpp = ctxt->context->proximityPosition;
13021
13022 newlocset = xmlXPtrLocationSetCreate(NULL);
13023
13024 for (i = 0; i < oldlocset->locNr; i++) {
13025 /*
13026 * Run the evaluation with a node list made of a
13027 * single item in the nodelocset.
13028 */
13029 ctxt->context->node = oldlocset->locTab[i]->user;
13030 ctxt->context->contextSize = oldlocset->locNr;
13031 ctxt->context->proximityPosition = i + 1;
13032 if (tmp == NULL) {
13033 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13034 ctxt->context->node);
13035 } else {
13036 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13037 ctxt->context->node) < 0) {
13038 ctxt->error = XPATH_MEMORY_ERROR;
13039 }
13040 }
13041 valuePush(ctxt, tmp);
13042 if (op->ch2 != -1)
13043 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13044 if (ctxt->error != XPATH_EXPRESSION_OK) {
13045 xmlXPtrFreeLocationSet(newlocset);
13046 goto xptr_error;
13047 }
13048 /*
13049 * The result of the evaluation need to be tested to
13050 * decided whether the filter succeeded or not
13051 */
13052 res = valuePop(ctxt);
13053 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13054 xmlXPtrLocationSetAdd(newlocset,
13055 xmlXPathCacheObjectCopy(ctxt->context,
13056 oldlocset->locTab[i]));
13057 }
13058 /*
13059 * Cleanup
13060 */
13061 if (res != NULL) {
13062 xmlXPathReleaseObject(ctxt->context, res);
13063 }
13064 if (ctxt->value == tmp) {
13065 valuePop(ctxt);
13066 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13067 /*
13068 * REVISIT TODO: Don't create a temporary nodeset
13069 * for everly iteration.
13070 */
13071 /* OLD: xmlXPathFreeObject(res); */
13072 } else
13073 tmp = NULL;
13074 /*
13075 * Only put the first node in the result, then leave.
13076 */
13077 if (newlocset->locNr > 0) {
13078 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
13079 break;
13080 }
13081 }
13082 if (tmp != NULL) {
13083 xmlXPathReleaseObject(ctxt->context, tmp);
13084 }
13085 /*
13086 * The result is used as the new evaluation locset.
13087 */
13088 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13089 xptr_error:
13090 xmlXPathReleaseObject(ctxt->context, obj);
13091 ctxt->context->node = oldnode;
13092 ctxt->context->contextSize = oldcs;
13093 ctxt->context->proximityPosition = oldpp;
13094 return (total);
13095 }
13096 #endif /* LIBXML_XPTR_ENABLED */
13097
13098 /*
13099 * Extract the old set, and then evaluate the result of the
13100 * expression for all the element in the set. use it to grow
13101 * up a new set.
13102 */
13103 CHECK_TYPE0(XPATH_NODESET);
13104
13105 if ((ctxt->value->nodesetval != NULL) &&
13106 (ctxt->value->nodesetval->nodeNr != 0)) {
13107 xmlNodeSetPtr newset;
13108 xmlXPathObjectPtr tmp = NULL;
13109
13110 obj = valuePop(ctxt);
13111 oldset = obj->nodesetval;
13112 oldnode = ctxt->context->node;
13113 oldDoc = ctxt->context->doc;
13114 oldcs = ctxt->context->contextSize;
13115 oldpp = ctxt->context->proximityPosition;
13116
13117 /*
13118 * Initialize the new set.
13119 * Also set the xpath document in case things like
13120 * key() evaluation are attempted on the predicate
13121 */
13122 newset = xmlXPathNodeSetCreate(NULL);
13123 /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13124
13125 for (i = 0; i < oldset->nodeNr; i++) {
13126 /*
13127 * Run the evaluation with a node list made of
13128 * a single item in the nodeset.
13129 */
13130 ctxt->context->node = oldset->nodeTab[i];
13131 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13132 (oldset->nodeTab[i]->doc != NULL))
13133 ctxt->context->doc = oldset->nodeTab[i]->doc;
13134 if (tmp == NULL) {
13135 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13136 ctxt->context->node);
13137 } else {
13138 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13139 ctxt->context->node) < 0) {
13140 ctxt->error = XPATH_MEMORY_ERROR;
13141 }
13142 }
13143 valuePush(ctxt, tmp);
13144 ctxt->context->contextSize = oldset->nodeNr;
13145 ctxt->context->proximityPosition = i + 1;
13146 if (op->ch2 != -1)
13147 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13148 if (ctxt->error != XPATH_EXPRESSION_OK) {
13149 xmlXPathFreeNodeSet(newset);
13150 goto error;
13151 }
13152 /*
13153 * The result of the evaluation needs to be tested to
13154 * decide whether the filter succeeded or not
13155 */
13156 res = valuePop(ctxt);
13157 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13158 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0)
13159 ctxt->error = XPATH_MEMORY_ERROR;
13160 }
13161 /*
13162 * Cleanup
13163 */
13164 if (res != NULL) {
13165 xmlXPathReleaseObject(ctxt->context, res);
13166 }
13167 if (ctxt->value == tmp) {
13168 valuePop(ctxt);
13169 /*
13170 * Don't free the temporary nodeset
13171 * in order to avoid massive recreation inside this
13172 * loop.
13173 */
13174 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13175 } else
13176 tmp = NULL;
13177 /*
13178 * Only put the first node in the result, then leave.
13179 */
13180 if (newset->nodeNr > 0) {
13181 *first = *(newset->nodeTab);
13182 break;
13183 }
13184 }
13185 if (tmp != NULL) {
13186 xmlXPathReleaseObject(ctxt->context, tmp);
13187 }
13188 /*
13189 * The result is used as the new evaluation set.
13190 */
13191 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13192 error:
13193 xmlXPathReleaseObject(ctxt->context, obj);
13194 ctxt->context->node = oldnode;
13195 ctxt->context->doc = oldDoc;
13196 ctxt->context->contextSize = oldcs;
13197 ctxt->context->proximityPosition = oldpp;
13198 }
13199 return(total);
13200 }
13201 #endif /* XP_OPTIMIZED_FILTER_FIRST */
13202
13203 /**
13204 * xmlXPathCompOpEval:
13205 * @ctxt: the XPath parser context with the compiled expression
13206 * @op: an XPath compiled operation
13207 *
13208 * Evaluate the Precompiled XPath operation
13209 * Returns the number of nodes traversed
13210 */
13211 static int
13212 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13213 {
13214 int total = 0;
13215 int equal, ret;
13216 xmlXPathCompExprPtr comp;
13217 xmlXPathObjectPtr arg1, arg2;
13218
13219 CHECK_ERROR0;
13220 comp = ctxt->comp;
13221 switch (op->op) {
13222 case XPATH_OP_END:
13223 return (0);
13224 case XPATH_OP_AND:
13225 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13226 CHECK_ERROR0;
13227 xmlXPathBooleanFunction(ctxt, 1);
13228 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13229 return (total);
13230 arg2 = valuePop(ctxt);
13231 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13232 if (ctxt->error) {
13233 xmlXPathFreeObject(arg2);
13234 return(0);
13235 }
13236 xmlXPathBooleanFunction(ctxt, 1);
13237 if (ctxt->value != NULL)
13238 ctxt->value->boolval &= arg2->boolval;
13239 xmlXPathReleaseObject(ctxt->context, arg2);
13240 return (total);
13241 case XPATH_OP_OR:
13242 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13243 CHECK_ERROR0;
13244 xmlXPathBooleanFunction(ctxt, 1);
13245 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13246 return (total);
13247 arg2 = valuePop(ctxt);
13248 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13249 if (ctxt->error) {
13250 xmlXPathFreeObject(arg2);
13251 return(0);
13252 }
13253 xmlXPathBooleanFunction(ctxt, 1);
13254 if (ctxt->value != NULL)
13255 ctxt->value->boolval |= arg2->boolval;
13256 xmlXPathReleaseObject(ctxt->context, arg2);
13257 return (total);
13258 case XPATH_OP_EQUAL:
13259 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13260 CHECK_ERROR0;
13261 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13262 CHECK_ERROR0;
13263 if (op->value)
13264 equal = xmlXPathEqualValues(ctxt);
13265 else
13266 equal = xmlXPathNotEqualValues(ctxt);
13267 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13268 return (total);
13269 case XPATH_OP_CMP:
13270 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13271 CHECK_ERROR0;
13272 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13273 CHECK_ERROR0;
13274 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13275 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13276 return (total);
13277 case XPATH_OP_PLUS:
13278 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13279 CHECK_ERROR0;
13280 if (op->ch2 != -1) {
13281 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13282 }
13283 CHECK_ERROR0;
13284 if (op->value == 0)
13285 xmlXPathSubValues(ctxt);
13286 else if (op->value == 1)
13287 xmlXPathAddValues(ctxt);
13288 else if (op->value == 2)
13289 xmlXPathValueFlipSign(ctxt);
13290 else if (op->value == 3) {
13291 CAST_TO_NUMBER;
13292 CHECK_TYPE0(XPATH_NUMBER);
13293 }
13294 return (total);
13295 case XPATH_OP_MULT:
13296 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13297 CHECK_ERROR0;
13298 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13299 CHECK_ERROR0;
13300 if (op->value == 0)
13301 xmlXPathMultValues(ctxt);
13302 else if (op->value == 1)
13303 xmlXPathDivValues(ctxt);
13304 else if (op->value == 2)
13305 xmlXPathModValues(ctxt);
13306 return (total);
13307 case XPATH_OP_UNION:
13308 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13309 CHECK_ERROR0;
13310 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13311 CHECK_ERROR0;
13312
13313 arg2 = valuePop(ctxt);
13314 arg1 = valuePop(ctxt);
13315 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13316 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13317 xmlXPathReleaseObject(ctxt->context, arg1);
13318 xmlXPathReleaseObject(ctxt->context, arg2);
13319 XP_ERROR0(XPATH_INVALID_TYPE);
13320 }
13321
13322 if ((arg1->nodesetval == NULL) ||
13323 ((arg2->nodesetval != NULL) &&
13324 (arg2->nodesetval->nodeNr != 0)))
13325 {
13326 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13327 arg2->nodesetval);
13328 }
13329
13330 valuePush(ctxt, arg1);
13331 xmlXPathReleaseObject(ctxt->context, arg2);
13332 return (total);
13333 case XPATH_OP_ROOT:
13334 xmlXPathRoot(ctxt);
13335 return (total);
13336 case XPATH_OP_NODE:
13337 if (op->ch1 != -1)
13338 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13339 CHECK_ERROR0;
13340 if (op->ch2 != -1)
13341 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13342 CHECK_ERROR0;
13343 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13344 ctxt->context->node));
13345 return (total);
13346 case XPATH_OP_COLLECT:{
13347 if (op->ch1 == -1)
13348 return (total);
13349
13350 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13351 CHECK_ERROR0;
13352
13353 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13354 return (total);
13355 }
13356 case XPATH_OP_VALUE:
13357 valuePush(ctxt,
13358 xmlXPathCacheObjectCopy(ctxt->context,
13359 (xmlXPathObjectPtr) op->value4));
13360 return (total);
13361 case XPATH_OP_VARIABLE:{
13362 xmlXPathObjectPtr val;
13363
13364 if (op->ch1 != -1)
13365 total +=
13366 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13367 if (op->value5 == NULL) {
13368 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13369 if (val == NULL)
13370 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13371 valuePush(ctxt, val);
13372 } else {
13373 const xmlChar *URI;
13374
13375 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13376 if (URI == NULL) {
13377 xmlGenericError(xmlGenericErrorContext,
13378 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13379 (char *) op->value4, (char *)op->value5);
13380 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13381 return (total);
13382 }
13383 val = xmlXPathVariableLookupNS(ctxt->context,
13384 op->value4, URI);
13385 if (val == NULL)
13386 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13387 valuePush(ctxt, val);
13388 }
13389 return (total);
13390 }
13391 case XPATH_OP_FUNCTION:{
13392 xmlXPathFunction func;
13393 const xmlChar *oldFunc, *oldFuncURI;
13394 int i;
13395 int frame;
13396
13397 frame = xmlXPathSetFrame(ctxt);
13398 if (op->ch1 != -1) {
13399 total +=
13400 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13401 if (ctxt->error != XPATH_EXPRESSION_OK) {
13402 xmlXPathPopFrame(ctxt, frame);
13403 return (total);
13404 }
13405 }
13406 if (ctxt->valueNr < ctxt->valueFrame + op->value) {
13407 xmlGenericError(xmlGenericErrorContext,
13408 "xmlXPathCompOpEval: parameter error\n");
13409 ctxt->error = XPATH_INVALID_OPERAND;
13410 xmlXPathPopFrame(ctxt, frame);
13411 return (total);
13412 }
13413 for (i = 0; i < op->value; i++) {
13414 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13415 xmlGenericError(xmlGenericErrorContext,
13416 "xmlXPathCompOpEval: parameter error\n");
13417 ctxt->error = XPATH_INVALID_OPERAND;
13418 xmlXPathPopFrame(ctxt, frame);
13419 return (total);
13420 }
13421 }
13422 if (op->cache != NULL)
13423 func = op->cache;
13424 else {
13425 const xmlChar *URI = NULL;
13426
13427 if (op->value5 == NULL)
13428 func =
13429 xmlXPathFunctionLookup(ctxt->context,
13430 op->value4);
13431 else {
13432 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13433 if (URI == NULL) {
13434 xmlGenericError(xmlGenericErrorContext,
13435 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13436 (char *)op->value4, (char *)op->value5);
13437 xmlXPathPopFrame(ctxt, frame);
13438 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13439 return (total);
13440 }
13441 func = xmlXPathFunctionLookupNS(ctxt->context,
13442 op->value4, URI);
13443 }
13444 if (func == NULL) {
13445 xmlGenericError(xmlGenericErrorContext,
13446 "xmlXPathCompOpEval: function %s not found\n",
13447 (char *)op->value4);
13448 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13449 }
13450 op->cache = func;
13451 op->cacheURI = (void *) URI;
13452 }
13453 oldFunc = ctxt->context->function;
13454 oldFuncURI = ctxt->context->functionURI;
13455 ctxt->context->function = op->value4;
13456 ctxt->context->functionURI = op->cacheURI;
13457 func(ctxt, op->value);
13458 ctxt->context->function = oldFunc;
13459 ctxt->context->functionURI = oldFuncURI;
13460 xmlXPathPopFrame(ctxt, frame);
13461 return (total);
13462 }
13463 case XPATH_OP_ARG:
13464 if (op->ch1 != -1) {
13465 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13466 CHECK_ERROR0;
13467 }
13468 if (op->ch2 != -1) {
13469 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13470 CHECK_ERROR0;
13471 }
13472 return (total);
13473 case XPATH_OP_PREDICATE:
13474 case XPATH_OP_FILTER:{
13475 xmlXPathObjectPtr res;
13476 xmlXPathObjectPtr obj, tmp;
13477 xmlNodeSetPtr newset = NULL;
13478 xmlNodeSetPtr oldset;
13479 xmlNodePtr oldnode;
13480 xmlDocPtr oldDoc;
13481 int oldcs, oldpp;
13482 int i;
13483
13484 /*
13485 * Optimization for ()[1] selection i.e. the first elem
13486 */
13487 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13488 #ifdef XP_OPTIMIZED_FILTER_FIRST
13489 /*
13490 * FILTER TODO: Can we assume that the inner processing
13491 * will result in an ordered list if we have an
13492 * XPATH_OP_FILTER?
13493 * What about an additional field or flag on
13494 * xmlXPathObject like @sorted ? This way we wouln'd need
13495 * to assume anything, so it would be more robust and
13496 * easier to optimize.
13497 */
13498 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13499 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13500 #else
13501 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13502 #endif
13503 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13504 xmlXPathObjectPtr val;
13505
13506 val = comp->steps[op->ch2].value4;
13507 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13508 (val->floatval == 1.0)) {
13509 xmlNodePtr first = NULL;
13510
13511 total +=
13512 xmlXPathCompOpEvalFirst(ctxt,
13513 &comp->steps[op->ch1],
13514 &first);
13515 CHECK_ERROR0;
13516 /*
13517 * The nodeset should be in document order,
13518 * Keep only the first value
13519 */
13520 if ((ctxt->value != NULL) &&
13521 (ctxt->value->type == XPATH_NODESET) &&
13522 (ctxt->value->nodesetval != NULL) &&
13523 (ctxt->value->nodesetval->nodeNr > 1))
13524 xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13525 1, 1);
13526 return (total);
13527 }
13528 }
13529 /*
13530 * Optimization for ()[last()] selection i.e. the last elem
13531 */
13532 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13533 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13534 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13535 int f = comp->steps[op->ch2].ch1;
13536
13537 if ((f != -1) &&
13538 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13539 (comp->steps[f].value5 == NULL) &&
13540 (comp->steps[f].value == 0) &&
13541 (comp->steps[f].value4 != NULL) &&
13542 (xmlStrEqual
13543 (comp->steps[f].value4, BAD_CAST "last"))) {
13544 xmlNodePtr last = NULL;
13545
13546 total +=
13547 xmlXPathCompOpEvalLast(ctxt,
13548 &comp->steps[op->ch1],
13549 &last);
13550 CHECK_ERROR0;
13551 /*
13552 * The nodeset should be in document order,
13553 * Keep only the last value
13554 */
13555 if ((ctxt->value != NULL) &&
13556 (ctxt->value->type == XPATH_NODESET) &&
13557 (ctxt->value->nodesetval != NULL) &&
13558 (ctxt->value->nodesetval->nodeTab != NULL) &&
13559 (ctxt->value->nodesetval->nodeNr > 1))
13560 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13561 return (total);
13562 }
13563 }
13564 /*
13565 * Process inner predicates first.
13566 * Example "index[parent::book][1]":
13567 * ...
13568 * PREDICATE <-- we are here "[1]"
13569 * PREDICATE <-- process "[parent::book]" first
13570 * SORT
13571 * COLLECT 'parent' 'name' 'node' book
13572 * NODE
13573 * ELEM Object is a number : 1
13574 */
13575 if (op->ch1 != -1)
13576 total +=
13577 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13578 CHECK_ERROR0;
13579 if (op->ch2 == -1)
13580 return (total);
13581 if (ctxt->value == NULL)
13582 return (total);
13583
13584 #ifdef LIBXML_XPTR_ENABLED
13585 /*
13586 * Hum are we filtering the result of an XPointer expression
13587 */
13588 if (ctxt->value->type == XPATH_LOCATIONSET) {
13589 xmlLocationSetPtr newlocset = NULL;
13590 xmlLocationSetPtr oldlocset;
13591
13592 /*
13593 * Extract the old locset, and then evaluate the result of the
13594 * expression for all the element in the locset. use it to grow
13595 * up a new locset.
13596 */
13597 CHECK_TYPE0(XPATH_LOCATIONSET);
13598
13599 if ((ctxt->value->user == NULL) ||
13600 (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
13601 return (total);
13602
13603 obj = valuePop(ctxt);
13604 oldlocset = obj->user;
13605 oldnode = ctxt->context->node;
13606 oldcs = ctxt->context->contextSize;
13607 oldpp = ctxt->context->proximityPosition;
13608
13609 newlocset = xmlXPtrLocationSetCreate(NULL);
13610
13611 for (i = 0; i < oldlocset->locNr; i++) {
13612 /*
13613 * Run the evaluation with a node list made of a
13614 * single item in the nodelocset.
13615 */
13616 ctxt->context->node = oldlocset->locTab[i]->user;
13617 ctxt->context->contextSize = oldlocset->locNr;
13618 ctxt->context->proximityPosition = i + 1;
13619 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13620 ctxt->context->node);
13621 valuePush(ctxt, tmp);
13622
13623 if (op->ch2 != -1)
13624 total +=
13625 xmlXPathCompOpEval(ctxt,
13626 &comp->steps[op->ch2]);
13627 if (ctxt->error != XPATH_EXPRESSION_OK) {
13628 xmlXPtrFreeLocationSet(newlocset);
13629 goto filter_xptr_error;
13630 }
13631
13632 /*
13633 * The result of the evaluation need to be tested to
13634 * decided whether the filter succeeded or not
13635 */
13636 res = valuePop(ctxt);
13637 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13638 xmlXPtrLocationSetAdd(newlocset,
13639 xmlXPathObjectCopy
13640 (oldlocset->locTab[i]));
13641 }
13642
13643 /*
13644 * Cleanup
13645 */
13646 if (res != NULL) {
13647 xmlXPathReleaseObject(ctxt->context, res);
13648 }
13649 if (ctxt->value == tmp) {
13650 res = valuePop(ctxt);
13651 xmlXPathReleaseObject(ctxt->context, res);
13652 }
13653 }
13654
13655 /*
13656 * The result is used as the new evaluation locset.
13657 */
13658 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13659 filter_xptr_error:
13660 xmlXPathReleaseObject(ctxt->context, obj);
13661 ctxt->context->node = oldnode;
13662 ctxt->context->contextSize = oldcs;
13663 ctxt->context->proximityPosition = oldpp;
13664 return (total);
13665 }
13666 #endif /* LIBXML_XPTR_ENABLED */
13667
13668 /*
13669 * Extract the old set, and then evaluate the result of the
13670 * expression for all the element in the set. use it to grow
13671 * up a new set.
13672 */
13673 CHECK_TYPE0(XPATH_NODESET);
13674
13675 if ((ctxt->value->nodesetval != NULL) &&
13676 (ctxt->value->nodesetval->nodeNr != 0)) {
13677 obj = valuePop(ctxt);
13678 oldset = obj->nodesetval;
13679 oldnode = ctxt->context->node;
13680 oldDoc = ctxt->context->doc;
13681 oldcs = ctxt->context->contextSize;
13682 oldpp = ctxt->context->proximityPosition;
13683 tmp = NULL;
13684 /*
13685 * Initialize the new set.
13686 * Also set the xpath document in case things like
13687 * key() evaluation are attempted on the predicate
13688 */
13689 newset = xmlXPathNodeSetCreate(NULL);
13690 /*
13691 * SPEC XPath 1.0:
13692 * "For each node in the node-set to be filtered, the
13693 * PredicateExpr is evaluated with that node as the
13694 * context node, with the number of nodes in the
13695 * node-set as the context size, and with the proximity
13696 * position of the node in the node-set with respect to
13697 * the axis as the context position;"
13698 * @oldset is the node-set" to be filtered.
13699 *
13700 * SPEC XPath 1.0:
13701 * "only predicates change the context position and
13702 * context size (see [2.4 Predicates])."
13703 * Example:
13704 * node-set context pos
13705 * nA 1
13706 * nB 2
13707 * nC 3
13708 * After applying predicate [position() > 1] :
13709 * node-set context pos
13710 * nB 1
13711 * nC 2
13712 *
13713 * removed the first node in the node-set, then
13714 * the context position of the
13715 */
13716 for (i = 0; i < oldset->nodeNr; i++) {
13717 /*
13718 * Run the evaluation with a node list made of
13719 * a single item in the nodeset.
13720 */
13721 ctxt->context->node = oldset->nodeTab[i];
13722 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13723 (oldset->nodeTab[i]->doc != NULL))
13724 ctxt->context->doc = oldset->nodeTab[i]->doc;
13725 if (tmp == NULL) {
13726 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13727 ctxt->context->node);
13728 } else {
13729 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13730 ctxt->context->node) < 0) {
13731 ctxt->error = XPATH_MEMORY_ERROR;
13732 }
13733 }
13734 valuePush(ctxt, tmp);
13735 ctxt->context->contextSize = oldset->nodeNr;
13736 ctxt->context->proximityPosition = i + 1;
13737 /*
13738 * Evaluate the predicate against the context node.
13739 * Can/should we optimize position() predicates
13740 * here (e.g. "[1]")?
13741 */
13742 if (op->ch2 != -1)
13743 total +=
13744 xmlXPathCompOpEval(ctxt,
13745 &comp->steps[op->ch2]);
13746 if (ctxt->error != XPATH_EXPRESSION_OK) {
13747 xmlXPathFreeNodeSet(newset);
13748 goto filter_error;
13749 }
13750
13751 /*
13752 * The result of the evaluation needs to be tested to
13753 * decide whether the filter succeeded or not
13754 */
13755 /*
13756 * OPTIMIZE TODO: Can we use
13757 * xmlXPathNodeSetAdd*Unique()* instead?
13758 */
13759 res = valuePop(ctxt);
13760 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13761 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i])
13762 < 0)
13763 ctxt->error = XPATH_MEMORY_ERROR;
13764 }
13765
13766 /*
13767 * Cleanup
13768 */
13769 if (res != NULL) {
13770 xmlXPathReleaseObject(ctxt->context, res);
13771 }
13772 if (ctxt->value == tmp) {
13773 valuePop(ctxt);
13774 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13775 /*
13776 * Don't free the temporary nodeset
13777 * in order to avoid massive recreation inside this
13778 * loop.
13779 */
13780 } else
13781 tmp = NULL;
13782 }
13783 if (tmp != NULL)
13784 xmlXPathReleaseObject(ctxt->context, tmp);
13785 /*
13786 * The result is used as the new evaluation set.
13787 */
13788 valuePush(ctxt,
13789 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13790 filter_error:
13791 xmlXPathReleaseObject(ctxt->context, obj);
13792 ctxt->context->node = oldnode;
13793 ctxt->context->doc = oldDoc;
13794 ctxt->context->contextSize = oldcs;
13795 ctxt->context->proximityPosition = oldpp;
13796 }
13797 return (total);
13798 }
13799 case XPATH_OP_SORT:
13800 if (op->ch1 != -1)
13801 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13802 CHECK_ERROR0;
13803 if ((ctxt->value != NULL) &&
13804 (ctxt->value->type == XPATH_NODESET) &&
13805 (ctxt->value->nodesetval != NULL) &&
13806 (ctxt->value->nodesetval->nodeNr > 1))
13807 {
13808 xmlXPathNodeSetSort(ctxt->value->nodesetval);
13809 }
13810 return (total);
13811 #ifdef LIBXML_XPTR_ENABLED
13812 case XPATH_OP_RANGETO:{
13813 xmlXPathObjectPtr range;
13814 xmlXPathObjectPtr res, obj;
13815 xmlXPathObjectPtr tmp;
13816 xmlLocationSetPtr newlocset = NULL;
13817 xmlLocationSetPtr oldlocset;
13818 xmlNodeSetPtr oldset;
13819 xmlNodePtr oldnode = ctxt->context->node;
13820 int oldcs = ctxt->context->contextSize;
13821 int oldpp = ctxt->context->proximityPosition;
13822 int i, j;
13823
13824 if (op->ch1 != -1) {
13825 total +=
13826 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13827 CHECK_ERROR0;
13828 }
13829 if (ctxt->value == NULL) {
13830 XP_ERROR0(XPATH_INVALID_OPERAND);
13831 }
13832 if (op->ch2 == -1)
13833 return (total);
13834
13835 if (ctxt->value->type == XPATH_LOCATIONSET) {
13836 /*
13837 * Extract the old locset, and then evaluate the result of the
13838 * expression for all the element in the locset. use it to grow
13839 * up a new locset.
13840 */
13841 CHECK_TYPE0(XPATH_LOCATIONSET);
13842
13843 if ((ctxt->value->user == NULL) ||
13844 (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
13845 return (total);
13846
13847 obj = valuePop(ctxt);
13848 oldlocset = obj->user;
13849
13850 newlocset = xmlXPtrLocationSetCreate(NULL);
13851
13852 for (i = 0; i < oldlocset->locNr; i++) {
13853 /*
13854 * Run the evaluation with a node list made of a
13855 * single item in the nodelocset.
13856 */
13857 ctxt->context->node = oldlocset->locTab[i]->user;
13858 ctxt->context->contextSize = oldlocset->locNr;
13859 ctxt->context->proximityPosition = i + 1;
13860 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13861 ctxt->context->node);
13862 valuePush(ctxt, tmp);
13863
13864 if (op->ch2 != -1)
13865 total +=
13866 xmlXPathCompOpEval(ctxt,
13867 &comp->steps[op->ch2]);
13868 if (ctxt->error != XPATH_EXPRESSION_OK) {
13869 xmlXPtrFreeLocationSet(newlocset);
13870 goto rangeto_error;
13871 }
13872
13873 res = valuePop(ctxt);
13874 if (res->type == XPATH_LOCATIONSET) {
13875 xmlLocationSetPtr rloc =
13876 (xmlLocationSetPtr)res->user;
13877 for (j=0; j<rloc->locNr; j++) {
13878 range = xmlXPtrNewRange(
13879 oldlocset->locTab[i]->user,
13880 oldlocset->locTab[i]->index,
13881 rloc->locTab[j]->user2,
13882 rloc->locTab[j]->index2);
13883 if (range != NULL) {
13884 xmlXPtrLocationSetAdd(newlocset, range);
13885 }
13886 }
13887 } else {
13888 range = xmlXPtrNewRangeNodeObject(
13889 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13890 if (range != NULL) {
13891 xmlXPtrLocationSetAdd(newlocset,range);
13892 }
13893 }
13894
13895 /*
13896 * Cleanup
13897 */
13898 if (res != NULL) {
13899 xmlXPathReleaseObject(ctxt->context, res);
13900 }
13901 if (ctxt->value == tmp) {
13902 res = valuePop(ctxt);
13903 xmlXPathReleaseObject(ctxt->context, res);
13904 }
13905 }
13906 } else { /* Not a location set */
13907 CHECK_TYPE0(XPATH_NODESET);
13908 obj = valuePop(ctxt);
13909 oldset = obj->nodesetval;
13910
13911 newlocset = xmlXPtrLocationSetCreate(NULL);
13912
13913 if (oldset != NULL) {
13914 for (i = 0; i < oldset->nodeNr; i++) {
13915 /*
13916 * Run the evaluation with a node list made of a single item
13917 * in the nodeset.
13918 */
13919 ctxt->context->node = oldset->nodeTab[i];
13920 /*
13921 * OPTIMIZE TODO: Avoid recreation for every iteration.
13922 */
13923 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13924 ctxt->context->node);
13925 valuePush(ctxt, tmp);
13926
13927 if (op->ch2 != -1)
13928 total +=
13929 xmlXPathCompOpEval(ctxt,
13930 &comp->steps[op->ch2]);
13931 if (ctxt->error != XPATH_EXPRESSION_OK) {
13932 xmlXPtrFreeLocationSet(newlocset);
13933 goto rangeto_error;
13934 }
13935
13936 res = valuePop(ctxt);
13937 range =
13938 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13939 res);
13940 if (range != NULL) {
13941 xmlXPtrLocationSetAdd(newlocset, range);
13942 }
13943
13944 /*
13945 * Cleanup
13946 */
13947 if (res != NULL) {
13948 xmlXPathReleaseObject(ctxt->context, res);
13949 }
13950 if (ctxt->value == tmp) {
13951 res = valuePop(ctxt);
13952 xmlXPathReleaseObject(ctxt->context, res);
13953 }
13954 }
13955 }
13956 }
13957
13958 /*
13959 * The result is used as the new evaluation set.
13960 */
13961 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13962 rangeto_error:
13963 xmlXPathReleaseObject(ctxt->context, obj);
13964 ctxt->context->node = oldnode;
13965 ctxt->context->contextSize = oldcs;
13966 ctxt->context->proximityPosition = oldpp;
13967 return (total);
13968 }
13969 #endif /* LIBXML_XPTR_ENABLED */
13970 }
13971 xmlGenericError(xmlGenericErrorContext,
13972 "XPath: unknown precompiled operation %d\n", op->op);
13973 ctxt->error = XPATH_INVALID_OPERAND;
13974 return (total);
13975 }
13976
13977 /**
13978 * xmlXPathCompOpEvalToBoolean:
13979 * @ctxt: the XPath parser context
13980 *
13981 * Evaluates if the expression evaluates to true.
13982 *
13983 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13984 */
13985 static int
13986 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13987 xmlXPathStepOpPtr op,
13988 int isPredicate)
13989 {
13990 xmlXPathObjectPtr resObj = NULL;
13991
13992 start:
13993 /* comp = ctxt->comp; */
13994 switch (op->op) {
13995 case XPATH_OP_END:
13996 return (0);
13997 case XPATH_OP_VALUE:
13998 resObj = (xmlXPathObjectPtr) op->value4;
13999 if (isPredicate)
14000 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14001 return(xmlXPathCastToBoolean(resObj));
14002 case XPATH_OP_SORT:
14003 /*
14004 * We don't need sorting for boolean results. Skip this one.
14005 */
14006 if (op->ch1 != -1) {
14007 op = &ctxt->comp->steps[op->ch1];
14008 goto start;
14009 }
14010 return(0);
14011 case XPATH_OP_COLLECT:
14012 if (op->ch1 == -1)
14013 return(0);
14014
14015 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14016 if (ctxt->error != XPATH_EXPRESSION_OK)
14017 return(-1);
14018
14019 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14020 if (ctxt->error != XPATH_EXPRESSION_OK)
14021 return(-1);
14022
14023 resObj = valuePop(ctxt);
14024 if (resObj == NULL)
14025 return(-1);
14026 break;
14027 default:
14028 /*
14029 * Fallback to call xmlXPathCompOpEval().
14030 */
14031 xmlXPathCompOpEval(ctxt, op);
14032 if (ctxt->error != XPATH_EXPRESSION_OK)
14033 return(-1);
14034
14035 resObj = valuePop(ctxt);
14036 if (resObj == NULL)
14037 return(-1);
14038 break;
14039 }
14040
14041 if (resObj) {
14042 int res;
14043
14044 if (resObj->type == XPATH_BOOLEAN) {
14045 res = resObj->boolval;
14046 } else if (isPredicate) {
14047 /*
14048 * For predicates a result of type "number" is handled
14049 * differently:
14050 * SPEC XPath 1.0:
14051 * "If the result is a number, the result will be converted
14052 * to true if the number is equal to the context position
14053 * and will be converted to false otherwise;"
14054 */
14055 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14056 } else {
14057 res = xmlXPathCastToBoolean(resObj);
14058 }
14059 xmlXPathReleaseObject(ctxt->context, resObj);
14060 return(res);
14061 }
14062
14063 return(0);
14064 }
14065
14066 #ifdef XPATH_STREAMING
14067 /**
14068 * xmlXPathRunStreamEval:
14069 * @ctxt: the XPath parser context with the compiled expression
14070 *
14071 * Evaluate the Precompiled Streamable XPath expression in the given context.
14072 */
14073 static int
14074 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14075 xmlXPathObjectPtr *resultSeq, int toBool)
14076 {
14077 int max_depth, min_depth;
14078 int from_root;
14079 int ret, depth;
14080 int eval_all_nodes;
14081 xmlNodePtr cur = NULL, limit = NULL;
14082 xmlStreamCtxtPtr patstream = NULL;
14083
14084 int nb_nodes = 0;
14085
14086 if ((ctxt == NULL) || (comp == NULL))
14087 return(-1);
14088 max_depth = xmlPatternMaxDepth(comp);
14089 if (max_depth == -1)
14090 return(-1);
14091 if (max_depth == -2)
14092 max_depth = 10000;
14093 min_depth = xmlPatternMinDepth(comp);
14094 if (min_depth == -1)
14095 return(-1);
14096 from_root = xmlPatternFromRoot(comp);
14097 if (from_root < 0)
14098 return(-1);
14099 #if 0
14100 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14101 #endif
14102
14103 if (! toBool) {
14104 if (resultSeq == NULL)
14105 return(-1);
14106 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14107 if (*resultSeq == NULL)
14108 return(-1);
14109 }
14110
14111 /*
14112 * handle the special cases of "/" amd "." being matched
14113 */
14114 if (min_depth == 0) {
14115 if (from_root) {
14116 /* Select "/" */
14117 if (toBool)
14118 return(1);
14119 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14120 (xmlNodePtr) ctxt->doc);
14121 } else {
14122 /* Select "self::node()" */
14123 if (toBool)
14124 return(1);
14125 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14126 }
14127 }
14128 if (max_depth == 0) {
14129 return(0);
14130 }
14131
14132 if (from_root) {
14133 cur = (xmlNodePtr)ctxt->doc;
14134 } else if (ctxt->node != NULL) {
14135 switch (ctxt->node->type) {
14136 case XML_ELEMENT_NODE:
14137 case XML_DOCUMENT_NODE:
14138 case XML_DOCUMENT_FRAG_NODE:
14139 case XML_HTML_DOCUMENT_NODE:
14140 #ifdef LIBXML_DOCB_ENABLED
14141 case XML_DOCB_DOCUMENT_NODE:
14142 #endif
14143 cur = ctxt->node;
14144 break;
14145 case XML_ATTRIBUTE_NODE:
14146 case XML_TEXT_NODE:
14147 case XML_CDATA_SECTION_NODE:
14148 case XML_ENTITY_REF_NODE:
14149 case XML_ENTITY_NODE:
14150 case XML_PI_NODE:
14151 case XML_COMMENT_NODE:
14152 case XML_NOTATION_NODE:
14153 case XML_DTD_NODE:
14154 case XML_DOCUMENT_TYPE_NODE:
14155 case XML_ELEMENT_DECL:
14156 case XML_ATTRIBUTE_DECL:
14157 case XML_ENTITY_DECL:
14158 case XML_NAMESPACE_DECL:
14159 case XML_XINCLUDE_START:
14160 case XML_XINCLUDE_END:
14161 break;
14162 }
14163 limit = cur;
14164 }
14165 if (cur == NULL) {
14166 return(0);
14167 }
14168
14169 patstream = xmlPatternGetStreamCtxt(comp);
14170 if (patstream == NULL) {
14171 /*
14172 * QUESTION TODO: Is this an error?
14173 */
14174 return(0);
14175 }
14176
14177 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14178
14179 if (from_root) {
14180 ret = xmlStreamPush(patstream, NULL, NULL);
14181 if (ret < 0) {
14182 } else if (ret == 1) {
14183 if (toBool)
14184 goto return_1;
14185 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14186 }
14187 }
14188 depth = 0;
14189 goto scan_children;
14190 next_node:
14191 do {
14192 nb_nodes++;
14193
14194 switch (cur->type) {
14195 case XML_ELEMENT_NODE:
14196 case XML_TEXT_NODE:
14197 case XML_CDATA_SECTION_NODE:
14198 case XML_COMMENT_NODE:
14199 case XML_PI_NODE:
14200 if (cur->type == XML_ELEMENT_NODE) {
14201 ret = xmlStreamPush(patstream, cur->name,
14202 (cur->ns ? cur->ns->href : NULL));
14203 } else if (eval_all_nodes)
14204 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14205 else
14206 break;
14207
14208 if (ret < 0) {
14209 /* NOP. */
14210 } else if (ret == 1) {
14211 if (toBool)
14212 goto return_1;
14213 if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
14214 < 0) {
14215 ctxt->lastError.domain = XML_FROM_XPATH;
14216 ctxt->lastError.code = XML_ERR_NO_MEMORY;
14217 }
14218 }
14219 if ((cur->children == NULL) || (depth >= max_depth)) {
14220 ret = xmlStreamPop(patstream);
14221 while (cur->next != NULL) {
14222 cur = cur->next;
14223 if ((cur->type != XML_ENTITY_DECL) &&
14224 (cur->type != XML_DTD_NODE))
14225 goto next_node;
14226 }
14227 }
14228 default:
14229 break;
14230 }
14231
14232 scan_children:
14233 if (cur->type == XML_NAMESPACE_DECL) break;
14234 if ((cur->children != NULL) && (depth < max_depth)) {
14235 /*
14236 * Do not descend on entities declarations
14237 */
14238 if (cur->children->type != XML_ENTITY_DECL) {
14239 cur = cur->children;
14240 depth++;
14241 /*
14242 * Skip DTDs
14243 */
14244 if (cur->type != XML_DTD_NODE)
14245 continue;
14246 }
14247 }
14248
14249 if (cur == limit)
14250 break;
14251
14252 while (cur->next != NULL) {
14253 cur = cur->next;
14254 if ((cur->type != XML_ENTITY_DECL) &&
14255 (cur->type != XML_DTD_NODE))
14256 goto next_node;
14257 }
14258
14259 do {
14260 cur = cur->parent;
14261 depth--;
14262 if ((cur == NULL) || (cur == limit))
14263 goto done;
14264 if (cur->type == XML_ELEMENT_NODE) {
14265 ret = xmlStreamPop(patstream);
14266 } else if ((eval_all_nodes) &&
14267 ((cur->type == XML_TEXT_NODE) ||
14268 (cur->type == XML_CDATA_SECTION_NODE) ||
14269 (cur->type == XML_COMMENT_NODE) ||
14270 (cur->type == XML_PI_NODE)))
14271 {
14272 ret = xmlStreamPop(patstream);
14273 }
14274 if (cur->next != NULL) {
14275 cur = cur->next;
14276 break;
14277 }
14278 } while (cur != NULL);
14279
14280 } while ((cur != NULL) && (depth >= 0));
14281
14282 done:
14283
14284 #if 0
14285 printf("stream eval: checked %d nodes selected %d\n",
14286 nb_nodes, retObj->nodesetval->nodeNr);
14287 #endif
14288
14289 if (patstream)
14290 xmlFreeStreamCtxt(patstream);
14291 return(0);
14292
14293 return_1:
14294 if (patstream)
14295 xmlFreeStreamCtxt(patstream);
14296 return(1);
14297 }
14298 #endif /* XPATH_STREAMING */
14299
14300 /**
14301 * xmlXPathRunEval:
14302 * @ctxt: the XPath parser context with the compiled expression
14303 * @toBool: evaluate to a boolean result
14304 *
14305 * Evaluate the Precompiled XPath expression in the given context.
14306 */
14307 static int
14308 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14309 {
14310 xmlXPathCompExprPtr comp;
14311
14312 if ((ctxt == NULL) || (ctxt->comp == NULL))
14313 return(-1);
14314
14315 if (ctxt->valueTab == NULL) {
14316 /* Allocate the value stack */
14317 ctxt->valueTab = (xmlXPathObjectPtr *)
14318 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14319 if (ctxt->valueTab == NULL) {
14320 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14321 xmlFree(ctxt);
14322 }
14323 ctxt->valueNr = 0;
14324 ctxt->valueMax = 10;
14325 ctxt->value = NULL;
14326 ctxt->valueFrame = 0;
14327 }
14328 #ifdef XPATH_STREAMING
14329 if (ctxt->comp->stream) {
14330 int res;
14331
14332 if (toBool) {
14333 /*
14334 * Evaluation to boolean result.
14335 */
14336 res = xmlXPathRunStreamEval(ctxt->context,
14337 ctxt->comp->stream, NULL, 1);
14338 if (res != -1)
14339 return(res);
14340 } else {
14341 xmlXPathObjectPtr resObj = NULL;
14342
14343 /*
14344 * Evaluation to a sequence.
14345 */
14346 res = xmlXPathRunStreamEval(ctxt->context,
14347 ctxt->comp->stream, &resObj, 0);
14348
14349 if ((res != -1) && (resObj != NULL)) {
14350 valuePush(ctxt, resObj);
14351 return(0);
14352 }
14353 if (resObj != NULL)
14354 xmlXPathReleaseObject(ctxt->context, resObj);
14355 }
14356 /*
14357 * QUESTION TODO: This falls back to normal XPath evaluation
14358 * if res == -1. Is this intended?
14359 */
14360 }
14361 #endif
14362 comp = ctxt->comp;
14363 if (comp->last < 0) {
14364 xmlGenericError(xmlGenericErrorContext,
14365 "xmlXPathRunEval: last is less than zero\n");
14366 return(-1);
14367 }
14368 if (toBool)
14369 return(xmlXPathCompOpEvalToBoolean(ctxt,
14370 &comp->steps[comp->last], 0));
14371 else
14372 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14373
14374 return(0);
14375 }
14376
14377 /************************************************************************
14378 * *
14379 * Public interfaces *
14380 * *
14381 ************************************************************************/
14382
14383 /**
14384 * xmlXPathEvalPredicate:
14385 * @ctxt: the XPath context
14386 * @res: the Predicate Expression evaluation result
14387 *
14388 * Evaluate a predicate result for the current node.
14389 * A PredicateExpr is evaluated by evaluating the Expr and converting
14390 * the result to a boolean. If the result is a number, the result will
14391 * be converted to true if the number is equal to the position of the
14392 * context node in the context node list (as returned by the position
14393 * function) and will be converted to false otherwise; if the result
14394 * is not a number, then the result will be converted as if by a call
14395 * to the boolean function.
14396 *
14397 * Returns 1 if predicate is true, 0 otherwise
14398 */
14399 int
14400 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14401 if ((ctxt == NULL) || (res == NULL)) return(0);
14402 switch (res->type) {
14403 case XPATH_BOOLEAN:
14404 return(res->boolval);
14405 case XPATH_NUMBER:
14406 return(res->floatval == ctxt->proximityPosition);
14407 case XPATH_NODESET:
14408 case XPATH_XSLT_TREE:
14409 if (res->nodesetval == NULL)
14410 return(0);
14411 return(res->nodesetval->nodeNr != 0);
14412 case XPATH_STRING:
14413 return((res->stringval != NULL) &&
14414 (xmlStrlen(res->stringval) != 0));
14415 default:
14416 STRANGE
14417 }
14418 return(0);
14419 }
14420
14421 /**
14422 * xmlXPathEvaluatePredicateResult:
14423 * @ctxt: the XPath Parser context
14424 * @res: the Predicate Expression evaluation result
14425 *
14426 * Evaluate a predicate result for the current node.
14427 * A PredicateExpr is evaluated by evaluating the Expr and converting
14428 * the result to a boolean. If the result is a number, the result will
14429 * be converted to true if the number is equal to the position of the
14430 * context node in the context node list (as returned by the position
14431 * function) and will be converted to false otherwise; if the result
14432 * is not a number, then the result will be converted as if by a call
14433 * to the boolean function.
14434 *
14435 * Returns 1 if predicate is true, 0 otherwise
14436 */
14437 int
14438 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14439 xmlXPathObjectPtr res) {
14440 if ((ctxt == NULL) || (res == NULL)) return(0);
14441 switch (res->type) {
14442 case XPATH_BOOLEAN:
14443 return(res->boolval);
14444 case XPATH_NUMBER:
14445 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14446 return((res->floatval == ctxt->context->proximityPosition) &&
14447 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14448 #else
14449 return(res->floatval == ctxt->context->proximityPosition);
14450 #endif
14451 case XPATH_NODESET:
14452 case XPATH_XSLT_TREE:
14453 if (res->nodesetval == NULL)
14454 return(0);
14455 return(res->nodesetval->nodeNr != 0);
14456 case XPATH_STRING:
14457 return((res->stringval != NULL) && (res->stringval[0] != 0));
14458 #ifdef LIBXML_XPTR_ENABLED
14459 case XPATH_LOCATIONSET:{
14460 xmlLocationSetPtr ptr = res->user;
14461 if (ptr == NULL)
14462 return(0);
14463 return (ptr->locNr != 0);
14464 }
14465 #endif
14466 default:
14467 STRANGE
14468 }
14469 return(0);
14470 }
14471
14472 #ifdef XPATH_STREAMING
14473 /**
14474 * xmlXPathTryStreamCompile:
14475 * @ctxt: an XPath context
14476 * @str: the XPath expression
14477 *
14478 * Try to compile the XPath expression as a streamable subset.
14479 *
14480 * Returns the compiled expression or NULL if failed to compile.
14481 */
14482 static xmlXPathCompExprPtr
14483 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14484 /*
14485 * Optimization: use streaming patterns when the XPath expression can
14486 * be compiled to a stream lookup
14487 */
14488 xmlPatternPtr stream;
14489 xmlXPathCompExprPtr comp;
14490 xmlDictPtr dict = NULL;
14491 const xmlChar **namespaces = NULL;
14492 xmlNsPtr ns;
14493 int i, j;
14494
14495 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14496 (!xmlStrchr(str, '@'))) {
14497 const xmlChar *tmp;
14498
14499 /*
14500 * We don't try to handle expressions using the verbose axis
14501 * specifiers ("::"), just the simplied form at this point.
14502 * Additionally, if there is no list of namespaces available and
14503 * there's a ":" in the expression, indicating a prefixed QName,
14504 * then we won't try to compile either. xmlPatterncompile() needs
14505 * to have a list of namespaces at compilation time in order to
14506 * compile prefixed name tests.
14507 */
14508 tmp = xmlStrchr(str, ':');
14509 if ((tmp != NULL) &&
14510 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14511 return(NULL);
14512
14513 if (ctxt != NULL) {
14514 dict = ctxt->dict;
14515 if (ctxt->nsNr > 0) {
14516 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14517 if (namespaces == NULL) {
14518 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14519 return(NULL);
14520 }
14521 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14522 ns = ctxt->namespaces[j];
14523 namespaces[i++] = ns->href;
14524 namespaces[i++] = ns->prefix;
14525 }
14526 namespaces[i++] = NULL;
14527 namespaces[i] = NULL;
14528 }
14529 }
14530
14531 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14532 &namespaces[0]);
14533 if (namespaces != NULL) {
14534 xmlFree((xmlChar **)namespaces);
14535 }
14536 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14537 comp = xmlXPathNewCompExpr();
14538 if (comp == NULL) {
14539 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14540 return(NULL);
14541 }
14542 comp->stream = stream;
14543 comp->dict = dict;
14544 if (comp->dict)
14545 xmlDictReference(comp->dict);
14546 return(comp);
14547 }
14548 xmlFreePattern(stream);
14549 }
14550 return(NULL);
14551 }
14552 #endif /* XPATH_STREAMING */
14553
14554 static void
14555 xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14556 {
14557 /*
14558 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14559 * internal representation.
14560 */
14561
14562 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14563 (op->ch1 != -1) &&
14564 (op->ch2 == -1 /* no predicate */))
14565 {
14566 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14567
14568 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14569 ((xmlXPathAxisVal) prevop->value ==
14570 AXIS_DESCENDANT_OR_SELF) &&
14571 (prevop->ch2 == -1) &&
14572 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14573 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14574 {
14575 /*
14576 * This is a "descendant-or-self::node()" without predicates.
14577 * Try to eliminate it.
14578 */
14579
14580 switch ((xmlXPathAxisVal) op->value) {
14581 case AXIS_CHILD:
14582 case AXIS_DESCENDANT:
14583 /*
14584 * Convert "descendant-or-self::node()/child::" or
14585 * "descendant-or-self::node()/descendant::" to
14586 * "descendant::"
14587 */
14588 op->ch1 = prevop->ch1;
14589 op->value = AXIS_DESCENDANT;
14590 break;
14591 case AXIS_SELF:
14592 case AXIS_DESCENDANT_OR_SELF:
14593 /*
14594 * Convert "descendant-or-self::node()/self::" or
14595 * "descendant-or-self::node()/descendant-or-self::" to
14596 * to "descendant-or-self::"
14597 */
14598 op->ch1 = prevop->ch1;
14599 op->value = AXIS_DESCENDANT_OR_SELF;
14600 break;
14601 default:
14602 break;
14603 }
14604 }
14605 }
14606
14607 /* OP_VALUE has invalid ch1. */
14608 if (op->op == XPATH_OP_VALUE)
14609 return;
14610
14611 /* Recurse */
14612 if (op->ch1 != -1)
14613 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
14614 if (op->ch2 != -1)
14615 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
14616 }
14617
14618 /**
14619 * xmlXPathCtxtCompile:
14620 * @ctxt: an XPath context
14621 * @str: the XPath expression
14622 *
14623 * Compile an XPath expression
14624 *
14625 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14626 * the caller has to free the object.
14627 */
14628 xmlXPathCompExprPtr
14629 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14630 xmlXPathParserContextPtr pctxt;
14631 xmlXPathCompExprPtr comp;
14632
14633 #ifdef XPATH_STREAMING
14634 comp = xmlXPathTryStreamCompile(ctxt, str);
14635 if (comp != NULL)
14636 return(comp);
14637 #endif
14638
14639 xmlXPathInit();
14640
14641 pctxt = xmlXPathNewParserContext(str, ctxt);
14642 if (pctxt == NULL)
14643 return NULL;
14644 xmlXPathCompileExpr(pctxt, 1);
14645
14646 if( pctxt->error != XPATH_EXPRESSION_OK )
14647 {
14648 xmlXPathFreeParserContext(pctxt);
14649 return(NULL);
14650 }
14651
14652 if (*pctxt->cur != 0) {
14653 /*
14654 * aleksey: in some cases this line prints *second* error message
14655 * (see bug #78858) and probably this should be fixed.
14656 * However, we are not sure that all error messages are printed
14657 * out in other places. It's not critical so we leave it as-is for now
14658 */
14659 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14660 comp = NULL;
14661 } else {
14662 comp = pctxt->comp;
14663 pctxt->comp = NULL;
14664 }
14665 xmlXPathFreeParserContext(pctxt);
14666
14667 if (comp != NULL) {
14668 comp->expr = xmlStrdup(str);
14669 #ifdef DEBUG_EVAL_COUNTS
14670 comp->string = xmlStrdup(str);
14671 comp->nb = 0;
14672 #endif
14673 if ((comp->nbStep > 1) && (comp->last >= 0)) {
14674 xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
14675 }
14676 }
14677 return(comp);
14678 }
14679
14680 /**
14681 * xmlXPathCompile:
14682 * @str: the XPath expression
14683 *
14684 * Compile an XPath expression
14685 *
14686 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14687 * the caller has to free the object.
14688 */
14689 xmlXPathCompExprPtr
14690 xmlXPathCompile(const xmlChar *str) {
14691 return(xmlXPathCtxtCompile(NULL, str));
14692 }
14693
14694 /**
14695 * xmlXPathCompiledEvalInternal:
14696 * @comp: the compiled XPath expression
14697 * @ctxt: the XPath context
14698 * @resObj: the resulting XPath object or NULL
14699 * @toBool: 1 if only a boolean result is requested
14700 *
14701 * Evaluate the Precompiled XPath expression in the given context.
14702 * The caller has to free @resObj.
14703 *
14704 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14705 * the caller has to free the object.
14706 */
14707 static int
14708 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14709 xmlXPathContextPtr ctxt,
14710 xmlXPathObjectPtr *resObjPtr,
14711 int toBool)
14712 {
14713 xmlXPathParserContextPtr pctxt;
14714 xmlXPathObjectPtr resObj;
14715 #ifndef LIBXML_THREAD_ENABLED
14716 static int reentance = 0;
14717 #endif
14718 int res;
14719
14720 CHECK_CTXT_NEG(ctxt)
14721
14722 if (comp == NULL)
14723 return(-1);
14724 xmlXPathInit();
14725
14726 #ifndef LIBXML_THREAD_ENABLED
14727 reentance++;
14728 if (reentance > 1)
14729 xmlXPathDisableOptimizer = 1;
14730 #endif
14731
14732 #ifdef DEBUG_EVAL_COUNTS
14733 comp->nb++;
14734 if ((comp->string != NULL) && (comp->nb > 100)) {
14735 fprintf(stderr, "100 x %s\n", comp->string);
14736 comp->nb = 0;
14737 }
14738 #endif
14739 pctxt = xmlXPathCompParserContext(comp, ctxt);
14740 res = xmlXPathRunEval(pctxt, toBool);
14741
14742 if (pctxt->error != XPATH_EXPRESSION_OK) {
14743 resObj = NULL;
14744 } else {
14745 resObj = valuePop(pctxt);
14746 if (resObj == NULL) {
14747 if (!toBool)
14748 xmlGenericError(xmlGenericErrorContext,
14749 "xmlXPathCompiledEval: No result on the stack.\n");
14750 } else if (pctxt->valueNr > 0) {
14751 xmlGenericError(xmlGenericErrorContext,
14752 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14753 pctxt->valueNr);
14754 }
14755 }
14756
14757 if (resObjPtr)
14758 *resObjPtr = resObj;
14759 else
14760 xmlXPathReleaseObject(ctxt, resObj);
14761
14762 pctxt->comp = NULL;
14763 xmlXPathFreeParserContext(pctxt);
14764 #ifndef LIBXML_THREAD_ENABLED
14765 reentance--;
14766 #endif
14767
14768 return(res);
14769 }
14770
14771 /**
14772 * xmlXPathCompiledEval:
14773 * @comp: the compiled XPath expression
14774 * @ctx: the XPath context
14775 *
14776 * Evaluate the Precompiled XPath expression in the given context.
14777 *
14778 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14779 * the caller has to free the object.
14780 */
14781 xmlXPathObjectPtr
14782 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14783 {
14784 xmlXPathObjectPtr res = NULL;
14785
14786 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14787 return(res);
14788 }
14789
14790 /**
14791 * xmlXPathCompiledEvalToBoolean:
14792 * @comp: the compiled XPath expression
14793 * @ctxt: the XPath context
14794 *
14795 * Applies the XPath boolean() function on the result of the given
14796 * compiled expression.
14797 *
14798 * Returns 1 if the expression evaluated to true, 0 if to false and
14799 * -1 in API and internal errors.
14800 */
14801 int
14802 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14803 xmlXPathContextPtr ctxt)
14804 {
14805 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14806 }
14807
14808 /**
14809 * xmlXPathEvalExpr:
14810 * @ctxt: the XPath Parser context
14811 *
14812 * Parse and evaluate an XPath expression in the given context,
14813 * then push the result on the context stack
14814 */
14815 void
14816 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14817 #ifdef XPATH_STREAMING
14818 xmlXPathCompExprPtr comp;
14819 #endif
14820
14821 if (ctxt == NULL) return;
14822
14823 #ifdef XPATH_STREAMING
14824 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14825 if (comp != NULL) {
14826 if (ctxt->comp != NULL)
14827 xmlXPathFreeCompExpr(ctxt->comp);
14828 ctxt->comp = comp;
14829 } else
14830 #endif
14831 {
14832 xmlXPathCompileExpr(ctxt, 1);
14833 CHECK_ERROR;
14834
14835 /* Check for trailing characters. */
14836 if (*ctxt->cur != 0)
14837 XP_ERROR(XPATH_EXPR_ERROR);
14838
14839 if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0))
14840 xmlXPathOptimizeExpression(ctxt->comp,
14841 &ctxt->comp->steps[ctxt->comp->last]);
14842 }
14843
14844 xmlXPathRunEval(ctxt, 0);
14845 }
14846
14847 /**
14848 * xmlXPathEval:
14849 * @str: the XPath expression
14850 * @ctx: the XPath context
14851 *
14852 * Evaluate the XPath Location Path in the given context.
14853 *
14854 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14855 * the caller has to free the object.
14856 */
14857 xmlXPathObjectPtr
14858 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14859 xmlXPathParserContextPtr ctxt;
14860 xmlXPathObjectPtr res;
14861
14862 CHECK_CTXT(ctx)
14863
14864 xmlXPathInit();
14865
14866 ctxt = xmlXPathNewParserContext(str, ctx);
14867 if (ctxt == NULL)
14868 return NULL;
14869 xmlXPathEvalExpr(ctxt);
14870
14871 if (ctxt->error != XPATH_EXPRESSION_OK) {
14872 res = NULL;
14873 } else {
14874 res = valuePop(ctxt);
14875 if (res == NULL) {
14876 xmlGenericError(xmlGenericErrorContext,
14877 "xmlXPathCompiledEval: No result on the stack.\n");
14878 } else if (ctxt->valueNr > 0) {
14879 xmlGenericError(xmlGenericErrorContext,
14880 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14881 ctxt->valueNr);
14882 }
14883 }
14884
14885 xmlXPathFreeParserContext(ctxt);
14886 return(res);
14887 }
14888
14889 /**
14890 * xmlXPathSetContextNode:
14891 * @node: the node to to use as the context node
14892 * @ctx: the XPath context
14893 *
14894 * Sets 'node' as the context node. The node must be in the same
14895 * document as that associated with the context.
14896 *
14897 * Returns -1 in case of error or 0 if successful
14898 */
14899 int
14900 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
14901 if ((node == NULL) || (ctx == NULL))
14902 return(-1);
14903
14904 if (node->doc == ctx->doc) {
14905 ctx->node = node;
14906 return(0);
14907 }
14908 return(-1);
14909 }
14910
14911 /**
14912 * xmlXPathNodeEval:
14913 * @node: the node to to use as the context node
14914 * @str: the XPath expression
14915 * @ctx: the XPath context
14916 *
14917 * Evaluate the XPath Location Path in the given context. The node 'node'
14918 * is set as the context node. The context node is not restored.
14919 *
14920 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14921 * the caller has to free the object.
14922 */
14923 xmlXPathObjectPtr
14924 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
14925 if (str == NULL)
14926 return(NULL);
14927 if (xmlXPathSetContextNode(node, ctx) < 0)
14928 return(NULL);
14929 return(xmlXPathEval(str, ctx));
14930 }
14931
14932 /**
14933 * xmlXPathEvalExpression:
14934 * @str: the XPath expression
14935 * @ctxt: the XPath context
14936 *
14937 * Alias for xmlXPathEval().
14938 *
14939 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14940 * the caller has to free the object.
14941 */
14942 xmlXPathObjectPtr
14943 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14944 return(xmlXPathEval(str, ctxt));
14945 }
14946
14947 /************************************************************************
14948 * *
14949 * Extra functions not pertaining to the XPath spec *
14950 * *
14951 ************************************************************************/
14952 /**
14953 * xmlXPathEscapeUriFunction:
14954 * @ctxt: the XPath Parser context
14955 * @nargs: the number of arguments
14956 *
14957 * Implement the escape-uri() XPath function
14958 * string escape-uri(string $str, bool $escape-reserved)
14959 *
14960 * This function applies the URI escaping rules defined in section 2 of [RFC
14961 * 2396] to the string supplied as $uri-part, which typically represents all
14962 * or part of a URI. The effect of the function is to replace any special
14963 * character in the string by an escape sequence of the form %xx%yy...,
14964 * where xxyy... is the hexadecimal representation of the octets used to
14965 * represent the character in UTF-8.
14966 *
14967 * The set of characters that are escaped depends on the setting of the
14968 * boolean argument $escape-reserved.
14969 *
14970 * If $escape-reserved is true, all characters are escaped other than lower
14971 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14972 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14973 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14974 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14975 * A-F).
14976 *
14977 * If $escape-reserved is false, the behavior differs in that characters
14978 * referred to in [RFC 2396] as reserved characters are not escaped. These
14979 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14980 *
14981 * [RFC 2396] does not define whether escaped URIs should use lower case or
14982 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14983 * compared using string comparison functions, this function must always use
14984 * the upper-case letters A-F.
14985 *
14986 * Generally, $escape-reserved should be set to true when escaping a string
14987 * that is to form a single part of a URI, and to false when escaping an
14988 * entire URI or URI reference.
14989 *
14990 * In the case of non-ascii characters, the string is encoded according to
14991 * utf-8 and then converted according to RFC 2396.
14992 *
14993 * Examples
14994 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14995 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14996 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14997 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14998 *
14999 */
15000 static void
15001 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15002 xmlXPathObjectPtr str;
15003 int escape_reserved;
15004 xmlBufPtr target;
15005 xmlChar *cptr;
15006 xmlChar escape[4];
15007
15008 CHECK_ARITY(2);
15009
15010 escape_reserved = xmlXPathPopBoolean(ctxt);
15011
15012 CAST_TO_STRING;
15013 str = valuePop(ctxt);
15014
15015 target = xmlBufCreate();
15016
15017 escape[0] = '%';
15018 escape[3] = 0;
15019
15020 if (target) {
15021 for (cptr = str->stringval; *cptr; cptr++) {
15022 if ((*cptr >= 'A' && *cptr <= 'Z') ||
15023 (*cptr >= 'a' && *cptr <= 'z') ||
15024 (*cptr >= '0' && *cptr <= '9') ||
15025 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
15026 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
15027 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
15028 (*cptr == '%' &&
15029 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15030 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15031 (cptr[1] >= '0' && cptr[1] <= '9')) &&
15032 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15033 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15034 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15035 (!escape_reserved &&
15036 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15037 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15038 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15039 *cptr == ','))) {
15040 xmlBufAdd(target, cptr, 1);
15041 } else {
15042 if ((*cptr >> 4) < 10)
15043 escape[1] = '0' + (*cptr >> 4);
15044 else
15045 escape[1] = 'A' - 10 + (*cptr >> 4);
15046 if ((*cptr & 0xF) < 10)
15047 escape[2] = '0' + (*cptr & 0xF);
15048 else
15049 escape[2] = 'A' - 10 + (*cptr & 0xF);
15050
15051 xmlBufAdd(target, &escape[0], 3);
15052 }
15053 }
15054 }
15055 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15056 xmlBufContent(target)));
15057 xmlBufFree(target);
15058 xmlXPathReleaseObject(ctxt->context, str);
15059 }
15060
15061 /**
15062 * xmlXPathRegisterAllFunctions:
15063 * @ctxt: the XPath context
15064 *
15065 * Registers all default XPath functions in this context
15066 */
15067 void
15068 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15069 {
15070 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15071 xmlXPathBooleanFunction);
15072 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15073 xmlXPathCeilingFunction);
15074 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15075 xmlXPathCountFunction);
15076 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15077 xmlXPathConcatFunction);
15078 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15079 xmlXPathContainsFunction);
15080 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15081 xmlXPathIdFunction);
15082 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15083 xmlXPathFalseFunction);
15084 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15085 xmlXPathFloorFunction);
15086 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15087 xmlXPathLastFunction);
15088 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15089 xmlXPathLangFunction);
15090 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15091 xmlXPathLocalNameFunction);
15092 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15093 xmlXPathNotFunction);
15094 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15095 xmlXPathNameFunction);
15096 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15097 xmlXPathNamespaceURIFunction);
15098 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15099 xmlXPathNormalizeFunction);
15100 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15101 xmlXPathNumberFunction);
15102 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15103 xmlXPathPositionFunction);
15104 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15105 xmlXPathRoundFunction);
15106 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15107 xmlXPathStringFunction);
15108 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15109 xmlXPathStringLengthFunction);
15110 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15111 xmlXPathStartsWithFunction);
15112 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15113 xmlXPathSubstringFunction);
15114 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15115 xmlXPathSubstringBeforeFunction);
15116 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15117 xmlXPathSubstringAfterFunction);
15118 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15119 xmlXPathSumFunction);
15120 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15121 xmlXPathTrueFunction);
15122 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15123 xmlXPathTranslateFunction);
15124
15125 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15126 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15127 xmlXPathEscapeUriFunction);
15128 }
15129
15130 #endif /* LIBXML_XPATH_ENABLED */
15131 #define bottom_xpath
15132 #include "elfgcchack.h"