- DBGKD_WAIT_STATE_CHANGE64 is used in KD protocol 5, not number 6 that we use. Proto...
[reactos.git] / reactos / lib / 3rdparty / libxml2 / xpath.c
1 /*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
5 *f
6 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
11 * See Copyright for the status of this software
12 *
13 * Author: daniel@veillard.com
14 *
15 */
16
17 #define IN_LIBXML
18 #include "libxml.h"
19
20 #include <string.h>
21
22 #ifdef HAVE_SYS_TYPES_H
23 #include <sys/types.h>
24 #endif
25 #ifdef HAVE_MATH_H
26 #include <math.h>
27 #endif
28 #ifdef HAVE_FLOAT_H
29 #include <float.h>
30 #endif
31 #ifdef HAVE_CTYPE_H
32 #include <ctype.h>
33 #endif
34 #ifdef HAVE_SIGNAL_H
35 #include <signal.h>
36 #endif
37
38 #include <libxml/xmlmemory.h>
39 #include <libxml/tree.h>
40 #include <libxml/valid.h>
41 #include <libxml/xpath.h>
42 #include <libxml/xpathInternals.h>
43 #include <libxml/parserInternals.h>
44 #include <libxml/hash.h>
45 #ifdef LIBXML_XPTR_ENABLED
46 #include <libxml/xpointer.h>
47 #endif
48 #ifdef LIBXML_DEBUG_ENABLED
49 #include <libxml/debugXML.h>
50 #endif
51 #include <libxml/xmlerror.h>
52 #include <libxml/threads.h>
53 #include <libxml/globals.h>
54 #ifdef LIBXML_PATTERN_ENABLED
55 #include <libxml/pattern.h>
56 #endif
57
58 #ifdef LIBXML_PATTERN_ENABLED
59 #define XPATH_STREAMING
60 #endif
61
62 #define TODO \
63 xmlGenericError(xmlGenericErrorContext, \
64 "Unimplemented block at %s:%d\n", \
65 __FILE__, __LINE__);
66
67 /*
68 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
69 * If defined, this will use xmlXPathCmpNodesExt() instead of
70 * xmlXPathCmpNodes(). The new function is optimized comparison of
71 * non-element nodes; actually it will speed up comparison only if
72 * xmlXPathOrderDocElems() was called in order to index the elements of
73 * a tree in document order; Libxslt does such an indexing, thus it will
74 * benefit from this optimization.
75 */
76 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
77
78 /*
79 * XP_OPTIMIZED_FILTER_FIRST:
80 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
81 * in a way, that it stop evaluation at the first node.
82 */
83 #define XP_OPTIMIZED_FILTER_FIRST
84
85 /*
86 * XP_DEBUG_OBJ_USAGE:
87 * Internal flag to enable tracking of how much XPath objects have been
88 * created.
89 */
90 /* #define XP_DEBUG_OBJ_USAGE */
91
92 /*
93 * TODO:
94 * There are a few spots where some tests are done which depend upon ascii
95 * data. These should be enhanced for full UTF8 support (see particularly
96 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
97 */
98
99 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
100
101 /************************************************************************
102 * *
103 * Floating point stuff *
104 * *
105 ************************************************************************/
106
107 #ifndef TRIO_REPLACE_STDIO
108 #define TRIO_PUBLIC static
109 #endif
110 #include "trionan.c"
111
112 /*
113 * The lack of portability of this section of the libc is annoying !
114 */
115 double xmlXPathNAN = 0;
116 double xmlXPathPINF = 1;
117 double xmlXPathNINF = -1;
118 static double xmlXPathNZERO = 0; /* not exported from headers */
119 static int xmlXPathInitialized = 0;
120
121 /**
122 * xmlXPathInit:
123 *
124 * Initialize the XPath environment
125 */
126 void
127 xmlXPathInit(void) {
128 if (xmlXPathInitialized) return;
129
130 xmlXPathPINF = trio_pinf();
131 xmlXPathNINF = trio_ninf();
132 xmlXPathNAN = trio_nan();
133 xmlXPathNZERO = trio_nzero();
134
135 xmlXPathInitialized = 1;
136 }
137
138 /**
139 * xmlXPathIsNaN:
140 * @val: a double value
141 *
142 * Provides a portable isnan() function to detect whether a double
143 * is a NotaNumber. Based on trio code
144 * http://sourceforge.net/projects/ctrio/
145 *
146 * Returns 1 if the value is a NaN, 0 otherwise
147 */
148 int
149 xmlXPathIsNaN(double val) {
150 return(trio_isnan(val));
151 }
152
153 /**
154 * xmlXPathIsInf:
155 * @val: a double value
156 *
157 * Provides a portable isinf() function to detect whether a double
158 * is a +Infinite or -Infinite. Based on trio code
159 * http://sourceforge.net/projects/ctrio/
160 *
161 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
162 */
163 int
164 xmlXPathIsInf(double val) {
165 return(trio_isinf(val));
166 }
167
168 #endif /* SCHEMAS or XPATH */
169 #ifdef LIBXML_XPATH_ENABLED
170 /**
171 * xmlXPathGetSign:
172 * @val: a double value
173 *
174 * Provides a portable function to detect the sign of a double
175 * Modified from trio code
176 * http://sourceforge.net/projects/ctrio/
177 *
178 * Returns 1 if the value is Negative, 0 if positive
179 */
180 static int
181 xmlXPathGetSign(double val) {
182 return(trio_signbit(val));
183 }
184
185
186 /*
187 * TODO: when compatibility allows remove all "fake node libxslt" strings
188 * the test should just be name[0] = ' '
189 */
190 #ifdef DEBUG_XPATH_EXPRESSION
191 #define DEBUG_STEP
192 #define DEBUG_EXPR
193 #define DEBUG_EVAL_COUNTS
194 #endif
195
196 static xmlNs xmlXPathXMLNamespaceStruct = {
197 NULL,
198 XML_NAMESPACE_DECL,
199 XML_XML_NAMESPACE,
200 BAD_CAST "xml",
201 NULL,
202 NULL
203 };
204 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
205 #ifndef LIBXML_THREAD_ENABLED
206 /*
207 * Optimizer is disabled only when threaded apps are detected while
208 * the library ain't compiled for thread safety.
209 */
210 static int xmlXPathDisableOptimizer = 0;
211 #endif
212
213 /************************************************************************
214 * *
215 * Error handling routines *
216 * *
217 ************************************************************************/
218
219 /**
220 * XP_ERRORNULL:
221 * @X: the error code
222 *
223 * Macro to raise an XPath error and return NULL.
224 */
225 #define XP_ERRORNULL(X) \
226 { xmlXPathErr(ctxt, X); return(NULL); }
227
228 /*
229 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
230 */
231 static const char *xmlXPathErrorMessages[] = {
232 "Ok\n",
233 "Number encoding\n",
234 "Unfinished literal\n",
235 "Start of literal\n",
236 "Expected $ for variable reference\n",
237 "Undefined variable\n",
238 "Invalid predicate\n",
239 "Invalid expression\n",
240 "Missing closing curly brace\n",
241 "Unregistered function\n",
242 "Invalid operand\n",
243 "Invalid type\n",
244 "Invalid number of arguments\n",
245 "Invalid context size\n",
246 "Invalid context position\n",
247 "Memory allocation error\n",
248 "Syntax error\n",
249 "Resource error\n",
250 "Sub resource error\n",
251 "Undefined namespace prefix\n",
252 "Encoding error\n",
253 "Char out of XML range\n",
254 "Invalid or incomplete context\n",
255 "?? Unknown error ??\n" /* Must be last in the list! */
256 };
257 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
258 sizeof(xmlXPathErrorMessages[0])) - 1)
259 /**
260 * xmlXPathErrMemory:
261 * @ctxt: an XPath context
262 * @extra: extra informations
263 *
264 * Handle a redefinition of attribute error
265 */
266 static void
267 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
268 {
269 if (ctxt != NULL) {
270 if (extra) {
271 xmlChar buf[200];
272
273 xmlStrPrintf(buf, 200,
274 BAD_CAST "Memory allocation failed : %s\n",
275 extra);
276 ctxt->lastError.message = (char *) xmlStrdup(buf);
277 } else {
278 ctxt->lastError.message = (char *)
279 xmlStrdup(BAD_CAST "Memory allocation failed\n");
280 }
281 ctxt->lastError.domain = XML_FROM_XPATH;
282 ctxt->lastError.code = XML_ERR_NO_MEMORY;
283 if (ctxt->error != NULL)
284 ctxt->error(ctxt->userData, &ctxt->lastError);
285 } else {
286 if (extra)
287 __xmlRaiseError(NULL, NULL, NULL,
288 NULL, NULL, XML_FROM_XPATH,
289 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
290 extra, NULL, NULL, 0, 0,
291 "Memory allocation failed : %s\n", extra);
292 else
293 __xmlRaiseError(NULL, NULL, NULL,
294 NULL, NULL, XML_FROM_XPATH,
295 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
296 NULL, NULL, NULL, 0, 0,
297 "Memory allocation failed\n");
298 }
299 }
300
301 /**
302 * xmlXPathPErrMemory:
303 * @ctxt: an XPath parser context
304 * @extra: extra informations
305 *
306 * Handle a redefinition of attribute error
307 */
308 static void
309 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
310 {
311 if (ctxt == NULL)
312 xmlXPathErrMemory(NULL, extra);
313 else {
314 ctxt->error = XPATH_MEMORY_ERROR;
315 xmlXPathErrMemory(ctxt->context, extra);
316 }
317 }
318
319 /**
320 * xmlXPathErr:
321 * @ctxt: a XPath parser context
322 * @error: the error code
323 *
324 * Handle an XPath error
325 */
326 void
327 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
328 {
329 if ((error < 0) || (error > MAXERRNO))
330 error = MAXERRNO;
331 if (ctxt == NULL) {
332 __xmlRaiseError(NULL, NULL, NULL,
333 NULL, NULL, XML_FROM_XPATH,
334 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
335 XML_ERR_ERROR, NULL, 0,
336 NULL, NULL, NULL, 0, 0,
337 "%s", xmlXPathErrorMessages[error]);
338 return;
339 }
340 ctxt->error = error;
341 if (ctxt->context == NULL) {
342 __xmlRaiseError(NULL, NULL, NULL,
343 NULL, NULL, XML_FROM_XPATH,
344 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
345 XML_ERR_ERROR, NULL, 0,
346 (const char *) ctxt->base, NULL, NULL,
347 ctxt->cur - ctxt->base, 0,
348 "%s", xmlXPathErrorMessages[error]);
349 return;
350 }
351
352 /* cleanup current last error */
353 xmlResetError(&ctxt->context->lastError);
354
355 ctxt->context->lastError.domain = XML_FROM_XPATH;
356 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
357 XPATH_EXPRESSION_OK;
358 ctxt->context->lastError.level = XML_ERR_ERROR;
359 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
360 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
361 ctxt->context->lastError.node = ctxt->context->debugNode;
362 if (ctxt->context->error != NULL) {
363 ctxt->context->error(ctxt->context->userData,
364 &ctxt->context->lastError);
365 } else {
366 __xmlRaiseError(NULL, NULL, NULL,
367 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
368 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
369 XML_ERR_ERROR, NULL, 0,
370 (const char *) ctxt->base, NULL, NULL,
371 ctxt->cur - ctxt->base, 0,
372 "%s", xmlXPathErrorMessages[error]);
373 }
374
375 }
376
377 /**
378 * xmlXPatherror:
379 * @ctxt: the XPath Parser context
380 * @file: the file name
381 * @line: the line number
382 * @no: the error number
383 *
384 * Formats an error message.
385 */
386 void
387 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
388 int line ATTRIBUTE_UNUSED, int no) {
389 xmlXPathErr(ctxt, no);
390 }
391
392 /************************************************************************
393 * *
394 * Utilities *
395 * *
396 ************************************************************************/
397
398 /**
399 * xsltPointerList:
400 *
401 * Pointer-list for various purposes.
402 */
403 typedef struct _xmlPointerList xmlPointerList;
404 typedef xmlPointerList *xmlPointerListPtr;
405 struct _xmlPointerList {
406 void **items;
407 int number;
408 int size;
409 };
410 /*
411 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
412 * and here, we should make the functions public.
413 */
414 static int
415 xmlPointerListAddSize(xmlPointerListPtr list,
416 void *item,
417 int initialSize)
418 {
419 if (list->items == NULL) {
420 if (initialSize <= 0)
421 initialSize = 1;
422 list->items = (void **) xmlMalloc(
423 initialSize * sizeof(void *));
424 if (list->items == NULL) {
425 xmlXPathErrMemory(NULL,
426 "xmlPointerListCreate: allocating item\n");
427 return(-1);
428 }
429 list->number = 0;
430 list->size = initialSize;
431 } else if (list->size <= list->number) {
432 list->size *= 2;
433 list->items = (void **) xmlRealloc(list->items,
434 list->size * sizeof(void *));
435 if (list->items == NULL) {
436 xmlXPathErrMemory(NULL,
437 "xmlPointerListCreate: re-allocating item\n");
438 list->size = 0;
439 return(-1);
440 }
441 }
442 list->items[list->number++] = item;
443 return(0);
444 }
445
446 /**
447 * xsltPointerListCreate:
448 *
449 * Creates an xsltPointerList structure.
450 *
451 * Returns a xsltPointerList structure or NULL in case of an error.
452 */
453 static xmlPointerListPtr
454 xmlPointerListCreate(int initialSize)
455 {
456 xmlPointerListPtr ret;
457
458 ret = xmlMalloc(sizeof(xmlPointerList));
459 if (ret == NULL) {
460 xmlXPathErrMemory(NULL,
461 "xmlPointerListCreate: allocating item\n");
462 return (NULL);
463 }
464 memset(ret, 0, sizeof(xmlPointerList));
465 if (initialSize > 0) {
466 xmlPointerListAddSize(ret, NULL, initialSize);
467 ret->number = 0;
468 }
469 return (ret);
470 }
471
472 /**
473 * xsltPointerListFree:
474 *
475 * Frees the xsltPointerList structure. This does not free
476 * the content of the list.
477 */
478 static void
479 xmlPointerListFree(xmlPointerListPtr list)
480 {
481 if (list == NULL)
482 return;
483 if (list->items != NULL)
484 xmlFree(list->items);
485 xmlFree(list);
486 }
487
488 /************************************************************************
489 * *
490 * Parser Types *
491 * *
492 ************************************************************************/
493
494 /*
495 * Types are private:
496 */
497
498 typedef enum {
499 XPATH_OP_END=0,
500 XPATH_OP_AND,
501 XPATH_OP_OR,
502 XPATH_OP_EQUAL,
503 XPATH_OP_CMP,
504 XPATH_OP_PLUS,
505 XPATH_OP_MULT,
506 XPATH_OP_UNION,
507 XPATH_OP_ROOT,
508 XPATH_OP_NODE,
509 XPATH_OP_RESET, /* 10 */
510 XPATH_OP_COLLECT,
511 XPATH_OP_VALUE, /* 12 */
512 XPATH_OP_VARIABLE,
513 XPATH_OP_FUNCTION,
514 XPATH_OP_ARG,
515 XPATH_OP_PREDICATE,
516 XPATH_OP_FILTER, /* 17 */
517 XPATH_OP_SORT /* 18 */
518 #ifdef LIBXML_XPTR_ENABLED
519 ,XPATH_OP_RANGETO
520 #endif
521 } xmlXPathOp;
522
523 typedef enum {
524 AXIS_ANCESTOR = 1,
525 AXIS_ANCESTOR_OR_SELF,
526 AXIS_ATTRIBUTE,
527 AXIS_CHILD,
528 AXIS_DESCENDANT,
529 AXIS_DESCENDANT_OR_SELF,
530 AXIS_FOLLOWING,
531 AXIS_FOLLOWING_SIBLING,
532 AXIS_NAMESPACE,
533 AXIS_PARENT,
534 AXIS_PRECEDING,
535 AXIS_PRECEDING_SIBLING,
536 AXIS_SELF
537 } xmlXPathAxisVal;
538
539 typedef enum {
540 NODE_TEST_NONE = 0,
541 NODE_TEST_TYPE = 1,
542 NODE_TEST_PI = 2,
543 NODE_TEST_ALL = 3,
544 NODE_TEST_NS = 4,
545 NODE_TEST_NAME = 5
546 } xmlXPathTestVal;
547
548 typedef enum {
549 NODE_TYPE_NODE = 0,
550 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
551 NODE_TYPE_TEXT = XML_TEXT_NODE,
552 NODE_TYPE_PI = XML_PI_NODE
553 } xmlXPathTypeVal;
554
555 #define XP_REWRITE_DOS_CHILD_ELEM 1
556
557 typedef struct _xmlXPathStepOp xmlXPathStepOp;
558 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
559 struct _xmlXPathStepOp {
560 xmlXPathOp op; /* The identifier of the operation */
561 int ch1; /* First child */
562 int ch2; /* Second child */
563 int value;
564 int value2;
565 int value3;
566 void *value4;
567 void *value5;
568 void *cache;
569 void *cacheURI;
570 int rewriteType;
571 };
572
573 struct _xmlXPathCompExpr {
574 int nbStep; /* Number of steps in this expression */
575 int maxStep; /* Maximum number of steps allocated */
576 xmlXPathStepOp *steps; /* ops for computation of this expression */
577 int last; /* index of last step in expression */
578 xmlChar *expr; /* the expression being computed */
579 xmlDictPtr dict; /* the dictionnary to use if any */
580 #ifdef DEBUG_EVAL_COUNTS
581 int nb;
582 xmlChar *string;
583 #endif
584 #ifdef XPATH_STREAMING
585 xmlPatternPtr stream;
586 #endif
587 };
588
589 /************************************************************************
590 * *
591 * Forward declarations *
592 * *
593 ************************************************************************/
594 static void
595 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
596 static void
597 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
598 static int
599 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
600 xmlXPathStepOpPtr op, xmlNodePtr *first);
601 static int
602 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
603 xmlXPathStepOpPtr op,
604 int isPredicate);
605
606 /************************************************************************
607 * *
608 * Parser Type functions *
609 * *
610 ************************************************************************/
611
612 /**
613 * xmlXPathNewCompExpr:
614 *
615 * Create a new Xpath component
616 *
617 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
618 */
619 static xmlXPathCompExprPtr
620 xmlXPathNewCompExpr(void) {
621 xmlXPathCompExprPtr cur;
622
623 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
624 if (cur == NULL) {
625 xmlXPathErrMemory(NULL, "allocating component\n");
626 return(NULL);
627 }
628 memset(cur, 0, sizeof(xmlXPathCompExpr));
629 cur->maxStep = 10;
630 cur->nbStep = 0;
631 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
632 sizeof(xmlXPathStepOp));
633 if (cur->steps == NULL) {
634 xmlXPathErrMemory(NULL, "allocating steps\n");
635 xmlFree(cur);
636 return(NULL);
637 }
638 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
639 cur->last = -1;
640 #ifdef DEBUG_EVAL_COUNTS
641 cur->nb = 0;
642 #endif
643 return(cur);
644 }
645
646 /**
647 * xmlXPathFreeCompExpr:
648 * @comp: an XPATH comp
649 *
650 * Free up the memory allocated by @comp
651 */
652 void
653 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
654 {
655 xmlXPathStepOpPtr op;
656 int i;
657
658 if (comp == NULL)
659 return;
660 if (comp->dict == NULL) {
661 for (i = 0; i < comp->nbStep; i++) {
662 op = &comp->steps[i];
663 if (op->value4 != NULL) {
664 if (op->op == XPATH_OP_VALUE)
665 xmlXPathFreeObject(op->value4);
666 else
667 xmlFree(op->value4);
668 }
669 if (op->value5 != NULL)
670 xmlFree(op->value5);
671 }
672 } else {
673 for (i = 0; i < comp->nbStep; i++) {
674 op = &comp->steps[i];
675 if (op->value4 != NULL) {
676 if (op->op == XPATH_OP_VALUE)
677 xmlXPathFreeObject(op->value4);
678 }
679 }
680 xmlDictFree(comp->dict);
681 }
682 if (comp->steps != NULL) {
683 xmlFree(comp->steps);
684 }
685 #ifdef DEBUG_EVAL_COUNTS
686 if (comp->string != NULL) {
687 xmlFree(comp->string);
688 }
689 #endif
690 #ifdef XPATH_STREAMING
691 if (comp->stream != NULL) {
692 xmlFreePatternList(comp->stream);
693 }
694 #endif
695 if (comp->expr != NULL) {
696 xmlFree(comp->expr);
697 }
698
699 xmlFree(comp);
700 }
701
702 /**
703 * xmlXPathCompExprAdd:
704 * @comp: the compiled expression
705 * @ch1: first child index
706 * @ch2: second child index
707 * @op: an op
708 * @value: the first int value
709 * @value2: the second int value
710 * @value3: the third int value
711 * @value4: the first string value
712 * @value5: the second string value
713 *
714 * Add a step to an XPath Compiled Expression
715 *
716 * Returns -1 in case of failure, the index otherwise
717 */
718 static int
719 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
720 xmlXPathOp op, int value,
721 int value2, int value3, void *value4, void *value5) {
722 if (comp->nbStep >= comp->maxStep) {
723 xmlXPathStepOp *real;
724
725 comp->maxStep *= 2;
726 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
727 comp->maxStep * sizeof(xmlXPathStepOp));
728 if (real == NULL) {
729 comp->maxStep /= 2;
730 xmlXPathErrMemory(NULL, "adding step\n");
731 return(-1);
732 }
733 comp->steps = real;
734 }
735 comp->last = comp->nbStep;
736 comp->steps[comp->nbStep].rewriteType = 0;
737 comp->steps[comp->nbStep].ch1 = ch1;
738 comp->steps[comp->nbStep].ch2 = ch2;
739 comp->steps[comp->nbStep].op = op;
740 comp->steps[comp->nbStep].value = value;
741 comp->steps[comp->nbStep].value2 = value2;
742 comp->steps[comp->nbStep].value3 = value3;
743 if ((comp->dict != NULL) &&
744 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
745 (op == XPATH_OP_COLLECT))) {
746 if (value4 != NULL) {
747 comp->steps[comp->nbStep].value4 = (xmlChar *)
748 (void *)xmlDictLookup(comp->dict, value4, -1);
749 xmlFree(value4);
750 } else
751 comp->steps[comp->nbStep].value4 = NULL;
752 if (value5 != NULL) {
753 comp->steps[comp->nbStep].value5 = (xmlChar *)
754 (void *)xmlDictLookup(comp->dict, value5, -1);
755 xmlFree(value5);
756 } else
757 comp->steps[comp->nbStep].value5 = NULL;
758 } else {
759 comp->steps[comp->nbStep].value4 = value4;
760 comp->steps[comp->nbStep].value5 = value5;
761 }
762 comp->steps[comp->nbStep].cache = NULL;
763 return(comp->nbStep++);
764 }
765
766 /**
767 * xmlXPathCompSwap:
768 * @comp: the compiled expression
769 * @op: operation index
770 *
771 * Swaps 2 operations in the compiled expression
772 */
773 static void
774 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
775 int tmp;
776
777 #ifndef LIBXML_THREAD_ENABLED
778 /*
779 * Since this manipulates possibly shared variables, this is
780 * disabled if one detects that the library is used in a multithreaded
781 * application
782 */
783 if (xmlXPathDisableOptimizer)
784 return;
785 #endif
786
787 tmp = op->ch1;
788 op->ch1 = op->ch2;
789 op->ch2 = tmp;
790 }
791
792 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
793 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
794 (op), (val), (val2), (val3), (val4), (val5))
795 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
796 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
797 (op), (val), (val2), (val3), (val4), (val5))
798
799 #define PUSH_LEAVE_EXPR(op, val, val2) \
800 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
801
802 #define PUSH_UNARY_EXPR(op, ch, val, val2) \
803 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
804
805 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
806 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
807 (val), (val2), 0 ,NULL ,NULL)
808
809 /************************************************************************
810 * *
811 * XPath object cache structures *
812 * *
813 ************************************************************************/
814
815 /* #define XP_DEFAULT_CACHE_ON */
816
817 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
818
819 typedef struct _xmlXPathContextCache xmlXPathContextCache;
820 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
821 struct _xmlXPathContextCache {
822 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
823 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
824 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
825 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
826 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
827 int maxNodeset;
828 int maxString;
829 int maxBoolean;
830 int maxNumber;
831 int maxMisc;
832 #ifdef XP_DEBUG_OBJ_USAGE
833 int dbgCachedAll;
834 int dbgCachedNodeset;
835 int dbgCachedString;
836 int dbgCachedBool;
837 int dbgCachedNumber;
838 int dbgCachedPoint;
839 int dbgCachedRange;
840 int dbgCachedLocset;
841 int dbgCachedUsers;
842 int dbgCachedXSLTTree;
843 int dbgCachedUndefined;
844
845
846 int dbgReusedAll;
847 int dbgReusedNodeset;
848 int dbgReusedString;
849 int dbgReusedBool;
850 int dbgReusedNumber;
851 int dbgReusedPoint;
852 int dbgReusedRange;
853 int dbgReusedLocset;
854 int dbgReusedUsers;
855 int dbgReusedXSLTTree;
856 int dbgReusedUndefined;
857
858 #endif
859 };
860
861 /************************************************************************
862 * *
863 * Debugging related functions *
864 * *
865 ************************************************************************/
866
867 #define STRANGE \
868 xmlGenericError(xmlGenericErrorContext, \
869 "Internal error at %s:%d\n", \
870 __FILE__, __LINE__);
871
872 #ifdef LIBXML_DEBUG_ENABLED
873 static void
874 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
875 int i;
876 char shift[100];
877
878 for (i = 0;((i < depth) && (i < 25));i++)
879 shift[2 * i] = shift[2 * i + 1] = ' ';
880 shift[2 * i] = shift[2 * i + 1] = 0;
881 if (cur == NULL) {
882 fprintf(output, "%s", shift);
883 fprintf(output, "Node is NULL !\n");
884 return;
885
886 }
887
888 if ((cur->type == XML_DOCUMENT_NODE) ||
889 (cur->type == XML_HTML_DOCUMENT_NODE)) {
890 fprintf(output, "%s", shift);
891 fprintf(output, " /\n");
892 } else if (cur->type == XML_ATTRIBUTE_NODE)
893 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
894 else
895 xmlDebugDumpOneNode(output, cur, depth);
896 }
897 static void
898 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
899 xmlNodePtr tmp;
900 int i;
901 char shift[100];
902
903 for (i = 0;((i < depth) && (i < 25));i++)
904 shift[2 * i] = shift[2 * i + 1] = ' ';
905 shift[2 * i] = shift[2 * i + 1] = 0;
906 if (cur == NULL) {
907 fprintf(output, "%s", shift);
908 fprintf(output, "Node is NULL !\n");
909 return;
910
911 }
912
913 while (cur != NULL) {
914 tmp = cur;
915 cur = cur->next;
916 xmlDebugDumpOneNode(output, tmp, depth);
917 }
918 }
919
920 static void
921 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
922 int i;
923 char shift[100];
924
925 for (i = 0;((i < depth) && (i < 25));i++)
926 shift[2 * i] = shift[2 * i + 1] = ' ';
927 shift[2 * i] = shift[2 * i + 1] = 0;
928
929 if (cur == NULL) {
930 fprintf(output, "%s", shift);
931 fprintf(output, "NodeSet is NULL !\n");
932 return;
933
934 }
935
936 if (cur != NULL) {
937 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
938 for (i = 0;i < cur->nodeNr;i++) {
939 fprintf(output, "%s", shift);
940 fprintf(output, "%d", i + 1);
941 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
942 }
943 }
944 }
945
946 static void
947 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
948 int i;
949 char shift[100];
950
951 for (i = 0;((i < depth) && (i < 25));i++)
952 shift[2 * i] = shift[2 * i + 1] = ' ';
953 shift[2 * i] = shift[2 * i + 1] = 0;
954
955 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
956 fprintf(output, "%s", shift);
957 fprintf(output, "Value Tree is NULL !\n");
958 return;
959
960 }
961
962 fprintf(output, "%s", shift);
963 fprintf(output, "%d", i + 1);
964 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
965 }
966 #if defined(LIBXML_XPTR_ENABLED)
967 static void
968 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
969 int i;
970 char shift[100];
971
972 for (i = 0;((i < depth) && (i < 25));i++)
973 shift[2 * i] = shift[2 * i + 1] = ' ';
974 shift[2 * i] = shift[2 * i + 1] = 0;
975
976 if (cur == NULL) {
977 fprintf(output, "%s", shift);
978 fprintf(output, "LocationSet is NULL !\n");
979 return;
980
981 }
982
983 for (i = 0;i < cur->locNr;i++) {
984 fprintf(output, "%s", shift);
985 fprintf(output, "%d : ", i + 1);
986 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
987 }
988 }
989 #endif /* LIBXML_XPTR_ENABLED */
990
991 /**
992 * xmlXPathDebugDumpObject:
993 * @output: the FILE * to dump the output
994 * @cur: the object to inspect
995 * @depth: indentation level
996 *
997 * Dump the content of the object for debugging purposes
998 */
999 void
1000 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1001 int i;
1002 char shift[100];
1003
1004 if (output == NULL) return;
1005
1006 for (i = 0;((i < depth) && (i < 25));i++)
1007 shift[2 * i] = shift[2 * i + 1] = ' ';
1008 shift[2 * i] = shift[2 * i + 1] = 0;
1009
1010
1011 fprintf(output, "%s", shift);
1012
1013 if (cur == NULL) {
1014 fprintf(output, "Object is empty (NULL)\n");
1015 return;
1016 }
1017 switch(cur->type) {
1018 case XPATH_UNDEFINED:
1019 fprintf(output, "Object is uninitialized\n");
1020 break;
1021 case XPATH_NODESET:
1022 fprintf(output, "Object is a Node Set :\n");
1023 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1024 break;
1025 case XPATH_XSLT_TREE:
1026 fprintf(output, "Object is an XSLT value tree :\n");
1027 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1028 break;
1029 case XPATH_BOOLEAN:
1030 fprintf(output, "Object is a Boolean : ");
1031 if (cur->boolval) fprintf(output, "true\n");
1032 else fprintf(output, "false\n");
1033 break;
1034 case XPATH_NUMBER:
1035 switch (xmlXPathIsInf(cur->floatval)) {
1036 case 1:
1037 fprintf(output, "Object is a number : Infinity\n");
1038 break;
1039 case -1:
1040 fprintf(output, "Object is a number : -Infinity\n");
1041 break;
1042 default:
1043 if (xmlXPathIsNaN(cur->floatval)) {
1044 fprintf(output, "Object is a number : NaN\n");
1045 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1046 fprintf(output, "Object is a number : 0\n");
1047 } else {
1048 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1049 }
1050 }
1051 break;
1052 case XPATH_STRING:
1053 fprintf(output, "Object is a string : ");
1054 xmlDebugDumpString(output, cur->stringval);
1055 fprintf(output, "\n");
1056 break;
1057 case XPATH_POINT:
1058 fprintf(output, "Object is a point : index %d in node", cur->index);
1059 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1060 fprintf(output, "\n");
1061 break;
1062 case XPATH_RANGE:
1063 if ((cur->user2 == NULL) ||
1064 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1065 fprintf(output, "Object is a collapsed range :\n");
1066 fprintf(output, "%s", shift);
1067 if (cur->index >= 0)
1068 fprintf(output, "index %d in ", cur->index);
1069 fprintf(output, "node\n");
1070 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1071 depth + 1);
1072 } else {
1073 fprintf(output, "Object is a range :\n");
1074 fprintf(output, "%s", shift);
1075 fprintf(output, "From ");
1076 if (cur->index >= 0)
1077 fprintf(output, "index %d in ", cur->index);
1078 fprintf(output, "node\n");
1079 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1080 depth + 1);
1081 fprintf(output, "%s", shift);
1082 fprintf(output, "To ");
1083 if (cur->index2 >= 0)
1084 fprintf(output, "index %d in ", cur->index2);
1085 fprintf(output, "node\n");
1086 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1087 depth + 1);
1088 fprintf(output, "\n");
1089 }
1090 break;
1091 case XPATH_LOCATIONSET:
1092 #if defined(LIBXML_XPTR_ENABLED)
1093 fprintf(output, "Object is a Location Set:\n");
1094 xmlXPathDebugDumpLocationSet(output,
1095 (xmlLocationSetPtr) cur->user, depth);
1096 #endif
1097 break;
1098 case XPATH_USERS:
1099 fprintf(output, "Object is user defined\n");
1100 break;
1101 }
1102 }
1103
1104 static void
1105 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1106 xmlXPathStepOpPtr op, int depth) {
1107 int i;
1108 char shift[100];
1109
1110 for (i = 0;((i < depth) && (i < 25));i++)
1111 shift[2 * i] = shift[2 * i + 1] = ' ';
1112 shift[2 * i] = shift[2 * i + 1] = 0;
1113
1114 fprintf(output, "%s", shift);
1115 if (op == NULL) {
1116 fprintf(output, "Step is NULL\n");
1117 return;
1118 }
1119 switch (op->op) {
1120 case XPATH_OP_END:
1121 fprintf(output, "END"); break;
1122 case XPATH_OP_AND:
1123 fprintf(output, "AND"); break;
1124 case XPATH_OP_OR:
1125 fprintf(output, "OR"); break;
1126 case XPATH_OP_EQUAL:
1127 if (op->value)
1128 fprintf(output, "EQUAL =");
1129 else
1130 fprintf(output, "EQUAL !=");
1131 break;
1132 case XPATH_OP_CMP:
1133 if (op->value)
1134 fprintf(output, "CMP <");
1135 else
1136 fprintf(output, "CMP >");
1137 if (!op->value2)
1138 fprintf(output, "=");
1139 break;
1140 case XPATH_OP_PLUS:
1141 if (op->value == 0)
1142 fprintf(output, "PLUS -");
1143 else if (op->value == 1)
1144 fprintf(output, "PLUS +");
1145 else if (op->value == 2)
1146 fprintf(output, "PLUS unary -");
1147 else if (op->value == 3)
1148 fprintf(output, "PLUS unary - -");
1149 break;
1150 case XPATH_OP_MULT:
1151 if (op->value == 0)
1152 fprintf(output, "MULT *");
1153 else if (op->value == 1)
1154 fprintf(output, "MULT div");
1155 else
1156 fprintf(output, "MULT mod");
1157 break;
1158 case XPATH_OP_UNION:
1159 fprintf(output, "UNION"); break;
1160 case XPATH_OP_ROOT:
1161 fprintf(output, "ROOT"); break;
1162 case XPATH_OP_NODE:
1163 fprintf(output, "NODE"); break;
1164 case XPATH_OP_RESET:
1165 fprintf(output, "RESET"); break;
1166 case XPATH_OP_SORT:
1167 fprintf(output, "SORT"); break;
1168 case XPATH_OP_COLLECT: {
1169 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1170 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1171 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1172 const xmlChar *prefix = op->value4;
1173 const xmlChar *name = op->value5;
1174
1175 fprintf(output, "COLLECT ");
1176 switch (axis) {
1177 case AXIS_ANCESTOR:
1178 fprintf(output, " 'ancestors' "); break;
1179 case AXIS_ANCESTOR_OR_SELF:
1180 fprintf(output, " 'ancestors-or-self' "); break;
1181 case AXIS_ATTRIBUTE:
1182 fprintf(output, " 'attributes' "); break;
1183 case AXIS_CHILD:
1184 fprintf(output, " 'child' "); break;
1185 case AXIS_DESCENDANT:
1186 fprintf(output, " 'descendant' "); break;
1187 case AXIS_DESCENDANT_OR_SELF:
1188 fprintf(output, " 'descendant-or-self' "); break;
1189 case AXIS_FOLLOWING:
1190 fprintf(output, " 'following' "); break;
1191 case AXIS_FOLLOWING_SIBLING:
1192 fprintf(output, " 'following-siblings' "); break;
1193 case AXIS_NAMESPACE:
1194 fprintf(output, " 'namespace' "); break;
1195 case AXIS_PARENT:
1196 fprintf(output, " 'parent' "); break;
1197 case AXIS_PRECEDING:
1198 fprintf(output, " 'preceding' "); break;
1199 case AXIS_PRECEDING_SIBLING:
1200 fprintf(output, " 'preceding-sibling' "); break;
1201 case AXIS_SELF:
1202 fprintf(output, " 'self' "); break;
1203 }
1204 switch (test) {
1205 case NODE_TEST_NONE:
1206 fprintf(output, "'none' "); break;
1207 case NODE_TEST_TYPE:
1208 fprintf(output, "'type' "); break;
1209 case NODE_TEST_PI:
1210 fprintf(output, "'PI' "); break;
1211 case NODE_TEST_ALL:
1212 fprintf(output, "'all' "); break;
1213 case NODE_TEST_NS:
1214 fprintf(output, "'namespace' "); break;
1215 case NODE_TEST_NAME:
1216 fprintf(output, "'name' "); break;
1217 }
1218 switch (type) {
1219 case NODE_TYPE_NODE:
1220 fprintf(output, "'node' "); break;
1221 case NODE_TYPE_COMMENT:
1222 fprintf(output, "'comment' "); break;
1223 case NODE_TYPE_TEXT:
1224 fprintf(output, "'text' "); break;
1225 case NODE_TYPE_PI:
1226 fprintf(output, "'PI' "); break;
1227 }
1228 if (prefix != NULL)
1229 fprintf(output, "%s:", prefix);
1230 if (name != NULL)
1231 fprintf(output, "%s", (const char *) name);
1232 break;
1233
1234 }
1235 case XPATH_OP_VALUE: {
1236 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1237
1238 fprintf(output, "ELEM ");
1239 xmlXPathDebugDumpObject(output, object, 0);
1240 goto finish;
1241 }
1242 case XPATH_OP_VARIABLE: {
1243 const xmlChar *prefix = op->value5;
1244 const xmlChar *name = op->value4;
1245
1246 if (prefix != NULL)
1247 fprintf(output, "VARIABLE %s:%s", prefix, name);
1248 else
1249 fprintf(output, "VARIABLE %s", name);
1250 break;
1251 }
1252 case XPATH_OP_FUNCTION: {
1253 int nbargs = op->value;
1254 const xmlChar *prefix = op->value5;
1255 const xmlChar *name = op->value4;
1256
1257 if (prefix != NULL)
1258 fprintf(output, "FUNCTION %s:%s(%d args)",
1259 prefix, name, nbargs);
1260 else
1261 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1262 break;
1263 }
1264 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1265 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1266 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1267 #ifdef LIBXML_XPTR_ENABLED
1268 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1269 #endif
1270 default:
1271 fprintf(output, "UNKNOWN %d\n", op->op); return;
1272 }
1273 fprintf(output, "\n");
1274 finish:
1275 if (op->ch1 >= 0)
1276 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1277 if (op->ch2 >= 0)
1278 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1279 }
1280
1281 /**
1282 * xmlXPathDebugDumpCompExpr:
1283 * @output: the FILE * for the output
1284 * @comp: the precompiled XPath expression
1285 * @depth: the indentation level.
1286 *
1287 * Dumps the tree of the compiled XPath expression.
1288 */
1289 void
1290 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1291 int depth) {
1292 int i;
1293 char shift[100];
1294
1295 if ((output == NULL) || (comp == NULL)) return;
1296
1297 for (i = 0;((i < depth) && (i < 25));i++)
1298 shift[2 * i] = shift[2 * i + 1] = ' ';
1299 shift[2 * i] = shift[2 * i + 1] = 0;
1300
1301 fprintf(output, "%s", shift);
1302
1303 fprintf(output, "Compiled Expression : %d elements\n",
1304 comp->nbStep);
1305 i = comp->last;
1306 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1307 }
1308
1309 #ifdef XP_DEBUG_OBJ_USAGE
1310
1311 /*
1312 * XPath object usage related debugging variables.
1313 */
1314 static int xmlXPathDebugObjCounterUndefined = 0;
1315 static int xmlXPathDebugObjCounterNodeset = 0;
1316 static int xmlXPathDebugObjCounterBool = 0;
1317 static int xmlXPathDebugObjCounterNumber = 0;
1318 static int xmlXPathDebugObjCounterString = 0;
1319 static int xmlXPathDebugObjCounterPoint = 0;
1320 static int xmlXPathDebugObjCounterRange = 0;
1321 static int xmlXPathDebugObjCounterLocset = 0;
1322 static int xmlXPathDebugObjCounterUsers = 0;
1323 static int xmlXPathDebugObjCounterXSLTTree = 0;
1324 static int xmlXPathDebugObjCounterAll = 0;
1325
1326 static int xmlXPathDebugObjTotalUndefined = 0;
1327 static int xmlXPathDebugObjTotalNodeset = 0;
1328 static int xmlXPathDebugObjTotalBool = 0;
1329 static int xmlXPathDebugObjTotalNumber = 0;
1330 static int xmlXPathDebugObjTotalString = 0;
1331 static int xmlXPathDebugObjTotalPoint = 0;
1332 static int xmlXPathDebugObjTotalRange = 0;
1333 static int xmlXPathDebugObjTotalLocset = 0;
1334 static int xmlXPathDebugObjTotalUsers = 0;
1335 static int xmlXPathDebugObjTotalXSLTTree = 0;
1336 static int xmlXPathDebugObjTotalAll = 0;
1337
1338 static int xmlXPathDebugObjMaxUndefined = 0;
1339 static int xmlXPathDebugObjMaxNodeset = 0;
1340 static int xmlXPathDebugObjMaxBool = 0;
1341 static int xmlXPathDebugObjMaxNumber = 0;
1342 static int xmlXPathDebugObjMaxString = 0;
1343 static int xmlXPathDebugObjMaxPoint = 0;
1344 static int xmlXPathDebugObjMaxRange = 0;
1345 static int xmlXPathDebugObjMaxLocset = 0;
1346 static int xmlXPathDebugObjMaxUsers = 0;
1347 static int xmlXPathDebugObjMaxXSLTTree = 0;
1348 static int xmlXPathDebugObjMaxAll = 0;
1349
1350 /* REVISIT TODO: Make this static when committing */
1351 static void
1352 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1353 {
1354 if (ctxt != NULL) {
1355 if (ctxt->cache != NULL) {
1356 xmlXPathContextCachePtr cache =
1357 (xmlXPathContextCachePtr) ctxt->cache;
1358
1359 cache->dbgCachedAll = 0;
1360 cache->dbgCachedNodeset = 0;
1361 cache->dbgCachedString = 0;
1362 cache->dbgCachedBool = 0;
1363 cache->dbgCachedNumber = 0;
1364 cache->dbgCachedPoint = 0;
1365 cache->dbgCachedRange = 0;
1366 cache->dbgCachedLocset = 0;
1367 cache->dbgCachedUsers = 0;
1368 cache->dbgCachedXSLTTree = 0;
1369 cache->dbgCachedUndefined = 0;
1370
1371 cache->dbgReusedAll = 0;
1372 cache->dbgReusedNodeset = 0;
1373 cache->dbgReusedString = 0;
1374 cache->dbgReusedBool = 0;
1375 cache->dbgReusedNumber = 0;
1376 cache->dbgReusedPoint = 0;
1377 cache->dbgReusedRange = 0;
1378 cache->dbgReusedLocset = 0;
1379 cache->dbgReusedUsers = 0;
1380 cache->dbgReusedXSLTTree = 0;
1381 cache->dbgReusedUndefined = 0;
1382 }
1383 }
1384
1385 xmlXPathDebugObjCounterUndefined = 0;
1386 xmlXPathDebugObjCounterNodeset = 0;
1387 xmlXPathDebugObjCounterBool = 0;
1388 xmlXPathDebugObjCounterNumber = 0;
1389 xmlXPathDebugObjCounterString = 0;
1390 xmlXPathDebugObjCounterPoint = 0;
1391 xmlXPathDebugObjCounterRange = 0;
1392 xmlXPathDebugObjCounterLocset = 0;
1393 xmlXPathDebugObjCounterUsers = 0;
1394 xmlXPathDebugObjCounterXSLTTree = 0;
1395 xmlXPathDebugObjCounterAll = 0;
1396
1397 xmlXPathDebugObjTotalUndefined = 0;
1398 xmlXPathDebugObjTotalNodeset = 0;
1399 xmlXPathDebugObjTotalBool = 0;
1400 xmlXPathDebugObjTotalNumber = 0;
1401 xmlXPathDebugObjTotalString = 0;
1402 xmlXPathDebugObjTotalPoint = 0;
1403 xmlXPathDebugObjTotalRange = 0;
1404 xmlXPathDebugObjTotalLocset = 0;
1405 xmlXPathDebugObjTotalUsers = 0;
1406 xmlXPathDebugObjTotalXSLTTree = 0;
1407 xmlXPathDebugObjTotalAll = 0;
1408
1409 xmlXPathDebugObjMaxUndefined = 0;
1410 xmlXPathDebugObjMaxNodeset = 0;
1411 xmlXPathDebugObjMaxBool = 0;
1412 xmlXPathDebugObjMaxNumber = 0;
1413 xmlXPathDebugObjMaxString = 0;
1414 xmlXPathDebugObjMaxPoint = 0;
1415 xmlXPathDebugObjMaxRange = 0;
1416 xmlXPathDebugObjMaxLocset = 0;
1417 xmlXPathDebugObjMaxUsers = 0;
1418 xmlXPathDebugObjMaxXSLTTree = 0;
1419 xmlXPathDebugObjMaxAll = 0;
1420
1421 }
1422
1423 static void
1424 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1425 xmlXPathObjectType objType)
1426 {
1427 int isCached = 0;
1428
1429 if (ctxt != NULL) {
1430 if (ctxt->cache != NULL) {
1431 xmlXPathContextCachePtr cache =
1432 (xmlXPathContextCachePtr) ctxt->cache;
1433
1434 isCached = 1;
1435
1436 cache->dbgReusedAll++;
1437 switch (objType) {
1438 case XPATH_UNDEFINED:
1439 cache->dbgReusedUndefined++;
1440 break;
1441 case XPATH_NODESET:
1442 cache->dbgReusedNodeset++;
1443 break;
1444 case XPATH_BOOLEAN:
1445 cache->dbgReusedBool++;
1446 break;
1447 case XPATH_NUMBER:
1448 cache->dbgReusedNumber++;
1449 break;
1450 case XPATH_STRING:
1451 cache->dbgReusedString++;
1452 break;
1453 case XPATH_POINT:
1454 cache->dbgReusedPoint++;
1455 break;
1456 case XPATH_RANGE:
1457 cache->dbgReusedRange++;
1458 break;
1459 case XPATH_LOCATIONSET:
1460 cache->dbgReusedLocset++;
1461 break;
1462 case XPATH_USERS:
1463 cache->dbgReusedUsers++;
1464 break;
1465 case XPATH_XSLT_TREE:
1466 cache->dbgReusedXSLTTree++;
1467 break;
1468 default:
1469 break;
1470 }
1471 }
1472 }
1473
1474 switch (objType) {
1475 case XPATH_UNDEFINED:
1476 if (! isCached)
1477 xmlXPathDebugObjTotalUndefined++;
1478 xmlXPathDebugObjCounterUndefined++;
1479 if (xmlXPathDebugObjCounterUndefined >
1480 xmlXPathDebugObjMaxUndefined)
1481 xmlXPathDebugObjMaxUndefined =
1482 xmlXPathDebugObjCounterUndefined;
1483 break;
1484 case XPATH_NODESET:
1485 if (! isCached)
1486 xmlXPathDebugObjTotalNodeset++;
1487 xmlXPathDebugObjCounterNodeset++;
1488 if (xmlXPathDebugObjCounterNodeset >
1489 xmlXPathDebugObjMaxNodeset)
1490 xmlXPathDebugObjMaxNodeset =
1491 xmlXPathDebugObjCounterNodeset;
1492 break;
1493 case XPATH_BOOLEAN:
1494 if (! isCached)
1495 xmlXPathDebugObjTotalBool++;
1496 xmlXPathDebugObjCounterBool++;
1497 if (xmlXPathDebugObjCounterBool >
1498 xmlXPathDebugObjMaxBool)
1499 xmlXPathDebugObjMaxBool =
1500 xmlXPathDebugObjCounterBool;
1501 break;
1502 case XPATH_NUMBER:
1503 if (! isCached)
1504 xmlXPathDebugObjTotalNumber++;
1505 xmlXPathDebugObjCounterNumber++;
1506 if (xmlXPathDebugObjCounterNumber >
1507 xmlXPathDebugObjMaxNumber)
1508 xmlXPathDebugObjMaxNumber =
1509 xmlXPathDebugObjCounterNumber;
1510 break;
1511 case XPATH_STRING:
1512 if (! isCached)
1513 xmlXPathDebugObjTotalString++;
1514 xmlXPathDebugObjCounterString++;
1515 if (xmlXPathDebugObjCounterString >
1516 xmlXPathDebugObjMaxString)
1517 xmlXPathDebugObjMaxString =
1518 xmlXPathDebugObjCounterString;
1519 break;
1520 case XPATH_POINT:
1521 if (! isCached)
1522 xmlXPathDebugObjTotalPoint++;
1523 xmlXPathDebugObjCounterPoint++;
1524 if (xmlXPathDebugObjCounterPoint >
1525 xmlXPathDebugObjMaxPoint)
1526 xmlXPathDebugObjMaxPoint =
1527 xmlXPathDebugObjCounterPoint;
1528 break;
1529 case XPATH_RANGE:
1530 if (! isCached)
1531 xmlXPathDebugObjTotalRange++;
1532 xmlXPathDebugObjCounterRange++;
1533 if (xmlXPathDebugObjCounterRange >
1534 xmlXPathDebugObjMaxRange)
1535 xmlXPathDebugObjMaxRange =
1536 xmlXPathDebugObjCounterRange;
1537 break;
1538 case XPATH_LOCATIONSET:
1539 if (! isCached)
1540 xmlXPathDebugObjTotalLocset++;
1541 xmlXPathDebugObjCounterLocset++;
1542 if (xmlXPathDebugObjCounterLocset >
1543 xmlXPathDebugObjMaxLocset)
1544 xmlXPathDebugObjMaxLocset =
1545 xmlXPathDebugObjCounterLocset;
1546 break;
1547 case XPATH_USERS:
1548 if (! isCached)
1549 xmlXPathDebugObjTotalUsers++;
1550 xmlXPathDebugObjCounterUsers++;
1551 if (xmlXPathDebugObjCounterUsers >
1552 xmlXPathDebugObjMaxUsers)
1553 xmlXPathDebugObjMaxUsers =
1554 xmlXPathDebugObjCounterUsers;
1555 break;
1556 case XPATH_XSLT_TREE:
1557 if (! isCached)
1558 xmlXPathDebugObjTotalXSLTTree++;
1559 xmlXPathDebugObjCounterXSLTTree++;
1560 if (xmlXPathDebugObjCounterXSLTTree >
1561 xmlXPathDebugObjMaxXSLTTree)
1562 xmlXPathDebugObjMaxXSLTTree =
1563 xmlXPathDebugObjCounterXSLTTree;
1564 break;
1565 default:
1566 break;
1567 }
1568 if (! isCached)
1569 xmlXPathDebugObjTotalAll++;
1570 xmlXPathDebugObjCounterAll++;
1571 if (xmlXPathDebugObjCounterAll >
1572 xmlXPathDebugObjMaxAll)
1573 xmlXPathDebugObjMaxAll =
1574 xmlXPathDebugObjCounterAll;
1575 }
1576
1577 static void
1578 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1579 xmlXPathObjectType objType)
1580 {
1581 int isCached = 0;
1582
1583 if (ctxt != NULL) {
1584 if (ctxt->cache != NULL) {
1585 xmlXPathContextCachePtr cache =
1586 (xmlXPathContextCachePtr) ctxt->cache;
1587
1588 isCached = 1;
1589
1590 cache->dbgCachedAll++;
1591 switch (objType) {
1592 case XPATH_UNDEFINED:
1593 cache->dbgCachedUndefined++;
1594 break;
1595 case XPATH_NODESET:
1596 cache->dbgCachedNodeset++;
1597 break;
1598 case XPATH_BOOLEAN:
1599 cache->dbgCachedBool++;
1600 break;
1601 case XPATH_NUMBER:
1602 cache->dbgCachedNumber++;
1603 break;
1604 case XPATH_STRING:
1605 cache->dbgCachedString++;
1606 break;
1607 case XPATH_POINT:
1608 cache->dbgCachedPoint++;
1609 break;
1610 case XPATH_RANGE:
1611 cache->dbgCachedRange++;
1612 break;
1613 case XPATH_LOCATIONSET:
1614 cache->dbgCachedLocset++;
1615 break;
1616 case XPATH_USERS:
1617 cache->dbgCachedUsers++;
1618 break;
1619 case XPATH_XSLT_TREE:
1620 cache->dbgCachedXSLTTree++;
1621 break;
1622 default:
1623 break;
1624 }
1625
1626 }
1627 }
1628 switch (objType) {
1629 case XPATH_UNDEFINED:
1630 xmlXPathDebugObjCounterUndefined--;
1631 break;
1632 case XPATH_NODESET:
1633 xmlXPathDebugObjCounterNodeset--;
1634 break;
1635 case XPATH_BOOLEAN:
1636 xmlXPathDebugObjCounterBool--;
1637 break;
1638 case XPATH_NUMBER:
1639 xmlXPathDebugObjCounterNumber--;
1640 break;
1641 case XPATH_STRING:
1642 xmlXPathDebugObjCounterString--;
1643 break;
1644 case XPATH_POINT:
1645 xmlXPathDebugObjCounterPoint--;
1646 break;
1647 case XPATH_RANGE:
1648 xmlXPathDebugObjCounterRange--;
1649 break;
1650 case XPATH_LOCATIONSET:
1651 xmlXPathDebugObjCounterLocset--;
1652 break;
1653 case XPATH_USERS:
1654 xmlXPathDebugObjCounterUsers--;
1655 break;
1656 case XPATH_XSLT_TREE:
1657 xmlXPathDebugObjCounterXSLTTree--;
1658 break;
1659 default:
1660 break;
1661 }
1662 xmlXPathDebugObjCounterAll--;
1663 }
1664
1665 /* REVISIT TODO: Make this static when committing */
1666 static void
1667 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
1668 {
1669 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
1670 reqXSLTTree, reqUndefined;
1671 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
1672 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
1673 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
1674 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
1675 int leftObjs = xmlXPathDebugObjCounterAll;
1676
1677 reqAll = xmlXPathDebugObjTotalAll;
1678 reqNodeset = xmlXPathDebugObjTotalNodeset;
1679 reqString = xmlXPathDebugObjTotalString;
1680 reqBool = xmlXPathDebugObjTotalBool;
1681 reqNumber = xmlXPathDebugObjTotalNumber;
1682 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
1683 reqUndefined = xmlXPathDebugObjTotalUndefined;
1684
1685 printf("# XPath object usage:\n");
1686
1687 if (ctxt != NULL) {
1688 if (ctxt->cache != NULL) {
1689 xmlXPathContextCachePtr cache =
1690 (xmlXPathContextCachePtr) ctxt->cache;
1691
1692 reAll = cache->dbgReusedAll;
1693 reqAll += reAll;
1694 reNodeset = cache->dbgReusedNodeset;
1695 reqNodeset += reNodeset;
1696 reString = cache->dbgReusedString;
1697 reqString += reString;
1698 reBool = cache->dbgReusedBool;
1699 reqBool += reBool;
1700 reNumber = cache->dbgReusedNumber;
1701 reqNumber += reNumber;
1702 reXSLTTree = cache->dbgReusedXSLTTree;
1703 reqXSLTTree += reXSLTTree;
1704 reUndefined = cache->dbgReusedUndefined;
1705 reqUndefined += reUndefined;
1706
1707 caAll = cache->dbgCachedAll;
1708 caBool = cache->dbgCachedBool;
1709 caNodeset = cache->dbgCachedNodeset;
1710 caString = cache->dbgCachedString;
1711 caNumber = cache->dbgCachedNumber;
1712 caXSLTTree = cache->dbgCachedXSLTTree;
1713 caUndefined = cache->dbgCachedUndefined;
1714
1715 if (cache->nodesetObjs)
1716 leftObjs -= cache->nodesetObjs->number;
1717 if (cache->stringObjs)
1718 leftObjs -= cache->stringObjs->number;
1719 if (cache->booleanObjs)
1720 leftObjs -= cache->booleanObjs->number;
1721 if (cache->numberObjs)
1722 leftObjs -= cache->numberObjs->number;
1723 if (cache->miscObjs)
1724 leftObjs -= cache->miscObjs->number;
1725 }
1726 }
1727
1728 printf("# all\n");
1729 printf("# total : %d\n", reqAll);
1730 printf("# left : %d\n", leftObjs);
1731 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
1732 printf("# reused : %d\n", reAll);
1733 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
1734
1735 printf("# node-sets\n");
1736 printf("# total : %d\n", reqNodeset);
1737 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
1738 printf("# reused : %d\n", reNodeset);
1739 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
1740
1741 printf("# strings\n");
1742 printf("# total : %d\n", reqString);
1743 printf("# created: %d\n", xmlXPathDebugObjTotalString);
1744 printf("# reused : %d\n", reString);
1745 printf("# max : %d\n", xmlXPathDebugObjMaxString);
1746
1747 printf("# booleans\n");
1748 printf("# total : %d\n", reqBool);
1749 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
1750 printf("# reused : %d\n", reBool);
1751 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
1752
1753 printf("# numbers\n");
1754 printf("# total : %d\n", reqNumber);
1755 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
1756 printf("# reused : %d\n", reNumber);
1757 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
1758
1759 printf("# XSLT result tree fragments\n");
1760 printf("# total : %d\n", reqXSLTTree);
1761 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
1762 printf("# reused : %d\n", reXSLTTree);
1763 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
1764
1765 printf("# undefined\n");
1766 printf("# total : %d\n", reqUndefined);
1767 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
1768 printf("# reused : %d\n", reUndefined);
1769 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
1770
1771 }
1772
1773 #endif /* XP_DEBUG_OBJ_USAGE */
1774
1775 #endif /* LIBXML_DEBUG_ENABLED */
1776
1777 /************************************************************************
1778 * *
1779 * XPath object caching *
1780 * *
1781 ************************************************************************/
1782
1783 /**
1784 * xmlXPathNewCache:
1785 *
1786 * Create a new object cache
1787 *
1788 * Returns the xmlXPathCache just allocated.
1789 */
1790 static xmlXPathContextCachePtr
1791 xmlXPathNewCache(void)
1792 {
1793 xmlXPathContextCachePtr ret;
1794
1795 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1796 if (ret == NULL) {
1797 xmlXPathErrMemory(NULL, "creating object cache\n");
1798 return(NULL);
1799 }
1800 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
1801 ret->maxNodeset = 100;
1802 ret->maxString = 100;
1803 ret->maxBoolean = 100;
1804 ret->maxNumber = 100;
1805 ret->maxMisc = 100;
1806 return(ret);
1807 }
1808
1809 static void
1810 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
1811 {
1812 int i;
1813 xmlXPathObjectPtr obj;
1814
1815 if (list == NULL)
1816 return;
1817
1818 for (i = 0; i < list->number; i++) {
1819 obj = list->items[i];
1820 /*
1821 * Note that it is already assured that we don't need to
1822 * look out for namespace nodes in the node-set.
1823 */
1824 if (obj->nodesetval != NULL) {
1825 if (obj->nodesetval->nodeTab != NULL)
1826 xmlFree(obj->nodesetval->nodeTab);
1827 xmlFree(obj->nodesetval);
1828 }
1829 xmlFree(obj);
1830 #ifdef XP_DEBUG_OBJ_USAGE
1831 xmlXPathDebugObjCounterAll--;
1832 #endif
1833 }
1834 xmlPointerListFree(list);
1835 }
1836
1837 static void
1838 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1839 {
1840 if (cache == NULL)
1841 return;
1842 if (cache->nodesetObjs)
1843 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1844 if (cache->stringObjs)
1845 xmlXPathCacheFreeObjectList(cache->stringObjs);
1846 if (cache->booleanObjs)
1847 xmlXPathCacheFreeObjectList(cache->booleanObjs);
1848 if (cache->numberObjs)
1849 xmlXPathCacheFreeObjectList(cache->numberObjs);
1850 if (cache->miscObjs)
1851 xmlXPathCacheFreeObjectList(cache->miscObjs);
1852 xmlFree(cache);
1853 }
1854
1855 /**
1856 * xmlXPathContextSetCache:
1857 *
1858 * @ctxt: the XPath context
1859 * @active: enables/disables (creates/frees) the cache
1860 * @value: a value with semantics dependant on @options
1861 * @options: options (currently only the value 0 is used)
1862 *
1863 * Creates/frees an object cache on the XPath context.
1864 * If activates XPath objects (xmlXPathObject) will be cached internally
1865 * to be reused.
1866 * @options:
1867 * 0: This will set the XPath object caching:
1868 * @value:
1869 * This will set the maximum number of XPath objects
1870 * to be cached per slot
1871 * There are 5 slots for: node-set, string, number, boolean, and
1872 * misc objects. Use <0 for the default number (100).
1873 * Other values for @options have currently no effect.
1874 *
1875 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1876 */
1877 int
1878 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1879 int active,
1880 int value,
1881 int options)
1882 {
1883 if (ctxt == NULL)
1884 return(-1);
1885 if (active) {
1886 xmlXPathContextCachePtr cache;
1887
1888 if (ctxt->cache == NULL) {
1889 ctxt->cache = xmlXPathNewCache();
1890 if (ctxt->cache == NULL)
1891 return(-1);
1892 }
1893 cache = (xmlXPathContextCachePtr) ctxt->cache;
1894 if (options == 0) {
1895 if (value < 0)
1896 value = 100;
1897 cache->maxNodeset = value;
1898 cache->maxString = value;
1899 cache->maxNumber = value;
1900 cache->maxBoolean = value;
1901 cache->maxMisc = value;
1902 }
1903 } else if (ctxt->cache != NULL) {
1904 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1905 ctxt->cache = NULL;
1906 }
1907 return(0);
1908 }
1909
1910 /**
1911 * xmlXPathCacheWrapNodeSet:
1912 * @ctxt: the XPath context
1913 * @val: the NodePtr value
1914 *
1915 * This is the cached version of xmlXPathWrapNodeSet().
1916 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1917 *
1918 * Returns the created or reused object.
1919 */
1920 static xmlXPathObjectPtr
1921 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
1922 {
1923 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1924 xmlXPathContextCachePtr cache =
1925 (xmlXPathContextCachePtr) ctxt->cache;
1926
1927 if ((cache->miscObjs != NULL) &&
1928 (cache->miscObjs->number != 0))
1929 {
1930 xmlXPathObjectPtr ret;
1931
1932 ret = (xmlXPathObjectPtr)
1933 cache->miscObjs->items[--cache->miscObjs->number];
1934 ret->type = XPATH_NODESET;
1935 ret->nodesetval = val;
1936 #ifdef XP_DEBUG_OBJ_USAGE
1937 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
1938 #endif
1939 return(ret);
1940 }
1941 }
1942
1943 return(xmlXPathWrapNodeSet(val));
1944
1945 }
1946
1947 /**
1948 * xmlXPathCacheWrapString:
1949 * @ctxt: the XPath context
1950 * @val: the xmlChar * value
1951 *
1952 * This is the cached version of xmlXPathWrapString().
1953 * Wraps the @val string into an XPath object.
1954 *
1955 * Returns the created or reused object.
1956 */
1957 static xmlXPathObjectPtr
1958 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
1959 {
1960 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1961 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1962
1963 if ((cache->stringObjs != NULL) &&
1964 (cache->stringObjs->number != 0))
1965 {
1966
1967 xmlXPathObjectPtr ret;
1968
1969 ret = (xmlXPathObjectPtr)
1970 cache->stringObjs->items[--cache->stringObjs->number];
1971 ret->type = XPATH_STRING;
1972 ret->stringval = val;
1973 #ifdef XP_DEBUG_OBJ_USAGE
1974 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1975 #endif
1976 return(ret);
1977 } else if ((cache->miscObjs != NULL) &&
1978 (cache->miscObjs->number != 0))
1979 {
1980 xmlXPathObjectPtr ret;
1981 /*
1982 * Fallback to misc-cache.
1983 */
1984 ret = (xmlXPathObjectPtr)
1985 cache->miscObjs->items[--cache->miscObjs->number];
1986
1987 ret->type = XPATH_STRING;
1988 ret->stringval = val;
1989 #ifdef XP_DEBUG_OBJ_USAGE
1990 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1991 #endif
1992 return(ret);
1993 }
1994 }
1995 return(xmlXPathWrapString(val));
1996 }
1997
1998 /**
1999 * xmlXPathCacheNewNodeSet:
2000 * @ctxt: the XPath context
2001 * @val: the NodePtr value
2002 *
2003 * This is the cached version of xmlXPathNewNodeSet().
2004 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2005 * it with the single Node @val
2006 *
2007 * Returns the created or reused object.
2008 */
2009 static xmlXPathObjectPtr
2010 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2011 {
2012 if ((ctxt != NULL) && (ctxt->cache)) {
2013 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2014
2015 if ((cache->nodesetObjs != NULL) &&
2016 (cache->nodesetObjs->number != 0))
2017 {
2018 xmlXPathObjectPtr ret;
2019 /*
2020 * Use the nodset-cache.
2021 */
2022 ret = (xmlXPathObjectPtr)
2023 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2024 ret->type = XPATH_NODESET;
2025 ret->boolval = 0;
2026 if (val) {
2027 if ((ret->nodesetval->nodeMax == 0) ||
2028 (val->type == XML_NAMESPACE_DECL))
2029 {
2030 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2031 } else {
2032 ret->nodesetval->nodeTab[0] = val;
2033 ret->nodesetval->nodeNr = 1;
2034 }
2035 }
2036 #ifdef XP_DEBUG_OBJ_USAGE
2037 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2038 #endif
2039 return(ret);
2040 } else if ((cache->miscObjs != NULL) &&
2041 (cache->miscObjs->number != 0))
2042 {
2043 xmlXPathObjectPtr ret;
2044 /*
2045 * Fallback to misc-cache.
2046 */
2047
2048 ret = (xmlXPathObjectPtr)
2049 cache->miscObjs->items[--cache->miscObjs->number];
2050
2051 ret->type = XPATH_NODESET;
2052 ret->boolval = 0;
2053 ret->nodesetval = xmlXPathNodeSetCreate(val);
2054 #ifdef XP_DEBUG_OBJ_USAGE
2055 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2056 #endif
2057 return(ret);
2058 }
2059 }
2060 return(xmlXPathNewNodeSet(val));
2061 }
2062
2063 /**
2064 * xmlXPathCacheNewCString:
2065 * @ctxt: the XPath context
2066 * @val: the char * value
2067 *
2068 * This is the cached version of xmlXPathNewCString().
2069 * Acquire an xmlXPathObjectPtr of type string and of value @val
2070 *
2071 * Returns the created or reused object.
2072 */
2073 static xmlXPathObjectPtr
2074 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2075 {
2076 if ((ctxt != NULL) && (ctxt->cache)) {
2077 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2078
2079 if ((cache->stringObjs != NULL) &&
2080 (cache->stringObjs->number != 0))
2081 {
2082 xmlXPathObjectPtr ret;
2083
2084 ret = (xmlXPathObjectPtr)
2085 cache->stringObjs->items[--cache->stringObjs->number];
2086
2087 ret->type = XPATH_STRING;
2088 ret->stringval = xmlStrdup(BAD_CAST val);
2089 #ifdef XP_DEBUG_OBJ_USAGE
2090 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2091 #endif
2092 return(ret);
2093 } else if ((cache->miscObjs != NULL) &&
2094 (cache->miscObjs->number != 0))
2095 {
2096 xmlXPathObjectPtr ret;
2097
2098 ret = (xmlXPathObjectPtr)
2099 cache->miscObjs->items[--cache->miscObjs->number];
2100
2101 ret->type = XPATH_STRING;
2102 ret->stringval = xmlStrdup(BAD_CAST val);
2103 #ifdef XP_DEBUG_OBJ_USAGE
2104 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2105 #endif
2106 return(ret);
2107 }
2108 }
2109 return(xmlXPathNewCString(val));
2110 }
2111
2112 /**
2113 * xmlXPathCacheNewString:
2114 * @ctxt: the XPath context
2115 * @val: the xmlChar * value
2116 *
2117 * This is the cached version of xmlXPathNewString().
2118 * Acquire an xmlXPathObjectPtr of type string and of value @val
2119 *
2120 * Returns the created or reused object.
2121 */
2122 static xmlXPathObjectPtr
2123 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2124 {
2125 if ((ctxt != NULL) && (ctxt->cache)) {
2126 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2127
2128 if ((cache->stringObjs != NULL) &&
2129 (cache->stringObjs->number != 0))
2130 {
2131 xmlXPathObjectPtr ret;
2132
2133 ret = (xmlXPathObjectPtr)
2134 cache->stringObjs->items[--cache->stringObjs->number];
2135 ret->type = XPATH_STRING;
2136 if (val != NULL)
2137 ret->stringval = xmlStrdup(val);
2138 else
2139 ret->stringval = xmlStrdup((const xmlChar *)"");
2140 #ifdef XP_DEBUG_OBJ_USAGE
2141 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2142 #endif
2143 return(ret);
2144 } else if ((cache->miscObjs != NULL) &&
2145 (cache->miscObjs->number != 0))
2146 {
2147 xmlXPathObjectPtr ret;
2148
2149 ret = (xmlXPathObjectPtr)
2150 cache->miscObjs->items[--cache->miscObjs->number];
2151
2152 ret->type = XPATH_STRING;
2153 if (val != NULL)
2154 ret->stringval = xmlStrdup(val);
2155 else
2156 ret->stringval = xmlStrdup((const xmlChar *)"");
2157 #ifdef XP_DEBUG_OBJ_USAGE
2158 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2159 #endif
2160 return(ret);
2161 }
2162 }
2163 return(xmlXPathNewString(val));
2164 }
2165
2166 /**
2167 * xmlXPathCacheNewBoolean:
2168 * @ctxt: the XPath context
2169 * @val: the boolean value
2170 *
2171 * This is the cached version of xmlXPathNewBoolean().
2172 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2173 *
2174 * Returns the created or reused object.
2175 */
2176 static xmlXPathObjectPtr
2177 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2178 {
2179 if ((ctxt != NULL) && (ctxt->cache)) {
2180 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2181
2182 if ((cache->booleanObjs != NULL) &&
2183 (cache->booleanObjs->number != 0))
2184 {
2185 xmlXPathObjectPtr ret;
2186
2187 ret = (xmlXPathObjectPtr)
2188 cache->booleanObjs->items[--cache->booleanObjs->number];
2189 ret->type = XPATH_BOOLEAN;
2190 ret->boolval = (val != 0);
2191 #ifdef XP_DEBUG_OBJ_USAGE
2192 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2193 #endif
2194 return(ret);
2195 } else if ((cache->miscObjs != NULL) &&
2196 (cache->miscObjs->number != 0))
2197 {
2198 xmlXPathObjectPtr ret;
2199
2200 ret = (xmlXPathObjectPtr)
2201 cache->miscObjs->items[--cache->miscObjs->number];
2202
2203 ret->type = XPATH_BOOLEAN;
2204 ret->boolval = (val != 0);
2205 #ifdef XP_DEBUG_OBJ_USAGE
2206 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2207 #endif
2208 return(ret);
2209 }
2210 }
2211 return(xmlXPathNewBoolean(val));
2212 }
2213
2214 /**
2215 * xmlXPathCacheNewFloat:
2216 * @ctxt: the XPath context
2217 * @val: the double value
2218 *
2219 * This is the cached version of xmlXPathNewFloat().
2220 * Acquires an xmlXPathObjectPtr of type double and of value @val
2221 *
2222 * Returns the created or reused object.
2223 */
2224 static xmlXPathObjectPtr
2225 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2226 {
2227 if ((ctxt != NULL) && (ctxt->cache)) {
2228 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2229
2230 if ((cache->numberObjs != NULL) &&
2231 (cache->numberObjs->number != 0))
2232 {
2233 xmlXPathObjectPtr ret;
2234
2235 ret = (xmlXPathObjectPtr)
2236 cache->numberObjs->items[--cache->numberObjs->number];
2237 ret->type = XPATH_NUMBER;
2238 ret->floatval = val;
2239 #ifdef XP_DEBUG_OBJ_USAGE
2240 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2241 #endif
2242 return(ret);
2243 } else if ((cache->miscObjs != NULL) &&
2244 (cache->miscObjs->number != 0))
2245 {
2246 xmlXPathObjectPtr ret;
2247
2248 ret = (xmlXPathObjectPtr)
2249 cache->miscObjs->items[--cache->miscObjs->number];
2250
2251 ret->type = XPATH_NUMBER;
2252 ret->floatval = val;
2253 #ifdef XP_DEBUG_OBJ_USAGE
2254 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2255 #endif
2256 return(ret);
2257 }
2258 }
2259 return(xmlXPathNewFloat(val));
2260 }
2261
2262 /**
2263 * xmlXPathCacheConvertString:
2264 * @ctxt: the XPath context
2265 * @val: an XPath object
2266 *
2267 * This is the cached version of xmlXPathConvertString().
2268 * Converts an existing object to its string() equivalent
2269 *
2270 * Returns a created or reused object, the old one is freed (cached)
2271 * (or the operation is done directly on @val)
2272 */
2273
2274 static xmlXPathObjectPtr
2275 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2276 xmlChar *res = NULL;
2277
2278 if (val == NULL)
2279 return(xmlXPathCacheNewCString(ctxt, ""));
2280
2281 switch (val->type) {
2282 case XPATH_UNDEFINED:
2283 #ifdef DEBUG_EXPR
2284 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2285 #endif
2286 break;
2287 case XPATH_NODESET:
2288 case XPATH_XSLT_TREE:
2289 res = xmlXPathCastNodeSetToString(val->nodesetval);
2290 break;
2291 case XPATH_STRING:
2292 return(val);
2293 case XPATH_BOOLEAN:
2294 res = xmlXPathCastBooleanToString(val->boolval);
2295 break;
2296 case XPATH_NUMBER:
2297 res = xmlXPathCastNumberToString(val->floatval);
2298 break;
2299 case XPATH_USERS:
2300 case XPATH_POINT:
2301 case XPATH_RANGE:
2302 case XPATH_LOCATIONSET:
2303 TODO;
2304 break;
2305 }
2306 xmlXPathReleaseObject(ctxt, val);
2307 if (res == NULL)
2308 return(xmlXPathCacheNewCString(ctxt, ""));
2309 return(xmlXPathCacheWrapString(ctxt, res));
2310 }
2311
2312 /**
2313 * xmlXPathCacheObjectCopy:
2314 * @ctxt: the XPath context
2315 * @val: the original object
2316 *
2317 * This is the cached version of xmlXPathObjectCopy().
2318 * Acquire a copy of a given object
2319 *
2320 * Returns a created or reused created object.
2321 */
2322 static xmlXPathObjectPtr
2323 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2324 {
2325 if (val == NULL)
2326 return(NULL);
2327
2328 if (XP_HAS_CACHE(ctxt)) {
2329 switch (val->type) {
2330 case XPATH_NODESET:
2331 return(xmlXPathCacheWrapNodeSet(ctxt,
2332 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2333 case XPATH_STRING:
2334 return(xmlXPathCacheNewString(ctxt, val->stringval));
2335 case XPATH_BOOLEAN:
2336 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2337 case XPATH_NUMBER:
2338 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2339 default:
2340 break;
2341 }
2342 }
2343 return(xmlXPathObjectCopy(val));
2344 }
2345
2346 /**
2347 * xmlXPathCacheConvertBoolean:
2348 * @ctxt: the XPath context
2349 * @val: an XPath object
2350 *
2351 * This is the cached version of xmlXPathConvertBoolean().
2352 * Converts an existing object to its boolean() equivalent
2353 *
2354 * Returns a created or reused object, the old one is freed (or the operation
2355 * is done directly on @val)
2356 */
2357 static xmlXPathObjectPtr
2358 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2359 xmlXPathObjectPtr ret;
2360
2361 if (val == NULL)
2362 return(xmlXPathCacheNewBoolean(ctxt, 0));
2363 if (val->type == XPATH_BOOLEAN)
2364 return(val);
2365 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2366 xmlXPathReleaseObject(ctxt, val);
2367 return(ret);
2368 }
2369
2370 /**
2371 * xmlXPathCacheConvertNumber:
2372 * @ctxt: the XPath context
2373 * @val: an XPath object
2374 *
2375 * This is the cached version of xmlXPathConvertNumber().
2376 * Converts an existing object to its number() equivalent
2377 *
2378 * Returns a created or reused object, the old one is freed (or the operation
2379 * is done directly on @val)
2380 */
2381 static xmlXPathObjectPtr
2382 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2383 xmlXPathObjectPtr ret;
2384
2385 if (val == NULL)
2386 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2387 if (val->type == XPATH_NUMBER)
2388 return(val);
2389 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2390 xmlXPathReleaseObject(ctxt, val);
2391 return(ret);
2392 }
2393
2394 /************************************************************************
2395 * *
2396 * Parser stacks related functions and macros *
2397 * *
2398 ************************************************************************/
2399
2400 /**
2401 * valuePop:
2402 * @ctxt: an XPath evaluation context
2403 *
2404 * Pops the top XPath object from the value stack
2405 *
2406 * Returns the XPath object just removed
2407 */
2408 xmlXPathObjectPtr
2409 valuePop(xmlXPathParserContextPtr ctxt)
2410 {
2411 xmlXPathObjectPtr ret;
2412
2413 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2414 return (NULL);
2415 ctxt->valueNr--;
2416 if (ctxt->valueNr > 0)
2417 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2418 else
2419 ctxt->value = NULL;
2420 ret = ctxt->valueTab[ctxt->valueNr];
2421 ctxt->valueTab[ctxt->valueNr] = NULL;
2422 return (ret);
2423 }
2424 /**
2425 * valuePush:
2426 * @ctxt: an XPath evaluation context
2427 * @value: the XPath object
2428 *
2429 * Pushes a new XPath object on top of the value stack
2430 *
2431 * returns the number of items on the value stack
2432 */
2433 int
2434 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2435 {
2436 if ((ctxt == NULL) || (value == NULL)) return(-1);
2437 if (ctxt->valueNr >= ctxt->valueMax) {
2438 xmlXPathObjectPtr *tmp;
2439
2440 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2441 2 * ctxt->valueMax *
2442 sizeof(ctxt->valueTab[0]));
2443 if (tmp == NULL) {
2444 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
2445 return (0);
2446 }
2447 ctxt->valueMax *= 2;
2448 ctxt->valueTab = tmp;
2449 }
2450 ctxt->valueTab[ctxt->valueNr] = value;
2451 ctxt->value = value;
2452 return (ctxt->valueNr++);
2453 }
2454
2455 /**
2456 * xmlXPathPopBoolean:
2457 * @ctxt: an XPath parser context
2458 *
2459 * Pops a boolean from the stack, handling conversion if needed.
2460 * Check error with #xmlXPathCheckError.
2461 *
2462 * Returns the boolean
2463 */
2464 int
2465 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2466 xmlXPathObjectPtr obj;
2467 int ret;
2468
2469 obj = valuePop(ctxt);
2470 if (obj == NULL) {
2471 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2472 return(0);
2473 }
2474 if (obj->type != XPATH_BOOLEAN)
2475 ret = xmlXPathCastToBoolean(obj);
2476 else
2477 ret = obj->boolval;
2478 xmlXPathReleaseObject(ctxt->context, obj);
2479 return(ret);
2480 }
2481
2482 /**
2483 * xmlXPathPopNumber:
2484 * @ctxt: an XPath parser context
2485 *
2486 * Pops a number from the stack, handling conversion if needed.
2487 * Check error with #xmlXPathCheckError.
2488 *
2489 * Returns the number
2490 */
2491 double
2492 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2493 xmlXPathObjectPtr obj;
2494 double ret;
2495
2496 obj = valuePop(ctxt);
2497 if (obj == NULL) {
2498 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2499 return(0);
2500 }
2501 if (obj->type != XPATH_NUMBER)
2502 ret = xmlXPathCastToNumber(obj);
2503 else
2504 ret = obj->floatval;
2505 xmlXPathReleaseObject(ctxt->context, obj);
2506 return(ret);
2507 }
2508
2509 /**
2510 * xmlXPathPopString:
2511 * @ctxt: an XPath parser context
2512 *
2513 * Pops a string from the stack, handling conversion if needed.
2514 * Check error with #xmlXPathCheckError.
2515 *
2516 * Returns the string
2517 */
2518 xmlChar *
2519 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2520 xmlXPathObjectPtr obj;
2521 xmlChar * ret;
2522
2523 obj = valuePop(ctxt);
2524 if (obj == NULL) {
2525 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2526 return(NULL);
2527 }
2528 ret = xmlXPathCastToString(obj); /* this does required strdup */
2529 /* TODO: needs refactoring somewhere else */
2530 if (obj->stringval == ret)
2531 obj->stringval = NULL;
2532 xmlXPathReleaseObject(ctxt->context, obj);
2533 return(ret);
2534 }
2535
2536 /**
2537 * xmlXPathPopNodeSet:
2538 * @ctxt: an XPath parser context
2539 *
2540 * Pops a node-set from the stack, handling conversion if needed.
2541 * Check error with #xmlXPathCheckError.
2542 *
2543 * Returns the node-set
2544 */
2545 xmlNodeSetPtr
2546 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2547 xmlXPathObjectPtr obj;
2548 xmlNodeSetPtr ret;
2549
2550 if (ctxt == NULL) return(NULL);
2551 if (ctxt->value == NULL) {
2552 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2553 return(NULL);
2554 }
2555 if (!xmlXPathStackIsNodeSet(ctxt)) {
2556 xmlXPathSetTypeError(ctxt);
2557 return(NULL);
2558 }
2559 obj = valuePop(ctxt);
2560 ret = obj->nodesetval;
2561 #if 0
2562 /* to fix memory leak of not clearing obj->user */
2563 if (obj->boolval && obj->user != NULL)
2564 xmlFreeNodeList((xmlNodePtr) obj->user);
2565 #endif
2566 obj->nodesetval = NULL;
2567 xmlXPathReleaseObject(ctxt->context, obj);
2568 return(ret);
2569 }
2570
2571 /**
2572 * xmlXPathPopExternal:
2573 * @ctxt: an XPath parser context
2574 *
2575 * Pops an external object from the stack, handling conversion if needed.
2576 * Check error with #xmlXPathCheckError.
2577 *
2578 * Returns the object
2579 */
2580 void *
2581 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2582 xmlXPathObjectPtr obj;
2583 void * ret;
2584
2585 if ((ctxt == NULL) || (ctxt->value == NULL)) {
2586 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2587 return(NULL);
2588 }
2589 if (ctxt->value->type != XPATH_USERS) {
2590 xmlXPathSetTypeError(ctxt);
2591 return(NULL);
2592 }
2593 obj = valuePop(ctxt);
2594 ret = obj->user;
2595 obj->user = NULL;
2596 xmlXPathReleaseObject(ctxt->context, obj);
2597 return(ret);
2598 }
2599
2600 /*
2601 * Macros for accessing the content. Those should be used only by the parser,
2602 * and not exported.
2603 *
2604 * Dirty macros, i.e. one need to make assumption on the context to use them
2605 *
2606 * CUR_PTR return the current pointer to the xmlChar to be parsed.
2607 * CUR returns the current xmlChar value, i.e. a 8 bit value
2608 * in ISO-Latin or UTF-8.
2609 * This should be used internally by the parser
2610 * only to compare to ASCII values otherwise it would break when
2611 * running with UTF-8 encoding.
2612 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
2613 * to compare on ASCII based substring.
2614 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2615 * strings within the parser.
2616 * CURRENT Returns the current char value, with the full decoding of
2617 * UTF-8 if we are using this mode. It returns an int.
2618 * NEXT Skip to the next character, this does the proper decoding
2619 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
2620 * It returns the pointer to the current xmlChar.
2621 */
2622
2623 #define CUR (*ctxt->cur)
2624 #define SKIP(val) ctxt->cur += (val)
2625 #define NXT(val) ctxt->cur[(val)]
2626 #define CUR_PTR ctxt->cur
2627 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2628
2629 #define COPY_BUF(l,b,i,v) \
2630 if (l == 1) b[i++] = (xmlChar) v; \
2631 else i += xmlCopyChar(l,&b[i],v)
2632
2633 #define NEXTL(l) ctxt->cur += l
2634
2635 #define SKIP_BLANKS \
2636 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2637
2638 #define CURRENT (*ctxt->cur)
2639 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
2640
2641
2642 #ifndef DBL_DIG
2643 #define DBL_DIG 16
2644 #endif
2645 #ifndef DBL_EPSILON
2646 #define DBL_EPSILON 1E-9
2647 #endif
2648
2649 #define UPPER_DOUBLE 1E9
2650 #define LOWER_DOUBLE 1E-5
2651 #define LOWER_DOUBLE_EXP 5
2652
2653 #define INTEGER_DIGITS DBL_DIG
2654 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
2655 #define EXPONENT_DIGITS (3 + 2)
2656
2657 /**
2658 * xmlXPathFormatNumber:
2659 * @number: number to format
2660 * @buffer: output buffer
2661 * @buffersize: size of output buffer
2662 *
2663 * Convert the number into a string representation.
2664 */
2665 static void
2666 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2667 {
2668 switch (xmlXPathIsInf(number)) {
2669 case 1:
2670 if (buffersize > (int)sizeof("Infinity"))
2671 snprintf(buffer, buffersize, "Infinity");
2672 break;
2673 case -1:
2674 if (buffersize > (int)sizeof("-Infinity"))
2675 snprintf(buffer, buffersize, "-Infinity");
2676 break;
2677 default:
2678 if (xmlXPathIsNaN(number)) {
2679 if (buffersize > (int)sizeof("NaN"))
2680 snprintf(buffer, buffersize, "NaN");
2681 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
2682 snprintf(buffer, buffersize, "0");
2683 } else if (number == ((int) number)) {
2684 char work[30];
2685 char *ptr, *cur;
2686 int value = (int) number;
2687
2688 ptr = &buffer[0];
2689 if (value == 0) {
2690 *ptr++ = '0';
2691 } else {
2692 snprintf(work, 29, "%d", value);
2693 cur = &work[0];
2694 while ((*cur) && (ptr - buffer < buffersize)) {
2695 *ptr++ = *cur++;
2696 }
2697 }
2698 if (ptr - buffer < buffersize) {
2699 *ptr = 0;
2700 } else if (buffersize > 0) {
2701 ptr--;
2702 *ptr = 0;
2703 }
2704 } else {
2705 /*
2706 For the dimension of work,
2707 DBL_DIG is number of significant digits
2708 EXPONENT is only needed for "scientific notation"
2709 3 is sign, decimal point, and terminating zero
2710 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2711 Note that this dimension is slightly (a few characters)
2712 larger than actually necessary.
2713 */
2714 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2715 int integer_place, fraction_place;
2716 char *ptr;
2717 char *after_fraction;
2718 double absolute_value;
2719 int size;
2720
2721 absolute_value = fabs(number);
2722
2723 /*
2724 * First choose format - scientific or regular floating point.
2725 * In either case, result is in work, and after_fraction points
2726 * just past the fractional part.
2727 */
2728 if ( ((absolute_value > UPPER_DOUBLE) ||
2729 (absolute_value < LOWER_DOUBLE)) &&
2730 (absolute_value != 0.0) ) {
2731 /* Use scientific notation */
2732 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2733 fraction_place = DBL_DIG - 1;
2734 size = snprintf(work, sizeof(work),"%*.*e",
2735 integer_place, fraction_place, number);
2736 while ((size > 0) && (work[size] != 'e')) size--;
2737
2738 }
2739 else {
2740 /* Use regular notation */
2741 if (absolute_value > 0.0) {
2742 integer_place = (int)log10(absolute_value);
2743 if (integer_place > 0)
2744 fraction_place = DBL_DIG - integer_place - 1;
2745 else
2746 fraction_place = DBL_DIG - integer_place;
2747 } else {
2748 fraction_place = 1;
2749 }
2750 size = snprintf(work, sizeof(work), "%0.*f",
2751 fraction_place, number);
2752 }
2753
2754 /* Remove fractional trailing zeroes */
2755 after_fraction = work + size;
2756 ptr = after_fraction;
2757 while (*(--ptr) == '0')
2758 ;
2759 if (*ptr != '.')
2760 ptr++;
2761 while ((*ptr++ = *after_fraction++) != 0);
2762
2763 /* Finally copy result back to caller */
2764 size = strlen(work) + 1;
2765 if (size > buffersize) {
2766 work[buffersize - 1] = 0;
2767 size = buffersize;
2768 }
2769 memmove(buffer, work, size);
2770 }
2771 break;
2772 }
2773 }
2774
2775
2776 /************************************************************************
2777 * *
2778 * Routines to handle NodeSets *
2779 * *
2780 ************************************************************************/
2781
2782 /**
2783 * xmlXPathOrderDocElems:
2784 * @doc: an input document
2785 *
2786 * Call this routine to speed up XPath computation on static documents.
2787 * This stamps all the element nodes with the document order
2788 * Like for line information, the order is kept in the element->content
2789 * field, the value stored is actually - the node number (starting at -1)
2790 * to be able to differentiate from line numbers.
2791 *
2792 * Returns the number of elements found in the document or -1 in case
2793 * of error.
2794 */
2795 long
2796 xmlXPathOrderDocElems(xmlDocPtr doc) {
2797 long count = 0;
2798 xmlNodePtr cur;
2799
2800 if (doc == NULL)
2801 return(-1);
2802 cur = doc->children;
2803 while (cur != NULL) {
2804 if (cur->type == XML_ELEMENT_NODE) {
2805 cur->content = (void *) (-(++count));
2806 if (cur->children != NULL) {
2807 cur = cur->children;
2808 continue;
2809 }
2810 }
2811 if (cur->next != NULL) {
2812 cur = cur->next;
2813 continue;
2814 }
2815 do {
2816 cur = cur->parent;
2817 if (cur == NULL)
2818 break;
2819 if (cur == (xmlNodePtr) doc) {
2820 cur = NULL;
2821 break;
2822 }
2823 if (cur->next != NULL) {
2824 cur = cur->next;
2825 break;
2826 }
2827 } while (cur != NULL);
2828 }
2829 return(count);
2830 }
2831
2832 /**
2833 * xmlXPathCmpNodes:
2834 * @node1: the first node
2835 * @node2: the second node
2836 *
2837 * Compare two nodes w.r.t document order
2838 *
2839 * Returns -2 in case of error 1 if first point < second point, 0 if
2840 * it's the same node, -1 otherwise
2841 */
2842 int
2843 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2844 int depth1, depth2;
2845 int attr1 = 0, attr2 = 0;
2846 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
2847 xmlNodePtr cur, root;
2848
2849 if ((node1 == NULL) || (node2 == NULL))
2850 return(-2);
2851 /*
2852 * a couple of optimizations which will avoid computations in most cases
2853 */
2854 if (node1 == node2) /* trivial case */
2855 return(0);
2856 if (node1->type == XML_ATTRIBUTE_NODE) {
2857 attr1 = 1;
2858 attrNode1 = node1;
2859 node1 = node1->parent;
2860 }
2861 if (node2->type == XML_ATTRIBUTE_NODE) {
2862 attr2 = 1;
2863 attrNode2 = node2;
2864 node2 = node2->parent;
2865 }
2866 if (node1 == node2) {
2867 if (attr1 == attr2) {
2868 /* not required, but we keep attributes in order */
2869 if (attr1 != 0) {
2870 cur = attrNode2->prev;
2871 while (cur != NULL) {
2872 if (cur == attrNode1)
2873 return (1);
2874 cur = cur->prev;
2875 }
2876 return (-1);
2877 }
2878 return(0);
2879 }
2880 if (attr2 == 1)
2881 return(1);
2882 return(-1);
2883 }
2884 if ((node1->type == XML_NAMESPACE_DECL) ||
2885 (node2->type == XML_NAMESPACE_DECL))
2886 return(1);
2887 if (node1 == node2->prev)
2888 return(1);
2889 if (node1 == node2->next)
2890 return(-1);
2891
2892 /*
2893 * Speedup using document order if availble.
2894 */
2895 if ((node1->type == XML_ELEMENT_NODE) &&
2896 (node2->type == XML_ELEMENT_NODE) &&
2897 (0 > (long) node1->content) &&
2898 (0 > (long) node2->content) &&
2899 (node1->doc == node2->doc)) {
2900 long l1, l2;
2901
2902 l1 = -((long) node1->content);
2903 l2 = -((long) node2->content);
2904 if (l1 < l2)
2905 return(1);
2906 if (l1 > l2)
2907 return(-1);
2908 }
2909
2910 /*
2911 * compute depth to root
2912 */
2913 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2914 if (cur == node1)
2915 return(1);
2916 depth2++;
2917 }
2918 root = cur;
2919 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2920 if (cur == node2)
2921 return(-1);
2922 depth1++;
2923 }
2924 /*
2925 * Distinct document (or distinct entities :-( ) case.
2926 */
2927 if (root != cur) {
2928 return(-2);
2929 }
2930 /*
2931 * get the nearest common ancestor.
2932 */
2933 while (depth1 > depth2) {
2934 depth1--;
2935 node1 = node1->parent;
2936 }
2937 while (depth2 > depth1) {
2938 depth2--;
2939 node2 = node2->parent;
2940 }
2941 while (node1->parent != node2->parent) {
2942 node1 = node1->parent;
2943 node2 = node2->parent;
2944 /* should not happen but just in case ... */
2945 if ((node1 == NULL) || (node2 == NULL))
2946 return(-2);
2947 }
2948 /*
2949 * Find who's first.
2950 */
2951 if (node1 == node2->prev)
2952 return(1);
2953 if (node1 == node2->next)
2954 return(-1);
2955 /*
2956 * Speedup using document order if availble.
2957 */
2958 if ((node1->type == XML_ELEMENT_NODE) &&
2959 (node2->type == XML_ELEMENT_NODE) &&
2960 (0 > (long) node1->content) &&
2961 (0 > (long) node2->content) &&
2962 (node1->doc == node2->doc)) {
2963 long l1, l2;
2964
2965 l1 = -((long) node1->content);
2966 l2 = -((long) node2->content);
2967 if (l1 < l2)
2968 return(1);
2969 if (l1 > l2)
2970 return(-1);
2971 }
2972
2973 for (cur = node1->next;cur != NULL;cur = cur->next)
2974 if (cur == node2)
2975 return(1);
2976 return(-1); /* assume there is no sibling list corruption */
2977 }
2978
2979 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
2980 /**
2981 * xmlXPathCmpNodesExt:
2982 * @node1: the first node
2983 * @node2: the second node
2984 *
2985 * Compare two nodes w.r.t document order.
2986 * This one is optimized for handling of non-element nodes.
2987 *
2988 * Returns -2 in case of error 1 if first point < second point, 0 if
2989 * it's the same node, -1 otherwise
2990 */
2991 static int
2992 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
2993 int depth1, depth2;
2994 int misc = 0, precedence1 = 0, precedence2 = 0;
2995 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
2996 xmlNodePtr cur, root;
2997 long l1, l2;
2998
2999 if ((node1 == NULL) || (node2 == NULL))
3000 return(-2);
3001
3002 if (node1 == node2)
3003 return(0);
3004
3005 /*
3006 * a couple of optimizations which will avoid computations in most cases
3007 */
3008 switch (node1->type) {
3009 case XML_ELEMENT_NODE:
3010 if (node2->type == XML_ELEMENT_NODE) {
3011 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
3012 (0 > (long) node2->content) &&
3013 (node1->doc == node2->doc))
3014 {
3015 l1 = -((long) node1->content);
3016 l2 = -((long) node2->content);
3017 if (l1 < l2)
3018 return(1);
3019 if (l1 > l2)
3020 return(-1);
3021 } else
3022 goto turtle_comparison;
3023 }
3024 break;
3025 case XML_ATTRIBUTE_NODE:
3026 precedence1 = 1; /* element is owner */
3027 miscNode1 = node1;
3028 node1 = node1->parent;
3029 misc = 1;
3030 break;
3031 case XML_TEXT_NODE:
3032 case XML_CDATA_SECTION_NODE:
3033 case XML_COMMENT_NODE:
3034 case XML_PI_NODE: {
3035 miscNode1 = node1;
3036 /*
3037 * Find nearest element node.
3038 */
3039 if (node1->prev != NULL) {
3040 do {
3041 node1 = node1->prev;
3042 if (node1->type == XML_ELEMENT_NODE) {
3043 precedence1 = 3; /* element in prev-sibl axis */
3044 break;
3045 }
3046 if (node1->prev == NULL) {
3047 precedence1 = 2; /* element is parent */
3048 /*
3049 * URGENT TODO: Are there any cases, where the
3050 * parent of such a node is not an element node?
3051 */
3052 node1 = node1->parent;
3053 break;
3054 }
3055 } while (1);
3056 } else {
3057 precedence1 = 2; /* element is parent */
3058 node1 = node1->parent;
3059 }
3060 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
3061 (0 <= (long) node1->content)) {
3062 /*
3063 * Fallback for whatever case.
3064 */
3065 node1 = miscNode1;
3066 precedence1 = 0;
3067 } else
3068 misc = 1;
3069 }
3070 break;
3071 case XML_NAMESPACE_DECL:
3072 /*
3073 * TODO: why do we return 1 for namespace nodes?
3074 */
3075 return(1);
3076 default:
3077 break;
3078 }
3079 switch (node2->type) {
3080 case XML_ELEMENT_NODE:
3081 break;
3082 case XML_ATTRIBUTE_NODE:
3083 precedence2 = 1; /* element is owner */
3084 miscNode2 = node2;
3085 node2 = node2->parent;
3086 misc = 1;
3087 break;
3088 case XML_TEXT_NODE:
3089 case XML_CDATA_SECTION_NODE:
3090 case XML_COMMENT_NODE:
3091 case XML_PI_NODE: {
3092 miscNode2 = node2;
3093 if (node2->prev != NULL) {
3094 do {
3095 node2 = node2->prev;
3096 if (node2->type == XML_ELEMENT_NODE) {
3097 precedence2 = 3; /* element in prev-sibl axis */
3098 break;
3099 }
3100 if (node2->prev == NULL) {
3101 precedence2 = 2; /* element is parent */
3102 node2 = node2->parent;
3103 break;
3104 }
3105 } while (1);
3106 } else {
3107 precedence2 = 2; /* element is parent */
3108 node2 = node2->parent;
3109 }
3110 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3111 (0 <= (long) node1->content))
3112 {
3113 node2 = miscNode2;
3114 precedence2 = 0;
3115 } else
3116 misc = 1;
3117 }
3118 break;
3119 case XML_NAMESPACE_DECL:
3120 return(1);
3121 default:
3122 break;
3123 }
3124 if (misc) {
3125 if (node1 == node2) {
3126 if (precedence1 == precedence2) {
3127 /*
3128 * The ugly case; but normally there aren't many
3129 * adjacent non-element nodes around.
3130 */
3131 cur = miscNode2->prev;
3132 while (cur != NULL) {
3133 if (cur == miscNode1)
3134 return(1);
3135 if (cur->type == XML_ELEMENT_NODE)
3136 return(-1);
3137 cur = cur->prev;
3138 }
3139 return (-1);
3140 } else {
3141 /*
3142 * Evaluate based on higher precedence wrt to the element.
3143 * TODO: This assumes attributes are sorted before content.
3144 * Is this 100% correct?
3145 */
3146 if (precedence1 < precedence2)
3147 return(1);
3148 else
3149 return(-1);
3150 }
3151 }
3152 /*
3153 * Special case: One of the helper-elements is contained by the other.
3154 * <foo>
3155 * <node2>
3156 * <node1>Text-1(precedence1 == 2)</node1>
3157 * </node2>
3158 * Text-6(precedence2 == 3)
3159 * </foo>
3160 */
3161 if ((precedence2 == 3) && (precedence1 > 1)) {
3162 cur = node1->parent;
3163 while (cur) {
3164 if (cur == node2)
3165 return(1);
3166 cur = cur->parent;
3167 }
3168 }
3169 if ((precedence1 == 3) && (precedence2 > 1)) {
3170 cur = node2->parent;
3171 while (cur) {
3172 if (cur == node1)
3173 return(-1);
3174 cur = cur->parent;
3175 }
3176 }
3177 }
3178
3179 /*
3180 * Speedup using document order if availble.
3181 */
3182 if ((node1->type == XML_ELEMENT_NODE) &&
3183 (node2->type == XML_ELEMENT_NODE) &&
3184 (0 > (long) node1->content) &&
3185 (0 > (long) node2->content) &&
3186 (node1->doc == node2->doc)) {
3187
3188 l1 = -((long) node1->content);
3189 l2 = -((long) node2->content);
3190 if (l1 < l2)
3191 return(1);
3192 if (l1 > l2)
3193 return(-1);
3194 }
3195
3196 turtle_comparison:
3197
3198 if (node1 == node2->prev)
3199 return(1);
3200 if (node1 == node2->next)
3201 return(-1);
3202 /*
3203 * compute depth to root
3204 */
3205 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3206 if (cur == node1)
3207 return(1);
3208 depth2++;
3209 }
3210 root = cur;
3211 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3212 if (cur == node2)
3213 return(-1);
3214 depth1++;
3215 }
3216 /*
3217 * Distinct document (or distinct entities :-( ) case.
3218 */
3219 if (root != cur) {
3220 return(-2);
3221 }
3222 /*
3223 * get the nearest common ancestor.
3224 */
3225 while (depth1 > depth2) {
3226 depth1--;
3227 node1 = node1->parent;
3228 }
3229 while (depth2 > depth1) {
3230 depth2--;
3231 node2 = node2->parent;
3232 }
3233 while (node1->parent != node2->parent) {
3234 node1 = node1->parent;
3235 node2 = node2->parent;
3236 /* should not happen but just in case ... */
3237 if ((node1 == NULL) || (node2 == NULL))
3238 return(-2);
3239 }
3240 /*
3241 * Find who's first.
3242 */
3243 if (node1 == node2->prev)
3244 return(1);
3245 if (node1 == node2->next)
3246 return(-1);
3247 /*
3248 * Speedup using document order if availble.
3249 */
3250 if ((node1->type == XML_ELEMENT_NODE) &&
3251 (node2->type == XML_ELEMENT_NODE) &&
3252 (0 > (long) node1->content) &&
3253 (0 > (long) node2->content) &&
3254 (node1->doc == node2->doc)) {
3255
3256 l1 = -((long) node1->content);
3257 l2 = -((long) node2->content);
3258 if (l1 < l2)
3259 return(1);
3260 if (l1 > l2)
3261 return(-1);
3262 }
3263
3264 for (cur = node1->next;cur != NULL;cur = cur->next)
3265 if (cur == node2)
3266 return(1);
3267 return(-1); /* assume there is no sibling list corruption */
3268 }
3269 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
3270
3271 /**
3272 * xmlXPathNodeSetSort:
3273 * @set: the node set
3274 *
3275 * Sort the node set in document order
3276 */
3277 void
3278 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3279 int i, j, incr, len;
3280 xmlNodePtr tmp;
3281
3282 if (set == NULL)
3283 return;
3284
3285 /* Use Shell's sort to sort the node-set */
3286 len = set->nodeNr;
3287 for (incr = len / 2; incr > 0; incr /= 2) {
3288 for (i = incr; i < len; i++) {
3289 j = i - incr;
3290 while (j >= 0) {
3291 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3292 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3293 set->nodeTab[j + incr]) == -1)
3294 #else
3295 if (xmlXPathCmpNodes(set->nodeTab[j],
3296 set->nodeTab[j + incr]) == -1)
3297 #endif
3298 {
3299 tmp = set->nodeTab[j];
3300 set->nodeTab[j] = set->nodeTab[j + incr];
3301 set->nodeTab[j + incr] = tmp;
3302 j -= incr;
3303 } else
3304 break;
3305 }
3306 }
3307 }
3308 }
3309
3310 #define XML_NODESET_DEFAULT 10
3311 /**
3312 * xmlXPathNodeSetDupNs:
3313 * @node: the parent node of the namespace XPath node
3314 * @ns: the libxml namespace declaration node.
3315 *
3316 * Namespace node in libxml don't match the XPath semantic. In a node set
3317 * the namespace nodes are duplicated and the next pointer is set to the
3318 * parent node in the XPath semantic.
3319 *
3320 * Returns the newly created object.
3321 */
3322 static xmlNodePtr
3323 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3324 xmlNsPtr cur;
3325
3326 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3327 return(NULL);
3328 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3329 return((xmlNodePtr) ns);
3330
3331 /*
3332 * Allocate a new Namespace and fill the fields.
3333 */
3334 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3335 if (cur == NULL) {
3336 xmlXPathErrMemory(NULL, "duplicating namespace\n");
3337 return(NULL);
3338 }
3339 memset(cur, 0, sizeof(xmlNs));
3340 cur->type = XML_NAMESPACE_DECL;
3341 if (ns->href != NULL)
3342 cur->href = xmlStrdup(ns->href);
3343 if (ns->prefix != NULL)
3344 cur->prefix = xmlStrdup(ns->prefix);
3345 cur->next = (xmlNsPtr) node;
3346 return((xmlNodePtr) cur);
3347 }
3348
3349 /**
3350 * xmlXPathNodeSetFreeNs:
3351 * @ns: the XPath namespace node found in a nodeset.
3352 *
3353 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3354 * the namespace nodes are duplicated and the next pointer is set to the
3355 * parent node in the XPath semantic. Check if such a node needs to be freed
3356 */
3357 void
3358 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3359 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3360 return;
3361
3362 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3363 if (ns->href != NULL)
3364 xmlFree((xmlChar *)ns->href);
3365 if (ns->prefix != NULL)
3366 xmlFree((xmlChar *)ns->prefix);
3367 xmlFree(ns);
3368 }
3369 }
3370
3371 /**
3372 * xmlXPathNodeSetCreate:
3373 * @val: an initial xmlNodePtr, or NULL
3374 *
3375 * Create a new xmlNodeSetPtr of type double and of value @val
3376 *
3377 * Returns the newly created object.
3378 */
3379 xmlNodeSetPtr
3380 xmlXPathNodeSetCreate(xmlNodePtr val) {
3381 xmlNodeSetPtr ret;
3382
3383 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3384 if (ret == NULL) {
3385 xmlXPathErrMemory(NULL, "creating nodeset\n");
3386 return(NULL);
3387 }
3388 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3389 if (val != NULL) {
3390 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3391 sizeof(xmlNodePtr));
3392 if (ret->nodeTab == NULL) {
3393 xmlXPathErrMemory(NULL, "creating nodeset\n");
3394 xmlFree(ret);
3395 return(NULL);
3396 }
3397 memset(ret->nodeTab, 0 ,
3398 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3399 ret->nodeMax = XML_NODESET_DEFAULT;
3400 if (val->type == XML_NAMESPACE_DECL) {
3401 xmlNsPtr ns = (xmlNsPtr) val;
3402
3403 ret->nodeTab[ret->nodeNr++] =
3404 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3405 } else
3406 ret->nodeTab[ret->nodeNr++] = val;
3407 }
3408 return(ret);
3409 }
3410
3411 /**
3412 * xmlXPathNodeSetCreateSize:
3413 * @size: the initial size of the set
3414 *
3415 * Create a new xmlNodeSetPtr of type double and of value @val
3416 *
3417 * Returns the newly created object.
3418 */
3419 static xmlNodeSetPtr
3420 xmlXPathNodeSetCreateSize(int size) {
3421 xmlNodeSetPtr ret;
3422
3423 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3424 if (ret == NULL) {
3425 xmlXPathErrMemory(NULL, "creating nodeset\n");
3426 return(NULL);
3427 }
3428 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3429 if (size < XML_NODESET_DEFAULT)
3430 size = XML_NODESET_DEFAULT;
3431 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3432 if (ret->nodeTab == NULL) {
3433 xmlXPathErrMemory(NULL, "creating nodeset\n");
3434 xmlFree(ret);
3435 return(NULL);
3436 }
3437 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3438 ret->nodeMax = size;
3439 return(ret);
3440 }
3441
3442 /**
3443 * xmlXPathNodeSetContains:
3444 * @cur: the node-set
3445 * @val: the node
3446 *
3447 * checks whether @cur contains @val
3448 *
3449 * Returns true (1) if @cur contains @val, false (0) otherwise
3450 */
3451 int
3452 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3453 int i;
3454
3455 if ((cur == NULL) || (val == NULL)) return(0);
3456 if (val->type == XML_NAMESPACE_DECL) {
3457 for (i = 0; i < cur->nodeNr; i++) {
3458 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3459 xmlNsPtr ns1, ns2;
3460
3461 ns1 = (xmlNsPtr) val;
3462 ns2 = (xmlNsPtr) cur->nodeTab[i];
3463 if (ns1 == ns2)
3464 return(1);
3465 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3466 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3467 return(1);
3468 }
3469 }
3470 } else {
3471 for (i = 0; i < cur->nodeNr; i++) {
3472 if (cur->nodeTab[i] == val)
3473 return(1);
3474 }
3475 }
3476 return(0);
3477 }
3478
3479 /**
3480 * xmlXPathNodeSetAddNs:
3481 * @cur: the initial node set
3482 * @node: the hosting node
3483 * @ns: a the namespace node
3484 *
3485 * add a new namespace node to an existing NodeSet
3486 */
3487 void
3488 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3489 int i;
3490
3491
3492 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3493 (ns->type != XML_NAMESPACE_DECL) ||
3494 (node->type != XML_ELEMENT_NODE))
3495 return;
3496
3497 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3498 /*
3499 * prevent duplicates
3500 */
3501 for (i = 0;i < cur->nodeNr;i++) {
3502 if ((cur->nodeTab[i] != NULL) &&
3503 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3504 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3505 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3506 return;
3507 }
3508
3509 /*
3510 * grow the nodeTab if needed
3511 */
3512 if (cur->nodeMax == 0) {
3513 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3514 sizeof(xmlNodePtr));
3515 if (cur->nodeTab == NULL) {
3516 xmlXPathErrMemory(NULL, "growing nodeset\n");
3517 return;
3518 }
3519 memset(cur->nodeTab, 0 ,
3520 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3521 cur->nodeMax = XML_NODESET_DEFAULT;
3522 } else if (cur->nodeNr == cur->nodeMax) {
3523 xmlNodePtr *temp;
3524
3525 cur->nodeMax *= 2;
3526 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3527 sizeof(xmlNodePtr));
3528 if (temp == NULL) {
3529 xmlXPathErrMemory(NULL, "growing nodeset\n");
3530 return;
3531 }
3532 cur->nodeTab = temp;
3533 }
3534 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3535 }
3536
3537 /**
3538 * xmlXPathNodeSetAdd:
3539 * @cur: the initial node set
3540 * @val: a new xmlNodePtr
3541 *
3542 * add a new xmlNodePtr to an existing NodeSet
3543 */
3544 void
3545 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3546 int i;
3547
3548 if ((cur == NULL) || (val == NULL)) return;
3549
3550 #if 0
3551 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3552 return; /* an XSLT fake node */
3553 #endif
3554
3555 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3556 /*
3557 * prevent duplcates
3558 */
3559 for (i = 0;i < cur->nodeNr;i++)
3560 if (cur->nodeTab[i] == val) return;
3561
3562 /*
3563 * grow the nodeTab if needed
3564 */
3565 if (cur->nodeMax == 0) {
3566 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3567 sizeof(xmlNodePtr));
3568 if (cur->nodeTab == NULL) {
3569 xmlXPathErrMemory(NULL, "growing nodeset\n");
3570 return;
3571 }
3572 memset(cur->nodeTab, 0 ,
3573 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3574 cur->nodeMax = XML_NODESET_DEFAULT;
3575 } else if (cur->nodeNr == cur->nodeMax) {
3576 xmlNodePtr *temp;
3577
3578 cur->nodeMax *= 2;
3579 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3580 sizeof(xmlNodePtr));
3581 if (temp == NULL) {
3582 xmlXPathErrMemory(NULL, "growing nodeset\n");
3583 return;
3584 }
3585 cur->nodeTab = temp;
3586 }
3587 if (val->type == XML_NAMESPACE_DECL) {
3588 xmlNsPtr ns = (xmlNsPtr) val;
3589
3590 cur->nodeTab[cur->nodeNr++] =
3591 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3592 } else
3593 cur->nodeTab[cur->nodeNr++] = val;
3594 }
3595
3596 /**
3597 * xmlXPathNodeSetAddUnique:
3598 * @cur: the initial node set
3599 * @val: a new xmlNodePtr
3600 *
3601 * add a new xmlNodePtr to an existing NodeSet, optimized version
3602 * when we are sure the node is not already in the set.
3603 */
3604 void
3605 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3606 if ((cur == NULL) || (val == NULL)) return;
3607
3608 #if 0
3609 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3610 return; /* an XSLT fake node */
3611 #endif
3612
3613 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3614 /*
3615 * grow the nodeTab if needed
3616 */
3617 if (cur->nodeMax == 0) {
3618 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3619 sizeof(xmlNodePtr));
3620 if (cur->nodeTab == NULL) {
3621 xmlXPathErrMemory(NULL, "growing nodeset\n");
3622 return;
3623 }
3624 memset(cur->nodeTab, 0 ,
3625 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3626 cur->nodeMax = XML_NODESET_DEFAULT;
3627 } else if (cur->nodeNr == cur->nodeMax) {
3628 xmlNodePtr *temp;
3629
3630 cur->nodeMax *= 2;
3631 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3632 sizeof(xmlNodePtr));
3633 if (temp == NULL) {
3634 xmlXPathErrMemory(NULL, "growing nodeset\n");
3635 return;
3636 }
3637 cur->nodeTab = temp;
3638 }
3639 if (val->type == XML_NAMESPACE_DECL) {
3640 xmlNsPtr ns = (xmlNsPtr) val;
3641
3642 cur->nodeTab[cur->nodeNr++] =
3643 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3644 } else
3645 cur->nodeTab[cur->nodeNr++] = val;
3646 }
3647
3648 /**
3649 * xmlXPathNodeSetMerge:
3650 * @val1: the first NodeSet or NULL
3651 * @val2: the second NodeSet
3652 *
3653 * Merges two nodesets, all nodes from @val2 are added to @val1
3654 * if @val1 is NULL, a new set is created and copied from @val2
3655 *
3656 * Returns @val1 once extended or NULL in case of error.
3657 */
3658 xmlNodeSetPtr
3659 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3660 int i, j, initNr, skip;
3661 xmlNodePtr n1, n2;
3662
3663 if (val2 == NULL) return(val1);
3664 if (val1 == NULL) {
3665 val1 = xmlXPathNodeSetCreate(NULL);
3666 if (val1 == NULL)
3667 return (NULL);
3668 #if 0
3669 /*
3670 * TODO: The optimization won't work in every case, since
3671 * those nasty namespace nodes need to be added with
3672 * xmlXPathNodeSetDupNs() to the set; thus a pure
3673 * memcpy is not possible.
3674 * If there was a flag on the nodesetval, indicating that
3675 * some temporary nodes are in, that would be helpfull.
3676 */
3677 /*
3678 * Optimization: Create an equally sized node-set
3679 * and memcpy the content.
3680 */
3681 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3682 if (val1 == NULL)
3683 return(NULL);
3684 if (val2->nodeNr != 0) {
3685 if (val2->nodeNr == 1)
3686 *(val1->nodeTab) = *(val2->nodeTab);
3687 else {
3688 memcpy(val1->nodeTab, val2->nodeTab,
3689 val2->nodeNr * sizeof(xmlNodePtr));
3690 }
3691 val1->nodeNr = val2->nodeNr;
3692 }
3693 return(val1);
3694 #endif
3695 }
3696
3697 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3698 initNr = val1->nodeNr;
3699
3700 for (i = 0;i < val2->nodeNr;i++) {
3701 n2 = val2->nodeTab[i];
3702 /*
3703 * check against duplicates
3704 */
3705 skip = 0;
3706 for (j = 0; j < initNr; j++) {
3707 n1 = val1->nodeTab[j];
3708 if (n1 == n2) {
3709 skip = 1;
3710 break;
3711 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3712 (n2->type == XML_NAMESPACE_DECL)) {
3713 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3714 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3715 ((xmlNsPtr) n2)->prefix)))
3716 {
3717 skip = 1;
3718 break;
3719 }
3720 }
3721 }
3722 if (skip)
3723 continue;
3724
3725 /*
3726 * grow the nodeTab if needed
3727 */
3728 if (val1->nodeMax == 0) {
3729 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3730 sizeof(xmlNodePtr));
3731 if (val1->nodeTab == NULL) {
3732 xmlXPathErrMemory(NULL, "merging nodeset\n");
3733 return(NULL);
3734 }
3735 memset(val1->nodeTab, 0 ,
3736 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3737 val1->nodeMax = XML_NODESET_DEFAULT;
3738 } else if (val1->nodeNr == val1->nodeMax) {
3739 xmlNodePtr *temp;
3740
3741 val1->nodeMax *= 2;
3742 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3743 sizeof(xmlNodePtr));
3744 if (temp == NULL) {
3745 xmlXPathErrMemory(NULL, "merging nodeset\n");
3746 return(NULL);
3747 }
3748 val1->nodeTab = temp;
3749 }
3750 if (n2->type == XML_NAMESPACE_DECL) {
3751 xmlNsPtr ns = (xmlNsPtr) n2;
3752
3753 val1->nodeTab[val1->nodeNr++] =
3754 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3755 } else
3756 val1->nodeTab[val1->nodeNr++] = n2;
3757 }
3758
3759 return(val1);
3760 }
3761
3762 #if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3763 /**
3764 * xmlXPathNodeSetMergeUnique:
3765 * @val1: the first NodeSet or NULL
3766 * @val2: the second NodeSet
3767 *
3768 * Merges two nodesets, all nodes from @val2 are added to @val1
3769 * if @val1 is NULL, a new set is created and copied from @val2
3770 *
3771 * Returns @val1 once extended or NULL in case of error.
3772 */
3773 static xmlNodeSetPtr
3774 xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3775 int i;
3776
3777 if (val2 == NULL) return(val1);
3778 if (val1 == NULL) {
3779 val1 = xmlXPathNodeSetCreate(NULL);
3780 }
3781 if (val1 == NULL)
3782 return (NULL);
3783
3784 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3785
3786 for (i = 0;i < val2->nodeNr;i++) {
3787 /*
3788 * grow the nodeTab if needed
3789 */
3790 if (val1->nodeMax == 0) {
3791 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3792 sizeof(xmlNodePtr));
3793 if (val1->nodeTab == NULL) {
3794 xmlXPathErrMemory(NULL, "merging nodeset\n");
3795 return(NULL);
3796 }
3797 memset(val1->nodeTab, 0 ,
3798 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3799 val1->nodeMax = XML_NODESET_DEFAULT;
3800 } else if (val1->nodeNr == val1->nodeMax) {
3801 xmlNodePtr *temp;
3802
3803 val1->nodeMax *= 2;
3804 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3805 sizeof(xmlNodePtr));
3806 if (temp == NULL) {
3807 xmlXPathErrMemory(NULL, "merging nodeset\n");
3808 return(NULL);
3809 }
3810 val1->nodeTab = temp;
3811 }
3812 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3813 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
3814
3815 val1->nodeTab[val1->nodeNr++] =
3816 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3817 } else
3818 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
3819 }
3820
3821 return(val1);
3822 }
3823 #endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3824
3825 /**
3826 * xmlXPathNodeSetMergeAndClear:
3827 * @set1: the first NodeSet or NULL
3828 * @set2: the second NodeSet
3829 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3830 *
3831 * Merges two nodesets, all nodes from @set2 are added to @set1
3832 * if @set1 is NULL, a new set is created and copied from @set2.
3833 * Checks for duplicate nodes. Clears set2.
3834 *
3835 * Returns @set1 once extended or NULL in case of error.
3836 */
3837 static xmlNodeSetPtr
3838 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3839 int hasNullEntries)
3840 {
3841 if ((set1 == NULL) && (hasNullEntries == 0)) {
3842 /*
3843 * Note that doing a memcpy of the list, namespace nodes are
3844 * just assigned to set1, since set2 is cleared anyway.
3845 */
3846 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3847 if (set1 == NULL)
3848 return(NULL);
3849 if (set2->nodeNr != 0) {
3850 memcpy(set1->nodeTab, set2->nodeTab,
3851 set2->nodeNr * sizeof(xmlNodePtr));
3852 set1->nodeNr = set2->nodeNr;
3853 }
3854 } else {
3855 int i, j, initNbSet1;
3856 xmlNodePtr n1, n2;
3857
3858 if (set1 == NULL)
3859 set1 = xmlXPathNodeSetCreate(NULL);
3860 if (set1 == NULL)
3861 return (NULL);
3862
3863 initNbSet1 = set1->nodeNr;
3864 for (i = 0;i < set2->nodeNr;i++) {
3865 n2 = set2->nodeTab[i];
3866 /*
3867 * Skip NULLed entries.
3868 */
3869 if (n2 == NULL)
3870 continue;
3871 /*
3872 * Skip duplicates.
3873 */
3874 for (j = 0; j < initNbSet1; j++) {
3875 n1 = set1->nodeTab[j];
3876 if (n1 == n2) {
3877 goto skip_node;
3878 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3879 (n2->type == XML_NAMESPACE_DECL))
3880 {
3881 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3882 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3883 ((xmlNsPtr) n2)->prefix)))
3884 {
3885 /*
3886 * Free the namespace node.
3887 */
3888 set2->nodeTab[i] = NULL;
3889 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3890 goto skip_node;
3891 }
3892 }
3893 }
3894 /*
3895 * grow the nodeTab if needed
3896 */
3897 if (set1->nodeMax == 0) {
3898 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3899 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3900 if (set1->nodeTab == NULL) {
3901 xmlXPathErrMemory(NULL, "merging nodeset\n");
3902 return(NULL);
3903 }
3904 memset(set1->nodeTab, 0,
3905 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3906 set1->nodeMax = XML_NODESET_DEFAULT;
3907 } else if (set1->nodeNr >= set1->nodeMax) {
3908 xmlNodePtr *temp;
3909
3910 set1->nodeMax *= 2;
3911 temp = (xmlNodePtr *) xmlRealloc(
3912 set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3913 if (temp == NULL) {
3914 xmlXPathErrMemory(NULL, "merging nodeset\n");
3915 return(NULL);
3916 }
3917 set1->nodeTab = temp;
3918 }
3919 if (n2->type == XML_NAMESPACE_DECL) {
3920 xmlNsPtr ns = (xmlNsPtr) n2;
3921
3922 set1->nodeTab[set1->nodeNr++] =
3923 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3924 } else
3925 set1->nodeTab[set1->nodeNr++] = n2;
3926 skip_node:
3927 {}
3928 }
3929 }
3930 set2->nodeNr = 0;
3931 return(set1);
3932 }
3933
3934 /**
3935 * xmlXPathNodeSetMergeAndClearNoDupls:
3936 * @set1: the first NodeSet or NULL
3937 * @set2: the second NodeSet
3938 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3939 *
3940 * Merges two nodesets, all nodes from @set2 are added to @set1
3941 * if @set1 is NULL, a new set is created and copied from @set2.
3942 * Doesn't chack for duplicate nodes. Clears set2.
3943 *
3944 * Returns @set1 once extended or NULL in case of error.
3945 */
3946 static xmlNodeSetPtr
3947 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3948 int hasNullEntries)
3949 {
3950 if (set2 == NULL)
3951 return(set1);
3952 if ((set1 == NULL) && (hasNullEntries == 0)) {
3953 /*
3954 * Note that doing a memcpy of the list, namespace nodes are
3955 * just assigned to set1, since set2 is cleared anyway.
3956 */
3957 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3958 if (set1 == NULL)
3959 return(NULL);
3960 if (set2->nodeNr != 0) {
3961 memcpy(set1->nodeTab, set2->nodeTab,
3962 set2->nodeNr * sizeof(xmlNodePtr));
3963 set1->nodeNr = set2->nodeNr;
3964 }
3965 } else {
3966 int i;
3967 xmlNodePtr n2;
3968
3969 if (set1 == NULL)
3970 set1 = xmlXPathNodeSetCreate(NULL);
3971 if (set1 == NULL)
3972 return (NULL);
3973
3974 for (i = 0;i < set2->nodeNr;i++) {
3975 n2 = set2->nodeTab[i];
3976 /*
3977 * Skip NULLed entries.
3978 */
3979 if (n2 == NULL)
3980 continue;
3981 if (set1->nodeMax == 0) {
3982 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3983 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3984 if (set1->nodeTab == NULL) {
3985 xmlXPathErrMemory(NULL, "merging nodeset\n");
3986 return(NULL);
3987 }
3988 memset(set1->nodeTab, 0,
3989 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3990 set1->nodeMax = XML_NODESET_DEFAULT;
3991 } else if (set1->nodeNr >= set1->nodeMax) {
3992 xmlNodePtr *temp;
3993
3994 set1->nodeMax *= 2;
3995 temp = (xmlNodePtr *) xmlRealloc(
3996 set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3997 if (temp == NULL) {
3998 xmlXPathErrMemory(NULL, "merging nodeset\n");
3999 return(NULL);
4000 }
4001 set1->nodeTab = temp;
4002 }
4003 set1->nodeTab[set1->nodeNr++] = n2;
4004 }
4005 }
4006 set2->nodeNr = 0;
4007 return(set1);
4008 }
4009
4010 /**
4011 * xmlXPathNodeSetDel:
4012 * @cur: the initial node set
4013 * @val: an xmlNodePtr
4014 *
4015 * Removes an xmlNodePtr from an existing NodeSet
4016 */
4017 void
4018 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4019 int i;
4020
4021 if (cur == NULL) return;
4022 if (val == NULL) return;
4023
4024 /*
4025 * find node in nodeTab
4026 */
4027 for (i = 0;i < cur->nodeNr;i++)
4028 if (cur->nodeTab[i] == val) break;
4029
4030 if (i >= cur->nodeNr) { /* not found */
4031 #ifdef DEBUG
4032 xmlGenericError(xmlGenericErrorContext,
4033 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4034 val->name);
4035 #endif
4036 return;
4037 }
4038 if ((cur->nodeTab[i] != NULL) &&
4039 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4040 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4041 cur->nodeNr--;
4042 for (;i < cur->nodeNr;i++)
4043 cur->nodeTab[i] = cur->nodeTab[i + 1];
4044 cur->nodeTab[cur->nodeNr] = NULL;
4045 }
4046
4047 /**
4048 * xmlXPathNodeSetRemove:
4049 * @cur: the initial node set
4050 * @val: the index to remove
4051 *
4052 * Removes an entry from an existing NodeSet list.
4053 */
4054 void
4055 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4056 if (cur == NULL) return;
4057 if (val >= cur->nodeNr) return;
4058 if ((cur->nodeTab[val] != NULL) &&
4059 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4060 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4061 cur->nodeNr--;
4062 for (;val < cur->nodeNr;val++)
4063 cur->nodeTab[val] = cur->nodeTab[val + 1];
4064 cur->nodeTab[cur->nodeNr] = NULL;
4065 }
4066
4067 /**
4068 * xmlXPathFreeNodeSet:
4069 * @obj: the xmlNodeSetPtr to free
4070 *
4071 * Free the NodeSet compound (not the actual nodes !).
4072 */
4073 void
4074 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4075 if (obj == NULL) return;
4076 if (obj->nodeTab != NULL) {
4077 int i;
4078
4079 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4080 for (i = 0;i < obj->nodeNr;i++)
4081 if ((obj->nodeTab[i] != NULL) &&
4082 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4083 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4084 xmlFree(obj->nodeTab);
4085 }
4086 xmlFree(obj);
4087 }
4088
4089 /**
4090 * xmlXPathNodeSetClear:
4091 * @set: the node set to clear
4092 *
4093 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4094 * are feed), but does *not* free the list itself. Sets the length of the
4095 * list to 0.
4096 */
4097 static void
4098 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4099 {
4100 if ((set == NULL) || (set->nodeNr <= 0))
4101 return;
4102 else if (hasNsNodes) {
4103 int i;
4104 xmlNodePtr node;
4105
4106 for (i = 0; i < set->nodeNr; i++) {
4107 node = set->nodeTab[i];
4108 if ((node != NULL) &&
4109 (node->type == XML_NAMESPACE_DECL))
4110 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4111 }
4112 }
4113 set->nodeNr = 0;
4114 }
4115
4116 /**
4117 * xmlXPathNodeSetClearFromPos:
4118 * @set: the node set to be cleared
4119 * @pos: the start position to clear from
4120 *
4121 * Clears the list from temporary XPath objects (e.g. namespace nodes
4122 * are feed) starting with the entry at @pos, but does *not* free the list
4123 * itself. Sets the length of the list to @pos.
4124 */
4125 static void
4126 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4127 {
4128 if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4129 return;
4130 else if ((hasNsNodes)) {
4131 int i;
4132 xmlNodePtr node;
4133
4134 for (i = pos; i < set->nodeNr; i++) {
4135 node = set->nodeTab[i];
4136 if ((node != NULL) &&
4137 (node->type == XML_NAMESPACE_DECL))
4138 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4139 }
4140 }
4141 set->nodeNr = pos;
4142 }
4143
4144 /**
4145 * xmlXPathFreeValueTree:
4146 * @obj: the xmlNodeSetPtr to free
4147 *
4148 * Free the NodeSet compound and the actual tree, this is different
4149 * from xmlXPathFreeNodeSet()
4150 */
4151 static void
4152 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4153 int i;
4154
4155 if (obj == NULL) return;
4156
4157 if (obj->nodeTab != NULL) {
4158 for (i = 0;i < obj->nodeNr;i++) {
4159 if (obj->nodeTab[i] != NULL) {
4160 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4161 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4162 } else {
4163 xmlFreeNodeList(obj->nodeTab[i]);
4164 }
4165 }
4166 }
4167 xmlFree(obj->nodeTab);
4168 }
4169 xmlFree(obj);
4170 }
4171
4172 #if defined(DEBUG) || defined(DEBUG_STEP)
4173 /**
4174 * xmlGenericErrorContextNodeSet:
4175 * @output: a FILE * for the output
4176 * @obj: the xmlNodeSetPtr to display
4177 *
4178 * Quick display of a NodeSet
4179 */
4180 void
4181 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4182 int i;
4183
4184 if (output == NULL) output = xmlGenericErrorContext;
4185 if (obj == NULL) {
4186 fprintf(output, "NodeSet == NULL !\n");
4187 return;
4188 }
4189 if (obj->nodeNr == 0) {
4190 fprintf(output, "NodeSet is empty\n");
4191 return;
4192 }
4193 if (obj->nodeTab == NULL) {
4194 fprintf(output, " nodeTab == NULL !\n");
4195 return;
4196 }
4197 for (i = 0; i < obj->nodeNr; i++) {
4198 if (obj->nodeTab[i] == NULL) {
4199 fprintf(output, " NULL !\n");
4200 return;
4201 }
4202 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4203 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4204 fprintf(output, " /");
4205 else if (obj->nodeTab[i]->name == NULL)
4206 fprintf(output, " noname!");
4207 else fprintf(output, " %s", obj->nodeTab[i]->name);
4208 }
4209 fprintf(output, "\n");
4210 }
4211 #endif
4212
4213 /**
4214 * xmlXPathNewNodeSet:
4215 * @val: the NodePtr value
4216 *
4217 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4218 * it with the single Node @val
4219 *
4220 * Returns the newly created object.
4221 */
4222 xmlXPathObjectPtr
4223 xmlXPathNewNodeSet(xmlNodePtr val) {
4224 xmlXPathObjectPtr ret;
4225
4226 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4227 if (ret == NULL) {
4228 xmlXPathErrMemory(NULL, "creating nodeset\n");
4229 return(NULL);
4230 }
4231 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4232 ret->type = XPATH_NODESET;
4233 ret->boolval = 0;
4234 ret->nodesetval = xmlXPathNodeSetCreate(val);
4235 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4236 #ifdef XP_DEBUG_OBJ_USAGE
4237 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4238 #endif
4239 return(ret);
4240 }
4241
4242 /**
4243 * xmlXPathNewValueTree:
4244 * @val: the NodePtr value
4245 *
4246 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4247 * it with the tree root @val
4248 *
4249 * Returns the newly created object.
4250 */
4251 xmlXPathObjectPtr
4252 xmlXPathNewValueTree(xmlNodePtr val) {
4253 xmlXPathObjectPtr ret;
4254
4255 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4256 if (ret == NULL) {
4257 xmlXPathErrMemory(NULL, "creating result value tree\n");
4258 return(NULL);
4259 }
4260 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4261 ret->type = XPATH_XSLT_TREE;
4262 ret->boolval = 1;
4263 ret->user = (void *) val;
4264 ret->nodesetval = xmlXPathNodeSetCreate(val);
4265 #ifdef XP_DEBUG_OBJ_USAGE
4266 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4267 #endif
4268 return(ret);
4269 }
4270
4271 /**
4272 * xmlXPathNewNodeSetList:
4273 * @val: an existing NodeSet
4274 *
4275 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4276 * it with the Nodeset @val
4277 *
4278 * Returns the newly created object.
4279 */
4280 xmlXPathObjectPtr
4281 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4282 {
4283 xmlXPathObjectPtr ret;
4284 int i;
4285
4286 if (val == NULL)
4287 ret = NULL;
4288 else if (val->nodeTab == NULL)
4289 ret = xmlXPathNewNodeSet(NULL);
4290 else {
4291 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4292 if (ret)
4293 for (i = 1; i < val->nodeNr; ++i)
4294 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
4295 }
4296
4297 return (ret);
4298 }
4299
4300 /**
4301 * xmlXPathWrapNodeSet:
4302 * @val: the NodePtr value
4303 *
4304 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4305 *
4306 * Returns the newly created object.
4307 */
4308 xmlXPathObjectPtr
4309 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4310 xmlXPathObjectPtr ret;
4311
4312 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4313 if (ret == NULL) {
4314 xmlXPathErrMemory(NULL, "creating node set object\n");
4315 return(NULL);
4316 }
4317 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4318 ret->type = XPATH_NODESET;
4319 ret->nodesetval = val;
4320 #ifdef XP_DEBUG_OBJ_USAGE
4321 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4322 #endif
4323 return(ret);
4324 }
4325
4326 /**
4327 * xmlXPathFreeNodeSetList:
4328 * @obj: an existing NodeSetList object
4329 *
4330 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4331 * the list contrary to xmlXPathFreeObject().
4332 */
4333 void
4334 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4335 if (obj == NULL) return;
4336 #ifdef XP_DEBUG_OBJ_USAGE
4337 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4338 #endif
4339 xmlFree(obj);
4340 }
4341
4342 /**
4343 * xmlXPathDifference:
4344 * @nodes1: a node-set
4345 * @nodes2: a node-set
4346 *
4347 * Implements the EXSLT - Sets difference() function:
4348 * node-set set:difference (node-set, node-set)
4349 *
4350 * Returns the difference between the two node sets, or nodes1 if
4351 * nodes2 is empty
4352 */
4353 xmlNodeSetPtr
4354 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4355 xmlNodeSetPtr ret;
4356 int i, l1;
4357 xmlNodePtr cur;
4358
4359 if (xmlXPathNodeSetIsEmpty(nodes2))
4360 return(nodes1);
4361
4362 ret = xmlXPathNodeSetCreate(NULL);
4363 if (xmlXPathNodeSetIsEmpty(nodes1))
4364 return(ret);
4365
4366 l1 = xmlXPathNodeSetGetLength(nodes1);
4367
4368 for (i = 0; i < l1; i++) {
4369 cur = xmlXPathNodeSetItem(nodes1, i);
4370 if (!xmlXPathNodeSetContains(nodes2, cur))
4371 xmlXPathNodeSetAddUnique(ret, cur);
4372 }
4373 return(ret);
4374 }
4375
4376 /**
4377 * xmlXPathIntersection:
4378 * @nodes1: a node-set
4379 * @nodes2: a node-set
4380 *
4381 * Implements the EXSLT - Sets intersection() function:
4382 * node-set set:intersection (node-set, node-set)
4383 *
4384 * Returns a node set comprising the nodes that are within both the
4385 * node sets passed as arguments
4386 */
4387 xmlNodeSetPtr
4388 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4389 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4390 int i, l1;
4391 xmlNodePtr cur;
4392
4393 if (ret == NULL)
4394 return(ret);
4395 if (xmlXPathNodeSetIsEmpty(nodes1))
4396 return(ret);
4397 if (xmlXPathNodeSetIsEmpty(nodes2))
4398 return(ret);
4399
4400 l1 = xmlXPathNodeSetGetLength(nodes1);
4401
4402 for (i = 0; i < l1; i++) {
4403 cur = xmlXPathNodeSetItem(nodes1, i);
4404 if (xmlXPathNodeSetContains(nodes2, cur))
4405 xmlXPathNodeSetAddUnique(ret, cur);
4406 }
4407 return(ret);
4408 }
4409
4410 /**
4411 * xmlXPathDistinctSorted:
4412 * @nodes: a node-set, sorted by document order
4413 *
4414 * Implements the EXSLT - Sets distinct() function:
4415 * node-set set:distinct (node-set)
4416 *
4417 * Returns a subset of the nodes contained in @nodes, or @nodes if
4418 * it is empty
4419 */
4420 xmlNodeSetPtr
4421 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4422 xmlNodeSetPtr ret;
4423 xmlHashTablePtr hash;
4424 int i, l;
4425 xmlChar * strval;
4426 xmlNodePtr cur;
4427
4428 if (xmlXPathNodeSetIsEmpty(nodes))
4429 return(nodes);
4430
4431 ret = xmlXPathNodeSetCreate(NULL);
4432 if (ret == NULL)
4433 return(ret);
4434 l = xmlXPathNodeSetGetLength(nodes);
4435 hash = xmlHashCreate (l);
4436 for (i = 0; i < l; i++) {
4437 cur = xmlXPathNodeSetItem(nodes, i);
4438 strval = xmlXPathCastNodeToString(cur);
4439 if (xmlHashLookup(hash, strval) == NULL) {
4440 xmlHashAddEntry(hash, strval, strval);
4441 xmlXPathNodeSetAddUnique(ret, cur);
4442 } else {
4443 xmlFree(strval);
4444 }
4445 }
4446 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4447 return(ret);
4448 }
4449
4450 /**
4451 * xmlXPathDistinct:
4452 * @nodes: a node-set
4453 *
4454 * Implements the EXSLT - Sets distinct() function:
4455 * node-set set:distinct (node-set)
4456 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4457 * is called with the sorted node-set
4458 *
4459 * Returns a subset of the nodes contained in @nodes, or @nodes if
4460 * it is empty
4461 */
4462 xmlNodeSetPtr
4463 xmlXPathDistinct (xmlNodeSetPtr nodes) {
4464 if (xmlXPathNodeSetIsEmpty(nodes))
4465 return(nodes);
4466
4467 xmlXPathNodeSetSort(nodes);
4468 return(xmlXPathDistinctSorted(nodes));
4469 }
4470
4471 /**
4472 * xmlXPathHasSameNodes:
4473 * @nodes1: a node-set
4474 * @nodes2: a node-set
4475 *
4476 * Implements the EXSLT - Sets has-same-nodes function:
4477 * boolean set:has-same-node(node-set, node-set)
4478 *
4479 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4480 * otherwise
4481 */
4482 int
4483 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4484 int i, l;
4485 xmlNodePtr cur;
4486
4487 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4488 xmlXPathNodeSetIsEmpty(nodes2))
4489 return(0);
4490
4491 l = xmlXPathNodeSetGetLength(nodes1);
4492 for (i = 0; i < l; i++) {
4493 cur = xmlXPathNodeSetItem(nodes1, i);
4494 if (xmlXPathNodeSetContains(nodes2, cur))
4495 return(1);
4496 }
4497 return(0);
4498 }
4499
4500 /**
4501 * xmlXPathNodeLeadingSorted:
4502 * @nodes: a node-set, sorted by document order
4503 * @node: a node
4504 *
4505 * Implements the EXSLT - Sets leading() function:
4506 * node-set set:leading (node-set, node-set)
4507 *
4508 * Returns the nodes in @nodes that precede @node in document order,
4509 * @nodes if @node is NULL or an empty node-set if @nodes
4510 * doesn't contain @node
4511 */
4512 xmlNodeSetPtr
4513 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4514 int i, l;
4515 xmlNodePtr cur;
4516 xmlNodeSetPtr ret;
4517
4518 if (node == NULL)
4519 return(nodes);
4520
4521 ret = xmlXPathNodeSetCreate(NULL);
4522 if (ret == NULL)
4523 return(ret);
4524 if (xmlXPathNodeSetIsEmpty(nodes) ||
4525 (!xmlXPathNodeSetContains(nodes, node)))
4526 return(ret);
4527
4528 l = xmlXPathNodeSetGetLength(nodes);
4529 for (i = 0; i < l; i++) {
4530 cur = xmlXPathNodeSetItem(nodes, i);
4531 if (cur == node)
4532 break;
4533 xmlXPathNodeSetAddUnique(ret, cur);
4534 }
4535 return(ret);
4536 }
4537
4538 /**
4539 * xmlXPathNodeLeading:
4540 * @nodes: a node-set
4541 * @node: a node
4542 *
4543 * Implements the EXSLT - Sets leading() function:
4544 * node-set set:leading (node-set, node-set)
4545 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4546 * is called.
4547 *
4548 * Returns the nodes in @nodes that precede @node in document order,
4549 * @nodes if @node is NULL or an empty node-set if @nodes
4550 * doesn't contain @node
4551 */
4552 xmlNodeSetPtr
4553 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4554 xmlXPathNodeSetSort(nodes);
4555 return(xmlXPathNodeLeadingSorted(nodes, node));
4556 }
4557
4558 /**
4559 * xmlXPathLeadingSorted:
4560 * @nodes1: a node-set, sorted by document order
4561 * @nodes2: a node-set, sorted by document order
4562 *
4563 * Implements the EXSLT - Sets leading() function:
4564 * node-set set:leading (node-set, node-set)
4565 *
4566 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4567 * in document order, @nodes1 if @nodes2 is NULL or empty or
4568 * an empty node-set if @nodes1 doesn't contain @nodes2
4569 */
4570 xmlNodeSetPtr
4571 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4572 if (xmlXPathNodeSetIsEmpty(nodes2))
4573 return(nodes1);
4574 return(xmlXPathNodeLeadingSorted(nodes1,
4575 xmlXPathNodeSetItem(nodes2, 1)));
4576 }
4577
4578 /**
4579 * xmlXPathLeading:
4580 * @nodes1: a node-set
4581 * @nodes2: a node-set
4582 *
4583 * Implements the EXSLT - Sets leading() function:
4584 * node-set set:leading (node-set, node-set)
4585 * @nodes1 and @nodes2 are sorted by document order, then
4586 * #exslSetsLeadingSorted is called.
4587 *
4588 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4589 * in document order, @nodes1 if @nodes2 is NULL or empty or
4590 * an empty node-set if @nodes1 doesn't contain @nodes2
4591 */
4592 xmlNodeSetPtr
4593 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4594 if (xmlXPathNodeSetIsEmpty(nodes2))
4595 return(nodes1);
4596 if (xmlXPathNodeSetIsEmpty(nodes1))
4597 return(xmlXPathNodeSetCreate(NULL));
4598 xmlXPathNodeSetSort(nodes1);
4599 xmlXPathNodeSetSort(nodes2);
4600 return(xmlXPathNodeLeadingSorted(nodes1,
4601 xmlXPathNodeSetItem(nodes2, 1)));
4602 }
4603
4604 /**
4605 * xmlXPathNodeTrailingSorted:
4606 * @nodes: a node-set, sorted by document order
4607 * @node: a node
4608 *
4609 * Implements the EXSLT - Sets trailing() function:
4610 * node-set set:trailing (node-set, node-set)
4611 *
4612 * Returns the nodes in @nodes that follow @node in document order,
4613 * @nodes if @node is NULL or an empty node-set if @nodes
4614 * doesn't contain @node
4615 */
4616 xmlNodeSetPtr
4617 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4618 int i, l;
4619 xmlNodePtr cur;
4620 xmlNodeSetPtr ret;
4621
4622 if (node == NULL)
4623 return(nodes);
4624
4625 ret = xmlXPathNodeSetCreate(NULL);
4626 if (ret == NULL)
4627 return(ret);
4628 if (xmlXPathNodeSetIsEmpty(nodes) ||
4629 (!xmlXPathNodeSetContains(nodes, node)))
4630 return(ret);
4631
4632 l = xmlXPathNodeSetGetLength(nodes);
4633 for (i = l - 1; i >= 0; i--) {
4634 cur = xmlXPathNodeSetItem(nodes, i);
4635 if (cur == node)
4636 break;
4637 xmlXPathNodeSetAddUnique(ret, cur);
4638 }
4639 xmlXPathNodeSetSort(ret); /* bug 413451 */
4640 return(ret);
4641 }
4642
4643 /**
4644 * xmlXPathNodeTrailing:
4645 * @nodes: a node-set
4646 * @node: a node
4647 *
4648 * Implements the EXSLT - Sets trailing() function:
4649 * node-set set:trailing (node-set, node-set)
4650 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4651 * is called.
4652 *
4653 * Returns the nodes in @nodes that follow @node in document order,
4654 * @nodes if @node is NULL or an empty node-set if @nodes
4655 * doesn't contain @node
4656 */
4657 xmlNodeSetPtr
4658 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4659 xmlXPathNodeSetSort(nodes);
4660 return(xmlXPathNodeTrailingSorted(nodes, node));
4661 }
4662
4663 /**
4664 * xmlXPathTrailingSorted:
4665 * @nodes1: a node-set, sorted by document order
4666 * @nodes2: a node-set, sorted by document order
4667 *
4668 * Implements the EXSLT - Sets trailing() function:
4669 * node-set set:trailing (node-set, node-set)
4670 *
4671 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4672 * in document order, @nodes1 if @nodes2 is NULL or empty or
4673 * an empty node-set if @nodes1 doesn't contain @nodes2
4674 */
4675 xmlNodeSetPtr
4676 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4677 if (xmlXPathNodeSetIsEmpty(nodes2))
4678 return(nodes1);
4679 return(xmlXPathNodeTrailingSorted(nodes1,
4680 xmlXPathNodeSetItem(nodes2, 0)));
4681 }
4682
4683 /**
4684 * xmlXPathTrailing:
4685 * @nodes1: a node-set
4686 * @nodes2: a node-set
4687 *
4688 * Implements the EXSLT - Sets trailing() function:
4689 * node-set set:trailing (node-set, node-set)
4690 * @nodes1 and @nodes2 are sorted by document order, then
4691 * #xmlXPathTrailingSorted is called.
4692 *
4693 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4694 * in document order, @nodes1 if @nodes2 is NULL or empty or
4695 * an empty node-set if @nodes1 doesn't contain @nodes2
4696 */
4697 xmlNodeSetPtr
4698 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4699 if (xmlXPathNodeSetIsEmpty(nodes2))
4700 return(nodes1);
4701 if (xmlXPathNodeSetIsEmpty(nodes1))
4702 return(xmlXPathNodeSetCreate(NULL));
4703 xmlXPathNodeSetSort(nodes1);
4704 xmlXPathNodeSetSort(nodes2);
4705 return(xmlXPathNodeTrailingSorted(nodes1,
4706 xmlXPathNodeSetItem(nodes2, 0)));
4707 }
4708
4709 /************************************************************************
4710 * *
4711 * Routines to handle extra functions *
4712 * *
4713 ************************************************************************/
4714
4715 /**
4716 * xmlXPathRegisterFunc:
4717 * @ctxt: the XPath context
4718 * @name: the function name
4719 * @f: the function implementation or NULL
4720 *
4721 * Register a new function. If @f is NULL it unregisters the function
4722 *
4723 * Returns 0 in case of success, -1 in case of error
4724 */
4725 int
4726 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4727 xmlXPathFunction f) {
4728 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4729 }
4730
4731 /**
4732 * xmlXPathRegisterFuncNS:
4733 * @ctxt: the XPath context
4734 * @name: the function name
4735 * @ns_uri: the function namespace URI
4736 * @f: the function implementation or NULL
4737 *
4738 * Register a new function. If @f is NULL it unregisters the function
4739 *
4740 * Returns 0 in case of success, -1 in case of error
4741 */
4742 int
4743 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4744 const xmlChar *ns_uri, xmlXPathFunction f) {
4745 if (ctxt == NULL)
4746 return(-1);
4747 if (name == NULL)
4748 return(-1);
4749
4750 if (ctxt->funcHash == NULL)
4751 ctxt->funcHash = xmlHashCreate(0);
4752 if (ctxt->funcHash == NULL)
4753 return(-1);
4754 if (f == NULL)
4755 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4756 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
4757 }
4758
4759 /**
4760 * xmlXPathRegisterFuncLookup:
4761 * @ctxt: the XPath context
4762 * @f: the lookup function
4763 * @funcCtxt: the lookup data
4764 *
4765 * Registers an external mechanism to do function lookup.
4766 */
4767 void
4768 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4769 xmlXPathFuncLookupFunc f,
4770 void *funcCtxt) {
4771 if (ctxt == NULL)
4772 return;
4773 ctxt->funcLookupFunc = f;
4774 ctxt->funcLookupData = funcCtxt;
4775 }
4776
4777 /**
4778 * xmlXPathFunctionLookup:
4779 * @ctxt: the XPath context
4780 * @name: the function name
4781 *
4782 * Search in the Function array of the context for the given
4783 * function.
4784 *
4785 * Returns the xmlXPathFunction or NULL if not found
4786 */
4787 xmlXPathFunction
4788 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4789 if (ctxt == NULL)
4790 return (NULL);
4791
4792 if (ctxt->funcLookupFunc != NULL) {
4793 xmlXPathFunction ret;
4794 xmlXPathFuncLookupFunc f;
4795
4796 f = ctxt->funcLookupFunc;
4797 ret = f(ctxt->funcLookupData, name, NULL);
4798 if (ret != NULL)
4799 return(ret);
4800 }
4801 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4802 }
4803
4804 /**
4805 * xmlXPathFunctionLookupNS:
4806 * @ctxt: the XPath context
4807 * @name: the function name
4808 * @ns_uri: the function namespace URI
4809 *
4810 * Search in the Function array of the context for the given
4811 * function.
4812 *
4813 * Returns the xmlXPathFunction or NULL if not found
4814 */
4815 xmlXPathFunction
4816 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4817 const xmlChar *ns_uri) {
4818 xmlXPathFunction ret;
4819
4820 if (ctxt == NULL)
4821 return(NULL);
4822 if (name == NULL)
4823 return(NULL);
4824
4825 if (ctxt->funcLookupFunc != NULL) {
4826 xmlXPathFuncLookupFunc f;
4827
4828 f = ctxt->funcLookupFunc;
4829 ret = f(ctxt->funcLookupData, name, ns_uri);
4830 if (ret != NULL)
4831 return(ret);
4832 }
4833
4834 if (ctxt->funcHash == NULL)
4835 return(NULL);
4836
4837 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4838 return(ret);
4839 }
4840
4841 /**
4842 * xmlXPathRegisteredFuncsCleanup:
4843 * @ctxt: the XPath context
4844 *
4845 * Cleanup the XPath context data associated to registered functions
4846 */
4847 void
4848 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4849 if (ctxt == NULL)
4850 return;
4851
4852 xmlHashFree(ctxt->funcHash, NULL);
4853 ctxt->funcHash = NULL;
4854 }
4855
4856 /************************************************************************
4857 * *
4858 * Routines to handle Variables *
4859 * *
4860 ************************************************************************/
4861
4862 /**
4863 * xmlXPathRegisterVariable:
4864 * @ctxt: the XPath context
4865 * @name: the variable name
4866 * @value: the variable value or NULL
4867 *
4868 * Register a new variable value. If @value is NULL it unregisters
4869 * the variable
4870 *
4871 * Returns 0 in case of success, -1 in case of error
4872 */
4873 int
4874 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4875 xmlXPathObjectPtr value) {
4876 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4877 }
4878
4879 /**
4880 * xmlXPathRegisterVariableNS:
4881 * @ctxt: the XPath context
4882 * @name: the variable name
4883 * @ns_uri: the variable namespace URI
4884 * @value: the variable value or NULL
4885 *
4886 * Register a new variable value. If @value is NULL it unregisters
4887 * the variable
4888 *
4889 * Returns 0 in case of success, -1 in case of error
4890 */
4891 int
4892 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4893 const xmlChar *ns_uri,
4894 xmlXPathObjectPtr value) {
4895 if (ctxt == NULL)
4896 return(-1);
4897 if (name == NULL)
4898 return(-1);
4899
4900 if (ctxt->varHash == NULL)
4901 ctxt->varHash = xmlHashCreate(0);
4902 if (ctxt->varHash == NULL)
4903 return(-1);
4904 if (value == NULL)
4905 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4906 (xmlHashDeallocator)xmlXPathFreeObject));
4907 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4908 (void *) value,
4909 (xmlHashDeallocator)xmlXPathFreeObject));
4910 }
4911
4912 /**
4913 * xmlXPathRegisterVariableLookup:
4914 * @ctxt: the XPath context
4915 * @f: the lookup function
4916 * @data: the lookup data
4917 *
4918 * register an external mechanism to do variable lookup
4919 */
4920 void
4921 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4922 xmlXPathVariableLookupFunc f, void *data) {
4923 if (ctxt == NULL)
4924 return;
4925 ctxt->varLookupFunc = f;
4926 ctxt->varLookupData = data;
4927 }
4928
4929 /**
4930 * xmlXPathVariableLookup:
4931 * @ctxt: the XPath context
4932 * @name: the variable name
4933 *
4934 * Search in the Variable array of the context for the given
4935 * variable value.
4936 *
4937 * Returns a copy of the value or NULL if not found
4938 */
4939 xmlXPathObjectPtr
4940 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4941 if (ctxt == NULL)
4942 return(NULL);
4943
4944 if (ctxt->varLookupFunc != NULL) {
4945 xmlXPathObjectPtr ret;
4946
4947 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4948 (ctxt->varLookupData, name, NULL);
4949 return(ret);
4950 }
4951 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4952 }
4953
4954 /**
4955 * xmlXPathVariableLookupNS:
4956 * @ctxt: the XPath context
4957 * @name: the variable name
4958 * @ns_uri: the variable namespace URI
4959 *
4960 * Search in the Variable array of the context for the given
4961 * variable value.
4962 *
4963 * Returns the a copy of the value or NULL if not found
4964 */
4965 xmlXPathObjectPtr
4966 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4967 const xmlChar *ns_uri) {
4968 if (ctxt == NULL)
4969 return(NULL);
4970
4971 if (ctxt->varLookupFunc != NULL) {
4972 xmlXPathObjectPtr ret;
4973
4974 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4975 (ctxt->varLookupData, name, ns_uri);
4976 if (ret != NULL) return(ret);
4977 }
4978
4979 if (ctxt->varHash == NULL)
4980 return(NULL);
4981 if (name == NULL)
4982 return(NULL);
4983
4984 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
4985 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
4986 }
4987
4988 /**
4989 * xmlXPathRegisteredVariablesCleanup:
4990 * @ctxt: the XPath context
4991 *
4992 * Cleanup the XPath context data associated to registered variables
4993 */
4994 void
4995 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4996 if (ctxt == NULL)
4997 return;
4998
4999 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
5000 ctxt->varHash = NULL;
5001 }
5002
5003 /**
5004 * xmlXPathRegisterNs:
5005 * @ctxt: the XPath context
5006 * @prefix: the namespace prefix cannot be NULL or empty string
5007 * @ns_uri: the namespace name
5008 *
5009 * Register a new namespace. If @ns_uri is NULL it unregisters
5010 * the namespace
5011 *
5012 * Returns 0 in case of success, -1 in case of error
5013 */
5014 int
5015 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5016 const xmlChar *ns_uri) {
5017 if (ctxt == NULL)
5018 return(-1);
5019 if (prefix == NULL)
5020 return(-1);
5021 if (prefix[0] == 0)
5022 return(-1);
5023
5024 if (ctxt->nsHash == NULL)
5025 ctxt->nsHash = xmlHashCreate(10);
5026 if (ctxt->nsHash == NULL)
5027 return(-1);
5028 if (ns_uri == NULL)
5029 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5030 (xmlHashDeallocator)xmlFree));
5031 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5032 (xmlHashDeallocator)xmlFree));
5033 }
5034
5035 /**
5036 * xmlXPathNsLookup:
5037 * @ctxt: the XPath context
5038 * @prefix: the namespace prefix value
5039 *
5040 * Search in the namespace declaration array of the context for the given
5041 * namespace name associated to the given prefix
5042 *
5043 * Returns the value or NULL if not found
5044 */
5045 const xmlChar *
5046 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5047 if (ctxt == NULL)
5048 return(NULL);
5049 if (prefix == NULL)
5050 return(NULL);
5051
5052 #ifdef XML_XML_NAMESPACE
5053 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5054 return(XML_XML_NAMESPACE);
5055 #endif
5056
5057 if (ctxt->namespaces != NULL) {
5058 int i;
5059
5060 for (i = 0;i < ctxt->nsNr;i++) {
5061 if ((ctxt->namespaces[i] != NULL) &&
5062 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5063 return(ctxt->namespaces[i]->href);
5064 }
5065 }
5066
5067 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5068 }
5069
5070 /**
5071 * xmlXPathRegisteredNsCleanup:
5072 * @ctxt: the XPath context
5073 *
5074 * Cleanup the XPath context data associated to registered variables
5075 */
5076 void
5077 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5078 if (ctxt == NULL)
5079 return;
5080
5081 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
5082 ctxt->nsHash = NULL;
5083 }
5084
5085 /************************************************************************
5086 * *
5087 * Routines to handle Values *
5088 * *
5089 ************************************************************************/
5090
5091 /* Allocations are terrible, one needs to optimize all this !!! */
5092
5093 /**
5094 * xmlXPathNewFloat:
5095 * @val: the double value
5096 *
5097 * Create a new xmlXPathObjectPtr of type double and of value @val
5098 *
5099 * Returns the newly created object.
5100 */
5101 xmlXPathObjectPtr
5102 xmlXPathNewFloat(double val) {
5103 xmlXPathObjectPtr ret;
5104
5105 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5106 if (ret == NULL) {
5107 xmlXPathErrMemory(NULL, "creating float object\n");
5108 return(NULL);
5109 }
5110 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5111 ret->type = XPATH_NUMBER;
5112 ret->floatval = val;
5113 #ifdef XP_DEBUG_OBJ_USAGE
5114 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5115 #endif
5116 return(ret);
5117 }
5118
5119 /**
5120 * xmlXPathNewBoolean:
5121 * @val: the boolean value
5122 *
5123 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5124 *
5125 * Returns the newly created object.
5126 */
5127 xmlXPathObjectPtr
5128 xmlXPathNewBoolean(int val) {
5129 xmlXPathObjectPtr ret;
5130
5131 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5132 if (ret == NULL) {
5133 xmlXPathErrMemory(NULL, "creating boolean object\n");
5134 return(NULL);
5135 }
5136 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5137 ret->type = XPATH_BOOLEAN;
5138 ret->boolval = (val != 0);
5139 #ifdef XP_DEBUG_OBJ_USAGE
5140 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5141 #endif
5142 return(ret);
5143 }
5144
5145 /**
5146 * xmlXPathNewString:
5147 * @val: the xmlChar * value
5148 *
5149 * Create a new xmlXPathObjectPtr of type string and of value @val
5150 *
5151 * Returns the newly created object.
5152 */
5153 xmlXPathObjectPtr
5154 xmlXPathNewString(const xmlChar *val) {
5155 xmlXPathObjectPtr ret;
5156
5157 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5158 if (ret == NULL) {
5159 xmlXPathErrMemory(NULL, "creating string object\n");
5160 return(NULL);
5161 }
5162 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5163 ret->type = XPATH_STRING;
5164 if (val != NULL)
5165 ret->stringval = xmlStrdup(val);
5166 else
5167 ret->stringval = xmlStrdup((const xmlChar *)"");
5168 #ifdef XP_DEBUG_OBJ_USAGE
5169 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5170 #endif
5171 return(ret);
5172 }
5173
5174 /**
5175 * xmlXPathWrapString:
5176 * @val: the xmlChar * value
5177 *
5178 * Wraps the @val string into an XPath object.
5179 *
5180 * Returns the newly created object.
5181 */
5182 xmlXPathObjectPtr
5183 xmlXPathWrapString (xmlChar *val) {
5184 xmlXPathObjectPtr ret;
5185
5186 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5187 if (ret == NULL) {
5188 xmlXPathErrMemory(NULL, "creating string object\n");
5189 return(NULL);
5190 }
5191 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5192 ret->type = XPATH_STRING;
5193 ret->stringval = val;
5194 #ifdef XP_DEBUG_OBJ_USAGE
5195 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5196 #endif
5197 return(ret);
5198 }
5199
5200 /**
5201 * xmlXPathNewCString:
5202 * @val: the char * value
5203 *
5204 * Create a new xmlXPathObjectPtr of type string and of value @val
5205 *
5206 * Returns the newly created object.
5207 */
5208 xmlXPathObjectPtr
5209 xmlXPathNewCString(const char *val) {
5210 xmlXPathObjectPtr ret;
5211
5212 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5213 if (ret == NULL) {
5214 xmlXPathErrMemory(NULL, "creating string object\n");
5215 return(NULL);
5216 }
5217 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5218 ret->type = XPATH_STRING;
5219 ret->stringval = xmlStrdup(BAD_CAST val);
5220 #ifdef XP_DEBUG_OBJ_USAGE
5221 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5222 #endif
5223 return(ret);
5224 }
5225
5226 /**
5227 * xmlXPathWrapCString:
5228 * @val: the char * value
5229 *
5230 * Wraps a string into an XPath object.
5231 *
5232 * Returns the newly created object.
5233 */
5234 xmlXPathObjectPtr
5235 xmlXPathWrapCString (char * val) {
5236 return(xmlXPathWrapString((xmlChar *)(val)));
5237 }
5238
5239 /**
5240 * xmlXPathWrapExternal:
5241 * @val: the user data
5242 *
5243 * Wraps the @val data into an XPath object.
5244 *
5245 * Returns the newly created object.
5246 */
5247 xmlXPathObjectPtr
5248 xmlXPathWrapExternal (void *val) {
5249 xmlXPathObjectPtr ret;
5250
5251 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5252 if (ret == NULL) {
5253 xmlXPathErrMemory(NULL, "creating user object\n");
5254 return(NULL);
5255 }
5256 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5257 ret->type = XPATH_USERS;
5258 ret->user = val;
5259 #ifdef XP_DEBUG_OBJ_USAGE
5260 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5261 #endif
5262 return(ret);
5263 }
5264
5265 /**
5266 * xmlXPathObjectCopy:
5267 * @val: the original object
5268 *
5269 * allocate a new copy of a given object
5270 *
5271 * Returns the newly created object.
5272 */
5273 xmlXPathObjectPtr
5274 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5275 xmlXPathObjectPtr ret;
5276
5277 if (val == NULL)
5278 return(NULL);
5279
5280 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5281 if (ret == NULL) {
5282 xmlXPathErrMemory(NULL, "copying object\n");
5283 return(NULL);
5284 }
5285 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5286 #ifdef XP_DEBUG_OBJ_USAGE
5287 xmlXPathDebugObjUsageRequested(NULL, val->type);
5288 #endif
5289 switch (val->type) {
5290 case XPATH_BOOLEAN:
5291 case XPATH_NUMBER:
5292 case XPATH_POINT:
5293 case XPATH_RANGE:
5294 break;
5295 case XPATH_STRING:
5296 ret->stringval = xmlStrdup(val->stringval);
5297 break;
5298 case XPATH_XSLT_TREE:
5299 #if 0
5300 /*
5301 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5302 this previous handling is no longer correct, and can cause some serious
5303 problems (ref. bug 145547)
5304 */
5305 if ((val->nodesetval != NULL) &&
5306 (val->nodesetval->nodeTab != NULL)) {
5307 xmlNodePtr cur, tmp;
5308 xmlDocPtr top;
5309
5310 ret->boolval = 1;
5311 top = xmlNewDoc(NULL);
5312 top->name = (char *)
5313 xmlStrdup(val->nodesetval->nodeTab[0]->name);
5314 ret->user = top;
5315 if (top != NULL) {
5316 top->doc = top;
5317 cur = val->nodesetval->nodeTab[0]->children;
5318 while (cur != NULL) {
5319 tmp = xmlDocCopyNode(cur, top, 1);
5320 xmlAddChild((xmlNodePtr) top, tmp);
5321 cur = cur->next;
5322 }
5323 }
5324
5325 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5326 } else
5327 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5328 /* Deallocate the copied tree value */
5329 break;
5330 #endif
5331 case XPATH_NODESET:
5332 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5333 /* Do not deallocate the copied tree value */
5334 ret->boolval = 0;
5335 break;
5336 case XPATH_LOCATIONSET:
5337 #ifdef LIBXML_XPTR_ENABLED
5338 {
5339 xmlLocationSetPtr loc = val->user;
5340 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5341 break;
5342 }
5343 #endif
5344 case XPATH_USERS:
5345 ret->user = val->user;
5346 break;
5347 case XPATH_UNDEFINED:
5348 xmlGenericError(xmlGenericErrorContext,
5349 "xmlXPathObjectCopy: unsupported type %d\n",
5350 val->type);
5351 break;
5352 }
5353 return(ret);
5354 }
5355
5356 /**
5357 * xmlXPathFreeObject:
5358 * @obj: the object to free
5359 *
5360 * Free up an xmlXPathObjectPtr object.
5361 */
5362 void
5363 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5364 if (obj == NULL) return;
5365 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5366 if (obj->boolval) {
5367 #if 0
5368 if (obj->user != NULL) {
5369 xmlXPathFreeNodeSet(obj->nodesetval);
5370 xmlFreeNodeList((xmlNodePtr) obj->user);
5371 } else
5372 #endif
5373 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5374 if (obj->nodesetval != NULL)
5375 xmlXPathFreeValueTree(obj->nodesetval);
5376 } else {
5377 if (obj->nodesetval != NULL)
5378 xmlXPathFreeNodeSet(obj->nodesetval);
5379 }
5380 #ifdef LIBXML_XPTR_ENABLED
5381 } else if (obj->type == XPATH_LOCATIONSET) {
5382 if (obj->user != NULL)
5383 xmlXPtrFreeLocationSet(obj->user);
5384 #endif
5385 } else if (obj->type == XPATH_STRING) {
5386 if (obj->stringval != NULL)
5387 xmlFree(obj->stringval);
5388 }
5389 #ifdef XP_DEBUG_OBJ_USAGE
5390 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5391 #endif
5392 xmlFree(obj);
5393 }
5394
5395 /**
5396 * xmlXPathReleaseObject:
5397 * @obj: the xmlXPathObjectPtr to free or to cache
5398 *
5399 * Depending on the state of the cache this frees the given
5400 * XPath object or stores it in the cache.
5401 */
5402 static void
5403 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5404 {
5405 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5406 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5407 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5408
5409 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5410
5411 if (obj == NULL)
5412 return;
5413 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5414 xmlXPathFreeObject(obj);
5415 } else {
5416 xmlXPathContextCachePtr cache =
5417 (xmlXPathContextCachePtr) ctxt->cache;
5418
5419 switch (obj->type) {
5420 case XPATH_NODESET:
5421 case XPATH_XSLT_TREE:
5422 if (obj->nodesetval != NULL) {
5423 if (obj->boolval) {
5424 /*
5425 * It looks like the @boolval is used for
5426 * evaluation if this an XSLT Result Tree Fragment.
5427 * TODO: Check if this assumption is correct.
5428 */
5429 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5430 xmlXPathFreeValueTree(obj->nodesetval);
5431 obj->nodesetval = NULL;
5432 } else if ((obj->nodesetval->nodeMax <= 40) &&
5433 (XP_CACHE_WANTS(cache->nodesetObjs,
5434 cache->maxNodeset)))
5435 {
5436 XP_CACHE_ADD(cache->nodesetObjs, obj);
5437 goto obj_cached;
5438 } else {
5439 xmlXPathFreeNodeSet(obj->nodesetval);
5440 obj->nodesetval = NULL;
5441 }
5442 }
5443 break;
5444 case XPATH_STRING:
5445 if (obj->stringval != NULL)
5446 xmlFree(obj->stringval);
5447
5448 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5449 XP_CACHE_ADD(cache->stringObjs, obj);
5450 goto obj_cached;
5451 }
5452 break;
5453 case XPATH_BOOLEAN:
5454 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5455 XP_CACHE_ADD(cache->booleanObjs, obj);
5456 goto obj_cached;
5457 }
5458 break;
5459 case XPATH_NUMBER:
5460 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5461 XP_CACHE_ADD(cache->numberObjs, obj);
5462 goto obj_cached;
5463 }
5464 break;
5465 #ifdef LIBXML_XPTR_ENABLED
5466 case XPATH_LOCATIONSET:
5467 if (obj->user != NULL) {
5468 xmlXPtrFreeLocationSet(obj->user);
5469 }
5470 goto free_obj;
5471 #endif
5472 default:
5473 goto free_obj;
5474 }
5475
5476 /*
5477 * Fallback to adding to the misc-objects slot.
5478 */
5479 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5480 XP_CACHE_ADD(cache->miscObjs, obj);
5481 } else
5482 goto free_obj;
5483
5484 obj_cached:
5485
5486 #ifdef XP_DEBUG_OBJ_USAGE
5487 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5488 #endif
5489
5490 if (obj->nodesetval != NULL) {
5491 xmlNodeSetPtr tmpset = obj->nodesetval;
5492
5493 /*
5494 * TODO: Due to those nasty ns-nodes, we need to traverse
5495 * the list and free the ns-nodes.
5496 * URGENT TODO: Check if it's actually slowing things down.
5497 * Maybe we shouldn't try to preserve the list.
5498 */
5499 if (tmpset->nodeNr > 1) {
5500 int i;
5501 xmlNodePtr node;
5502
5503 for (i = 0; i < tmpset->nodeNr; i++) {
5504 node = tmpset->nodeTab[i];
5505 if ((node != NULL) &&
5506 (node->type == XML_NAMESPACE_DECL))
5507 {
5508 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5509 }
5510 }
5511 } else if (tmpset->nodeNr == 1) {
5512 if ((tmpset->nodeTab[0] != NULL) &&
5513 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5514 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5515 }
5516 tmpset->nodeNr = 0;
5517 memset(obj, 0, sizeof(xmlXPathObject));
5518 obj->nodesetval = tmpset;
5519 } else
5520 memset(obj, 0, sizeof(xmlXPathObject));
5521
5522 return;
5523
5524 free_obj:
5525 /*
5526 * Cache is full; free the object.
5527 */
5528 if (obj->nodesetval != NULL)
5529 xmlXPathFreeNodeSet(obj->nodesetval);
5530 #ifdef XP_DEBUG_OBJ_USAGE
5531 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5532 #endif
5533 xmlFree(obj);
5534 }
5535 return;
5536 }
5537
5538
5539 /************************************************************************
5540 * *
5541 * Type Casting Routines *
5542 * *
5543 ************************************************************************/
5544
5545 /**
5546 * xmlXPathCastBooleanToString:
5547 * @val: a boolean
5548 *
5549 * Converts a boolean to its string value.
5550 *
5551 * Returns a newly allocated string.
5552 */
5553 xmlChar *
5554 xmlXPathCastBooleanToString (int val) {
5555 xmlChar *ret;
5556 if (val)
5557 ret = xmlStrdup((const xmlChar *) "true");
5558 else
5559 ret = xmlStrdup((const xmlChar *) "false");
5560 return(ret);
5561 }
5562
5563 /**
5564 * xmlXPathCastNumberToString:
5565 * @val: a number
5566 *
5567 * Converts a number to its string value.
5568 *
5569 * Returns a newly allocated string.
5570 */
5571 xmlChar *
5572 xmlXPathCastNumberToString (double val) {
5573 xmlChar *ret;
5574 switch (xmlXPathIsInf(val)) {
5575 case 1:
5576 ret = xmlStrdup((const xmlChar *) "Infinity");
5577 break;
5578 case -1:
5579 ret = xmlStrdup((const xmlChar *) "-Infinity");
5580 break;
5581 default:
5582 if (xmlXPathIsNaN(val)) {
5583 ret = xmlStrdup((const xmlChar *) "NaN");
5584 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5585 ret = xmlStrdup((const xmlChar *) "0");
5586 } else {
5587 /* could be improved */
5588 char buf[100];
5589 xmlXPathFormatNumber(val, buf, 99);
5590 buf[99] = 0;
5591 ret = xmlStrdup((const xmlChar *) buf);
5592 }
5593 }
5594 return(ret);
5595 }
5596
5597 /**
5598 * xmlXPathCastNodeToString:
5599 * @node: a node
5600 *
5601 * Converts a node to its string value.
5602 *
5603 * Returns a newly allocated string.
5604 */
5605 xmlChar *
5606 xmlXPathCastNodeToString (xmlNodePtr node) {
5607 xmlChar *ret;
5608 if ((ret = xmlNodeGetContent(node)) == NULL)
5609 ret = xmlStrdup((const xmlChar *) "");
5610 return(ret);
5611 }
5612
5613 /**
5614 * xmlXPathCastNodeSetToString:
5615 * @ns: a node-set
5616 *
5617 * Converts a node-set to its string value.
5618 *
5619 * Returns a newly allocated string.
5620 */
5621 xmlChar *
5622 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5623 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5624 return(xmlStrdup((const xmlChar *) ""));
5625
5626 if (ns->nodeNr > 1)
5627 xmlXPathNodeSetSort(ns);
5628 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5629 }
5630
5631 /**
5632 * xmlXPathCastToString:
5633 * @val: an XPath object
5634 *
5635 * Converts an existing object to its string() equivalent
5636 *
5637 * Returns the allocated string value of the object, NULL in case of error.
5638 * It's up to the caller to free the string memory with xmlFree().
5639 */
5640 xmlChar *
5641 xmlXPathCastToString(xmlXPathObjectPtr val) {
5642 xmlChar *ret = NULL;
5643
5644 if (val == NULL)
5645 return(xmlStrdup((const xmlChar *) ""));
5646 switch (val->type) {
5647 case XPATH_UNDEFINED:
5648 #ifdef DEBUG_EXPR
5649 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5650 #endif
5651 ret = xmlStrdup((const xmlChar *) "");
5652 break;
5653 case XPATH_NODESET:
5654 case XPATH_XSLT_TREE:
5655 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5656 break;
5657 case XPATH_STRING:
5658 return(xmlStrdup(val->stringval));
5659 case XPATH_BOOLEAN:
5660 ret = xmlXPathCastBooleanToString(val->boolval);
5661 break;
5662 case XPATH_NUMBER: {
5663 ret = xmlXPathCastNumberToString(val->floatval);
5664 break;
5665 }
5666 case XPATH_USERS:
5667 case XPATH_POINT:
5668 case XPATH_RANGE:
5669 case XPATH_LOCATIONSET:
5670 TODO
5671 ret = xmlStrdup((const xmlChar *) "");
5672 break;
5673 }
5674 return(ret);
5675 }
5676
5677 /**
5678 * xmlXPathConvertString:
5679 * @val: an XPath object
5680 *
5681 * Converts an existing object to its string() equivalent
5682 *
5683 * Returns the new object, the old one is freed (or the operation
5684 * is done directly on @val)
5685 */
5686 xmlXPathObjectPtr
5687 xmlXPathConvertString(xmlXPathObjectPtr val) {
5688 xmlChar *res = NULL;
5689
5690 if (val == NULL)
5691 return(xmlXPathNewCString(""));
5692
5693 switch (val->type) {
5694 case XPATH_UNDEFINED:
5695 #ifdef DEBUG_EXPR
5696 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5697 #endif
5698 break;
5699 case XPATH_NODESET:
5700 case XPATH_XSLT_TREE:
5701 res = xmlXPathCastNodeSetToString(val->nodesetval);
5702 break;
5703 case XPATH_STRING:
5704 return(val);
5705 case XPATH_BOOLEAN:
5706 res = xmlXPathCastBooleanToString(val->boolval);
5707 break;
5708 case XPATH_NUMBER:
5709 res = xmlXPathCastNumberToString(val->floatval);
5710 break;
5711 case XPATH_USERS:
5712 case XPATH_POINT:
5713 case XPATH_RANGE:
5714 case XPATH_LOCATIONSET:
5715 TODO;
5716 break;
5717 }
5718 xmlXPathFreeObject(val);
5719 if (res == NULL)
5720 return(xmlXPathNewCString(""));
5721 return(xmlXPathWrapString(res));
5722 }
5723
5724 /**
5725 * xmlXPathCastBooleanToNumber:
5726 * @val: a boolean
5727 *
5728 * Converts a boolean to its number value
5729 *
5730 * Returns the number value
5731 */
5732 double
5733 xmlXPathCastBooleanToNumber(int val) {
5734 if (val)
5735 return(1.0);
5736 return(0.0);
5737 }
5738
5739 /**
5740 * xmlXPathCastStringToNumber:
5741 * @val: a string
5742 *
5743 * Converts a string to its number value
5744 *
5745 * Returns the number value
5746 */
5747 double
5748 xmlXPathCastStringToNumber(const xmlChar * val) {
5749 return(xmlXPathStringEvalNumber(val));
5750 }
5751
5752 /**
5753 * xmlXPathCastNodeToNumber:
5754 * @node: a node
5755 *
5756 * Converts a node to its number value
5757 *
5758 * Returns the number value
5759 */
5760 double
5761 xmlXPathCastNodeToNumber (xmlNodePtr node) {
5762 xmlChar *strval;
5763 double ret;
5764
5765 if (node == NULL)
5766 return(xmlXPathNAN);
5767 strval = xmlXPathCastNodeToString(node);
5768 if (strval == NULL)
5769 return(xmlXPathNAN);
5770 ret = xmlXPathCastStringToNumber(strval);
5771 xmlFree(strval);
5772
5773 return(ret);
5774 }
5775
5776 /**
5777 * xmlXPathCastNodeSetToNumber:
5778 * @ns: a node-set
5779 *
5780 * Converts a node-set to its number value
5781 *
5782 * Returns the number value
5783 */
5784 double
5785 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5786 xmlChar *str;
5787 double ret;
5788
5789 if (ns == NULL)
5790 return(xmlXPathNAN);
5791 str = xmlXPathCastNodeSetToString(ns);
5792 ret = xmlXPathCastStringToNumber(str);
5793 xmlFree(str);
5794 return(ret);
5795 }
5796
5797 /**
5798 * xmlXPathCastToNumber:
5799 * @val: an XPath object
5800 *
5801 * Converts an XPath object to its number value
5802 *
5803 * Returns the number value
5804 */
5805 double
5806 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5807 double ret = 0.0;
5808
5809 if (val == NULL)
5810 return(xmlXPathNAN);
5811 switch (val->type) {
5812 case XPATH_UNDEFINED:
5813 #ifdef DEGUB_EXPR
5814 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5815 #endif
5816 ret = xmlXPathNAN;
5817 break;
5818 case XPATH_NODESET:
5819 case XPATH_XSLT_TREE:
5820 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5821 break;
5822 case XPATH_STRING:
5823 ret = xmlXPathCastStringToNumber(val->stringval);
5824 break;
5825 case XPATH_NUMBER:
5826 ret = val->floatval;
5827 break;
5828 case XPATH_BOOLEAN:
5829 ret = xmlXPathCastBooleanToNumber(val->boolval);
5830 break;
5831 case XPATH_USERS:
5832 case XPATH_POINT:
5833 case XPATH_RANGE:
5834 case XPATH_LOCATIONSET:
5835 TODO;
5836 ret = xmlXPathNAN;
5837 break;
5838 }
5839 return(ret);
5840 }
5841
5842 /**
5843 * xmlXPathConvertNumber:
5844 * @val: an XPath object
5845 *
5846 * Converts an existing object to its number() equivalent
5847 *
5848 * Returns the new object, the old one is freed (or the operation
5849 * is done directly on @val)
5850 */
5851 xmlXPathObjectPtr
5852 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5853 xmlXPathObjectPtr ret;
5854
5855 if (val == NULL)
5856 return(xmlXPathNewFloat(0.0));
5857 if (val->type == XPATH_NUMBER)
5858 return(val);
5859 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5860 xmlXPathFreeObject(val);
5861 return(ret);
5862 }
5863
5864 /**
5865 * xmlXPathCastNumberToBoolean:
5866 * @val: a number
5867 *
5868 * Converts a number to its boolean value
5869 *
5870 * Returns the boolean value
5871 */
5872 int
5873 xmlXPathCastNumberToBoolean (double val) {
5874 if (xmlXPathIsNaN(val) || (val == 0.0))
5875 return(0);
5876 return(1);
5877 }
5878
5879 /**
5880 * xmlXPathCastStringToBoolean:
5881 * @val: a string
5882 *
5883 * Converts a string to its boolean value
5884 *
5885 * Returns the boolean value
5886 */
5887 int
5888 xmlXPathCastStringToBoolean (const xmlChar *val) {
5889 if ((val == NULL) || (xmlStrlen(val) == 0))
5890 return(0);
5891 return(1);
5892 }
5893
5894 /**
5895 * xmlXPathCastNodeSetToBoolean:
5896 * @ns: a node-set
5897 *
5898 * Converts a node-set to its boolean value
5899 *
5900 * Returns the boolean value
5901 */
5902 int
5903 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5904 if ((ns == NULL) || (ns->nodeNr == 0))
5905 return(0);
5906 return(1);
5907 }
5908
5909 /**
5910 * xmlXPathCastToBoolean:
5911 * @val: an XPath object
5912 *
5913 * Converts an XPath object to its boolean value
5914 *
5915 * Returns the boolean value
5916 */
5917 int
5918 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5919 int ret = 0;
5920
5921 if (val == NULL)
5922 return(0);
5923 switch (val->type) {
5924 case XPATH_UNDEFINED:
5925 #ifdef DEBUG_EXPR
5926 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
5927 #endif
5928 ret = 0;
5929 break;
5930 case XPATH_NODESET:
5931 case XPATH_XSLT_TREE:
5932 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5933 break;
5934 case XPATH_STRING:
5935 ret = xmlXPathCastStringToBoolean(val->stringval);
5936 break;
5937 case XPATH_NUMBER:
5938 ret = xmlXPathCastNumberToBoolean(val->floatval);
5939 break;
5940 case XPATH_BOOLEAN:
5941 ret = val->boolval;
5942 break;
5943 case XPATH_USERS:
5944 case XPATH_POINT:
5945 case XPATH_RANGE:
5946 case XPATH_LOCATIONSET:
5947 TODO;
5948 ret = 0;
5949 break;
5950 }
5951 return(ret);
5952 }
5953
5954
5955 /**
5956 * xmlXPathConvertBoolean:
5957 * @val: an XPath object
5958 *
5959 * Converts an existing object to its boolean() equivalent
5960 *
5961 * Returns the new object, the old one is freed (or the operation
5962 * is done directly on @val)
5963 */
5964 xmlXPathObjectPtr
5965 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
5966 xmlXPathObjectPtr ret;
5967
5968 if (val == NULL)
5969 return(xmlXPathNewBoolean(0));
5970 if (val->type == XPATH_BOOLEAN)
5971 return(val);
5972 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
5973 xmlXPathFreeObject(val);
5974 return(ret);
5975 }
5976
5977 /************************************************************************
5978 * *
5979 * Routines to handle XPath contexts *
5980 * *
5981 ************************************************************************/
5982
5983 /**
5984 * xmlXPathNewContext:
5985 * @doc: the XML document
5986 *
5987 * Create a new xmlXPathContext
5988 *
5989 * Returns the xmlXPathContext just allocated. The caller will need to free it.
5990 */
5991 xmlXPathContextPtr
5992 xmlXPathNewContext(xmlDocPtr doc) {
5993 xmlXPathContextPtr ret;
5994
5995 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
5996 if (ret == NULL) {
5997 xmlXPathErrMemory(NULL, "creating context\n");
5998 return(NULL);
5999 }
6000 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6001 ret->doc = doc;
6002 ret->node = NULL;
6003
6004 ret->varHash = NULL;
6005
6006 ret->nb_types = 0;
6007 ret->max_types = 0;
6008 ret->types = NULL;
6009
6010 ret->funcHash = xmlHashCreate(0);
6011
6012 ret->nb_axis = 0;
6013 ret->max_axis = 0;
6014 ret->axis = NULL;
6015
6016 ret->nsHash = NULL;
6017 ret->user = NULL;
6018
6019 ret->contextSize = -1;
6020 ret->proximityPosition = -1;
6021
6022 #ifdef XP_DEFAULT_CACHE_ON
6023 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6024 xmlXPathFreeContext(ret);
6025 return(NULL);
6026 }
6027 #endif
6028
6029 xmlXPathRegisterAllFunctions(ret);
6030
6031 return(ret);
6032 }
6033
6034 /**
6035 * xmlXPathFreeContext:
6036 * @ctxt: the context to free
6037 *
6038 * Free up an xmlXPathContext
6039 */
6040 void
6041 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6042 if (ctxt == NULL) return;
6043
6044 if (ctxt->cache != NULL)
6045 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6046 xmlXPathRegisteredNsCleanup(ctxt);
6047 xmlXPathRegisteredFuncsCleanup(ctxt);
6048 xmlXPathRegisteredVariablesCleanup(ctxt);
6049 xmlResetError(&ctxt->lastError);
6050 xmlFree(ctxt);
6051 }
6052
6053 /************************************************************************
6054 * *
6055 * Routines to handle XPath parser contexts *
6056 * *
6057 ************************************************************************/
6058
6059 #define CHECK_CTXT(ctxt) \
6060 if (ctxt == NULL) { \
6061 __xmlRaiseError(NULL, NULL, NULL, \
6062 NULL, NULL, XML_FROM_XPATH, \
6063 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6064 __FILE__, __LINE__, \
6065 NULL, NULL, NULL, 0, 0, \
6066 "NULL context pointer\n"); \
6067 return(NULL); \
6068 } \
6069
6070 #define CHECK_CTXT_NEG(ctxt) \
6071 if (ctxt == NULL) { \
6072 __xmlRaiseError(NULL, NULL, NULL, \
6073 NULL, NULL, XML_FROM_XPATH, \
6074 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6075 __FILE__, __LINE__, \
6076 NULL, NULL, NULL, 0, 0, \
6077 "NULL context pointer\n"); \
6078 return(-1); \
6079 } \
6080
6081
6082 #define CHECK_CONTEXT(ctxt) \
6083 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
6084 (ctxt->doc->children == NULL)) { \
6085 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
6086 return(NULL); \
6087 }
6088
6089
6090 /**
6091 * xmlXPathNewParserContext:
6092 * @str: the XPath expression
6093 * @ctxt: the XPath context
6094 *
6095 * Create a new xmlXPathParserContext
6096 *
6097 * Returns the xmlXPathParserContext just allocated.
6098 */
6099 xmlXPathParserContextPtr
6100 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6101 xmlXPathParserContextPtr ret;
6102
6103 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6104 if (ret == NULL) {
6105 xmlXPathErrMemory(ctxt, "creating parser context\n");
6106 return(NULL);
6107 }
6108 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6109 ret->cur = ret->base = str;
6110 ret->context = ctxt;
6111
6112 ret->comp = xmlXPathNewCompExpr();
6113 if (ret->comp == NULL) {
6114 xmlFree(ret->valueTab);
6115 xmlFree(ret);
6116 return(NULL);
6117 }
6118 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6119 ret->comp->dict = ctxt->dict;
6120 xmlDictReference(ret->comp->dict);
6121 }
6122
6123 return(ret);
6124 }
6125
6126 /**
6127 * xmlXPathCompParserContext:
6128 * @comp: the XPath compiled expression
6129 * @ctxt: the XPath context
6130 *
6131 * Create a new xmlXPathParserContext when processing a compiled expression
6132 *
6133 * Returns the xmlXPathParserContext just allocated.
6134 */
6135 static xmlXPathParserContextPtr
6136 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6137 xmlXPathParserContextPtr ret;
6138
6139 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6140 if (ret == NULL) {
6141 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6142 return(NULL);
6143 }
6144 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6145
6146 /* Allocate the value stack */
6147 ret->valueTab = (xmlXPathObjectPtr *)
6148 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6149 if (ret->valueTab == NULL) {
6150 xmlFree(ret);
6151 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6152 return(NULL);
6153 }
6154 ret->valueNr = 0;
6155 ret->valueMax = 10;
6156 ret->value = NULL;
6157
6158 ret->context = ctxt;
6159 ret->comp = comp;
6160
6161 return(ret);
6162 }
6163
6164 /**
6165 * xmlXPathFreeParserContext:
6166 * @ctxt: the context to free
6167 *
6168 * Free up an xmlXPathParserContext
6169 */
6170 void
6171 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6172 if (ctxt->valueTab != NULL) {
6173 xmlFree(ctxt->valueTab);
6174 }
6175 if (ctxt->comp != NULL) {
6176 #ifdef XPATH_STREAMING
6177 if (ctxt->comp->stream != NULL) {
6178 xmlFreePatternList(ctxt->comp->stream);
6179 ctxt->comp->stream = NULL;
6180 }
6181 #endif
6182 xmlXPathFreeCompExpr(ctxt->comp);
6183 }
6184 xmlFree(ctxt);
6185 }
6186
6187 /************************************************************************
6188 * *
6189 * The implicit core function library *
6190 * *
6191 ************************************************************************/
6192
6193 /**
6194 * xmlXPathNodeValHash:
6195 * @node: a node pointer
6196 *
6197 * Function computing the beginning of the string value of the node,
6198 * used to speed up comparisons
6199 *
6200 * Returns an int usable as a hash
6201 */
6202 static unsigned int
6203 xmlXPathNodeValHash(xmlNodePtr node) {
6204 int len = 2;
6205 const xmlChar * string = NULL;
6206 xmlNodePtr tmp = NULL;
6207 unsigned int ret = 0;
6208
6209 if (node == NULL)
6210 return(0);
6211
6212 if (node->type == XML_DOCUMENT_NODE) {
6213 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6214 if (tmp == NULL)
6215 node = node->children;
6216 else
6217 node = tmp;
6218
6219 if (node == NULL)
6220 return(0);
6221 }
6222
6223 switch (node->type) {
6224 case XML_COMMENT_NODE:
6225 case XML_PI_NODE:
6226 case XML_CDATA_SECTION_NODE:
6227 case XML_TEXT_NODE:
6228 string = node->content;
6229 if (string == NULL)
6230 return(0);
6231 if (string[0] == 0)
6232 return(0);
6233 return(((unsigned int) string[0]) +
6234 (((unsigned int) string[1]) << 8));
6235 case XML_NAMESPACE_DECL:
6236 string = ((xmlNsPtr)node)->href;
6237 if (string == NULL)
6238 return(0);
6239 if (string[0] == 0)
6240 return(0);
6241 return(((unsigned int) string[0]) +
6242 (((unsigned int) string[1]) << 8));
6243 case XML_ATTRIBUTE_NODE:
6244 tmp = ((xmlAttrPtr) node)->children;
6245 break;
6246 case XML_ELEMENT_NODE:
6247 tmp = node->children;
6248 break;
6249 default:
6250 return(0);
6251 }
6252 while (tmp != NULL) {
6253 switch (tmp->type) {
6254 case XML_COMMENT_NODE:
6255 case XML_PI_NODE:
6256 case XML_CDATA_SECTION_NODE:
6257 case XML_TEXT_NODE:
6258 string = tmp->content;
6259 break;
6260 case XML_NAMESPACE_DECL:
6261 string = ((xmlNsPtr)tmp)->href;
6262 break;
6263 default:
6264 break;
6265 }
6266 if ((string != NULL) && (string[0] != 0)) {
6267 if (len == 1) {
6268 return(ret + (((unsigned int) string[0]) << 8));
6269 }
6270 if (string[1] == 0) {
6271 len = 1;
6272 ret = (unsigned int) string[0];
6273 } else {
6274 return(((unsigned int) string[0]) +
6275 (((unsigned int) string[1]) << 8));
6276 }
6277 }
6278 /*
6279 * Skip to next node
6280 */
6281 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6282 if (tmp->children->type != XML_ENTITY_DECL) {
6283 tmp = tmp->children;
6284 continue;
6285 }
6286 }
6287 if (tmp == node)
6288 break;
6289
6290 if (tmp->next != NULL) {
6291 tmp = tmp->next;
6292 continue;
6293 }
6294
6295 do {
6296 tmp = tmp->parent;
6297 if (tmp == NULL)
6298 break;
6299 if (tmp == node) {
6300 tmp = NULL;
6301 break;
6302 }
6303 if (tmp->next != NULL) {
6304 tmp = tmp->next;
6305 break;
6306 }
6307 } while (tmp != NULL);
6308 }
6309 return(ret);
6310 }
6311
6312 /**
6313 * xmlXPathStringHash:
6314 * @string: a string
6315 *
6316 * Function computing the beginning of the string value of the node,
6317 * used to speed up comparisons
6318 *
6319 * Returns an int usable as a hash
6320 */
6321 static unsigned int
6322 xmlXPathStringHash(const xmlChar * string) {
6323 if (string == NULL)
6324 return((unsigned int) 0);
6325 if (string[0] == 0)
6326 return(0);
6327 return(((unsigned int) string[0]) +
6328 (((unsigned int) string[1]) << 8));
6329 }
6330
6331 /**
6332 * xmlXPathCompareNodeSetFloat:
6333 * @ctxt: the XPath Parser context
6334 * @inf: less than (1) or greater than (0)
6335 * @strict: is the comparison strict
6336 * @arg: the node set
6337 * @f: the value
6338 *
6339 * Implement the compare operation between a nodeset and a number
6340 * @ns < @val (1, 1, ...
6341 * @ns <= @val (1, 0, ...
6342 * @ns > @val (0, 1, ...
6343 * @ns >= @val (0, 0, ...
6344 *
6345 * If one object to be compared is a node-set and the other is a number,
6346 * then the comparison will be true if and only if there is a node in the
6347 * node-set such that the result of performing the comparison on the number
6348 * to be compared and on the result of converting the string-value of that
6349 * node to a number using the number function is true.
6350 *
6351 * Returns 0 or 1 depending on the results of the test.
6352 */
6353 static int
6354 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6355 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6356 int i, ret = 0;
6357 xmlNodeSetPtr ns;
6358 xmlChar *str2;
6359
6360 if ((f == NULL) || (arg == NULL) ||
6361 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6362 xmlXPathReleaseObject(ctxt->context, arg);
6363 xmlXPathReleaseObject(ctxt->context, f);
6364 return(0);
6365 }
6366 ns = arg->nodesetval;
6367 if (ns != NULL) {
6368 for (i = 0;i < ns->nodeNr;i++) {
6369 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6370 if (str2 != NULL) {
6371 valuePush(ctxt,
6372 xmlXPathCacheNewString(ctxt->context, str2));
6373 xmlFree(str2);
6374 xmlXPathNumberFunction(ctxt, 1);
6375 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6376 ret = xmlXPathCompareValues(ctxt, inf, strict);
6377 if (ret)
6378 break;
6379 }
6380 }
6381 }
6382 xmlXPathReleaseObject(ctxt->context, arg);
6383 xmlXPathReleaseObject(ctxt->context, f);
6384 return(ret);
6385 }
6386
6387 /**
6388 * xmlXPathCompareNodeSetString:
6389 * @ctxt: the XPath Parser context
6390 * @inf: less than (1) or greater than (0)
6391 * @strict: is the comparison strict
6392 * @arg: the node set
6393 * @s: the value
6394 *
6395 * Implement the compare operation between a nodeset and a string
6396 * @ns < @val (1, 1, ...
6397 * @ns <= @val (1, 0, ...
6398 * @ns > @val (0, 1, ...
6399 * @ns >= @val (0, 0, ...
6400 *
6401 * If one object to be compared is a node-set and the other is a string,
6402 * then the comparison will be true if and only if there is a node in
6403 * the node-set such that the result of performing the comparison on the
6404 * string-value of the node and the other string is true.
6405 *
6406 * Returns 0 or 1 depending on the results of the test.
6407 */
6408 static int
6409 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6410 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6411 int i, ret = 0;
6412 xmlNodeSetPtr ns;
6413 xmlChar *str2;
6414
6415 if ((s == NULL) || (arg == NULL) ||
6416 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6417 xmlXPathReleaseObject(ctxt->context, arg);
6418 xmlXPathReleaseObject(ctxt->context, s);
6419 return(0);
6420 }
6421 ns = arg->nodesetval;
6422 if (ns != NULL) {
6423 for (i = 0;i < ns->nodeNr;i++) {
6424 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6425 if (str2 != NULL) {
6426 valuePush(ctxt,
6427 xmlXPathCacheNewString(ctxt->context, str2));
6428 xmlFree(str2);
6429 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6430 ret = xmlXPathCompareValues(ctxt, inf, strict);
6431 if (ret)
6432 break;
6433 }
6434 }
6435 }
6436 xmlXPathReleaseObject(ctxt->context, arg);
6437 xmlXPathReleaseObject(ctxt->context, s);
6438 return(ret);
6439 }
6440
6441 /**
6442 * xmlXPathCompareNodeSets:
6443 * @inf: less than (1) or greater than (0)
6444 * @strict: is the comparison strict
6445 * @arg1: the first node set object
6446 * @arg2: the second node set object
6447 *
6448 * Implement the compare operation on nodesets:
6449 *
6450 * If both objects to be compared are node-sets, then the comparison
6451 * will be true if and only if there is a node in the first node-set
6452 * and a node in the second node-set such that the result of performing
6453 * the comparison on the string-values of the two nodes is true.
6454 * ....
6455 * When neither object to be compared is a node-set and the operator
6456 * is <=, <, >= or >, then the objects are compared by converting both
6457 * objects to numbers and comparing the numbers according to IEEE 754.
6458 * ....
6459 * The number function converts its argument to a number as follows:
6460 * - a string that consists of optional whitespace followed by an
6461 * optional minus sign followed by a Number followed by whitespace
6462 * is converted to the IEEE 754 number that is nearest (according
6463 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6464 * represented by the string; any other string is converted to NaN
6465 *
6466 * Conclusion all nodes need to be converted first to their string value
6467 * and then the comparison must be done when possible
6468 */
6469 static int
6470 xmlXPathCompareNodeSets(int inf, int strict,
6471 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6472 int i, j, init = 0;
6473 double val1;
6474 double *values2;
6475 int ret = 0;
6476 xmlNodeSetPtr ns1;
6477 xmlNodeSetPtr ns2;
6478
6479 if ((arg1 == NULL) ||
6480 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6481 xmlXPathFreeObject(arg2);
6482 return(0);
6483 }
6484 if ((arg2 == NULL) ||
6485 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6486 xmlXPathFreeObject(arg1);
6487 xmlXPathFreeObject(arg2);
6488 return(0);
6489 }
6490
6491 ns1 = arg1->nodesetval;
6492 ns2 = arg2->nodesetval;
6493
6494 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6495 xmlXPathFreeObject(arg1);
6496 xmlXPathFreeObject(arg2);
6497 return(0);
6498 }
6499 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6500 xmlXPathFreeObject(arg1);
6501 xmlXPathFreeObject(arg2);
6502 return(0);
6503 }
6504
6505 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6506 if (values2 == NULL) {
6507 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6508 xmlXPathFreeObject(arg1);
6509 xmlXPathFreeObject(arg2);
6510 return(0);
6511 }
6512 for (i = 0;i < ns1->nodeNr;i++) {
6513 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6514 if (xmlXPathIsNaN(val1))
6515 continue;
6516 for (j = 0;j < ns2->nodeNr;j++) {
6517 if (init == 0) {
6518 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6519 }
6520 if (xmlXPathIsNaN(values2[j]))
6521 continue;
6522 if (inf && strict)
6523 ret = (val1 < values2[j]);
6524 else if (inf && !strict)
6525 ret = (val1 <= values2[j]);
6526 else if (!inf && strict)
6527 ret = (val1 > values2[j]);
6528 else if (!inf && !strict)
6529 ret = (val1 >= values2[j]);
6530 if (ret)
6531 break;
6532 }
6533 if (ret)
6534 break;
6535 init = 1;
6536 }
6537 xmlFree(values2);
6538 xmlXPathFreeObject(arg1);
6539 xmlXPathFreeObject(arg2);
6540 return(ret);
6541 }
6542
6543 /**
6544 * xmlXPathCompareNodeSetValue:
6545 * @ctxt: the XPath Parser context
6546 * @inf: less than (1) or greater than (0)
6547 * @strict: is the comparison strict
6548 * @arg: the node set
6549 * @val: the value
6550 *
6551 * Implement the compare operation between a nodeset and a value
6552 * @ns < @val (1, 1, ...
6553 * @ns <= @val (1, 0, ...
6554 * @ns > @val (0, 1, ...
6555 * @ns >= @val (0, 0, ...
6556 *
6557 * If one object to be compared is a node-set and the other is a boolean,
6558 * then the comparison will be true if and only if the result of performing
6559 * the comparison on the boolean and on the result of converting
6560 * the node-set to a boolean using the boolean function is true.
6561 *
6562 * Returns 0 or 1 depending on the results of the test.
6563 */
6564 static int
6565 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6566 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6567 if ((val == NULL) || (arg == NULL) ||
6568 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6569 return(0);
6570
6571 switch(val->type) {
6572 case XPATH_NUMBER:
6573 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6574 case XPATH_NODESET:
6575 case XPATH_XSLT_TREE:
6576 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6577 case XPATH_STRING:
6578 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6579 case XPATH_BOOLEAN:
6580 valuePush(ctxt, arg);
6581 xmlXPathBooleanFunction(ctxt, 1);
6582 valuePush(ctxt, val);
6583 return(xmlXPathCompareValues(ctxt, inf, strict));
6584 default:
6585 TODO
6586 }
6587 return(0);
6588 }
6589
6590 /**
6591 * xmlXPathEqualNodeSetString:
6592 * @arg: the nodeset object argument
6593 * @str: the string to compare to.
6594 * @neq: flag to show whether for '=' (0) or '!=' (1)
6595 *
6596 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6597 * If one object to be compared is a node-set and the other is a string,
6598 * then the comparison will be true if and only if there is a node in
6599 * the node-set such that the result of performing the comparison on the
6600 * string-value of the node and the other string is true.
6601 *
6602 * Returns 0 or 1 depending on the results of the test.
6603 */
6604 static int
6605 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6606 {
6607 int i;
6608 xmlNodeSetPtr ns;
6609 xmlChar *str2;
6610 unsigned int hash;
6611
6612 if ((str == NULL) || (arg == NULL) ||
6613 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6614 return (0);
6615 ns = arg->nodesetval;
6616 /*
6617 * A NULL nodeset compared with a string is always false
6618 * (since there is no node equal, and no node not equal)
6619 */
6620 if ((ns == NULL) || (ns->nodeNr <= 0) )
6621 return (0);
6622 hash = xmlXPathStringHash(str);
6623 for (i = 0; i < ns->nodeNr; i++) {
6624 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6625 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6626 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6627 xmlFree(str2);
6628 if (neq)
6629 continue;
6630 return (1);
6631 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6632 if (neq)
6633 continue;
6634 return (1);
6635 } else if (neq) {
6636 if (str2 != NULL)
6637 xmlFree(str2);
6638 return (1);
6639 }
6640 if (str2 != NULL)
6641 xmlFree(str2);
6642 } else if (neq)
6643 return (1);
6644 }
6645 return (0);
6646 }
6647
6648 /**
6649 * xmlXPathEqualNodeSetFloat:
6650 * @arg: the nodeset object argument
6651 * @f: the float to compare to
6652 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
6653 *
6654 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6655 * If one object to be compared is a node-set and the other is a number,
6656 * then the comparison will be true if and only if there is a node in
6657 * the node-set such that the result of performing the comparison on the
6658 * number to be compared and on the result of converting the string-value
6659 * of that node to a number using the number function is true.
6660 *
6661 * Returns 0 or 1 depending on the results of the test.
6662 */
6663 static int
6664 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6665 xmlXPathObjectPtr arg, double f, int neq) {
6666 int i, ret=0;
6667 xmlNodeSetPtr ns;
6668 xmlChar *str2;
6669 xmlXPathObjectPtr val;
6670 double v;
6671
6672 if ((arg == NULL) ||
6673 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6674 return(0);
6675
6676 ns = arg->nodesetval;
6677 if (ns != NULL) {
6678 for (i=0;i<ns->nodeNr;i++) {
6679 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6680 if (str2 != NULL) {
6681 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6682 xmlFree(str2);
6683 xmlXPathNumberFunction(ctxt, 1);
6684 val = valuePop(ctxt);
6685 v = val->floatval;
6686 xmlXPathReleaseObject(ctxt->context, val);
6687 if (!xmlXPathIsNaN(v)) {
6688 if ((!neq) && (v==f)) {
6689 ret = 1;
6690 break;
6691 } else if ((neq) && (v!=f)) {
6692 ret = 1;
6693 break;
6694 }
6695 } else { /* NaN is unequal to any value */
6696 if (neq)
6697 ret = 1;
6698 }
6699 }
6700 }
6701 }
6702
6703 return(ret);
6704 }
6705
6706
6707 /**
6708 * xmlXPathEqualNodeSets:
6709 * @arg1: first nodeset object argument
6710 * @arg2: second nodeset object argument
6711 * @neq: flag to show whether to test '=' (0) or '!=' (1)
6712 *
6713 * Implement the equal / not equal operation on XPath nodesets:
6714 * @arg1 == @arg2 or @arg1 != @arg2
6715 * If both objects to be compared are node-sets, then the comparison
6716 * will be true if and only if there is a node in the first node-set and
6717 * a node in the second node-set such that the result of performing the
6718 * comparison on the string-values of the two nodes is true.
6719 *
6720 * (needless to say, this is a costly operation)
6721 *
6722 * Returns 0 or 1 depending on the results of the test.
6723 */
6724 static int
6725 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6726 int i, j;
6727 unsigned int *hashs1;
6728 unsigned int *hashs2;
6729 xmlChar **values1;
6730 xmlChar **values2;
6731 int ret = 0;
6732 xmlNodeSetPtr ns1;
6733 xmlNodeSetPtr ns2;
6734
6735 if ((arg1 == NULL) ||
6736 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6737 return(0);
6738 if ((arg2 == NULL) ||
6739 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6740 return(0);
6741
6742 ns1 = arg1->nodesetval;
6743 ns2 = arg2->nodesetval;
6744
6745 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6746 return(0);
6747 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6748 return(0);
6749
6750 /*
6751 * for equal, check if there is a node pertaining to both sets
6752 */
6753 if (neq == 0)
6754 for (i = 0;i < ns1->nodeNr;i++)
6755 for (j = 0;j < ns2->nodeNr;j++)
6756 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6757 return(1);
6758
6759 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6760 if (values1 == NULL) {
6761 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6762 return(0);
6763 }
6764 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6765 if (hashs1 == NULL) {
6766 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6767 xmlFree(values1);
6768 return(0);
6769 }
6770 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6771 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6772 if (values2 == NULL) {
6773 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6774 xmlFree(hashs1);
6775 xmlFree(values1);
6776 return(0);
6777 }
6778 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6779 if (hashs2 == NULL) {
6780 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6781 xmlFree(hashs1);
6782 xmlFree(values1);
6783 xmlFree(values2);
6784 return(0);
6785 }
6786 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6787 for (i = 0;i < ns1->nodeNr;i++) {
6788 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6789 for (j = 0;j < ns2->nodeNr;j++) {
6790 if (i == 0)
6791 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6792 if (hashs1[i] != hashs2[j]) {
6793 if (neq) {
6794 ret = 1;
6795 break;
6796 }
6797 }
6798 else {
6799 if (values1[i] == NULL)
6800 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6801 if (values2[j] == NULL)
6802 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6803 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6804 if (ret)
6805 break;
6806 }
6807 }
6808 if (ret)
6809 break;
6810 }
6811 for (i = 0;i < ns1->nodeNr;i++)
6812 if (values1[i] != NULL)
6813 xmlFree(values1[i]);
6814 for (j = 0;j < ns2->nodeNr;j++)
6815 if (values2[j] != NULL)
6816 xmlFree(values2[j]);
6817 xmlFree(values1);
6818 xmlFree(values2);
6819 xmlFree(hashs1);
6820 xmlFree(hashs2);
6821 return(ret);
6822 }
6823
6824 static int
6825 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6826 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6827 int ret = 0;
6828 /*
6829 *At this point we are assured neither arg1 nor arg2
6830 *is a nodeset, so we can just pick the appropriate routine.
6831 */
6832 switch (arg1->type) {
6833 case XPATH_UNDEFINED:
6834 #ifdef DEBUG_EXPR
6835 xmlGenericError(xmlGenericErrorContext,
6836 "Equal: undefined\n");
6837 #endif
6838 break;
6839 case XPATH_BOOLEAN:
6840 switch (arg2->type) {
6841 case XPATH_UNDEFINED:
6842 #ifdef DEBUG_EXPR
6843 xmlGenericError(xmlGenericErrorContext,
6844 "Equal: undefined\n");
6845 #endif
6846 break;
6847 case XPATH_BOOLEAN:
6848 #ifdef DEBUG_EXPR
6849 xmlGenericError(xmlGenericErrorContext,
6850 "Equal: %d boolean %d \n",
6851 arg1->boolval, arg2->boolval);
6852 #endif
6853 ret = (arg1->boolval == arg2->boolval);
6854 break;
6855 case XPATH_NUMBER:
6856 ret = (arg1->boolval ==
6857 xmlXPathCastNumberToBoolean(arg2->floatval));
6858 break;
6859 case XPATH_STRING:
6860 if ((arg2->stringval == NULL) ||
6861 (arg2->stringval[0] == 0)) ret = 0;
6862 else
6863 ret = 1;
6864 ret = (arg1->boolval == ret);
6865 break;
6866 case XPATH_USERS:
6867 case XPATH_POINT:
6868 case XPATH_RANGE:
6869 case XPATH_LOCATIONSET:
6870 TODO
6871 break;
6872 case XPATH_NODESET:
6873 case XPATH_XSLT_TREE:
6874 break;
6875 }
6876 break;
6877 case XPATH_NUMBER:
6878 switch (arg2->type) {
6879 case XPATH_UNDEFINED:
6880 #ifdef DEBUG_EXPR
6881 xmlGenericError(xmlGenericErrorContext,
6882 "Equal: undefined\n");
6883 #endif
6884 break;
6885 case XPATH_BOOLEAN:
6886 ret = (arg2->boolval==
6887 xmlXPathCastNumberToBoolean(arg1->floatval));
6888 break;
6889 case XPATH_STRING:
6890 valuePush(ctxt, arg2);
6891 xmlXPathNumberFunction(ctxt, 1);
6892 arg2 = valuePop(ctxt);
6893 /* no break on purpose */
6894 case XPATH_NUMBER:
6895 /* Hand check NaN and Infinity equalities */
6896 if (xmlXPathIsNaN(arg1->floatval) ||
6897 xmlXPathIsNaN(arg2->floatval)) {
6898 ret = 0;
6899 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6900 if (xmlXPathIsInf(arg2->floatval) == 1)
6901 ret = 1;
6902 else
6903 ret = 0;
6904 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6905 if (xmlXPathIsInf(arg2->floatval) == -1)
6906 ret = 1;
6907 else
6908 ret = 0;
6909 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6910 if (xmlXPathIsInf(arg1->floatval) == 1)
6911 ret = 1;
6912 else
6913 ret = 0;
6914 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6915 if (xmlXPathIsInf(arg1->floatval) == -1)
6916 ret = 1;
6917 else
6918 ret = 0;
6919 } else {
6920 ret = (arg1->floatval == arg2->floatval);
6921 }
6922 break;
6923 case XPATH_USERS:
6924 case XPATH_POINT:
6925 case XPATH_RANGE:
6926 case XPATH_LOCATIONSET:
6927 TODO
6928 break;
6929 case XPATH_NODESET:
6930 case XPATH_XSLT_TREE:
6931 break;
6932 }
6933 break;
6934 case XPATH_STRING:
6935 switch (arg2->type) {
6936 case XPATH_UNDEFINED:
6937 #ifdef DEBUG_EXPR
6938 xmlGenericError(xmlGenericErrorContext,
6939 "Equal: undefined\n");
6940 #endif
6941 break;
6942 case XPATH_BOOLEAN:
6943 if ((arg1->stringval == NULL) ||
6944 (arg1->stringval[0] == 0)) ret = 0;
6945 else
6946 ret = 1;
6947 ret = (arg2->boolval == ret);
6948 break;
6949 case XPATH_STRING:
6950 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6951 break;
6952 case XPATH_NUMBER:
6953 valuePush(ctxt, arg1);
6954 xmlXPathNumberFunction(ctxt, 1);
6955 arg1 = valuePop(ctxt);
6956 /* Hand check NaN and Infinity equalities */
6957 if (xmlXPathIsNaN(arg1->floatval) ||
6958 xmlXPathIsNaN(arg2->floatval)) {
6959 ret = 0;
6960 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6961 if (xmlXPathIsInf(arg2->floatval) == 1)
6962 ret = 1;
6963 else
6964 ret = 0;
6965 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6966 if (xmlXPathIsInf(arg2->floatval) == -1)
6967 ret = 1;
6968 else
6969 ret = 0;
6970 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6971 if (xmlXPathIsInf(arg1->floatval) == 1)
6972 ret = 1;
6973 else
6974 ret = 0;
6975 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6976 if (xmlXPathIsInf(arg1->floatval) == -1)
6977 ret = 1;
6978 else
6979 ret = 0;
6980 } else {
6981 ret = (arg1->floatval == arg2->floatval);
6982 }
6983 break;
6984 case XPATH_USERS:
6985 case XPATH_POINT:
6986 case XPATH_RANGE:
6987 case XPATH_LOCATIONSET:
6988 TODO
6989 break;
6990 case XPATH_NODESET:
6991 case XPATH_XSLT_TREE:
6992 break;
6993 }
6994 break;
6995 case XPATH_USERS:
6996 case XPATH_POINT:
6997 case XPATH_RANGE:
6998 case XPATH_LOCATIONSET:
6999 TODO
7000 break;
7001 case XPATH_NODESET:
7002 case XPATH_XSLT_TREE:
7003 break;
7004 }
7005 xmlXPathReleaseObject(ctxt->context, arg1);
7006 xmlXPathReleaseObject(ctxt->context, arg2);
7007 return(ret);
7008 }
7009
7010 /**
7011 * xmlXPathEqualValues:
7012 * @ctxt: the XPath Parser context
7013 *
7014 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7015 *
7016 * Returns 0 or 1 depending on the results of the test.
7017 */
7018 int
7019 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7020 xmlXPathObjectPtr arg1, arg2, argtmp;
7021 int ret = 0;
7022
7023 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7024 arg2 = valuePop(ctxt);
7025 arg1 = valuePop(ctxt);
7026 if ((arg1 == NULL) || (arg2 == NULL)) {
7027 if (arg1 != NULL)
7028 xmlXPathReleaseObject(ctxt->context, arg1);
7029 else
7030 xmlXPathReleaseObject(ctxt->context, arg2);
7031 XP_ERROR0(XPATH_INVALID_OPERAND);
7032 }
7033
7034 if (arg1 == arg2) {
7035 #ifdef DEBUG_EXPR
7036 xmlGenericError(xmlGenericErrorContext,
7037 "Equal: by pointer\n");
7038 #endif
7039 xmlXPathFreeObject(arg1);
7040 return(1);
7041 }
7042
7043 /*
7044 *If either argument is a nodeset, it's a 'special case'
7045 */
7046 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7047 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7048 /*
7049 *Hack it to assure arg1 is the nodeset
7050 */
7051 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7052 argtmp = arg2;
7053 arg2 = arg1;
7054 arg1 = argtmp;
7055 }
7056 switch (arg2->type) {
7057 case XPATH_UNDEFINED:
7058 #ifdef DEBUG_EXPR
7059 xmlGenericError(xmlGenericErrorContext,
7060 "Equal: undefined\n");
7061 #endif
7062 break;
7063 case XPATH_NODESET:
7064 case XPATH_XSLT_TREE:
7065 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7066 break;
7067 case XPATH_BOOLEAN:
7068 if ((arg1->nodesetval == NULL) ||
7069 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7070 else
7071 ret = 1;
7072 ret = (ret == arg2->boolval);
7073 break;
7074 case XPATH_NUMBER:
7075 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7076 break;
7077 case XPATH_STRING:
7078 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7079 break;
7080 case XPATH_USERS:
7081 case XPATH_POINT:
7082 case XPATH_RANGE:
7083 case XPATH_LOCATIONSET:
7084 TODO
7085 break;
7086 }
7087 xmlXPathReleaseObject(ctxt->context, arg1);
7088 xmlXPathReleaseObject(ctxt->context, arg2);
7089 return(ret);
7090 }
7091
7092 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7093 }
7094
7095 /**
7096 * xmlXPathNotEqualValues:
7097 * @ctxt: the XPath Parser context
7098 *
7099 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7100 *
7101 * Returns 0 or 1 depending on the results of the test.
7102 */
7103 int
7104 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7105 xmlXPathObjectPtr arg1, arg2, argtmp;
7106 int ret = 0;
7107
7108 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7109 arg2 = valuePop(ctxt);
7110 arg1 = valuePop(ctxt);
7111 if ((arg1 == NULL) || (arg2 == NULL)) {
7112 if (arg1 != NULL)
7113 xmlXPathReleaseObject(ctxt->context, arg1);
7114 else
7115 xmlXPathReleaseObject(ctxt->context, arg2);
7116 XP_ERROR0(XPATH_INVALID_OPERAND);
7117 }
7118
7119 if (arg1 == arg2) {
7120 #ifdef DEBUG_EXPR
7121 xmlGenericError(xmlGenericErrorContext,
7122 "NotEqual: by pointer\n");
7123 #endif
7124 xmlXPathReleaseObject(ctxt->context, arg1);
7125 return(0);
7126 }
7127
7128 /*
7129 *If either argument is a nodeset, it's a 'special case'
7130 */
7131 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7132 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7133 /*
7134 *Hack it to assure arg1 is the nodeset
7135 */
7136 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7137 argtmp = arg2;
7138 arg2 = arg1;
7139 arg1 = argtmp;
7140 }
7141 switch (arg2->type) {
7142 case XPATH_UNDEFINED:
7143 #ifdef DEBUG_EXPR
7144 xmlGenericError(xmlGenericErrorContext,
7145 "NotEqual: undefined\n");
7146 #endif
7147 break;
7148 case XPATH_NODESET:
7149 case XPATH_XSLT_TREE:
7150 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7151 break;
7152 case XPATH_BOOLEAN:
7153 if ((arg1->nodesetval == NULL) ||
7154 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7155 else
7156 ret = 1;
7157 ret = (ret != arg2->boolval);
7158 break;
7159 case XPATH_NUMBER:
7160 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7161 break;
7162 case XPATH_STRING:
7163 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7164 break;
7165 case XPATH_USERS:
7166 case XPATH_POINT:
7167 case XPATH_RANGE:
7168 case XPATH_LOCATIONSET:
7169 TODO
7170 break;
7171 }
7172 xmlXPathReleaseObject(ctxt->context, arg1);
7173 xmlXPathReleaseObject(ctxt->context, arg2);
7174 return(ret);
7175 }
7176
7177 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7178 }
7179
7180 /**
7181 * xmlXPathCompareValues:
7182 * @ctxt: the XPath Parser context
7183 * @inf: less than (1) or greater than (0)
7184 * @strict: is the comparison strict
7185 *
7186 * Implement the compare operation on XPath objects:
7187 * @arg1 < @arg2 (1, 1, ...
7188 * @arg1 <= @arg2 (1, 0, ...
7189 * @arg1 > @arg2 (0, 1, ...
7190 * @arg1 >= @arg2 (0, 0, ...
7191 *
7192 * When neither object to be compared is a node-set and the operator is
7193 * <=, <, >=, >, then the objects are compared by converted both objects
7194 * to numbers and comparing the numbers according to IEEE 754. The <
7195 * comparison will be true if and only if the first number is less than the
7196 * second number. The <= comparison will be true if and only if the first
7197 * number is less than or equal to the second number. The > comparison
7198 * will be true if and only if the first number is greater than the second
7199 * number. The >= comparison will be true if and only if the first number
7200 * is greater than or equal to the second number.
7201 *
7202 * Returns 1 if the comparison succeeded, 0 if it failed
7203 */
7204 int
7205 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7206 int ret = 0, arg1i = 0, arg2i = 0;
7207 xmlXPathObjectPtr arg1, arg2;
7208
7209 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7210 arg2 = valuePop(ctxt);
7211 arg1 = valuePop(ctxt);
7212 if ((arg1 == NULL) || (arg2 == NULL)) {
7213 if (arg1 != NULL)
7214 xmlXPathReleaseObject(ctxt->context, arg1);
7215 else
7216 xmlXPathReleaseObject(ctxt->context, arg2);
7217 XP_ERROR0(XPATH_INVALID_OPERAND);
7218 }
7219
7220 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7221 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7222 /*
7223 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7224 * are not freed from within this routine; they will be freed from the
7225 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7226 */
7227 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7228 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7229 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7230 } else {
7231 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7232 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7233 arg1, arg2);
7234 } else {
7235 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7236 arg2, arg1);
7237 }
7238 }
7239 return(ret);
7240 }
7241
7242 if (arg1->type != XPATH_NUMBER) {
7243 valuePush(ctxt, arg1);
7244 xmlXPathNumberFunction(ctxt, 1);
7245 arg1 = valuePop(ctxt);
7246 }
7247 if (arg1->type != XPATH_NUMBER) {
7248 xmlXPathFreeObject(arg1);
7249 xmlXPathFreeObject(arg2);
7250 XP_ERROR0(XPATH_INVALID_OPERAND);
7251 }
7252 if (arg2->type != XPATH_NUMBER) {
7253 valuePush(ctxt, arg2);
7254 xmlXPathNumberFunction(ctxt, 1);
7255 arg2 = valuePop(ctxt);
7256 }
7257 if (arg2->type != XPATH_NUMBER) {
7258 xmlXPathReleaseObject(ctxt->context, arg1);
7259 xmlXPathReleaseObject(ctxt->context, arg2);
7260 XP_ERROR0(XPATH_INVALID_OPERAND);
7261 }
7262 /*
7263 * Add tests for infinity and nan
7264 * => feedback on 3.4 for Inf and NaN
7265 */
7266 /* Hand check NaN and Infinity comparisons */
7267 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7268 ret=0;
7269 } else {
7270 arg1i=xmlXPathIsInf(arg1->floatval);
7271 arg2i=xmlXPathIsInf(arg2->floatval);
7272 if (inf && strict) {
7273 if ((arg1i == -1 && arg2i != -1) ||
7274 (arg2i == 1 && arg1i != 1)) {
7275 ret = 1;
7276 } else if (arg1i == 0 && arg2i == 0) {
7277 ret = (arg1->floatval < arg2->floatval);
7278 } else {
7279 ret = 0;
7280 }
7281 }
7282 else if (inf && !strict) {
7283 if (arg1i == -1 || arg2i == 1) {
7284 ret = 1;
7285 } else if (arg1i == 0 && arg2i == 0) {
7286 ret = (arg1->floatval <= arg2->floatval);
7287 } else {
7288 ret = 0;
7289 }
7290 }
7291 else if (!inf && strict) {
7292 if ((arg1i == 1 && arg2i != 1) ||
7293 (arg2i == -1 && arg1i != -1)) {
7294 ret = 1;
7295 } else if (arg1i == 0 && arg2i == 0) {
7296 ret = (arg1->floatval > arg2->floatval);
7297 } else {
7298 ret = 0;
7299 }
7300 }
7301 else if (!inf && !strict) {
7302 if (arg1i == 1 || arg2i == -1) {
7303 ret = 1;
7304 } else if (arg1i == 0 && arg2i == 0) {
7305 ret = (arg1->floatval >= arg2->floatval);
7306 } else {
7307 ret = 0;
7308 }
7309 }
7310 }
7311 xmlXPathReleaseObject(ctxt->context, arg1);
7312 xmlXPathReleaseObject(ctxt->context, arg2);
7313 return(ret);
7314 }
7315
7316 /**
7317 * xmlXPathValueFlipSign:
7318 * @ctxt: the XPath Parser context
7319 *
7320 * Implement the unary - operation on an XPath object
7321 * The numeric operators convert their operands to numbers as if
7322 * by calling the number function.
7323 */
7324 void
7325 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7326 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7327 CAST_TO_NUMBER;
7328 CHECK_TYPE(XPATH_NUMBER);
7329 if (xmlXPathIsNaN(ctxt->value->floatval))
7330 ctxt->value->floatval=xmlXPathNAN;
7331 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7332 ctxt->value->floatval=xmlXPathNINF;
7333 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7334 ctxt->value->floatval=xmlXPathPINF;
7335 else if (ctxt->value->floatval == 0) {
7336 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7337 ctxt->value->floatval = xmlXPathNZERO;
7338 else
7339 ctxt->value->floatval = 0;
7340 }
7341 else
7342 ctxt->value->floatval = - ctxt->value->floatval;
7343 }
7344
7345 /**
7346 * xmlXPathAddValues:
7347 * @ctxt: the XPath Parser context
7348 *
7349 * Implement the add operation on XPath objects:
7350 * The numeric operators convert their operands to numbers as if
7351 * by calling the number function.
7352 */
7353 void
7354 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7355 xmlXPathObjectPtr arg;
7356 double val;
7357
7358 arg = valuePop(ctxt);
7359 if (arg == NULL)
7360 XP_ERROR(XPATH_INVALID_OPERAND);
7361 val = xmlXPathCastToNumber(arg);
7362 xmlXPathReleaseObject(ctxt->context, arg);
7363 CAST_TO_NUMBER;
7364 CHECK_TYPE(XPATH_NUMBER);
7365 ctxt->value->floatval += val;
7366 }
7367
7368 /**
7369 * xmlXPathSubValues:
7370 * @ctxt: the XPath Parser context
7371 *
7372 * Implement the subtraction operation on XPath objects:
7373 * The numeric operators convert their operands to numbers as if
7374 * by calling the number function.
7375 */
7376 void
7377 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7378 xmlXPathObjectPtr arg;
7379 double val;
7380
7381 arg = valuePop(ctxt);
7382 if (arg == NULL)
7383 XP_ERROR(XPATH_INVALID_OPERAND);
7384 val = xmlXPathCastToNumber(arg);
7385 xmlXPathReleaseObject(ctxt->context, arg);
7386 CAST_TO_NUMBER;
7387 CHECK_TYPE(XPATH_NUMBER);
7388 ctxt->value->floatval -= val;
7389 }
7390
7391 /**
7392 * xmlXPathMultValues:
7393 * @ctxt: the XPath Parser context
7394 *
7395 * Implement the multiply operation on XPath objects:
7396 * The numeric operators convert their operands to numbers as if
7397 * by calling the number function.
7398 */
7399 void
7400 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7401 xmlXPathObjectPtr arg;
7402 double val;
7403
7404 arg = valuePop(ctxt);
7405 if (arg == NULL)
7406 XP_ERROR(XPATH_INVALID_OPERAND);
7407 val = xmlXPathCastToNumber(arg);
7408 xmlXPathReleaseObject(ctxt->context, arg);
7409 CAST_TO_NUMBER;
7410 CHECK_TYPE(XPATH_NUMBER);
7411 ctxt->value->floatval *= val;
7412 }
7413
7414 /**
7415 * xmlXPathDivValues:
7416 * @ctxt: the XPath Parser context
7417 *
7418 * Implement the div operation on XPath objects @arg1 / @arg2:
7419 * The numeric operators convert their operands to numbers as if
7420 * by calling the number function.
7421 */
7422 void
7423 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7424 xmlXPathObjectPtr arg;
7425 double val;
7426
7427 arg = valuePop(ctxt);
7428 if (arg == NULL)
7429 XP_ERROR(XPATH_INVALID_OPERAND);
7430 val = xmlXPathCastToNumber(arg);
7431 xmlXPathReleaseObject(ctxt->context, arg);
7432 CAST_TO_NUMBER;
7433 CHECK_TYPE(XPATH_NUMBER);
7434 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7435 ctxt->value->floatval = xmlXPathNAN;
7436 else if (val == 0 && xmlXPathGetSign(val) != 0) {
7437 if (ctxt->value->floatval == 0)
7438 ctxt->value->floatval = xmlXPathNAN;
7439 else if (ctxt->value->floatval > 0)
7440 ctxt->value->floatval = xmlXPathNINF;
7441 else if (ctxt->value->floatval < 0)
7442 ctxt->value->floatval = xmlXPathPINF;
7443 }
7444 else if (val == 0) {
7445 if (ctxt->value->floatval == 0)
7446 ctxt->value->floatval = xmlXPathNAN;
7447 else if (ctxt->value->floatval > 0)
7448 ctxt->value->floatval = xmlXPathPINF;
7449 else if (ctxt->value->floatval < 0)
7450 ctxt->value->floatval = xmlXPathNINF;
7451 } else
7452 ctxt->value->floatval /= val;
7453 }
7454
7455 /**
7456 * xmlXPathModValues:
7457 * @ctxt: the XPath Parser context
7458 *
7459 * Implement the mod operation on XPath objects: @arg1 / @arg2
7460 * The numeric operators convert their operands to numbers as if
7461 * by calling the number function.
7462 */
7463 void
7464 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7465 xmlXPathObjectPtr arg;
7466 double arg1, arg2;
7467
7468 arg = valuePop(ctxt);
7469 if (arg == NULL)
7470 XP_ERROR(XPATH_INVALID_OPERAND);
7471 arg2 = xmlXPathCastToNumber(arg);
7472 xmlXPathReleaseObject(ctxt->context, arg);
7473 CAST_TO_NUMBER;
7474 CHECK_TYPE(XPATH_NUMBER);
7475 arg1 = ctxt->value->floatval;
7476 if (arg2 == 0)
7477 ctxt->value->floatval = xmlXPathNAN;
7478 else {
7479 ctxt->value->floatval = fmod(arg1, arg2);
7480 }
7481 }
7482
7483 /************************************************************************
7484 * *
7485 * The traversal functions *
7486 * *
7487 ************************************************************************/
7488
7489 /*
7490 * A traversal function enumerates nodes along an axis.
7491 * Initially it must be called with NULL, and it indicates
7492 * termination on the axis by returning NULL.
7493 */
7494 typedef xmlNodePtr (*xmlXPathTraversalFunction)
7495 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7496
7497 /*
7498 * xmlXPathTraversalFunctionExt:
7499 * A traversal function enumerates nodes along an axis.
7500 * Initially it must be called with NULL, and it indicates
7501 * termination on the axis by returning NULL.
7502 * The context node of the traversal is specified via @contextNode.
7503 */
7504 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7505 (xmlNodePtr cur, xmlNodePtr contextNode);
7506
7507 /*
7508 * xmlXPathNodeSetMergeFunction:
7509 * Used for merging node sets in xmlXPathCollectAndTest().
7510 */
7511 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7512 (xmlNodeSetPtr, xmlNodeSetPtr, int);
7513
7514
7515 /**
7516 * xmlXPathNextSelf:
7517 * @ctxt: the XPath Parser context
7518 * @cur: the current node in the traversal
7519 *
7520 * Traversal function for the "self" direction
7521 * The self axis contains just the context node itself
7522 *
7523 * Returns the next element following that axis
7524 */
7525 xmlNodePtr
7526 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7527 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7528 if (cur == NULL)
7529 return(ctxt->context->node);
7530 return(NULL);
7531 }
7532
7533 /**
7534 * xmlXPathNextChild:
7535 * @ctxt: the XPath Parser context
7536 * @cur: the current node in the traversal
7537 *
7538 * Traversal function for the "child" direction
7539 * The child axis contains the children of the context node in document order.
7540 *
7541 * Returns the next element following that axis
7542 */
7543 xmlNodePtr
7544 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7545 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7546 if (cur == NULL) {
7547 if (ctxt->context->node == NULL) return(NULL);
7548 switch (ctxt->context->node->type) {
7549 case XML_ELEMENT_NODE:
7550 case XML_TEXT_NODE:
7551 case XML_CDATA_SECTION_NODE:
7552 case XML_ENTITY_REF_NODE:
7553 case XML_ENTITY_NODE:
7554 case XML_PI_NODE:
7555 case XML_COMMENT_NODE:
7556 case XML_NOTATION_NODE:
7557 case XML_DTD_NODE:
7558 return(ctxt->context->node->children);
7559 case XML_DOCUMENT_NODE:
7560 case XML_DOCUMENT_TYPE_NODE:
7561 case XML_DOCUMENT_FRAG_NODE:
7562 case XML_HTML_DOCUMENT_NODE:
7563 #ifdef LIBXML_DOCB_ENABLED
7564 case XML_DOCB_DOCUMENT_NODE:
7565 #endif
7566 return(((xmlDocPtr) ctxt->context->node)->children);
7567 case XML_ELEMENT_DECL:
7568 case XML_ATTRIBUTE_DECL:
7569 case XML_ENTITY_DECL:
7570 case XML_ATTRIBUTE_NODE:
7571 case XML_NAMESPACE_DECL:
7572 case XML_XINCLUDE_START:
7573 case XML_XINCLUDE_END:
7574 return(NULL);
7575 }
7576 return(NULL);
7577 }
7578 if ((cur->type == XML_DOCUMENT_NODE) ||
7579 (cur->type == XML_HTML_DOCUMENT_NODE))
7580 return(NULL);
7581 return(cur->next);
7582 }
7583
7584 /**
7585 * xmlXPathNextChildElement:
7586 * @ctxt: the XPath Parser context
7587 * @cur: the current node in the traversal
7588 *
7589 * Traversal function for the "child" direction and nodes of type element.
7590 * The child axis contains the children of the context node in document order.
7591 *
7592 * Returns the next element following that axis
7593 */
7594 static xmlNodePtr
7595 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7596 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7597 if (cur == NULL) {
7598 cur = ctxt->context->node;
7599 if (cur == NULL) return(NULL);
7600 /*
7601 * Get the first element child.
7602 */
7603 switch (cur->type) {
7604 case XML_ELEMENT_NODE:
7605 case XML_DOCUMENT_FRAG_NODE:
7606 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7607 case XML_ENTITY_NODE:
7608 cur = cur->children;
7609 if (cur != NULL) {
7610 if (cur->type == XML_ELEMENT_NODE)
7611 return(cur);
7612 do {
7613 cur = cur->next;
7614 } while ((cur != NULL) &&
7615 (cur->type != XML_ELEMENT_NODE));
7616 return(cur);
7617 }
7618 return(NULL);
7619 case XML_DOCUMENT_NODE:
7620 case XML_HTML_DOCUMENT_NODE:
7621 #ifdef LIBXML_DOCB_ENABLED
7622 case XML_DOCB_DOCUMENT_NODE:
7623 #endif
7624 return(xmlDocGetRootElement((xmlDocPtr) cur));
7625 default:
7626 return(NULL);
7627 }
7628 return(NULL);
7629 }
7630 /*
7631 * Get the next sibling element node.
7632 */
7633 switch (cur->type) {
7634 case XML_ELEMENT_NODE:
7635 case XML_TEXT_NODE:
7636 case XML_ENTITY_REF_NODE:
7637 case XML_ENTITY_NODE:
7638 case XML_CDATA_SECTION_NODE:
7639 case XML_PI_NODE:
7640 case XML_COMMENT_NODE:
7641 case XML_XINCLUDE_END:
7642 break;
7643 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7644 default:
7645 return(NULL);
7646 }
7647 if (cur->next != NULL) {
7648 if (cur->next->type == XML_ELEMENT_NODE)
7649 return(cur->next);
7650 cur = cur->next;
7651 do {
7652 cur = cur->next;
7653 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7654 return(cur);
7655 }
7656 return(NULL);
7657 }
7658
7659 /**
7660 * xmlXPathNextDescendantOrSelfElemParent:
7661 * @ctxt: the XPath Parser context
7662 * @cur: the current node in the traversal
7663 *
7664 * Traversal function for the "descendant-or-self" axis.
7665 * Additionally it returns only nodes which can be parents of
7666 * element nodes.
7667 *
7668 *
7669 * Returns the next element following that axis
7670 */
7671 static xmlNodePtr
7672 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7673 xmlNodePtr contextNode)
7674 {
7675 if (cur == NULL) {
7676 if (contextNode == NULL)
7677 return(NULL);
7678 switch (contextNode->type) {
7679 case XML_ELEMENT_NODE:
7680 case XML_XINCLUDE_START:
7681 case XML_DOCUMENT_FRAG_NODE:
7682 case XML_DOCUMENT_NODE:
7683 #ifdef LIBXML_DOCB_ENABLED
7684 case XML_DOCB_DOCUMENT_NODE:
7685 #endif
7686 case XML_HTML_DOCUMENT_NODE:
7687 return(contextNode);
7688 default:
7689 return(NULL);
7690 }
7691 return(NULL);
7692 } else {
7693 xmlNodePtr start = cur;
7694
7695 while (cur != NULL) {
7696 switch (cur->type) {
7697 case XML_ELEMENT_NODE:
7698 /* TODO: OK to have XInclude here? */
7699 case XML_XINCLUDE_START:
7700 case XML_DOCUMENT_FRAG_NODE:
7701 if (cur != start)
7702 return(cur);
7703 if (cur->children != NULL) {
7704 cur = cur->children;
7705 continue;
7706 }
7707 break;
7708 /* Not sure if we need those here. */
7709 case XML_DOCUMENT_NODE:
7710 #ifdef LIBXML_DOCB_ENABLED
7711 case XML_DOCB_DOCUMENT_NODE:
7712 #endif
7713 case XML_HTML_DOCUMENT_NODE:
7714 if (cur != start)
7715 return(cur);
7716 return(xmlDocGetRootElement((xmlDocPtr) cur));
7717 default:
7718 break;
7719 }
7720
7721 next_sibling:
7722 if ((cur == NULL) || (cur == contextNode))
7723 return(NULL);
7724 if (cur->next != NULL) {
7725 cur = cur->next;
7726 } else {
7727 cur = cur->parent;
7728 goto next_sibling;
7729 }
7730 }
7731 }
7732 return(NULL);
7733 }
7734
7735 /**
7736 * xmlXPathNextDescendant:
7737 * @ctxt: the XPath Parser context
7738 * @cur: the current node in the traversal
7739 *
7740 * Traversal function for the "descendant" direction
7741 * the descendant axis contains the descendants of the context node in document
7742 * order; a descendant is a child or a child of a child and so on.
7743 *
7744 * Returns the next element following that axis
7745 */
7746 xmlNodePtr
7747 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7748 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7749 if (cur == NULL) {
7750 if (ctxt->context->node == NULL)
7751 return(NULL);
7752 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7753 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7754 return(NULL);
7755
7756 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7757 return(ctxt->context->doc->children);
7758 return(ctxt->context->node->children);
7759 }
7760
7761 if (cur->children != NULL) {
7762 /*
7763 * Do not descend on entities declarations
7764 */
7765 if (cur->children->type != XML_ENTITY_DECL) {
7766 cur = cur->children;
7767 /*
7768 * Skip DTDs
7769 */
7770 if (cur->type != XML_DTD_NODE)
7771 return(cur);
7772 }
7773 }
7774
7775 if (cur == ctxt->context->node) return(NULL);
7776
7777 while (cur->next != NULL) {
7778 cur = cur->next;
7779 if ((cur->type != XML_ENTITY_DECL) &&
7780 (cur->type != XML_DTD_NODE))
7781 return(cur);
7782 }
7783
7784 do {
7785 cur = cur->parent;
7786 if (cur == NULL) break;
7787 if (cur == ctxt->context->node) return(NULL);
7788 if (cur->next != NULL) {
7789 cur = cur->next;
7790 return(cur);
7791 }
7792 } while (cur != NULL);
7793 return(cur);
7794 }
7795
7796 /**
7797 * xmlXPathNextDescendantOrSelf:
7798 * @ctxt: the XPath Parser context
7799 * @cur: the current node in the traversal
7800 *
7801 * Traversal function for the "descendant-or-self" direction
7802 * the descendant-or-self axis contains the context node and the descendants
7803 * of the context node in document order; thus the context node is the first
7804 * node on the axis, and the first child of the context node is the second node
7805 * on the axis
7806 *
7807 * Returns the next element following that axis
7808 */
7809 xmlNodePtr
7810 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7811 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7812 if (cur == NULL) {
7813 if (ctxt->context->node == NULL)
7814 return(NULL);
7815 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7816 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7817 return(NULL);
7818 return(ctxt->context->node);
7819 }
7820
7821 return(xmlXPathNextDescendant(ctxt, cur));
7822 }
7823
7824 /**
7825 * xmlXPathNextParent:
7826 * @ctxt: the XPath Parser context
7827 * @cur: the current node in the traversal
7828 *
7829 * Traversal function for the "parent" direction
7830 * The parent axis contains the parent of the context node, if there is one.
7831 *
7832 * Returns the next element following that axis
7833 */
7834 xmlNodePtr
7835 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7836 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7837 /*
7838 * the parent of an attribute or namespace node is the element
7839 * to which the attribute or namespace node is attached
7840 * Namespace handling !!!
7841 */
7842 if (cur == NULL) {
7843 if (ctxt->context->node == NULL) return(NULL);
7844 switch (ctxt->context->node->type) {
7845 case XML_ELEMENT_NODE:
7846 case XML_TEXT_NODE:
7847 case XML_CDATA_SECTION_NODE:
7848 case XML_ENTITY_REF_NODE:
7849 case XML_ENTITY_NODE:
7850 case XML_PI_NODE:
7851 case XML_COMMENT_NODE:
7852 case XML_NOTATION_NODE:
7853 case XML_DTD_NODE:
7854 case XML_ELEMENT_DECL:
7855 case XML_ATTRIBUTE_DECL:
7856 case XML_XINCLUDE_START:
7857 case XML_XINCLUDE_END:
7858 case XML_ENTITY_DECL:
7859 if (ctxt->context->node->parent == NULL)
7860 return((xmlNodePtr) ctxt->context->doc);
7861 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7862 ((ctxt->context->node->parent->name[0] == ' ') ||
7863 (xmlStrEqual(ctxt->context->node->parent->name,
7864 BAD_CAST "fake node libxslt"))))
7865 return(NULL);
7866 return(ctxt->context->node->parent);
7867 case XML_ATTRIBUTE_NODE: {
7868 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7869
7870 return(att->parent);
7871 }
7872 case XML_DOCUMENT_NODE:
7873 case XML_DOCUMENT_TYPE_NODE:
7874 case XML_DOCUMENT_FRAG_NODE:
7875 case XML_HTML_DOCUMENT_NODE:
7876 #ifdef LIBXML_DOCB_ENABLED
7877 case XML_DOCB_DOCUMENT_NODE:
7878 #endif
7879 return(NULL);
7880 case XML_NAMESPACE_DECL: {
7881 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7882
7883 if ((ns->next != NULL) &&
7884 (ns->next->type != XML_NAMESPACE_DECL))
7885 return((xmlNodePtr) ns->next);
7886 return(NULL);
7887 }
7888 }
7889 }
7890 return(NULL);
7891 }
7892
7893 /**
7894 * xmlXPathNextAncestor:
7895 * @ctxt: the XPath Parser context
7896 * @cur: the current node in the traversal
7897 *
7898 * Traversal function for the "ancestor" direction
7899 * the ancestor axis contains the ancestors of the context node; the ancestors
7900 * of the context node consist of the parent of context node and the parent's
7901 * parent and so on; the nodes are ordered in reverse document order; thus the
7902 * parent is the first node on the axis, and the parent's parent is the second
7903 * node on the axis
7904 *
7905 * Returns the next element following that axis
7906 */
7907 xmlNodePtr
7908 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7909 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7910 /*
7911 * the parent of an attribute or namespace node is the element
7912 * to which the attribute or namespace node is attached
7913 * !!!!!!!!!!!!!
7914 */
7915 if (cur == NULL) {
7916 if (ctxt->context->node == NULL) return(NULL);
7917 switch (ctxt->context->node->type) {
7918 case XML_ELEMENT_NODE:
7919 case XML_TEXT_NODE:
7920 case XML_CDATA_SECTION_NODE:
7921 case XML_ENTITY_REF_NODE:
7922 case XML_ENTITY_NODE:
7923 case XML_PI_NODE:
7924 case XML_COMMENT_NODE:
7925 case XML_DTD_NODE:
7926 case XML_ELEMENT_DECL:
7927 case XML_ATTRIBUTE_DECL:
7928 case XML_ENTITY_DECL:
7929 case XML_NOTATION_NODE:
7930 case XML_XINCLUDE_START:
7931 case XML_XINCLUDE_END:
7932 if (ctxt->context->node->parent == NULL)
7933 return((xmlNodePtr) ctxt->context->doc);
7934 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7935 ((ctxt->context->node->parent->name[0] == ' ') ||
7936 (xmlStrEqual(ctxt->context->node->parent->name,
7937 BAD_CAST "fake node libxslt"))))
7938 return(NULL);
7939 return(ctxt->context->node->parent);
7940 case XML_ATTRIBUTE_NODE: {
7941 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
7942
7943 return(tmp->parent);
7944 }
7945 case XML_DOCUMENT_NODE:
7946 case XML_DOCUMENT_TYPE_NODE:
7947 case XML_DOCUMENT_FRAG_NODE:
7948 case XML_HTML_DOCUMENT_NODE:
7949 #ifdef LIBXML_DOCB_ENABLED
7950 case XML_DOCB_DOCUMENT_NODE:
7951 #endif
7952 return(NULL);
7953 case XML_NAMESPACE_DECL: {
7954 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7955
7956 if ((ns->next != NULL) &&
7957 (ns->next->type != XML_NAMESPACE_DECL))
7958 return((xmlNodePtr) ns->next);
7959 /* Bad, how did that namespace end up here ? */
7960 return(NULL);
7961 }
7962 }
7963 return(NULL);
7964 }
7965 if (cur == ctxt->context->doc->children)
7966 return((xmlNodePtr) ctxt->context->doc);
7967 if (cur == (xmlNodePtr) ctxt->context->doc)
7968 return(NULL);
7969 switch (cur->type) {
7970 case XML_ELEMENT_NODE:
7971 case XML_TEXT_NODE:
7972 case XML_CDATA_SECTION_NODE:
7973 case XML_ENTITY_REF_NODE:
7974 case XML_ENTITY_NODE:
7975 case XML_PI_NODE:
7976 case XML_COMMENT_NODE:
7977 case XML_NOTATION_NODE:
7978 case XML_DTD_NODE:
7979 case XML_ELEMENT_DECL:
7980 case XML_ATTRIBUTE_DECL:
7981 case XML_ENTITY_DECL:
7982 case XML_XINCLUDE_START:
7983 case XML_XINCLUDE_END:
7984 if (cur->parent == NULL)
7985 return(NULL);
7986 if ((cur->parent->type == XML_ELEMENT_NODE) &&
7987 ((cur->parent->name[0] == ' ') ||
7988 (xmlStrEqual(cur->parent->name,
7989 BAD_CAST "fake node libxslt"))))
7990 return(NULL);
7991 return(cur->parent);
7992 case XML_ATTRIBUTE_NODE: {
7993 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7994
7995 return(att->parent);
7996 }
7997 case XML_NAMESPACE_DECL: {
7998 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7999
8000 if ((ns->next != NULL) &&
8001 (ns->next->type != XML_NAMESPACE_DECL))
8002 return((xmlNodePtr) ns->next);
8003 /* Bad, how did that namespace end up here ? */
8004 return(NULL);
8005 }
8006 case XML_DOCUMENT_NODE:
8007 case XML_DOCUMENT_TYPE_NODE:
8008 case XML_DOCUMENT_FRAG_NODE:
8009 case XML_HTML_DOCUMENT_NODE:
8010 #ifdef LIBXML_DOCB_ENABLED
8011 case XML_DOCB_DOCUMENT_NODE:
8012 #endif
8013 return(NULL);
8014 }
8015 return(NULL);
8016 }
8017
8018 /**
8019 * xmlXPathNextAncestorOrSelf:
8020 * @ctxt: the XPath Parser context
8021 * @cur: the current node in the traversal
8022 *
8023 * Traversal function for the "ancestor-or-self" direction
8024 * he ancestor-or-self axis contains the context node and ancestors of
8025 * the context node in reverse document order; thus the context node is
8026 * the first node on the axis, and the context node's parent the second;
8027 * parent here is defined the same as with the parent axis.
8028 *
8029 * Returns the next element following that axis
8030 */
8031 xmlNodePtr
8032 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8033 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8034 if (cur == NULL)
8035 return(ctxt->context->node);
8036 return(xmlXPathNextAncestor(ctxt, cur));
8037 }
8038
8039 /**
8040 * xmlXPathNextFollowingSibling:
8041 * @ctxt: the XPath Parser context
8042 * @cur: the current node in the traversal
8043 *
8044 * Traversal function for the "following-sibling" direction
8045 * The following-sibling axis contains the following siblings of the context
8046 * node in document order.
8047 *
8048 * Returns the next element following that axis
8049 */
8050 xmlNodePtr
8051 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8052 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8053 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8054 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8055 return(NULL);
8056 if (cur == (xmlNodePtr) ctxt->context->doc)
8057 return(NULL);
8058 if (cur == NULL)
8059 return(ctxt->context->node->next);
8060 return(cur->next);
8061 }
8062
8063 /**
8064 * xmlXPathNextPrecedingSibling:
8065 * @ctxt: the XPath Parser context
8066 * @cur: the current node in the traversal
8067 *
8068 * Traversal function for the "preceding-sibling" direction
8069 * The preceding-sibling axis contains the preceding siblings of the context
8070 * node in reverse document order; the first preceding sibling is first on the
8071 * axis; the sibling preceding that node is the second on the axis and so on.
8072 *
8073 * Returns the next element following that axis
8074 */
8075 xmlNodePtr
8076 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8077 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8078 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8079 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8080 return(NULL);
8081 if (cur == (xmlNodePtr) ctxt->context->doc)
8082 return(NULL);
8083 if (cur == NULL)
8084 return(ctxt->context->node->prev);
8085 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8086 cur = cur->prev;
8087 if (cur == NULL)
8088 return(ctxt->context->node->prev);
8089 }
8090 return(cur->prev);
8091 }
8092
8093 /**
8094 * xmlXPathNextFollowing:
8095 * @ctxt: the XPath Parser context
8096 * @cur: the current node in the traversal
8097 *
8098 * Traversal function for the "following" direction
8099 * The following axis contains all nodes in the same document as the context
8100 * node that are after the context node in document order, excluding any
8101 * descendants and excluding attribute nodes and namespace nodes; the nodes
8102 * are ordered in document order
8103 *
8104 * Returns the next element following that axis
8105 */
8106 xmlNodePtr
8107 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8108 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8109 if (cur != NULL && cur->children != NULL)
8110 return cur->children ;
8111 if (cur == NULL) cur = ctxt->context->node;
8112 if (cur == NULL) return(NULL) ; /* ERROR */
8113 if (cur->next != NULL) return(cur->next) ;
8114 do {
8115 cur = cur->parent;
8116 if (cur == NULL) break;
8117 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8118 if (cur->next != NULL) return(cur->next);
8119 } while (cur != NULL);
8120 return(cur);
8121 }
8122
8123 /*
8124 * xmlXPathIsAncestor:
8125 * @ancestor: the ancestor node
8126 * @node: the current node
8127 *
8128 * Check that @ancestor is a @node's ancestor
8129 *
8130 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8131 */
8132 static int
8133 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8134 if ((ancestor == NULL) || (node == NULL)) return(0);
8135 /* nodes need to be in the same document */
8136 if (ancestor->doc != node->doc) return(0);
8137 /* avoid searching if ancestor or node is the root node */
8138 if (ancestor == (xmlNodePtr) node->doc) return(1);
8139 if (node == (xmlNodePtr) ancestor->doc) return(0);
8140 while (node->parent != NULL) {
8141 if (node->parent == ancestor)
8142 return(1);
8143 node = node->parent;
8144 }
8145 return(0);
8146 }
8147
8148 /**
8149 * xmlXPathNextPreceding:
8150 * @ctxt: the XPath Parser context
8151 * @cur: the current node in the traversal
8152 *
8153 * Traversal function for the "preceding" direction
8154 * the preceding axis contains all nodes in the same document as the context
8155 * node that are before the context node in document order, excluding any
8156 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8157 * ordered in reverse document order
8158 *
8159 * Returns the next element following that axis
8160 */
8161 xmlNodePtr
8162 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8163 {
8164 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8165 if (cur == NULL)
8166 cur = ctxt->context->node;
8167 if (cur == NULL)
8168 return (NULL);
8169 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8170 cur = cur->prev;
8171 do {
8172 if (cur->prev != NULL) {
8173 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8174 return (cur);
8175 }
8176
8177 cur = cur->parent;
8178 if (cur == NULL)
8179 return (NULL);
8180 if (cur == ctxt->context->doc->children)
8181 return (NULL);
8182 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8183 return (cur);
8184 }
8185
8186 /**
8187 * xmlXPathNextPrecedingInternal:
8188 * @ctxt: the XPath Parser context
8189 * @cur: the current node in the traversal
8190 *
8191 * Traversal function for the "preceding" direction
8192 * the preceding axis contains all nodes in the same document as the context
8193 * node that are before the context node in document order, excluding any
8194 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8195 * ordered in reverse document order
8196 * This is a faster implementation but internal only since it requires a
8197 * state kept in the parser context: ctxt->ancestor.
8198 *
8199 * Returns the next element following that axis
8200 */
8201 static xmlNodePtr
8202 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8203 xmlNodePtr cur)
8204 {
8205 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8206 if (cur == NULL) {
8207 cur = ctxt->context->node;
8208 if (cur == NULL)
8209 return (NULL);
8210 if (cur->type == XML_NAMESPACE_DECL)
8211 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
8212 ctxt->ancestor = cur->parent;
8213 }
8214 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8215 cur = cur->prev;
8216 while (cur->prev == NULL) {
8217 cur = cur->parent;
8218 if (cur == NULL)
8219 return (NULL);
8220 if (cur == ctxt->context->doc->children)
8221 return (NULL);
8222 if (cur != ctxt->ancestor)
8223 return (cur);
8224 ctxt->ancestor = cur->parent;
8225 }
8226 cur = cur->prev;
8227 while (cur->last != NULL)
8228 cur = cur->last;
8229 return (cur);
8230 }
8231
8232 /**
8233 * xmlXPathNextNamespace:
8234 * @ctxt: the XPath Parser context
8235 * @cur: the current attribute in the traversal
8236 *
8237 * Traversal function for the "namespace" direction
8238 * the namespace axis contains the namespace nodes of the context node;
8239 * the order of nodes on this axis is implementation-defined; the axis will
8240 * be empty unless the context node is an element
8241 *
8242 * We keep the XML namespace node at the end of the list.
8243 *
8244 * Returns the next element following that axis
8245 */
8246 xmlNodePtr
8247 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8248 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8249 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8250 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
8251 if (ctxt->context->tmpNsList != NULL)
8252 xmlFree(ctxt->context->tmpNsList);
8253 ctxt->context->tmpNsList =
8254 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8255 ctxt->context->tmpNsNr = 0;
8256 if (ctxt->context->tmpNsList != NULL) {
8257 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8258 ctxt->context->tmpNsNr++;
8259 }
8260 }
8261 return((xmlNodePtr) xmlXPathXMLNamespace);
8262 }
8263 if (ctxt->context->tmpNsNr > 0) {
8264 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8265 } else {
8266 if (ctxt->context->tmpNsList != NULL)
8267 xmlFree(ctxt->context->tmpNsList);
8268 ctxt->context->tmpNsList = NULL;
8269 return(NULL);
8270 }
8271 }
8272
8273 /**
8274 * xmlXPathNextAttribute:
8275 * @ctxt: the XPath Parser context
8276 * @cur: the current attribute in the traversal
8277 *
8278 * Traversal function for the "attribute" direction
8279 * TODO: support DTD inherited default attributes
8280 *
8281 * Returns the next element following that axis
8282 */
8283 xmlNodePtr
8284 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8285 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8286 if (ctxt->context->node == NULL)
8287 return(NULL);
8288 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8289 return(NULL);
8290 if (cur == NULL) {
8291 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8292 return(NULL);
8293 return((xmlNodePtr)ctxt->context->node->properties);
8294 }
8295 return((xmlNodePtr)cur->next);
8296 }
8297
8298 /************************************************************************
8299 * *
8300 * NodeTest Functions *
8301 * *
8302 ************************************************************************/
8303
8304 #define IS_FUNCTION 200
8305
8306
8307 /************************************************************************
8308 * *
8309 * Implicit tree core function library *
8310 * *
8311 ************************************************************************/
8312
8313 /**
8314 * xmlXPathRoot:
8315 * @ctxt: the XPath Parser context
8316 *
8317 * Initialize the context to the root of the document
8318 */
8319 void
8320 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8321 if ((ctxt == NULL) || (ctxt->context == NULL))
8322 return;
8323 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
8324 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8325 ctxt->context->node));
8326 }
8327
8328 /************************************************************************
8329 * *
8330 * The explicit core function library *
8331 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8332 * *
8333 ************************************************************************/
8334
8335
8336 /**
8337 * xmlXPathLastFunction:
8338 * @ctxt: the XPath Parser context
8339 * @nargs: the number of arguments
8340 *
8341 * Implement the last() XPath function
8342 * number last()
8343 * The last function returns the number of nodes in the context node list.
8344 */
8345 void
8346 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8347 CHECK_ARITY(0);
8348 if (ctxt->context->contextSize >= 0) {
8349 valuePush(ctxt,
8350 xmlXPathCacheNewFloat(ctxt->context,
8351 (double) ctxt->context->contextSize));
8352 #ifdef DEBUG_EXPR
8353 xmlGenericError(xmlGenericErrorContext,
8354 "last() : %d\n", ctxt->context->contextSize);
8355 #endif
8356 } else {
8357 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8358 }
8359 }
8360
8361 /**
8362 * xmlXPathPositionFunction:
8363 * @ctxt: the XPath Parser context
8364 * @nargs: the number of arguments
8365 *
8366 * Implement the position() XPath function
8367 * number position()
8368 * The position function returns the position of the context node in the
8369 * context node list. The first position is 1, and so the last position
8370 * will be equal to last().
8371 */
8372 void
8373 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8374 CHECK_ARITY(0);
8375 if (ctxt->context->proximityPosition >= 0) {
8376 valuePush(ctxt,
8377 xmlXPathCacheNewFloat(ctxt->context,
8378 (double) ctxt->context->proximityPosition));
8379 #ifdef DEBUG_EXPR
8380 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8381 ctxt->context->proximityPosition);
8382 #endif
8383 } else {
8384 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8385 }
8386 }
8387
8388 /**
8389 * xmlXPathCountFunction:
8390 * @ctxt: the XPath Parser context
8391 * @nargs: the number of arguments
8392 *
8393 * Implement the count() XPath function
8394 * number count(node-set)
8395 */
8396 void
8397 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8398 xmlXPathObjectPtr cur;
8399
8400 CHECK_ARITY(1);
8401 if ((ctxt->value == NULL) ||
8402 ((ctxt->value->type != XPATH_NODESET) &&
8403 (ctxt->value->type != XPATH_XSLT_TREE)))
8404 XP_ERROR(XPATH_INVALID_TYPE);
8405 cur = valuePop(ctxt);
8406
8407 if ((cur == NULL) || (cur->nodesetval == NULL))
8408 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8409 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8410 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8411 (double) cur->nodesetval->nodeNr));
8412 } else {
8413 if ((cur->nodesetval->nodeNr != 1) ||
8414 (cur->nodesetval->nodeTab == NULL)) {
8415 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8416 } else {
8417 xmlNodePtr tmp;
8418 int i = 0;
8419
8420 tmp = cur->nodesetval->nodeTab[0];
8421 if (tmp != NULL) {
8422 tmp = tmp->children;
8423 while (tmp != NULL) {
8424 tmp = tmp->next;
8425 i++;
8426 }
8427 }
8428 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8429 }
8430 }
8431 xmlXPathReleaseObject(ctxt->context, cur);
8432 }
8433
8434 /**
8435 * xmlXPathGetElementsByIds:
8436 * @doc: the document
8437 * @ids: a whitespace separated list of IDs
8438 *
8439 * Selects elements by their unique ID.
8440 *
8441 * Returns a node-set of selected elements.
8442 */
8443 static xmlNodeSetPtr
8444 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8445 xmlNodeSetPtr ret;
8446 const xmlChar *cur = ids;
8447 xmlChar *ID;
8448 xmlAttrPtr attr;
8449 xmlNodePtr elem = NULL;
8450
8451 if (ids == NULL) return(NULL);
8452
8453 ret = xmlXPathNodeSetCreate(NULL);
8454 if (ret == NULL)
8455 return(ret);
8456
8457 while (IS_BLANK_CH(*cur)) cur++;
8458 while (*cur != 0) {
8459 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8460 cur++;
8461
8462 ID = xmlStrndup(ids, cur - ids);
8463 if (ID != NULL) {
8464 /*
8465 * We used to check the fact that the value passed
8466 * was an NCName, but this generated much troubles for
8467 * me and Aleksey Sanin, people blatantly violated that
8468 * constaint, like Visa3D spec.
8469 * if (xmlValidateNCName(ID, 1) == 0)
8470 */
8471 attr = xmlGetID(doc, ID);
8472 if (attr != NULL) {
8473 if (attr->type == XML_ATTRIBUTE_NODE)
8474 elem = attr->parent;
8475 else if (attr->type == XML_ELEMENT_NODE)
8476 elem = (xmlNodePtr) attr;
8477 else
8478 elem = NULL;
8479 if (elem != NULL)
8480 xmlXPathNodeSetAdd(ret, elem);
8481 }
8482 xmlFree(ID);
8483 }
8484
8485 while (IS_BLANK_CH(*cur)) cur++;
8486 ids = cur;
8487 }
8488 return(ret);
8489 }
8490
8491 /**
8492 * xmlXPathIdFunction:
8493 * @ctxt: the XPath Parser context
8494 * @nargs: the number of arguments
8495 *
8496 * Implement the id() XPath function
8497 * node-set id(object)
8498 * The id function selects elements by their unique ID
8499 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8500 * then the result is the union of the result of applying id to the
8501 * string value of each of the nodes in the argument node-set. When the
8502 * argument to id is of any other type, the argument is converted to a
8503 * string as if by a call to the string function; the string is split
8504 * into a whitespace-separated list of tokens (whitespace is any sequence
8505 * of characters matching the production S); the result is a node-set
8506 * containing the elements in the same document as the context node that
8507 * have a unique ID equal to any of the tokens in the list.
8508 */
8509 void
8510 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8511 xmlChar *tokens;
8512 xmlNodeSetPtr ret;
8513 xmlXPathObjectPtr obj;
8514
8515 CHECK_ARITY(1);
8516 obj = valuePop(ctxt);
8517 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8518 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8519 xmlNodeSetPtr ns;
8520 int i;
8521
8522 ret = xmlXPathNodeSetCreate(NULL);
8523 /*
8524 * FIXME -- in an out-of-memory condition this will behave badly.
8525 * The solution is not clear -- we already popped an item from
8526 * ctxt, so the object is in a corrupt state.
8527 */
8528
8529 if (obj->nodesetval != NULL) {
8530 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8531 tokens =
8532 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8533 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8534 ret = xmlXPathNodeSetMerge(ret, ns);
8535 xmlXPathFreeNodeSet(ns);
8536 if (tokens != NULL)
8537 xmlFree(tokens);
8538 }
8539 }
8540 xmlXPathReleaseObject(ctxt->context, obj);
8541 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8542 return;
8543 }
8544 obj = xmlXPathCacheConvertString(ctxt->context, obj);
8545 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8546 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8547 xmlXPathReleaseObject(ctxt->context, obj);
8548 return;
8549 }
8550
8551 /**
8552 * xmlXPathLocalNameFunction:
8553 * @ctxt: the XPath Parser context
8554 * @nargs: the number of arguments
8555 *
8556 * Implement the local-name() XPath function
8557 * string local-name(node-set?)
8558 * The local-name function returns a string containing the local part
8559 * of the name of the node in the argument node-set that is first in
8560 * document order. If the node-set is empty or the first node has no
8561 * name, an empty string is returned. If the argument is omitted it
8562 * defaults to the context node.
8563 */
8564 void
8565 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8566 xmlXPathObjectPtr cur;
8567
8568 if (ctxt == NULL) return;
8569
8570 if (nargs == 0) {
8571 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8572 ctxt->context->node));
8573 nargs = 1;
8574 }
8575
8576 CHECK_ARITY(1);
8577 if ((ctxt->value == NULL) ||
8578 ((ctxt->value->type != XPATH_NODESET) &&
8579 (ctxt->value->type != XPATH_XSLT_TREE)))
8580 XP_ERROR(XPATH_INVALID_TYPE);
8581 cur = valuePop(ctxt);
8582
8583 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8584 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8585 } else {
8586 int i = 0; /* Should be first in document order !!!!! */
8587 switch (cur->nodesetval->nodeTab[i]->type) {
8588 case XML_ELEMENT_NODE:
8589 case XML_ATTRIBUTE_NODE:
8590 case XML_PI_NODE:
8591 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8592 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8593 else
8594 valuePush(ctxt,
8595 xmlXPathCacheNewString(ctxt->context,
8596 cur->nodesetval->nodeTab[i]->name));
8597 break;
8598 case XML_NAMESPACE_DECL:
8599 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8600 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8601 break;
8602 default:
8603 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8604 }
8605 }
8606 xmlXPathReleaseObject(ctxt->context, cur);
8607 }
8608
8609 /**
8610 * xmlXPathNamespaceURIFunction:
8611 * @ctxt: the XPath Parser context
8612 * @nargs: the number of arguments
8613 *
8614 * Implement the namespace-uri() XPath function
8615 * string namespace-uri(node-set?)
8616 * The namespace-uri function returns a string containing the
8617 * namespace URI of the expanded name of the node in the argument
8618 * node-set that is first in document order. If the node-set is empty,
8619 * the first node has no name, or the expanded name has no namespace
8620 * URI, an empty string is returned. If the argument is omitted it
8621 * defaults to the context node.
8622 */
8623 void
8624 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8625 xmlXPathObjectPtr cur;
8626
8627 if (ctxt == NULL) return;
8628
8629 if (nargs == 0) {
8630 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8631 ctxt->context->node));
8632 nargs = 1;
8633 }
8634 CHECK_ARITY(1);
8635 if ((ctxt->value == NULL) ||
8636 ((ctxt->value->type != XPATH_NODESET) &&
8637 (ctxt->value->type != XPATH_XSLT_TREE)))
8638 XP_ERROR(XPATH_INVALID_TYPE);
8639 cur = valuePop(ctxt);
8640
8641 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8642 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8643 } else {
8644 int i = 0; /* Should be first in document order !!!!! */
8645 switch (cur->nodesetval->nodeTab[i]->type) {
8646 case XML_ELEMENT_NODE:
8647 case XML_ATTRIBUTE_NODE:
8648 if (cur->nodesetval->nodeTab[i]->ns == NULL)
8649 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8650 else
8651 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8652 cur->nodesetval->nodeTab[i]->ns->href));
8653 break;
8654 default:
8655 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8656 }
8657 }
8658 xmlXPathReleaseObject(ctxt->context, cur);
8659 }
8660
8661 /**
8662 * xmlXPathNameFunction:
8663 * @ctxt: the XPath Parser context
8664 * @nargs: the number of arguments
8665 *
8666 * Implement the name() XPath function
8667 * string name(node-set?)
8668 * The name function returns a string containing a QName representing
8669 * the name of the node in the argument node-set that is first in document
8670 * order. The QName must represent the name with respect to the namespace
8671 * declarations in effect on the node whose name is being represented.
8672 * Typically, this will be the form in which the name occurred in the XML
8673 * source. This need not be the case if there are namespace declarations
8674 * in effect on the node that associate multiple prefixes with the same
8675 * namespace. However, an implementation may include information about
8676 * the original prefix in its representation of nodes; in this case, an
8677 * implementation can ensure that the returned string is always the same
8678 * as the QName used in the XML source. If the argument it omitted it
8679 * defaults to the context node.
8680 * Libxml keep the original prefix so the "real qualified name" used is
8681 * returned.
8682 */
8683 static void
8684 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8685 {
8686 xmlXPathObjectPtr cur;
8687
8688 if (nargs == 0) {
8689 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8690 ctxt->context->node));
8691 nargs = 1;
8692 }
8693
8694 CHECK_ARITY(1);
8695 if ((ctxt->value == NULL) ||
8696 ((ctxt->value->type != XPATH_NODESET) &&
8697 (ctxt->value->type != XPATH_XSLT_TREE)))
8698 XP_ERROR(XPATH_INVALID_TYPE);
8699 cur = valuePop(ctxt);
8700
8701 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8702 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8703 } else {
8704 int i = 0; /* Should be first in document order !!!!! */
8705
8706 switch (cur->nodesetval->nodeTab[i]->type) {
8707 case XML_ELEMENT_NODE:
8708 case XML_ATTRIBUTE_NODE:
8709 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8710 valuePush(ctxt,
8711 xmlXPathCacheNewCString(ctxt->context, ""));
8712 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8713 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8714 valuePush(ctxt,
8715 xmlXPathCacheNewString(ctxt->context,
8716 cur->nodesetval->nodeTab[i]->name));
8717 } else {
8718 xmlChar *fullname;
8719
8720 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8721 cur->nodesetval->nodeTab[i]->ns->prefix,
8722 NULL, 0);
8723 if (fullname == cur->nodesetval->nodeTab[i]->name)
8724 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8725 if (fullname == NULL) {
8726 XP_ERROR(XPATH_MEMORY_ERROR);
8727 }
8728 valuePush(ctxt, xmlXPathCacheWrapString(
8729 ctxt->context, fullname));
8730 }
8731 break;
8732 default:
8733 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8734 cur->nodesetval->nodeTab[i]));
8735 xmlXPathLocalNameFunction(ctxt, 1);
8736 }
8737 }
8738 xmlXPathReleaseObject(ctxt->context, cur);
8739 }
8740
8741
8742 /**
8743 * xmlXPathStringFunction:
8744 * @ctxt: the XPath Parser context
8745 * @nargs: the number of arguments
8746 *
8747 * Implement the string() XPath function
8748 * string string(object?)
8749 * The string function converts an object to a string as follows:
8750 * - A node-set is converted to a string by returning the value of
8751 * the node in the node-set that is first in document order.
8752 * If the node-set is empty, an empty string is returned.
8753 * - A number is converted to a string as follows
8754 * + NaN is converted to the string NaN
8755 * + positive zero is converted to the string 0
8756 * + negative zero is converted to the string 0
8757 * + positive infinity is converted to the string Infinity
8758 * + negative infinity is converted to the string -Infinity
8759 * + if the number is an integer, the number is represented in
8760 * decimal form as a Number with no decimal point and no leading
8761 * zeros, preceded by a minus sign (-) if the number is negative
8762 * + otherwise, the number is represented in decimal form as a
8763 * Number including a decimal point with at least one digit
8764 * before the decimal point and at least one digit after the
8765 * decimal point, preceded by a minus sign (-) if the number
8766 * is negative; there must be no leading zeros before the decimal
8767 * point apart possibly from the one required digit immediately
8768 * before the decimal point; beyond the one required digit
8769 * after the decimal point there must be as many, but only as
8770 * many, more digits as are needed to uniquely distinguish the
8771 * number from all other IEEE 754 numeric values.
8772 * - The boolean false value is converted to the string false.
8773 * The boolean true value is converted to the string true.
8774 *
8775 * If the argument is omitted, it defaults to a node-set with the
8776 * context node as its only member.
8777 */
8778 void
8779 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8780 xmlXPathObjectPtr cur;
8781
8782 if (ctxt == NULL) return;
8783 if (nargs == 0) {
8784 valuePush(ctxt,
8785 xmlXPathCacheWrapString(ctxt->context,
8786 xmlXPathCastNodeToString(ctxt->context->node)));
8787 return;
8788 }
8789
8790 CHECK_ARITY(1);
8791 cur = valuePop(ctxt);
8792 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8793 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8794 }
8795
8796 /**
8797 * xmlXPathStringLengthFunction:
8798 * @ctxt: the XPath Parser context
8799 * @nargs: the number of arguments
8800 *
8801 * Implement the string-length() XPath function
8802 * number string-length(string?)
8803 * The string-length returns the number of characters in the string
8804 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8805 * the context node converted to a string, in other words the value
8806 * of the context node.
8807 */
8808 void
8809 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8810 xmlXPathObjectPtr cur;
8811
8812 if (nargs == 0) {
8813 if ((ctxt == NULL) || (ctxt->context == NULL))
8814 return;
8815 if (ctxt->context->node == NULL) {
8816 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8817 } else {
8818 xmlChar *content;
8819
8820 content = xmlXPathCastNodeToString(ctxt->context->node);
8821 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8822 xmlUTF8Strlen(content)));
8823 xmlFree(content);
8824 }
8825 return;
8826 }
8827 CHECK_ARITY(1);
8828 CAST_TO_STRING;
8829 CHECK_TYPE(XPATH_STRING);
8830 cur = valuePop(ctxt);
8831 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8832 xmlUTF8Strlen(cur->stringval)));
8833 xmlXPathReleaseObject(ctxt->context, cur);
8834 }
8835
8836 /**
8837 * xmlXPathConcatFunction:
8838 * @ctxt: the XPath Parser context
8839 * @nargs: the number of arguments
8840 *
8841 * Implement the concat() XPath function
8842 * string concat(string, string, string*)
8843 * The concat function returns the concatenation of its arguments.
8844 */
8845 void
8846 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8847 xmlXPathObjectPtr cur, newobj;
8848 xmlChar *tmp;
8849
8850 if (ctxt == NULL) return;
8851 if (nargs < 2) {
8852 CHECK_ARITY(2);
8853 }
8854
8855 CAST_TO_STRING;
8856 cur = valuePop(ctxt);
8857 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8858 xmlXPathReleaseObject(ctxt->context, cur);
8859 return;
8860 }
8861 nargs--;
8862
8863 while (nargs > 0) {
8864 CAST_TO_STRING;
8865 newobj = valuePop(ctxt);
8866 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8867 xmlXPathReleaseObject(ctxt->context, newobj);
8868 xmlXPathReleaseObject(ctxt->context, cur);
8869 XP_ERROR(XPATH_INVALID_TYPE);
8870 }
8871 tmp = xmlStrcat(newobj->stringval, cur->stringval);
8872 newobj->stringval = cur->stringval;
8873 cur->stringval = tmp;
8874 xmlXPathReleaseObject(ctxt->context, newobj);
8875 nargs--;
8876 }
8877 valuePush(ctxt, cur);
8878 }
8879
8880 /**
8881 * xmlXPathContainsFunction:
8882 * @ctxt: the XPath Parser context
8883 * @nargs: the number of arguments
8884 *
8885 * Implement the contains() XPath function
8886 * boolean contains(string, string)
8887 * The contains function returns true if the first argument string
8888 * contains the second argument string, and otherwise returns false.
8889 */
8890 void
8891 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8892 xmlXPathObjectPtr hay, needle;
8893
8894 CHECK_ARITY(2);
8895 CAST_TO_STRING;
8896 CHECK_TYPE(XPATH_STRING);
8897 needle = valuePop(ctxt);
8898 CAST_TO_STRING;
8899 hay = valuePop(ctxt);
8900
8901 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8902 xmlXPathReleaseObject(ctxt->context, hay);
8903 xmlXPathReleaseObject(ctxt->context, needle);
8904 XP_ERROR(XPATH_INVALID_TYPE);
8905 }
8906 if (xmlStrstr(hay->stringval, needle->stringval))
8907 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8908 else
8909 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8910 xmlXPathReleaseObject(ctxt->context, hay);
8911 xmlXPathReleaseObject(ctxt->context, needle);
8912 }
8913
8914 /**
8915 * xmlXPathStartsWithFunction:
8916 * @ctxt: the XPath Parser context
8917 * @nargs: the number of arguments
8918 *
8919 * Implement the starts-with() XPath function
8920 * boolean starts-with(string, string)
8921 * The starts-with function returns true if the first argument string
8922 * starts with the second argument string, and otherwise returns false.
8923 */
8924 void
8925 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8926 xmlXPathObjectPtr hay, needle;
8927 int n;
8928
8929 CHECK_ARITY(2);
8930 CAST_TO_STRING;
8931 CHECK_TYPE(XPATH_STRING);
8932 needle = valuePop(ctxt);
8933 CAST_TO_STRING;
8934 hay = valuePop(ctxt);
8935
8936 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8937 xmlXPathReleaseObject(ctxt->context, hay);
8938 xmlXPathReleaseObject(ctxt->context, needle);
8939 XP_ERROR(XPATH_INVALID_TYPE);
8940 }
8941 n = xmlStrlen(needle->stringval);
8942 if (xmlStrncmp(hay->stringval, needle->stringval, n))
8943 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8944 else
8945 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8946 xmlXPathReleaseObject(ctxt->context, hay);
8947 xmlXPathReleaseObject(ctxt->context, needle);
8948 }
8949
8950 /**
8951 * xmlXPathSubstringFunction:
8952 * @ctxt: the XPath Parser context
8953 * @nargs: the number of arguments
8954 *
8955 * Implement the substring() XPath function
8956 * string substring(string, number, number?)
8957 * The substring function returns the substring of the first argument
8958 * starting at the position specified in the second argument with
8959 * length specified in the third argument. For example,
8960 * substring("12345",2,3) returns "234". If the third argument is not
8961 * specified, it returns the substring starting at the position specified
8962 * in the second argument and continuing to the end of the string. For
8963 * example, substring("12345",2) returns "2345". More precisely, each
8964 * character in the string (see [3.6 Strings]) is considered to have a
8965 * numeric position: the position of the first character is 1, the position
8966 * of the second character is 2 and so on. The returned substring contains
8967 * those characters for which the position of the character is greater than
8968 * or equal to the second argument and, if the third argument is specified,
8969 * less than the sum of the second and third arguments; the comparisons
8970 * and addition used for the above follow the standard IEEE 754 rules. Thus:
8971 * - substring("12345", 1.5, 2.6) returns "234"
8972 * - substring("12345", 0, 3) returns "12"
8973 * - substring("12345", 0 div 0, 3) returns ""
8974 * - substring("12345", 1, 0 div 0) returns ""
8975 * - substring("12345", -42, 1 div 0) returns "12345"
8976 * - substring("12345", -1 div 0, 1 div 0) returns ""
8977 */
8978 void
8979 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8980 xmlXPathObjectPtr str, start, len;
8981 double le=0, in;
8982 int i, l, m;
8983 xmlChar *ret;
8984
8985 if (nargs < 2) {
8986 CHECK_ARITY(2);
8987 }
8988 if (nargs > 3) {
8989 CHECK_ARITY(3);
8990 }
8991 /*
8992 * take care of possible last (position) argument
8993 */
8994 if (nargs == 3) {
8995 CAST_TO_NUMBER;
8996 CHECK_TYPE(XPATH_NUMBER);
8997 len = valuePop(ctxt);
8998 le = len->floatval;
8999 xmlXPathReleaseObject(ctxt->context, len);
9000 }
9001
9002 CAST_TO_NUMBER;
9003 CHECK_TYPE(XPATH_NUMBER);
9004 start = valuePop(ctxt);
9005 in = start->floatval;
9006 xmlXPathReleaseObject(ctxt->context, start);
9007 CAST_TO_STRING;
9008 CHECK_TYPE(XPATH_STRING);
9009 str = valuePop(ctxt);
9010 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
9011
9012 /*
9013 * If last pos not present, calculate last position
9014 */
9015 if (nargs != 3) {
9016 le = (double)m;
9017 if (in < 1.0)
9018 in = 1.0;
9019 }
9020
9021 /* Need to check for the special cases where either
9022 * the index is NaN, the length is NaN, or both
9023 * arguments are infinity (relying on Inf + -Inf = NaN)
9024 */
9025 if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
9026 /*
9027 * To meet the requirements of the spec, the arguments
9028 * must be converted to integer format before
9029 * initial index calculations are done
9030 *
9031 * First we go to integer form, rounding up
9032 * and checking for special cases
9033 */
9034 i = (int) in;
9035 if (((double)i)+0.5 <= in) i++;
9036
9037 if (xmlXPathIsInf(le) == 1) {
9038 l = m;
9039 if (i < 1)
9040 i = 1;
9041 }
9042 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9043 l = 0;
9044 else {
9045 l = (int) le;
9046 if (((double)l)+0.5 <= le) l++;
9047 }
9048
9049 /* Now we normalize inidices */
9050 i -= 1;
9051 l += i;
9052 if (i < 0)
9053 i = 0;
9054 if (l > m)
9055 l = m;
9056
9057 /* number of chars to copy */
9058 l -= i;
9059
9060 ret = xmlUTF8Strsub(str->stringval, i, l);
9061 }
9062 else {
9063 ret = NULL;
9064 }
9065 if (ret == NULL)
9066 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9067 else {
9068 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9069 xmlFree(ret);
9070 }
9071 xmlXPathReleaseObject(ctxt->context, str);
9072 }
9073
9074 /**
9075 * xmlXPathSubstringBeforeFunction:
9076 * @ctxt: the XPath Parser context
9077 * @nargs: the number of arguments
9078 *
9079 * Implement the substring-before() XPath function
9080 * string substring-before(string, string)
9081 * The substring-before function returns the substring of the first
9082 * argument string that precedes the first occurrence of the second
9083 * argument string in the first argument string, or the empty string
9084 * if the first argument string does not contain the second argument
9085 * string. For example, substring-before("1999/04/01","/") returns 1999.
9086 */
9087 void
9088 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9089 xmlXPathObjectPtr str;
9090 xmlXPathObjectPtr find;
9091 xmlBufferPtr target;
9092 const xmlChar *point;
9093 int offset;
9094
9095 CHECK_ARITY(2);
9096 CAST_TO_STRING;
9097 find = valuePop(ctxt);
9098 CAST_TO_STRING;
9099 str = valuePop(ctxt);
9100
9101 target = xmlBufferCreate();
9102 if (target) {
9103 point = xmlStrstr(str->stringval, find->stringval);
9104 if (point) {
9105 offset = (int)(point - str->stringval);
9106 xmlBufferAdd(target, str->stringval, offset);
9107 }
9108 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9109 xmlBufferContent(target)));
9110 xmlBufferFree(target);
9111 }
9112 xmlXPathReleaseObject(ctxt->context, str);
9113 xmlXPathReleaseObject(ctxt->context, find);
9114 }
9115
9116 /**
9117 * xmlXPathSubstringAfterFunction:
9118 * @ctxt: the XPath Parser context
9119 * @nargs: the number of arguments
9120 *
9121 * Implement the substring-after() XPath function
9122 * string substring-after(string, string)
9123 * The substring-after function returns the substring of the first
9124 * argument string that follows the first occurrence of the second
9125 * argument string in the first argument string, or the empty stringi
9126 * if the first argument string does not contain the second argument
9127 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9128 * and substring-after("1999/04/01","19") returns 99/04/01.
9129 */
9130 void
9131 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9132 xmlXPathObjectPtr str;
9133 xmlXPathObjectPtr find;
9134 xmlBufferPtr target;
9135 const xmlChar *point;
9136 int offset;
9137
9138 CHECK_ARITY(2);
9139 CAST_TO_STRING;
9140 find = valuePop(ctxt);
9141 CAST_TO_STRING;
9142 str = valuePop(ctxt);
9143
9144 target = xmlBufferCreate();
9145 if (target) {
9146 point = xmlStrstr(str->stringval, find->stringval);
9147 if (point) {
9148 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9149 xmlBufferAdd(target, &str->stringval[offset],
9150 xmlStrlen(str->stringval) - offset);
9151 }
9152 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9153 xmlBufferContent(target)));
9154 xmlBufferFree(target);
9155 }
9156 xmlXPathReleaseObject(ctxt->context, str);
9157 xmlXPathReleaseObject(ctxt->context, find);
9158 }
9159
9160 /**
9161 * xmlXPathNormalizeFunction:
9162 * @ctxt: the XPath Parser context
9163 * @nargs: the number of arguments
9164 *
9165 * Implement the normalize-space() XPath function
9166 * string normalize-space(string?)
9167 * The normalize-space function returns the argument string with white
9168 * space normalized by stripping leading and trailing whitespace
9169 * and replacing sequences of whitespace characters by a single
9170 * space. Whitespace characters are the same allowed by the S production
9171 * in XML. If the argument is omitted, it defaults to the context
9172 * node converted to a string, in other words the value of the context node.
9173 */
9174 void
9175 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9176 xmlXPathObjectPtr obj = NULL;
9177 xmlChar *source = NULL;
9178 xmlBufferPtr target;
9179 xmlChar blank;
9180
9181 if (ctxt == NULL) return;
9182 if (nargs == 0) {
9183 /* Use current context node */
9184 valuePush(ctxt,
9185 xmlXPathCacheWrapString(ctxt->context,
9186 xmlXPathCastNodeToString(ctxt->context->node)));
9187 nargs = 1;
9188 }
9189
9190 CHECK_ARITY(1);
9191 CAST_TO_STRING;
9192 CHECK_TYPE(XPATH_STRING);
9193 obj = valuePop(ctxt);
9194 source = obj->stringval;
9195
9196 target = xmlBufferCreate();
9197 if (target && source) {
9198
9199 /* Skip leading whitespaces */
9200 while (IS_BLANK_CH(*source))
9201 source++;
9202
9203 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9204 blank = 0;
9205 while (*source) {
9206 if (IS_BLANK_CH(*source)) {
9207 blank = 0x20;
9208 } else {
9209 if (blank) {
9210 xmlBufferAdd(target, &blank, 1);
9211 blank = 0;
9212 }
9213 xmlBufferAdd(target, source, 1);
9214 }
9215 source++;
9216 }
9217 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9218 xmlBufferContent(target)));
9219 xmlBufferFree(target);
9220 }
9221 xmlXPathReleaseObject(ctxt->context, obj);
9222 }
9223
9224 /**
9225 * xmlXPathTranslateFunction:
9226 * @ctxt: the XPath Parser context
9227 * @nargs: the number of arguments
9228 *
9229 * Implement the translate() XPath function
9230 * string translate(string, string, string)
9231 * The translate function returns the first argument string with
9232 * occurrences of characters in the second argument string replaced
9233 * by the character at the corresponding position in the third argument
9234 * string. For example, translate("bar","abc","ABC") returns the string
9235 * BAr. If there is a character in the second argument string with no
9236 * character at a corresponding position in the third argument string
9237 * (because the second argument string is longer than the third argument
9238 * string), then occurrences of that character in the first argument
9239 * string are removed. For example, translate("--aaa--","abc-","ABC")
9240 * returns "AAA". If a character occurs more than once in second
9241 * argument string, then the first occurrence determines the replacement
9242 * character. If the third argument string is longer than the second
9243 * argument string, then excess characters are ignored.
9244 */
9245 void
9246 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9247 xmlXPathObjectPtr str;
9248 xmlXPathObjectPtr from;
9249 xmlXPathObjectPtr to;
9250 xmlBufferPtr target;
9251 int offset, max;
9252 xmlChar ch;
9253 const xmlChar *point;
9254 xmlChar *cptr;
9255
9256 CHECK_ARITY(3);
9257
9258 CAST_TO_STRING;
9259 to = valuePop(ctxt);
9260 CAST_TO_STRING;
9261 from = valuePop(ctxt);
9262 CAST_TO_STRING;
9263 str = valuePop(ctxt);
9264
9265 target = xmlBufferCreate();
9266 if (target) {
9267 max = xmlUTF8Strlen(to->stringval);
9268 for (cptr = str->stringval; (ch=*cptr); ) {
9269 offset = xmlUTF8Strloc(from->stringval, cptr);
9270 if (offset >= 0) {
9271 if (offset < max) {
9272 point = xmlUTF8Strpos(to->stringval, offset);
9273 if (point)
9274 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
9275 }
9276 } else
9277 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9278
9279 /* Step to next character in input */
9280 cptr++;
9281 if ( ch & 0x80 ) {
9282 /* if not simple ascii, verify proper format */
9283 if ( (ch & 0xc0) != 0xc0 ) {
9284 xmlGenericError(xmlGenericErrorContext,
9285 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9286 break;
9287 }
9288 /* then skip over remaining bytes for this char */
9289 while ( (ch <<= 1) & 0x80 )
9290 if ( (*cptr++ & 0xc0) != 0x80 ) {
9291 xmlGenericError(xmlGenericErrorContext,
9292 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9293 break;
9294 }
9295 if (ch & 0x80) /* must have had error encountered */
9296 break;
9297 }
9298 }
9299 }
9300 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9301 xmlBufferContent(target)));
9302 xmlBufferFree(target);
9303 xmlXPathReleaseObject(ctxt->context, str);
9304 xmlXPathReleaseObject(ctxt->context, from);
9305 xmlXPathReleaseObject(ctxt->context, to);
9306 }
9307
9308 /**
9309 * xmlXPathBooleanFunction:
9310 * @ctxt: the XPath Parser context
9311 * @nargs: the number of arguments
9312 *
9313 * Implement the boolean() XPath function
9314 * boolean boolean(object)
9315 * The boolean function converts its argument to a boolean as follows:
9316 * - a number is true if and only if it is neither positive or
9317 * negative zero nor NaN
9318 * - a node-set is true if and only if it is non-empty
9319 * - a string is true if and only if its length is non-zero
9320 */
9321 void
9322 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9323 xmlXPathObjectPtr cur;
9324
9325 CHECK_ARITY(1);
9326 cur = valuePop(ctxt);
9327 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9328 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9329 valuePush(ctxt, cur);
9330 }
9331
9332 /**
9333 * xmlXPathNotFunction:
9334 * @ctxt: the XPath Parser context
9335 * @nargs: the number of arguments
9336 *
9337 * Implement the not() XPath function
9338 * boolean not(boolean)
9339 * The not function returns true if its argument is false,
9340 * and false otherwise.
9341 */
9342 void
9343 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9344 CHECK_ARITY(1);
9345 CAST_TO_BOOLEAN;
9346 CHECK_TYPE(XPATH_BOOLEAN);
9347 ctxt->value->boolval = ! ctxt->value->boolval;
9348 }
9349
9350 /**
9351 * xmlXPathTrueFunction:
9352 * @ctxt: the XPath Parser context
9353 * @nargs: the number of arguments
9354 *
9355 * Implement the true() XPath function
9356 * boolean true()
9357 */
9358 void
9359 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9360 CHECK_ARITY(0);
9361 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9362 }
9363
9364 /**
9365 * xmlXPathFalseFunction:
9366 * @ctxt: the XPath Parser context
9367 * @nargs: the number of arguments
9368 *
9369 * Implement the false() XPath function
9370 * boolean false()
9371 */
9372 void
9373 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9374 CHECK_ARITY(0);
9375 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9376 }
9377
9378 /**
9379 * xmlXPathLangFunction:
9380 * @ctxt: the XPath Parser context
9381 * @nargs: the number of arguments
9382 *
9383 * Implement the lang() XPath function
9384 * boolean lang(string)
9385 * The lang function returns true or false depending on whether the
9386 * language of the context node as specified by xml:lang attributes
9387 * is the same as or is a sublanguage of the language specified by
9388 * the argument string. The language of the context node is determined
9389 * by the value of the xml:lang attribute on the context node, or, if
9390 * the context node has no xml:lang attribute, by the value of the
9391 * xml:lang attribute on the nearest ancestor of the context node that
9392 * has an xml:lang attribute. If there is no such attribute, then lang
9393 * returns false. If there is such an attribute, then lang returns
9394 * true if the attribute value is equal to the argument ignoring case,
9395 * or if there is some suffix starting with - such that the attribute
9396 * value is equal to the argument ignoring that suffix of the attribute
9397 * value and ignoring case.
9398 */
9399 void
9400 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9401 xmlXPathObjectPtr val = NULL;
9402 const xmlChar *theLang = NULL;
9403 const xmlChar *lang;
9404 int ret = 0;
9405 int i;
9406
9407 CHECK_ARITY(1);
9408 CAST_TO_STRING;
9409 CHECK_TYPE(XPATH_STRING);
9410 val = valuePop(ctxt);
9411 lang = val->stringval;
9412 theLang = xmlNodeGetLang(ctxt->context->node);
9413 if ((theLang != NULL) && (lang != NULL)) {
9414 for (i = 0;lang[i] != 0;i++)
9415 if (toupper(lang[i]) != toupper(theLang[i]))
9416 goto not_equal;
9417 if ((theLang[i] == 0) || (theLang[i] == '-'))
9418 ret = 1;
9419 }
9420 not_equal:
9421 if (theLang != NULL)
9422 xmlFree((void *)theLang);
9423
9424 xmlXPathReleaseObject(ctxt->context, val);
9425 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9426 }
9427
9428 /**
9429 * xmlXPathNumberFunction:
9430 * @ctxt: the XPath Parser context
9431 * @nargs: the number of arguments
9432 *
9433 * Implement the number() XPath function
9434 * number number(object?)
9435 */
9436 void
9437 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9438 xmlXPathObjectPtr cur;
9439 double res;
9440
9441 if (ctxt == NULL) return;
9442 if (nargs == 0) {
9443 if (ctxt->context->node == NULL) {
9444 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9445 } else {
9446 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9447
9448 res = xmlXPathStringEvalNumber(content);
9449 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9450 xmlFree(content);
9451 }
9452 return;
9453 }
9454
9455 CHECK_ARITY(1);
9456 cur = valuePop(ctxt);
9457 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9458 }
9459
9460 /**
9461 * xmlXPathSumFunction:
9462 * @ctxt: the XPath Parser context
9463 * @nargs: the number of arguments
9464 *
9465 * Implement the sum() XPath function
9466 * number sum(node-set)
9467 * The sum function returns the sum of the values of the nodes in
9468 * the argument node-set.
9469 */
9470 void
9471 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9472 xmlXPathObjectPtr cur;
9473 int i;
9474 double res = 0.0;
9475
9476 CHECK_ARITY(1);
9477 if ((ctxt->value == NULL) ||
9478 ((ctxt->value->type != XPATH_NODESET) &&
9479 (ctxt->value->type != XPATH_XSLT_TREE)))
9480 XP_ERROR(XPATH_INVALID_TYPE);
9481 cur = valuePop(ctxt);
9482
9483 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9484 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9485 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9486 }
9487 }
9488 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9489 xmlXPathReleaseObject(ctxt->context, cur);
9490 }
9491
9492 /*
9493 * To assure working code on multiple platforms, we want to only depend
9494 * upon the characteristic truncation of converting a floating point value
9495 * to an integer. Unfortunately, because of the different storage sizes
9496 * of our internal floating point value (double) and integer (int), we
9497 * can't directly convert (see bug 301162). This macro is a messy
9498 * 'workaround'
9499 */
9500 #define XTRUNC(f, v) \
9501 f = fmod((v), INT_MAX); \
9502 f = (v) - (f) + (double)((int)(f));
9503
9504 /**
9505 * xmlXPathFloorFunction:
9506 * @ctxt: the XPath Parser context
9507 * @nargs: the number of arguments
9508 *
9509 * Implement the floor() XPath function
9510 * number floor(number)
9511 * The floor function returns the largest (closest to positive infinity)
9512 * number that is not greater than the argument and that is an integer.
9513 */
9514 void
9515 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9516 double f;
9517
9518 CHECK_ARITY(1);
9519 CAST_TO_NUMBER;
9520 CHECK_TYPE(XPATH_NUMBER);
9521
9522 XTRUNC(f, ctxt->value->floatval);
9523 if (f != ctxt->value->floatval) {
9524 if (ctxt->value->floatval > 0)
9525 ctxt->value->floatval = f;
9526 else
9527 ctxt->value->floatval = f - 1;
9528 }
9529 }
9530
9531 /**
9532 * xmlXPathCeilingFunction:
9533 * @ctxt: the XPath Parser context
9534 * @nargs: the number of arguments
9535 *
9536 * Implement the ceiling() XPath function
9537 * number ceiling(number)
9538 * The ceiling function returns the smallest (closest to negative infinity)
9539 * number that is not less than the argument and that is an integer.
9540 */
9541 void
9542 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9543 double f;
9544
9545 CHECK_ARITY(1);
9546 CAST_TO_NUMBER;
9547 CHECK_TYPE(XPATH_NUMBER);
9548
9549 #if 0
9550 ctxt->value->floatval = ceil(ctxt->value->floatval);
9551 #else
9552 XTRUNC(f, ctxt->value->floatval);
9553 if (f != ctxt->value->floatval) {
9554 if (ctxt->value->floatval > 0)
9555 ctxt->value->floatval = f + 1;
9556 else {
9557 if (ctxt->value->floatval < 0 && f == 0)
9558 ctxt->value->floatval = xmlXPathNZERO;
9559 else
9560 ctxt->value->floatval = f;
9561 }
9562
9563 }
9564 #endif
9565 }
9566
9567 /**
9568 * xmlXPathRoundFunction:
9569 * @ctxt: the XPath Parser context
9570 * @nargs: the number of arguments
9571 *
9572 * Implement the round() XPath function
9573 * number round(number)
9574 * The round function returns the number that is closest to the
9575 * argument and that is an integer. If there are two such numbers,
9576 * then the one that is even is returned.
9577 */
9578 void
9579 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9580 double f;
9581
9582 CHECK_ARITY(1);
9583 CAST_TO_NUMBER;
9584 CHECK_TYPE(XPATH_NUMBER);
9585
9586 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9587 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9588 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
9589 (ctxt->value->floatval == 0.0))
9590 return;
9591
9592 XTRUNC(f, ctxt->value->floatval);
9593 if (ctxt->value->floatval < 0) {
9594 if (ctxt->value->floatval < f - 0.5)
9595 ctxt->value->floatval = f - 1;
9596 else
9597 ctxt->value->floatval = f;
9598 if (ctxt->value->floatval == 0)
9599 ctxt->value->floatval = xmlXPathNZERO;
9600 } else {
9601 if (ctxt->value->floatval < f + 0.5)
9602 ctxt->value->floatval = f;
9603 else
9604 ctxt->value->floatval = f + 1;
9605 }
9606 }
9607
9608 /************************************************************************
9609 * *
9610 * The Parser *
9611 * *
9612 ************************************************************************/
9613
9614 /*
9615 * a few forward declarations since we use a recursive call based
9616 * implementation.
9617 */
9618 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9619 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9620 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9621 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9622 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9623 int qualified);
9624
9625 /**
9626 * xmlXPathCurrentChar:
9627 * @ctxt: the XPath parser context
9628 * @cur: pointer to the beginning of the char
9629 * @len: pointer to the length of the char read
9630 *
9631 * The current char value, if using UTF-8 this may actually span multiple
9632 * bytes in the input buffer.
9633 *
9634 * Returns the current char value and its length
9635 */
9636
9637 static int
9638 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9639 unsigned char c;
9640 unsigned int val;
9641 const xmlChar *cur;
9642
9643 if (ctxt == NULL)
9644 return(0);
9645 cur = ctxt->cur;
9646
9647 /*
9648 * We are supposed to handle UTF8, check it's valid
9649 * From rfc2044: encoding of the Unicode values on UTF-8:
9650 *
9651 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9652 * 0000 0000-0000 007F 0xxxxxxx
9653 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
9654 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
9655 *
9656 * Check for the 0x110000 limit too
9657 */
9658 c = *cur;
9659 if (c & 0x80) {
9660 if ((cur[1] & 0xc0) != 0x80)
9661 goto encoding_error;
9662 if ((c & 0xe0) == 0xe0) {
9663
9664 if ((cur[2] & 0xc0) != 0x80)
9665 goto encoding_error;
9666 if ((c & 0xf0) == 0xf0) {
9667 if (((c & 0xf8) != 0xf0) ||
9668 ((cur[3] & 0xc0) != 0x80))
9669 goto encoding_error;
9670 /* 4-byte code */
9671 *len = 4;
9672 val = (cur[0] & 0x7) << 18;
9673 val |= (cur[1] & 0x3f) << 12;
9674 val |= (cur[2] & 0x3f) << 6;
9675 val |= cur[3] & 0x3f;
9676 } else {
9677 /* 3-byte code */
9678 *len = 3;
9679 val = (cur[0] & 0xf) << 12;
9680 val |= (cur[1] & 0x3f) << 6;
9681 val |= cur[2] & 0x3f;
9682 }
9683 } else {
9684 /* 2-byte code */
9685 *len = 2;
9686 val = (cur[0] & 0x1f) << 6;
9687 val |= cur[1] & 0x3f;
9688 }
9689 if (!IS_CHAR(val)) {
9690 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9691 }
9692 return(val);
9693 } else {
9694 /* 1-byte code */
9695 *len = 1;
9696 return((int) *cur);
9697 }
9698 encoding_error:
9699 /*
9700 * If we detect an UTF8 error that probably means that the
9701 * input encoding didn't get properly advertised in the
9702 * declaration header. Report the error and switch the encoding
9703 * to ISO-Latin-1 (if you don't like this policy, just declare the
9704 * encoding !)
9705 */
9706 *len = 0;
9707 XP_ERROR0(XPATH_ENCODING_ERROR);
9708 }
9709
9710 /**
9711 * xmlXPathParseNCName:
9712 * @ctxt: the XPath Parser context
9713 *
9714 * parse an XML namespace non qualified name.
9715 *
9716 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9717 *
9718 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9719 * CombiningChar | Extender
9720 *
9721 * Returns the namespace name or NULL
9722 */
9723
9724 xmlChar *
9725 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9726 const xmlChar *in;
9727 xmlChar *ret;
9728 int count = 0;
9729
9730 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9731 /*
9732 * Accelerator for simple ASCII names
9733 */
9734 in = ctxt->cur;
9735 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9736 ((*in >= 0x41) && (*in <= 0x5A)) ||
9737 (*in == '_')) {
9738 in++;
9739 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9740 ((*in >= 0x41) && (*in <= 0x5A)) ||
9741 ((*in >= 0x30) && (*in <= 0x39)) ||
9742 (*in == '_') || (*in == '.') ||
9743 (*in == '-'))
9744 in++;
9745 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9746 (*in == '[') || (*in == ']') || (*in == ':') ||
9747 (*in == '@') || (*in == '*')) {
9748 count = in - ctxt->cur;
9749 if (count == 0)
9750 return(NULL);
9751 ret = xmlStrndup(ctxt->cur, count);
9752 ctxt->cur = in;
9753 return(ret);
9754 }
9755 }
9756 return(xmlXPathParseNameComplex(ctxt, 0));
9757 }
9758
9759
9760 /**
9761 * xmlXPathParseQName:
9762 * @ctxt: the XPath Parser context
9763 * @prefix: a xmlChar **
9764 *
9765 * parse an XML qualified name
9766 *
9767 * [NS 5] QName ::= (Prefix ':')? LocalPart
9768 *
9769 * [NS 6] Prefix ::= NCName
9770 *
9771 * [NS 7] LocalPart ::= NCName
9772 *
9773 * Returns the function returns the local part, and prefix is updated
9774 * to get the Prefix if any.
9775 */
9776
9777 static xmlChar *
9778 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9779 xmlChar *ret = NULL;
9780
9781 *prefix = NULL;
9782 ret = xmlXPathParseNCName(ctxt);
9783 if (ret && CUR == ':') {
9784 *prefix = ret;
9785 NEXT;
9786 ret = xmlXPathParseNCName(ctxt);
9787 }
9788 return(ret);
9789 }
9790
9791 /**
9792 * xmlXPathParseName:
9793 * @ctxt: the XPath Parser context
9794 *
9795 * parse an XML name
9796 *
9797 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9798 * CombiningChar | Extender
9799 *
9800 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9801 *
9802 * Returns the namespace name or NULL
9803 */
9804
9805 xmlChar *
9806 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9807 const xmlChar *in;
9808 xmlChar *ret;
9809 int count = 0;
9810
9811 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9812 /*
9813 * Accelerator for simple ASCII names
9814 */
9815 in = ctxt->cur;
9816 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9817 ((*in >= 0x41) && (*in <= 0x5A)) ||
9818 (*in == '_') || (*in == ':')) {
9819 in++;
9820 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9821 ((*in >= 0x41) && (*in <= 0x5A)) ||
9822 ((*in >= 0x30) && (*in <= 0x39)) ||
9823 (*in == '_') || (*in == '-') ||
9824 (*in == ':') || (*in == '.'))
9825 in++;
9826 if ((*in > 0) && (*in < 0x80)) {
9827 count = in - ctxt->cur;
9828 ret = xmlStrndup(ctxt->cur, count);
9829 ctxt->cur = in;
9830 return(ret);
9831 }
9832 }
9833 return(xmlXPathParseNameComplex(ctxt, 1));
9834 }
9835
9836 static xmlChar *
9837 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9838 xmlChar buf[XML_MAX_NAMELEN + 5];
9839 int len = 0, l;
9840 int c;
9841
9842 /*
9843 * Handler for more complex cases
9844 */
9845 c = CUR_CHAR(l);
9846 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9847 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9848 (c == '*') || /* accelerators */
9849 (!IS_LETTER(c) && (c != '_') &&
9850 ((qualified) && (c != ':')))) {
9851 return(NULL);
9852 }
9853
9854 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9855 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9856 (c == '.') || (c == '-') ||
9857 (c == '_') || ((qualified) && (c == ':')) ||
9858 (IS_COMBINING(c)) ||
9859 (IS_EXTENDER(c)))) {
9860 COPY_BUF(l,buf,len,c);
9861 NEXTL(l);
9862 c = CUR_CHAR(l);
9863 if (len >= XML_MAX_NAMELEN) {
9864 /*
9865 * Okay someone managed to make a huge name, so he's ready to pay
9866 * for the processing speed.
9867 */
9868 xmlChar *buffer;
9869 int max = len * 2;
9870
9871 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
9872 if (buffer == NULL) {
9873 XP_ERRORNULL(XPATH_MEMORY_ERROR);
9874 }
9875 memcpy(buffer, buf, len);
9876 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9877 (c == '.') || (c == '-') ||
9878 (c == '_') || ((qualified) && (c == ':')) ||
9879 (IS_COMBINING(c)) ||
9880 (IS_EXTENDER(c))) {
9881 if (len + 10 > max) {
9882 max *= 2;
9883 buffer = (xmlChar *) xmlRealloc(buffer,
9884 max * sizeof(xmlChar));
9885 if (buffer == NULL) {
9886 XP_ERRORNULL(XPATH_MEMORY_ERROR);
9887 }
9888 }
9889 COPY_BUF(l,buffer,len,c);
9890 NEXTL(l);
9891 c = CUR_CHAR(l);
9892 }
9893 buffer[len] = 0;
9894 return(buffer);
9895 }
9896 }
9897 if (len == 0)
9898 return(NULL);
9899 return(xmlStrndup(buf, len));
9900 }
9901
9902 #define MAX_FRAC 20
9903
9904 /*
9905 * These are used as divisors for the fractional part of a number.
9906 * Since the table includes 1.0 (representing '0' fractional digits),
9907 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
9908 */
9909 static double my_pow10[MAX_FRAC+1] = {
9910 1.0, 10.0, 100.0, 1000.0, 10000.0,
9911 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
9912 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
9913 100000000000000.0,
9914 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
9915 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
9916 };
9917
9918 /**
9919 * xmlXPathStringEvalNumber:
9920 * @str: A string to scan
9921 *
9922 * [30a] Float ::= Number ('e' Digits?)?
9923 *
9924 * [30] Number ::= Digits ('.' Digits?)?
9925 * | '.' Digits
9926 * [31] Digits ::= [0-9]+
9927 *
9928 * Compile a Number in the string
9929 * In complement of the Number expression, this function also handles
9930 * negative values : '-' Number.
9931 *
9932 * Returns the double value.
9933 */
9934 double
9935 xmlXPathStringEvalNumber(const xmlChar *str) {
9936 const xmlChar *cur = str;
9937 double ret;
9938 int ok = 0;
9939 int isneg = 0;
9940 int exponent = 0;
9941 int is_exponent_negative = 0;
9942 #ifdef __GNUC__
9943 unsigned long tmp = 0;
9944 double temp;
9945 #endif
9946 if (cur == NULL) return(0);
9947 while (IS_BLANK_CH(*cur)) cur++;
9948 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9949 return(xmlXPathNAN);
9950 }
9951 if (*cur == '-') {
9952 isneg = 1;
9953 cur++;
9954 }
9955
9956 #ifdef __GNUC__
9957 /*
9958 * tmp/temp is a workaround against a gcc compiler bug
9959 * http://veillard.com/gcc.bug
9960 */
9961 ret = 0;
9962 while ((*cur >= '0') && (*cur <= '9')) {
9963 ret = ret * 10;
9964 tmp = (*cur - '0');
9965 ok = 1;
9966 cur++;
9967 temp = (double) tmp;
9968 ret = ret + temp;
9969 }
9970 #else
9971 ret = 0;
9972 while ((*cur >= '0') && (*cur <= '9')) {
9973 ret = ret * 10 + (*cur - '0');
9974 ok = 1;
9975 cur++;
9976 }
9977 #endif
9978
9979 if (*cur == '.') {
9980 int v, frac = 0;
9981 double fraction = 0;
9982
9983 cur++;
9984 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
9985 return(xmlXPathNAN);
9986 }
9987 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
9988 v = (*cur - '0');
9989 fraction = fraction * 10 + v;
9990 frac = frac + 1;
9991 cur++;
9992 }
9993 fraction /= my_pow10[frac];
9994 ret = ret + fraction;
9995 while ((*cur >= '0') && (*cur <= '9'))
9996 cur++;
9997 }
9998 if ((*cur == 'e') || (*cur == 'E')) {
9999 cur++;
10000 if (*cur == '-') {
10001 is_exponent_negative = 1;
10002 cur++;
10003 } else if (*cur == '+') {
10004 cur++;
10005 }
10006 while ((*cur >= '0') && (*cur <= '9')) {
10007 exponent = exponent * 10 + (*cur - '0');
10008 cur++;
10009 }
10010 }
10011 while (IS_BLANK_CH(*cur)) cur++;
10012 if (*cur != 0) return(xmlXPathNAN);
10013 if (isneg) ret = -ret;
10014 if (is_exponent_negative) exponent = -exponent;
10015 ret *= pow(10.0, (double)exponent);
10016 return(ret);
10017 }
10018
10019 /**
10020 * xmlXPathCompNumber:
10021 * @ctxt: the XPath Parser context
10022 *
10023 * [30] Number ::= Digits ('.' Digits?)?
10024 * | '.' Digits
10025 * [31] Digits ::= [0-9]+
10026 *
10027 * Compile a Number, then push it on the stack
10028 *
10029 */
10030 static void
10031 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10032 {
10033 double ret = 0.0;
10034 double mult = 1;
10035 int ok = 0;
10036 int exponent = 0;
10037 int is_exponent_negative = 0;
10038 #ifdef __GNUC__
10039 unsigned long tmp = 0;
10040 double temp;
10041 #endif
10042
10043 CHECK_ERROR;
10044 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10045 XP_ERROR(XPATH_NUMBER_ERROR);
10046 }
10047 #ifdef __GNUC__
10048 /*
10049 * tmp/temp is a workaround against a gcc compiler bug
10050 * http://veillard.com/gcc.bug
10051 */
10052 ret = 0;
10053 while ((CUR >= '0') && (CUR <= '9')) {
10054 ret = ret * 10;
10055 tmp = (CUR - '0');
10056 ok = 1;
10057 NEXT;
10058 temp = (double) tmp;
10059 ret = ret + temp;
10060 }
10061 #else
10062 ret = 0;
10063 while ((CUR >= '0') && (CUR <= '9')) {
10064 ret = ret * 10 + (CUR - '0');
10065 ok = 1;
10066 NEXT;
10067 }
10068 #endif
10069 if (CUR == '.') {
10070 NEXT;
10071 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10072 XP_ERROR(XPATH_NUMBER_ERROR);
10073 }
10074 while ((CUR >= '0') && (CUR <= '9')) {
10075 mult /= 10;
10076 ret = ret + (CUR - '0') * mult;
10077 NEXT;
10078 }
10079 }
10080 if ((CUR == 'e') || (CUR == 'E')) {
10081 NEXT;
10082 if (CUR == '-') {
10083 is_exponent_negative = 1;
10084 NEXT;
10085 } else if (CUR == '+') {
10086 NEXT;
10087 }
10088 while ((CUR >= '0') && (CUR <= '9')) {
10089 exponent = exponent * 10 + (CUR - '0');
10090 NEXT;
10091 }
10092 if (is_exponent_negative)
10093 exponent = -exponent;
10094 ret *= pow(10.0, (double) exponent);
10095 }
10096 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10097 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10098 }
10099
10100 /**
10101 * xmlXPathParseLiteral:
10102 * @ctxt: the XPath Parser context
10103 *
10104 * Parse a Literal
10105 *
10106 * [29] Literal ::= '"' [^"]* '"'
10107 * | "'" [^']* "'"
10108 *
10109 * Returns the value found or NULL in case of error
10110 */
10111 static xmlChar *
10112 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10113 const xmlChar *q;
10114 xmlChar *ret = NULL;
10115
10116 if (CUR == '"') {
10117 NEXT;
10118 q = CUR_PTR;
10119 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10120 NEXT;
10121 if (!IS_CHAR_CH(CUR)) {
10122 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10123 } else {
10124 ret = xmlStrndup(q, CUR_PTR - q);
10125 NEXT;
10126 }
10127 } else if (CUR == '\'') {
10128 NEXT;
10129 q = CUR_PTR;
10130 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10131 NEXT;
10132 if (!IS_CHAR_CH(CUR)) {
10133 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10134 } else {
10135 ret = xmlStrndup(q, CUR_PTR - q);
10136 NEXT;
10137 }
10138 } else {
10139 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10140 }
10141 return(ret);
10142 }
10143
10144 /**
10145 * xmlXPathCompLiteral:
10146 * @ctxt: the XPath Parser context
10147 *
10148 * Parse a Literal and push it on the stack.
10149 *
10150 * [29] Literal ::= '"' [^"]* '"'
10151 * | "'" [^']* "'"
10152 *
10153 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10154 */
10155 static void
10156 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10157 const xmlChar *q;
10158 xmlChar *ret = NULL;
10159
10160 if (CUR == '"') {
10161 NEXT;
10162 q = CUR_PTR;
10163 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10164 NEXT;
10165 if (!IS_CHAR_CH(CUR)) {
10166 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10167 } else {
10168 ret = xmlStrndup(q, CUR_PTR - q);
10169 NEXT;
10170 }
10171 } else if (CUR == '\'') {
10172 NEXT;
10173 q = CUR_PTR;
10174 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10175 NEXT;
10176 if (!IS_CHAR_CH(CUR)) {
10177 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10178 } else {
10179 ret = xmlStrndup(q, CUR_PTR - q);
10180 NEXT;
10181 }
10182 } else {
10183 XP_ERROR(XPATH_START_LITERAL_ERROR);
10184 }
10185 if (ret == NULL) return;
10186 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10187 xmlXPathCacheNewString(ctxt->context, ret), NULL);
10188 xmlFree(ret);
10189 }
10190
10191 /**
10192 * xmlXPathCompVariableReference:
10193 * @ctxt: the XPath Parser context
10194 *
10195 * Parse a VariableReference, evaluate it and push it on the stack.
10196 *
10197 * The variable bindings consist of a mapping from variable names
10198 * to variable values. The value of a variable is an object, which can be
10199 * of any of the types that are possible for the value of an expression,
10200 * and may also be of additional types not specified here.
10201 *
10202 * Early evaluation is possible since:
10203 * The variable bindings [...] used to evaluate a subexpression are
10204 * always the same as those used to evaluate the containing expression.
10205 *
10206 * [36] VariableReference ::= '$' QName
10207 */
10208 static void
10209 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10210 xmlChar *name;
10211 xmlChar *prefix;
10212
10213 SKIP_BLANKS;
10214 if (CUR != '$') {
10215 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10216 }
10217 NEXT;
10218 name = xmlXPathParseQName(ctxt, &prefix);
10219 if (name == NULL) {
10220 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10221 }
10222 ctxt->comp->last = -1;
10223 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10224 name, prefix);
10225 SKIP_BLANKS;
10226 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10227 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
10228 }
10229 }
10230
10231 /**
10232 * xmlXPathIsNodeType:
10233 * @name: a name string
10234 *
10235 * Is the name given a NodeType one.
10236 *
10237 * [38] NodeType ::= 'comment'
10238 * | 'text'
10239 * | 'processing-instruction'
10240 * | 'node'
10241 *
10242 * Returns 1 if true 0 otherwise
10243 */
10244 int
10245 xmlXPathIsNodeType(const xmlChar *name) {
10246 if (name == NULL)
10247 return(0);
10248
10249 if (xmlStrEqual(name, BAD_CAST "node"))
10250 return(1);
10251 if (xmlStrEqual(name, BAD_CAST "text"))
10252 return(1);
10253 if (xmlStrEqual(name, BAD_CAST "comment"))
10254 return(1);
10255 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10256 return(1);
10257 return(0);
10258 }
10259
10260 /**
10261 * xmlXPathCompFunctionCall:
10262 * @ctxt: the XPath Parser context
10263 *
10264 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10265 * [17] Argument ::= Expr
10266 *
10267 * Compile a function call, the evaluation of all arguments are
10268 * pushed on the stack
10269 */
10270 static void
10271 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10272 xmlChar *name;
10273 xmlChar *prefix;
10274 int nbargs = 0;
10275 int sort = 1;
10276
10277 name = xmlXPathParseQName(ctxt, &prefix);
10278 if (name == NULL) {
10279 xmlFree(prefix);
10280 XP_ERROR(XPATH_EXPR_ERROR);
10281 }
10282 SKIP_BLANKS;
10283 #ifdef DEBUG_EXPR
10284 if (prefix == NULL)
10285 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10286 name);
10287 else
10288 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10289 prefix, name);
10290 #endif
10291
10292 if (CUR != '(') {
10293 XP_ERROR(XPATH_EXPR_ERROR);
10294 }
10295 NEXT;
10296 SKIP_BLANKS;
10297
10298 /*
10299 * Optimization for count(): we don't need the node-set to be sorted.
10300 */
10301 if ((prefix == NULL) && (name[0] == 'c') &&
10302 xmlStrEqual(name, BAD_CAST "count"))
10303 {
10304 sort = 0;
10305 }
10306 ctxt->comp->last = -1;
10307 if (CUR != ')') {
10308 while (CUR != 0) {
10309 int op1 = ctxt->comp->last;
10310 ctxt->comp->last = -1;
10311 xmlXPathCompileExpr(ctxt, sort);
10312 if (ctxt->error != XPATH_EXPRESSION_OK) {
10313 xmlFree(name);
10314 xmlFree(prefix);
10315 return;
10316 }
10317 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10318 nbargs++;
10319 if (CUR == ')') break;
10320 if (CUR != ',') {
10321 XP_ERROR(XPATH_EXPR_ERROR);
10322 }
10323 NEXT;
10324 SKIP_BLANKS;
10325 }
10326 }
10327 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10328 name, prefix);
10329 NEXT;
10330 SKIP_BLANKS;
10331 }
10332
10333 /**
10334 * xmlXPathCompPrimaryExpr:
10335 * @ctxt: the XPath Parser context
10336 *
10337 * [15] PrimaryExpr ::= VariableReference
10338 * | '(' Expr ')'
10339 * | Literal
10340 * | Number
10341 * | FunctionCall
10342 *
10343 * Compile a primary expression.
10344 */
10345 static void
10346 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10347 SKIP_BLANKS;
10348 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10349 else if (CUR == '(') {
10350 NEXT;
10351 SKIP_BLANKS;
10352 xmlXPathCompileExpr(ctxt, 1);
10353 CHECK_ERROR;
10354 if (CUR != ')') {
10355 XP_ERROR(XPATH_EXPR_ERROR);
10356 }
10357 NEXT;
10358 SKIP_BLANKS;
10359 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10360 xmlXPathCompNumber(ctxt);
10361 } else if ((CUR == '\'') || (CUR == '"')) {
10362 xmlXPathCompLiteral(ctxt);
10363 } else {
10364 xmlXPathCompFunctionCall(ctxt);
10365 }
10366 SKIP_BLANKS;
10367 }
10368
10369 /**
10370 * xmlXPathCompFilterExpr:
10371 * @ctxt: the XPath Parser context
10372 *
10373 * [20] FilterExpr ::= PrimaryExpr
10374 * | FilterExpr Predicate
10375 *
10376 * Compile a filter expression.
10377 * Square brackets are used to filter expressions in the same way that
10378 * they are used in location paths. It is an error if the expression to
10379 * be filtered does not evaluate to a node-set. The context node list
10380 * used for evaluating the expression in square brackets is the node-set
10381 * to be filtered listed in document order.
10382 */
10383
10384 static void
10385 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10386 xmlXPathCompPrimaryExpr(ctxt);
10387 CHECK_ERROR;
10388 SKIP_BLANKS;
10389
10390 while (CUR == '[') {
10391 xmlXPathCompPredicate(ctxt, 1);
10392 SKIP_BLANKS;
10393 }
10394
10395
10396 }
10397
10398 /**
10399 * xmlXPathScanName:
10400 * @ctxt: the XPath Parser context
10401 *
10402 * Trickery: parse an XML name but without consuming the input flow
10403 * Needed to avoid insanity in the parser state.
10404 *
10405 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10406 * CombiningChar | Extender
10407 *
10408 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10409 *
10410 * [6] Names ::= Name (S Name)*
10411 *
10412 * Returns the Name parsed or NULL
10413 */
10414
10415 static xmlChar *
10416 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10417 int len = 0, l;
10418 int c;
10419 const xmlChar *cur;
10420 xmlChar *ret;
10421
10422 cur = ctxt->cur;
10423
10424 c = CUR_CHAR(l);
10425 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10426 (!IS_LETTER(c) && (c != '_') &&
10427 (c != ':'))) {
10428 return(NULL);
10429 }
10430
10431 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10432 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10433 (c == '.') || (c == '-') ||
10434 (c == '_') || (c == ':') ||
10435 (IS_COMBINING(c)) ||
10436 (IS_EXTENDER(c)))) {
10437 len += l;
10438 NEXTL(l);
10439 c = CUR_CHAR(l);
10440 }
10441 ret = xmlStrndup(cur, ctxt->cur - cur);
10442 ctxt->cur = cur;
10443 return(ret);
10444 }
10445
10446 /**
10447 * xmlXPathCompPathExpr:
10448 * @ctxt: the XPath Parser context
10449 *
10450 * [19] PathExpr ::= LocationPath
10451 * | FilterExpr
10452 * | FilterExpr '/' RelativeLocationPath
10453 * | FilterExpr '//' RelativeLocationPath
10454 *
10455 * Compile a path expression.
10456 * The / operator and // operators combine an arbitrary expression
10457 * and a relative location path. It is an error if the expression
10458 * does not evaluate to a node-set.
10459 * The / operator does composition in the same way as when / is
10460 * used in a location path. As in location paths, // is short for
10461 * /descendant-or-self::node()/.
10462 */
10463
10464 static void
10465 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10466 int lc = 1; /* Should we branch to LocationPath ? */
10467 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10468
10469 SKIP_BLANKS;
10470 if ((CUR == '$') || (CUR == '(') ||
10471 (IS_ASCII_DIGIT(CUR)) ||
10472 (CUR == '\'') || (CUR == '"') ||
10473 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10474 lc = 0;
10475 } else if (CUR == '*') {
10476 /* relative or absolute location path */
10477 lc = 1;
10478 } else if (CUR == '/') {
10479 /* relative or absolute location path */
10480 lc = 1;
10481 } else if (CUR == '@') {
10482 /* relative abbreviated attribute location path */
10483 lc = 1;
10484 } else if (CUR == '.') {
10485 /* relative abbreviated attribute location path */
10486 lc = 1;
10487 } else {
10488 /*
10489 * Problem is finding if we have a name here whether it's:
10490 * - a nodetype
10491 * - a function call in which case it's followed by '('
10492 * - an axis in which case it's followed by ':'
10493 * - a element name
10494 * We do an a priori analysis here rather than having to
10495 * maintain parsed token content through the recursive function
10496 * calls. This looks uglier but makes the code easier to
10497 * read/write/debug.
10498 */
10499 SKIP_BLANKS;
10500 name = xmlXPathScanName(ctxt);
10501 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10502 #ifdef DEBUG_STEP
10503 xmlGenericError(xmlGenericErrorContext,
10504 "PathExpr: Axis\n");
10505 #endif
10506 lc = 1;
10507 xmlFree(name);
10508 } else if (name != NULL) {
10509 int len =xmlStrlen(name);
10510
10511
10512 while (NXT(len) != 0) {
10513 if (NXT(len) == '/') {
10514 /* element name */
10515 #ifdef DEBUG_STEP
10516 xmlGenericError(xmlGenericErrorContext,
10517 "PathExpr: AbbrRelLocation\n");
10518 #endif
10519 lc = 1;
10520 break;
10521 } else if (IS_BLANK_CH(NXT(len))) {
10522 /* ignore blanks */
10523 ;
10524 } else if (NXT(len) == ':') {
10525 #ifdef DEBUG_STEP
10526 xmlGenericError(xmlGenericErrorContext,
10527 "PathExpr: AbbrRelLocation\n");
10528 #endif
10529 lc = 1;
10530 break;
10531 } else if ((NXT(len) == '(')) {
10532 /* Note Type or Function */
10533 if (xmlXPathIsNodeType(name)) {
10534 #ifdef DEBUG_STEP
10535 xmlGenericError(xmlGenericErrorContext,
10536 "PathExpr: Type search\n");
10537 #endif
10538 lc = 1;
10539 } else {
10540 #ifdef DEBUG_STEP
10541 xmlGenericError(xmlGenericErrorContext,
10542 "PathExpr: function call\n");
10543 #endif
10544 lc = 0;
10545 }
10546 break;
10547 } else if ((NXT(len) == '[')) {
10548 /* element name */
10549 #ifdef DEBUG_STEP
10550 xmlGenericError(xmlGenericErrorContext,
10551 "PathExpr: AbbrRelLocation\n");
10552 #endif
10553 lc = 1;
10554 break;
10555 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10556 (NXT(len) == '=')) {
10557 lc = 1;
10558 break;
10559 } else {
10560 lc = 1;
10561 break;
10562 }
10563 len++;
10564 }
10565 if (NXT(len) == 0) {
10566 #ifdef DEBUG_STEP
10567 xmlGenericError(xmlGenericErrorContext,
10568 "PathExpr: AbbrRelLocation\n");
10569 #endif
10570 /* element name */
10571 lc = 1;
10572 }
10573 xmlFree(name);
10574 } else {
10575 /* make sure all cases are covered explicitly */
10576 XP_ERROR(XPATH_EXPR_ERROR);
10577 }
10578 }
10579
10580 if (lc) {
10581 if (CUR == '/') {
10582 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10583 } else {
10584 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10585 }
10586 xmlXPathCompLocationPath(ctxt);
10587 } else {
10588 xmlXPathCompFilterExpr(ctxt);
10589 CHECK_ERROR;
10590 if ((CUR == '/') && (NXT(1) == '/')) {
10591 SKIP(2);
10592 SKIP_BLANKS;
10593
10594 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10595 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10596 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10597
10598 xmlXPathCompRelativeLocationPath(ctxt);
10599 } else if (CUR == '/') {
10600 xmlXPathCompRelativeLocationPath(ctxt);
10601 }
10602 }
10603 SKIP_BLANKS;
10604 }
10605
10606 /**
10607 * xmlXPathCompUnionExpr:
10608 * @ctxt: the XPath Parser context
10609 *
10610 * [18] UnionExpr ::= PathExpr
10611 * | UnionExpr '|' PathExpr
10612 *
10613 * Compile an union expression.
10614 */
10615
10616 static void
10617 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10618 xmlXPathCompPathExpr(ctxt);
10619 CHECK_ERROR;
10620 SKIP_BLANKS;
10621 while (CUR == '|') {
10622 int op1 = ctxt->comp->last;
10623 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10624
10625 NEXT;
10626 SKIP_BLANKS;
10627 xmlXPathCompPathExpr(ctxt);
10628
10629 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10630
10631 SKIP_BLANKS;
10632 }
10633 }
10634
10635 /**
10636 * xmlXPathCompUnaryExpr:
10637 * @ctxt: the XPath Parser context
10638 *
10639 * [27] UnaryExpr ::= UnionExpr
10640 * | '-' UnaryExpr
10641 *
10642 * Compile an unary expression.
10643 */
10644
10645 static void
10646 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10647 int minus = 0;
10648 int found = 0;
10649
10650 SKIP_BLANKS;
10651 while (CUR == '-') {
10652 minus = 1 - minus;
10653 found = 1;
10654 NEXT;
10655 SKIP_BLANKS;
10656 }
10657
10658 xmlXPathCompUnionExpr(ctxt);
10659 CHECK_ERROR;
10660 if (found) {
10661 if (minus)
10662 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10663 else
10664 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10665 }
10666 }
10667
10668 /**
10669 * xmlXPathCompMultiplicativeExpr:
10670 * @ctxt: the XPath Parser context
10671 *
10672 * [26] MultiplicativeExpr ::= UnaryExpr
10673 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10674 * | MultiplicativeExpr 'div' UnaryExpr
10675 * | MultiplicativeExpr 'mod' UnaryExpr
10676 * [34] MultiplyOperator ::= '*'
10677 *
10678 * Compile an Additive expression.
10679 */
10680
10681 static void
10682 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10683 xmlXPathCompUnaryExpr(ctxt);
10684 CHECK_ERROR;
10685 SKIP_BLANKS;
10686 while ((CUR == '*') ||
10687 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10688 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10689 int op = -1;
10690 int op1 = ctxt->comp->last;
10691
10692 if (CUR == '*') {
10693 op = 0;
10694 NEXT;
10695 } else if (CUR == 'd') {
10696 op = 1;
10697 SKIP(3);
10698 } else if (CUR == 'm') {
10699 op = 2;
10700 SKIP(3);
10701 }
10702 SKIP_BLANKS;
10703 xmlXPathCompUnaryExpr(ctxt);
10704 CHECK_ERROR;
10705 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10706 SKIP_BLANKS;
10707 }
10708 }
10709
10710 /**
10711 * xmlXPathCompAdditiveExpr:
10712 * @ctxt: the XPath Parser context
10713 *
10714 * [25] AdditiveExpr ::= MultiplicativeExpr
10715 * | AdditiveExpr '+' MultiplicativeExpr
10716 * | AdditiveExpr '-' MultiplicativeExpr
10717 *
10718 * Compile an Additive expression.
10719 */
10720
10721 static void
10722 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10723
10724 xmlXPathCompMultiplicativeExpr(ctxt);
10725 CHECK_ERROR;
10726 SKIP_BLANKS;
10727 while ((CUR == '+') || (CUR == '-')) {
10728 int plus;
10729 int op1 = ctxt->comp->last;
10730
10731 if (CUR == '+') plus = 1;
10732 else plus = 0;
10733 NEXT;
10734 SKIP_BLANKS;
10735 xmlXPathCompMultiplicativeExpr(ctxt);
10736 CHECK_ERROR;
10737 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10738 SKIP_BLANKS;
10739 }
10740 }
10741
10742 /**
10743 * xmlXPathCompRelationalExpr:
10744 * @ctxt: the XPath Parser context
10745 *
10746 * [24] RelationalExpr ::= AdditiveExpr
10747 * | RelationalExpr '<' AdditiveExpr
10748 * | RelationalExpr '>' AdditiveExpr
10749 * | RelationalExpr '<=' AdditiveExpr
10750 * | RelationalExpr '>=' AdditiveExpr
10751 *
10752 * A <= B > C is allowed ? Answer from James, yes with
10753 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10754 * which is basically what got implemented.
10755 *
10756 * Compile a Relational expression, then push the result
10757 * on the stack
10758 */
10759
10760 static void
10761 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10762 xmlXPathCompAdditiveExpr(ctxt);
10763 CHECK_ERROR;
10764 SKIP_BLANKS;
10765 while ((CUR == '<') ||
10766 (CUR == '>') ||
10767 ((CUR == '<') && (NXT(1) == '=')) ||
10768 ((CUR == '>') && (NXT(1) == '='))) {
10769 int inf, strict;
10770 int op1 = ctxt->comp->last;
10771
10772 if (CUR == '<') inf = 1;
10773 else inf = 0;
10774 if (NXT(1) == '=') strict = 0;
10775 else strict = 1;
10776 NEXT;
10777 if (!strict) NEXT;
10778 SKIP_BLANKS;
10779 xmlXPathCompAdditiveExpr(ctxt);
10780 CHECK_ERROR;
10781 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10782 SKIP_BLANKS;
10783 }
10784 }
10785
10786 /**
10787 * xmlXPathCompEqualityExpr:
10788 * @ctxt: the XPath Parser context
10789 *
10790 * [23] EqualityExpr ::= RelationalExpr
10791 * | EqualityExpr '=' RelationalExpr
10792 * | EqualityExpr '!=' RelationalExpr
10793 *
10794 * A != B != C is allowed ? Answer from James, yes with
10795 * (RelationalExpr = RelationalExpr) = RelationalExpr
10796 * (RelationalExpr != RelationalExpr) != RelationalExpr
10797 * which is basically what got implemented.
10798 *
10799 * Compile an Equality expression.
10800 *
10801 */
10802 static void
10803 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10804 xmlXPathCompRelationalExpr(ctxt);
10805 CHECK_ERROR;
10806 SKIP_BLANKS;
10807 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10808 int eq;
10809 int op1 = ctxt->comp->last;
10810
10811 if (CUR == '=') eq = 1;
10812 else eq = 0;
10813 NEXT;
10814 if (!eq) NEXT;
10815 SKIP_BLANKS;
10816 xmlXPathCompRelationalExpr(ctxt);
10817 CHECK_ERROR;
10818 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10819 SKIP_BLANKS;
10820 }
10821 }
10822
10823 /**
10824 * xmlXPathCompAndExpr:
10825 * @ctxt: the XPath Parser context
10826 *
10827 * [22] AndExpr ::= EqualityExpr
10828 * | AndExpr 'and' EqualityExpr
10829 *
10830 * Compile an AND expression.
10831 *
10832 */
10833 static void
10834 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10835 xmlXPathCompEqualityExpr(ctxt);
10836 CHECK_ERROR;
10837 SKIP_BLANKS;
10838 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10839 int op1 = ctxt->comp->last;
10840 SKIP(3);
10841 SKIP_BLANKS;
10842 xmlXPathCompEqualityExpr(ctxt);
10843 CHECK_ERROR;
10844 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10845 SKIP_BLANKS;
10846 }
10847 }
10848
10849 /**
10850 * xmlXPathCompileExpr:
10851 * @ctxt: the XPath Parser context
10852 *
10853 * [14] Expr ::= OrExpr
10854 * [21] OrExpr ::= AndExpr
10855 * | OrExpr 'or' AndExpr
10856 *
10857 * Parse and compile an expression
10858 */
10859 static void
10860 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10861 xmlXPathCompAndExpr(ctxt);
10862 CHECK_ERROR;
10863 SKIP_BLANKS;
10864 while ((CUR == 'o') && (NXT(1) == 'r')) {
10865 int op1 = ctxt->comp->last;
10866 SKIP(2);
10867 SKIP_BLANKS;
10868 xmlXPathCompAndExpr(ctxt);
10869 CHECK_ERROR;
10870 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10871 SKIP_BLANKS;
10872 }
10873 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10874 /* more ops could be optimized too */
10875 /*
10876 * This is the main place to eliminate sorting for
10877 * operations which don't require a sorted node-set.
10878 * E.g. count().
10879 */
10880 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10881 }
10882 }
10883
10884 /**
10885 * xmlXPathCompPredicate:
10886 * @ctxt: the XPath Parser context
10887 * @filter: act as a filter
10888 *
10889 * [8] Predicate ::= '[' PredicateExpr ']'
10890 * [9] PredicateExpr ::= Expr
10891 *
10892 * Compile a predicate expression
10893 */
10894 static void
10895 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10896 int op1 = ctxt->comp->last;
10897
10898 SKIP_BLANKS;
10899 if (CUR != '[') {
10900 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10901 }
10902 NEXT;
10903 SKIP_BLANKS;
10904
10905 ctxt->comp->last = -1;
10906 /*
10907 * This call to xmlXPathCompileExpr() will deactivate sorting
10908 * of the predicate result.
10909 * TODO: Sorting is still activated for filters, since I'm not
10910 * sure if needed. Normally sorting should not be needed, since
10911 * a filter can only diminish the number of items in a sequence,
10912 * but won't change its order; so if the initial sequence is sorted,
10913 * subsequent sorting is not needed.
10914 */
10915 if (! filter)
10916 xmlXPathCompileExpr(ctxt, 0);
10917 else
10918 xmlXPathCompileExpr(ctxt, 1);
10919 CHECK_ERROR;
10920
10921 if (CUR != ']') {
10922 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10923 }
10924
10925 if (filter)
10926 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10927 else
10928 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
10929
10930 NEXT;
10931 SKIP_BLANKS;
10932 }
10933
10934 /**
10935 * xmlXPathCompNodeTest:
10936 * @ctxt: the XPath Parser context
10937 * @test: pointer to a xmlXPathTestVal
10938 * @type: pointer to a xmlXPathTypeVal
10939 * @prefix: placeholder for a possible name prefix
10940 *
10941 * [7] NodeTest ::= NameTest
10942 * | NodeType '(' ')'
10943 * | 'processing-instruction' '(' Literal ')'
10944 *
10945 * [37] NameTest ::= '*'
10946 * | NCName ':' '*'
10947 * | QName
10948 * [38] NodeType ::= 'comment'
10949 * | 'text'
10950 * | 'processing-instruction'
10951 * | 'node'
10952 *
10953 * Returns the name found and updates @test, @type and @prefix appropriately
10954 */
10955 static xmlChar *
10956 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10957 xmlXPathTypeVal *type, const xmlChar **prefix,
10958 xmlChar *name) {
10959 int blanks;
10960
10961 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10962 STRANGE;
10963 return(NULL);
10964 }
10965 *type = (xmlXPathTypeVal) 0;
10966 *test = (xmlXPathTestVal) 0;
10967 *prefix = NULL;
10968 SKIP_BLANKS;
10969
10970 if ((name == NULL) && (CUR == '*')) {
10971 /*
10972 * All elements
10973 */
10974 NEXT;
10975 *test = NODE_TEST_ALL;
10976 return(NULL);
10977 }
10978
10979 if (name == NULL)
10980 name = xmlXPathParseNCName(ctxt);
10981 if (name == NULL) {
10982 XP_ERRORNULL(XPATH_EXPR_ERROR);
10983 }
10984
10985 blanks = IS_BLANK_CH(CUR);
10986 SKIP_BLANKS;
10987 if (CUR == '(') {
10988 NEXT;
10989 /*
10990 * NodeType or PI search
10991 */
10992 if (xmlStrEqual(name, BAD_CAST "comment"))
10993 *type = NODE_TYPE_COMMENT;
10994 else if (xmlStrEqual(name, BAD_CAST "node"))
10995 *type = NODE_TYPE_NODE;
10996 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10997 *type = NODE_TYPE_PI;
10998 else if (xmlStrEqual(name, BAD_CAST "text"))
10999 *type = NODE_TYPE_TEXT;
11000 else {
11001 if (name != NULL)
11002 xmlFree(name);
11003 XP_ERRORNULL(XPATH_EXPR_ERROR);
11004 }
11005
11006 *test = NODE_TEST_TYPE;
11007
11008 SKIP_BLANKS;
11009 if (*type == NODE_TYPE_PI) {
11010 /*
11011 * Specific case: search a PI by name.
11012 */
11013 if (name != NULL)
11014 xmlFree(name);
11015 name = NULL;
11016 if (CUR != ')') {
11017 name = xmlXPathParseLiteral(ctxt);
11018 CHECK_ERROR NULL;
11019 *test = NODE_TEST_PI;
11020 SKIP_BLANKS;
11021 }
11022 }
11023 if (CUR != ')') {
11024 if (name != NULL)
11025 xmlFree(name);
11026 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11027 }
11028 NEXT;
11029 return(name);
11030 }
11031 *test = NODE_TEST_NAME;
11032 if ((!blanks) && (CUR == ':')) {
11033 NEXT;
11034
11035 /*
11036 * Since currently the parser context don't have a
11037 * namespace list associated:
11038 * The namespace name for this prefix can be computed
11039 * only at evaluation time. The compilation is done
11040 * outside of any context.
11041 */
11042 #if 0
11043 *prefix = xmlXPathNsLookup(ctxt->context, name);
11044 if (name != NULL)
11045 xmlFree(name);
11046 if (*prefix == NULL) {
11047 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11048 }
11049 #else
11050 *prefix = name;
11051 #endif
11052
11053 if (CUR == '*') {
11054 /*
11055 * All elements
11056 */
11057 NEXT;
11058 *test = NODE_TEST_ALL;
11059 return(NULL);
11060 }
11061
11062 name = xmlXPathParseNCName(ctxt);
11063 if (name == NULL) {
11064 XP_ERRORNULL(XPATH_EXPR_ERROR);
11065 }
11066 }
11067 return(name);
11068 }
11069
11070 /**
11071 * xmlXPathIsAxisName:
11072 * @name: a preparsed name token
11073 *
11074 * [6] AxisName ::= 'ancestor'
11075 * | 'ancestor-or-self'
11076 * | 'attribute'
11077 * | 'child'
11078 * | 'descendant'
11079 * | 'descendant-or-self'
11080 * | 'following'
11081 * | 'following-sibling'
11082 * | 'namespace'
11083 * | 'parent'
11084 * | 'preceding'
11085 * | 'preceding-sibling'
11086 * | 'self'
11087 *
11088 * Returns the axis or 0
11089 */
11090 static xmlXPathAxisVal
11091 xmlXPathIsAxisName(const xmlChar *name) {
11092 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11093 switch (name[0]) {
11094 case 'a':
11095 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11096 ret = AXIS_ANCESTOR;
11097 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11098 ret = AXIS_ANCESTOR_OR_SELF;
11099 if (xmlStrEqual(name, BAD_CAST "attribute"))
11100 ret = AXIS_ATTRIBUTE;
11101 break;
11102 case 'c':
11103 if (xmlStrEqual(name, BAD_CAST "child"))
11104 ret = AXIS_CHILD;
11105 break;
11106 case 'd':
11107 if (xmlStrEqual(name, BAD_CAST "descendant"))
11108 ret = AXIS_DESCENDANT;
11109 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11110 ret = AXIS_DESCENDANT_OR_SELF;
11111 break;
11112 case 'f':
11113 if (xmlStrEqual(name, BAD_CAST "following"))
11114 ret = AXIS_FOLLOWING;
11115 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11116 ret = AXIS_FOLLOWING_SIBLING;
11117 break;
11118 case 'n':
11119 if (xmlStrEqual(name, BAD_CAST "namespace"))
11120 ret = AXIS_NAMESPACE;
11121 break;
11122 case 'p':
11123 if (xmlStrEqual(name, BAD_CAST "parent"))
11124 ret = AXIS_PARENT;
11125 if (xmlStrEqual(name, BAD_CAST "preceding"))
11126 ret = AXIS_PRECEDING;
11127 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11128 ret = AXIS_PRECEDING_SIBLING;
11129 break;
11130 case 's':
11131 if (xmlStrEqual(name, BAD_CAST "self"))
11132 ret = AXIS_SELF;
11133 break;
11134 }
11135 return(ret);
11136 }
11137
11138 /**
11139 * xmlXPathCompStep:
11140 * @ctxt: the XPath Parser context
11141 *
11142 * [4] Step ::= AxisSpecifier NodeTest Predicate*
11143 * | AbbreviatedStep
11144 *
11145 * [12] AbbreviatedStep ::= '.' | '..'
11146 *
11147 * [5] AxisSpecifier ::= AxisName '::'
11148 * | AbbreviatedAxisSpecifier
11149 *
11150 * [13] AbbreviatedAxisSpecifier ::= '@'?
11151 *
11152 * Modified for XPtr range support as:
11153 *
11154 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11155 * | AbbreviatedStep
11156 * | 'range-to' '(' Expr ')' Predicate*
11157 *
11158 * Compile one step in a Location Path
11159 * A location step of . is short for self::node(). This is
11160 * particularly useful in conjunction with //. For example, the
11161 * location path .//para is short for
11162 * self::node()/descendant-or-self::node()/child::para
11163 * and so will select all para descendant elements of the context
11164 * node.
11165 * Similarly, a location step of .. is short for parent::node().
11166 * For example, ../title is short for parent::node()/child::title
11167 * and so will select the title children of the parent of the context
11168 * node.
11169 */
11170 static void
11171 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11172 #ifdef LIBXML_XPTR_ENABLED
11173 int rangeto = 0;
11174 int op2 = -1;
11175 #endif
11176
11177 SKIP_BLANKS;
11178 if ((CUR == '.') && (NXT(1) == '.')) {
11179 SKIP(2);
11180 SKIP_BLANKS;
11181 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11182 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11183 } else if (CUR == '.') {
11184 NEXT;
11185 SKIP_BLANKS;
11186 } else {
11187 xmlChar *name = NULL;
11188 const xmlChar *prefix = NULL;
11189 xmlXPathTestVal test = (xmlXPathTestVal) 0;
11190 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11191 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11192 int op1;
11193
11194 /*
11195 * The modification needed for XPointer change to the production
11196 */
11197 #ifdef LIBXML_XPTR_ENABLED
11198 if (ctxt->xptr) {
11199 name = xmlXPathParseNCName(ctxt);
11200 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11201 op2 = ctxt->comp->last;
11202 xmlFree(name);
11203 SKIP_BLANKS;
11204 if (CUR != '(') {
11205 XP_ERROR(XPATH_EXPR_ERROR);
11206 }
11207 NEXT;
11208 SKIP_BLANKS;
11209
11210 xmlXPathCompileExpr(ctxt, 1);
11211 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11212 CHECK_ERROR;
11213
11214 SKIP_BLANKS;
11215 if (CUR != ')') {
11216 XP_ERROR(XPATH_EXPR_ERROR);
11217 }
11218 NEXT;
11219 rangeto = 1;
11220 goto eval_predicates;
11221 }
11222 }
11223 #endif
11224 if (CUR == '*') {
11225 axis = AXIS_CHILD;
11226 } else {
11227 if (name == NULL)
11228 name = xmlXPathParseNCName(ctxt);
11229 if (name != NULL) {
11230 axis = xmlXPathIsAxisName(name);
11231 if (axis != 0) {
11232 SKIP_BLANKS;
11233 if ((CUR == ':') && (NXT(1) == ':')) {
11234 SKIP(2);
11235 xmlFree(name);
11236 name = NULL;
11237 } else {
11238 /* an element name can conflict with an axis one :-\ */
11239 axis = AXIS_CHILD;
11240 }
11241 } else {
11242 axis = AXIS_CHILD;
11243 }
11244 } else if (CUR == '@') {
11245 NEXT;
11246 axis = AXIS_ATTRIBUTE;
11247 } else {
11248 axis = AXIS_CHILD;
11249 }
11250 }
11251
11252 CHECK_ERROR;
11253
11254 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11255 if (test == 0)
11256 return;
11257
11258 if ((prefix != NULL) && (ctxt->context != NULL) &&
11259 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11260 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11261 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11262 }
11263 }
11264 #ifdef DEBUG_STEP
11265 xmlGenericError(xmlGenericErrorContext,
11266 "Basis : computing new set\n");
11267 #endif
11268
11269 #ifdef DEBUG_STEP
11270 xmlGenericError(xmlGenericErrorContext, "Basis : ");
11271 if (ctxt->value == NULL)
11272 xmlGenericError(xmlGenericErrorContext, "no value\n");
11273 else if (ctxt->value->nodesetval == NULL)
11274 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11275 else
11276 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11277 #endif
11278
11279 #ifdef LIBXML_XPTR_ENABLED
11280 eval_predicates:
11281 #endif
11282 op1 = ctxt->comp->last;
11283 ctxt->comp->last = -1;
11284
11285 SKIP_BLANKS;
11286 while (CUR == '[') {
11287 xmlXPathCompPredicate(ctxt, 0);
11288 }
11289
11290 #ifdef LIBXML_XPTR_ENABLED
11291 if (rangeto) {
11292 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11293 } else
11294 #endif
11295 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11296 test, type, (void *)prefix, (void *)name);
11297
11298 }
11299 #ifdef DEBUG_STEP
11300 xmlGenericError(xmlGenericErrorContext, "Step : ");
11301 if (ctxt->value == NULL)
11302 xmlGenericError(xmlGenericErrorContext, "no value\n");
11303 else if (ctxt->value->nodesetval == NULL)
11304 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11305 else
11306 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11307 ctxt->value->nodesetval);
11308 #endif
11309 }
11310
11311 /**
11312 * xmlXPathCompRelativeLocationPath:
11313 * @ctxt: the XPath Parser context
11314 *
11315 * [3] RelativeLocationPath ::= Step
11316 * | RelativeLocationPath '/' Step
11317 * | AbbreviatedRelativeLocationPath
11318 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
11319 *
11320 * Compile a relative location path.
11321 */
11322 static void
11323 xmlXPathCompRelativeLocationPath
11324 (xmlXPathParserContextPtr ctxt) {
11325 SKIP_BLANKS;
11326 if ((CUR == '/') && (NXT(1) == '/')) {
11327 SKIP(2);
11328 SKIP_BLANKS;
11329 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11330 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11331 } else if (CUR == '/') {
11332 NEXT;
11333 SKIP_BLANKS;
11334 }
11335 xmlXPathCompStep(ctxt);
11336 SKIP_BLANKS;
11337 while (CUR == '/') {
11338 if ((CUR == '/') && (NXT(1) == '/')) {
11339 SKIP(2);
11340 SKIP_BLANKS;
11341 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11342 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11343 xmlXPathCompStep(ctxt);
11344 } else if (CUR == '/') {
11345 NEXT;
11346 SKIP_BLANKS;
11347 xmlXPathCompStep(ctxt);
11348 }
11349 SKIP_BLANKS;
11350 }
11351 }
11352
11353 /**
11354 * xmlXPathCompLocationPath:
11355 * @ctxt: the XPath Parser context
11356 *
11357 * [1] LocationPath ::= RelativeLocationPath
11358 * | AbsoluteLocationPath
11359 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
11360 * | AbbreviatedAbsoluteLocationPath
11361 * [10] AbbreviatedAbsoluteLocationPath ::=
11362 * '//' RelativeLocationPath
11363 *
11364 * Compile a location path
11365 *
11366 * // is short for /descendant-or-self::node()/. For example,
11367 * //para is short for /descendant-or-self::node()/child::para and
11368 * so will select any para element in the document (even a para element
11369 * that is a document element will be selected by //para since the
11370 * document element node is a child of the root node); div//para is
11371 * short for div/descendant-or-self::node()/child::para and so will
11372 * select all para descendants of div children.
11373 */
11374 static void
11375 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11376 SKIP_BLANKS;
11377 if (CUR != '/') {
11378 xmlXPathCompRelativeLocationPath(ctxt);
11379 } else {
11380 while (CUR == '/') {
11381 if ((CUR == '/') && (NXT(1) == '/')) {
11382 SKIP(2);
11383 SKIP_BLANKS;
11384 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11385 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11386 xmlXPathCompRelativeLocationPath(ctxt);
11387 } else if (CUR == '/') {
11388 NEXT;
11389 SKIP_BLANKS;
11390 if ((CUR != 0 ) &&
11391 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11392 (CUR == '@') || (CUR == '*')))
11393 xmlXPathCompRelativeLocationPath(ctxt);
11394 }
11395 }
11396 }
11397 }
11398
11399 /************************************************************************
11400 * *
11401 * XPath precompiled expression evaluation *
11402 * *
11403 ************************************************************************/
11404
11405 static int
11406 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11407
11408 #ifdef DEBUG_STEP
11409 static void
11410 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11411 int nbNodes)
11412 {
11413 xmlGenericError(xmlGenericErrorContext, "new step : ");
11414 switch (op->value) {
11415 case AXIS_ANCESTOR:
11416 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11417 break;
11418 case AXIS_ANCESTOR_OR_SELF:
11419 xmlGenericError(xmlGenericErrorContext,
11420 "axis 'ancestors-or-self' ");
11421 break;
11422 case AXIS_ATTRIBUTE:
11423 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11424 break;
11425 case AXIS_CHILD:
11426 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11427 break;
11428 case AXIS_DESCENDANT:
11429 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11430 break;
11431 case AXIS_DESCENDANT_OR_SELF:
11432 xmlGenericError(xmlGenericErrorContext,
11433 "axis 'descendant-or-self' ");
11434 break;
11435 case AXIS_FOLLOWING:
11436 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11437 break;
11438 case AXIS_FOLLOWING_SIBLING:
11439 xmlGenericError(xmlGenericErrorContext,
11440 "axis 'following-siblings' ");
11441 break;
11442 case AXIS_NAMESPACE:
11443 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11444 break;
11445 case AXIS_PARENT:
11446 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11447 break;
11448 case AXIS_PRECEDING:
11449 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11450 break;
11451 case AXIS_PRECEDING_SIBLING:
11452 xmlGenericError(xmlGenericErrorContext,
11453 "axis 'preceding-sibling' ");
11454 break;
11455 case AXIS_SELF:
11456 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11457 break;
11458 }
11459 xmlGenericError(xmlGenericErrorContext,
11460 " context contains %d nodes\n", nbNodes);
11461 switch (op->value2) {
11462 case NODE_TEST_NONE:
11463 xmlGenericError(xmlGenericErrorContext,
11464 " searching for none !!!\n");
11465 break;
11466 case NODE_TEST_TYPE:
11467 xmlGenericError(xmlGenericErrorContext,
11468 " searching for type %d\n", op->value3);
11469 break;
11470 case NODE_TEST_PI:
11471 xmlGenericError(xmlGenericErrorContext,
11472 " searching for PI !!!\n");
11473 break;
11474 case NODE_TEST_ALL:
11475 xmlGenericError(xmlGenericErrorContext,
11476 " searching for *\n");
11477 break;
11478 case NODE_TEST_NS:
11479 xmlGenericError(xmlGenericErrorContext,
11480 " searching for namespace %s\n",
11481 op->value5);
11482 break;
11483 case NODE_TEST_NAME:
11484 xmlGenericError(xmlGenericErrorContext,
11485 " searching for name %s\n", op->value5);
11486 if (op->value4)
11487 xmlGenericError(xmlGenericErrorContext,
11488 " with namespace %s\n", op->value4);
11489 break;
11490 }
11491 xmlGenericError(xmlGenericErrorContext, "Testing : ");
11492 }
11493 #endif /* DEBUG_STEP */
11494
11495 static int
11496 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11497 xmlXPathStepOpPtr op,
11498 xmlNodeSetPtr set,
11499 int contextSize,
11500 int hasNsNodes)
11501 {
11502 if (op->ch1 != -1) {
11503 xmlXPathCompExprPtr comp = ctxt->comp;
11504 /*
11505 * Process inner predicates first.
11506 */
11507 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11508 /*
11509 * TODO: raise an internal error.
11510 */
11511 }
11512 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11513 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11514 CHECK_ERROR0;
11515 if (contextSize <= 0)
11516 return(0);
11517 }
11518 if (op->ch2 != -1) {
11519 xmlXPathContextPtr xpctxt = ctxt->context;
11520 xmlNodePtr contextNode, oldContextNode;
11521 xmlDocPtr oldContextDoc;
11522 int i, res, contextPos = 0, newContextSize;
11523 xmlXPathStepOpPtr exprOp;
11524 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11525
11526 #ifdef LIBXML_XPTR_ENABLED
11527 /*
11528 * URGENT TODO: Check the following:
11529 * We don't expect location sets if evaluating prediates, right?
11530 * Only filters should expect location sets, right?
11531 */
11532 #endif
11533 /*
11534 * SPEC XPath 1.0:
11535 * "For each node in the node-set to be filtered, the
11536 * PredicateExpr is evaluated with that node as the
11537 * context node, with the number of nodes in the
11538 * node-set as the context size, and with the proximity
11539 * position of the node in the node-set with respect to
11540 * the axis as the context position;"
11541 * @oldset is the node-set" to be filtered.
11542 *
11543 * SPEC XPath 1.0:
11544 * "only predicates change the context position and
11545 * context size (see [2.4 Predicates])."
11546 * Example:
11547 * node-set context pos
11548 * nA 1
11549 * nB 2
11550 * nC 3
11551 * After applying predicate [position() > 1] :
11552 * node-set context pos
11553 * nB 1
11554 * nC 2
11555 */
11556 oldContextNode = xpctxt->node;
11557 oldContextDoc = xpctxt->doc;
11558 /*
11559 * Get the expression of this predicate.
11560 */
11561 exprOp = &ctxt->comp->steps[op->ch2];
11562 newContextSize = 0;
11563 for (i = 0; i < set->nodeNr; i++) {
11564 if (set->nodeTab[i] == NULL)
11565 continue;
11566
11567 contextNode = set->nodeTab[i];
11568 xpctxt->node = contextNode;
11569 xpctxt->contextSize = contextSize;
11570 xpctxt->proximityPosition = ++contextPos;
11571
11572 /*
11573 * Also set the xpath document in case things like
11574 * key() are evaluated in the predicate.
11575 */
11576 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11577 (contextNode->doc != NULL))
11578 xpctxt->doc = contextNode->doc;
11579 /*
11580 * Evaluate the predicate expression with 1 context node
11581 * at a time; this node is packaged into a node set; this
11582 * node set is handed over to the evaluation mechanism.
11583 */
11584 if (contextObj == NULL)
11585 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11586 else
11587 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11588 contextNode);
11589
11590 valuePush(ctxt, contextObj);
11591
11592 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11593
11594 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11595 xmlXPathNodeSetClear(set, hasNsNodes);
11596 newContextSize = 0;
11597 goto evaluation_exit;
11598 }
11599
11600 if (res != 0) {
11601 newContextSize++;
11602 } else {
11603 /*
11604 * Remove the entry from the initial node set.
11605 */
11606 set->nodeTab[i] = NULL;
11607 if (contextNode->type == XML_NAMESPACE_DECL)
11608 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11609 }
11610 if (ctxt->value == contextObj) {
11611 /*
11612 * Don't free the temporary XPath object holding the
11613 * context node, in order to avoid massive recreation
11614 * inside this loop.
11615 */
11616 valuePop(ctxt);
11617 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11618 } else {
11619 /*
11620 * TODO: The object was lost in the evaluation machinery.
11621 * Can this happen? Maybe in internal-error cases.
11622 */
11623 contextObj = NULL;
11624 }
11625 }
11626
11627 if (contextObj != NULL) {
11628 if (ctxt->value == contextObj)
11629 valuePop(ctxt);
11630 xmlXPathReleaseObject(xpctxt, contextObj);
11631 }
11632 evaluation_exit:
11633 if (exprRes != NULL)
11634 xmlXPathReleaseObject(ctxt->context, exprRes);
11635 /*
11636 * Reset/invalidate the context.
11637 */
11638 xpctxt->node = oldContextNode;
11639 xpctxt->doc = oldContextDoc;
11640 xpctxt->contextSize = -1;
11641 xpctxt->proximityPosition = -1;
11642 return(newContextSize);
11643 }
11644 return(contextSize);
11645 }
11646
11647 static int
11648 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11649 xmlXPathStepOpPtr op,
11650 xmlNodeSetPtr set,
11651 int contextSize,
11652 int minPos,
11653 int maxPos,
11654 int hasNsNodes)
11655 {
11656 if (op->ch1 != -1) {
11657 xmlXPathCompExprPtr comp = ctxt->comp;
11658 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11659 /*
11660 * TODO: raise an internal error.
11661 */
11662 }
11663 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11664 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11665 CHECK_ERROR0;
11666 if (contextSize <= 0)
11667 return(0);
11668 }
11669 /*
11670 * Check if the node set contains a sufficient number of nodes for
11671 * the requested range.
11672 */
11673 if (contextSize < minPos) {
11674 xmlXPathNodeSetClear(set, hasNsNodes);
11675 return(0);
11676 }
11677 if (op->ch2 == -1) {
11678 /*
11679 * TODO: Can this ever happen?
11680 */
11681 return (contextSize);
11682 } else {
11683 xmlDocPtr oldContextDoc;
11684 int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11685 xmlXPathStepOpPtr exprOp;
11686 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11687 xmlNodePtr oldContextNode, contextNode = NULL;
11688 xmlXPathContextPtr xpctxt = ctxt->context;
11689
11690 #ifdef LIBXML_XPTR_ENABLED
11691 /*
11692 * URGENT TODO: Check the following:
11693 * We don't expect location sets if evaluating prediates, right?
11694 * Only filters should expect location sets, right?
11695 */
11696 #endif /* LIBXML_XPTR_ENABLED */
11697
11698 /*
11699 * Save old context.
11700 */
11701 oldContextNode = xpctxt->node;
11702 oldContextDoc = xpctxt->doc;
11703 /*
11704 * Get the expression of this predicate.
11705 */
11706 exprOp = &ctxt->comp->steps[op->ch2];
11707 for (i = 0; i < set->nodeNr; i++) {
11708 if (set->nodeTab[i] == NULL)
11709 continue;
11710
11711 contextNode = set->nodeTab[i];
11712 xpctxt->node = contextNode;
11713 xpctxt->contextSize = contextSize;
11714 xpctxt->proximityPosition = ++contextPos;
11715
11716 /*
11717 * Initialize the new set.
11718 * Also set the xpath document in case things like
11719 * key() evaluation are attempted on 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 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11733 contextNode);
11734
11735 valuePush(ctxt, contextObj);
11736 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11737
11738 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11739 xmlXPathObjectPtr tmp;
11740 /* pop the result */
11741 tmp = valuePop(ctxt);
11742 xmlXPathReleaseObject(xpctxt, tmp);
11743 /* then pop off contextObj, which will be freed later */
11744 valuePop(ctxt);
11745 goto evaluation_error;
11746 }
11747
11748 if (res)
11749 pos++;
11750
11751 if (res && (pos >= minPos) && (pos <= maxPos)) {
11752 /*
11753 * Fits in the requested range.
11754 */
11755 newContextSize++;
11756 if (minPos == maxPos) {
11757 /*
11758 * Only 1 node was requested.
11759 */
11760 if (contextNode->type == XML_NAMESPACE_DECL) {
11761 /*
11762 * As always: take care of those nasty
11763 * namespace nodes.
11764 */
11765 set->nodeTab[i] = NULL;
11766 }
11767 xmlXPathNodeSetClear(set, hasNsNodes);
11768 set->nodeNr = 1;
11769 set->nodeTab[0] = contextNode;
11770 goto evaluation_exit;
11771 }
11772 if (pos == maxPos) {
11773 /*
11774 * We are done.
11775 */
11776 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11777 goto evaluation_exit;
11778 }
11779 } else {
11780 /*
11781 * Remove the entry from the initial node set.
11782 */
11783 set->nodeTab[i] = NULL;
11784 if (contextNode->type == XML_NAMESPACE_DECL)
11785 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11786 }
11787 if (exprRes != NULL) {
11788 xmlXPathReleaseObject(ctxt->context, exprRes);
11789 exprRes = NULL;
11790 }
11791 if (ctxt->value == contextObj) {
11792 /*
11793 * Don't free the temporary XPath object holding the
11794 * context node, in order to avoid massive recreation
11795 * inside this loop.
11796 */
11797 valuePop(ctxt);
11798 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11799 } else {
11800 /*
11801 * The object was lost in the evaluation machinery.
11802 * Can this happen? Maybe in case of internal-errors.
11803 */
11804 contextObj = NULL;
11805 }
11806 }
11807 goto evaluation_exit;
11808
11809 evaluation_error:
11810 xmlXPathNodeSetClear(set, hasNsNodes);
11811 newContextSize = 0;
11812
11813 evaluation_exit:
11814 if (contextObj != NULL) {
11815 if (ctxt->value == contextObj)
11816 valuePop(ctxt);
11817 xmlXPathReleaseObject(xpctxt, contextObj);
11818 }
11819 if (exprRes != NULL)
11820 xmlXPathReleaseObject(ctxt->context, exprRes);
11821 /*
11822 * Reset/invalidate the context.
11823 */
11824 xpctxt->node = oldContextNode;
11825 xpctxt->doc = oldContextDoc;
11826 xpctxt->contextSize = -1;
11827 xpctxt->proximityPosition = -1;
11828 return(newContextSize);
11829 }
11830 return(contextSize);
11831 }
11832
11833 static int
11834 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11835 xmlXPathStepOpPtr op,
11836 int *maxPos)
11837 {
11838
11839 xmlXPathStepOpPtr exprOp;
11840
11841 /*
11842 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11843 */
11844
11845 /*
11846 * If not -1, then ch1 will point to:
11847 * 1) For predicates (XPATH_OP_PREDICATE):
11848 * - an inner predicate operator
11849 * 2) For filters (XPATH_OP_FILTER):
11850 * - an inner filter operater OR
11851 * - an expression selecting the node set.
11852 * E.g. "key('a', 'b')" or "(//foo | //bar)".
11853 */
11854 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11855 return(0);
11856
11857 if (op->ch2 != -1) {
11858 exprOp = &ctxt->comp->steps[op->ch2];
11859 } else
11860 return(0);
11861
11862 if ((exprOp != NULL) &&
11863 (exprOp->op == XPATH_OP_VALUE) &&
11864 (exprOp->value4 != NULL) &&
11865 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11866 {
11867 /*
11868 * We have a "[n]" predicate here.
11869 * TODO: Unfortunately this simplistic test here is not
11870 * able to detect a position() predicate in compound
11871 * expressions like "[@attr = 'a" and position() = 1],
11872 * and even not the usage of position() in
11873 * "[position() = 1]"; thus - obviously - a position-range,
11874 * like it "[position() < 5]", is also not detected.
11875 * Maybe we could rewrite the AST to ease the optimization.
11876 */
11877 *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11878
11879 if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
11880 (float) *maxPos)
11881 {
11882 return(1);
11883 }
11884 }
11885 return(0);
11886 }
11887
11888 static int
11889 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11890 xmlXPathStepOpPtr op,
11891 xmlNodePtr * first, xmlNodePtr * last,
11892 int toBool)
11893 {
11894
11895 #define XP_TEST_HIT \
11896 if (hasAxisRange != 0) { \
11897 if (++pos == maxPos) { \
11898 addNode(seq, cur); \
11899 goto axis_range_end; } \
11900 } else { \
11901 addNode(seq, cur); \
11902 if (breakOnFirstHit) goto first_hit; }
11903
11904 #define XP_TEST_HIT_NS \
11905 if (hasAxisRange != 0) { \
11906 if (++pos == maxPos) { \
11907 hasNsNodes = 1; \
11908 xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
11909 goto axis_range_end; } \
11910 } else { \
11911 hasNsNodes = 1; \
11912 xmlXPathNodeSetAddNs(seq, \
11913 xpctxt->node, (xmlNsPtr) cur); \
11914 if (breakOnFirstHit) goto first_hit; }
11915
11916 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11917 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11918 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11919 const xmlChar *prefix = op->value4;
11920 const xmlChar *name = op->value5;
11921 const xmlChar *URI = NULL;
11922
11923 #ifdef DEBUG_STEP
11924 int nbMatches = 0, prevMatches = 0;
11925 #endif
11926 int total = 0, hasNsNodes = 0;
11927 /* The popped object holding the context nodes */
11928 xmlXPathObjectPtr obj;
11929 /* The set of context nodes for the node tests */
11930 xmlNodeSetPtr contextSeq;
11931 int contextIdx;
11932 xmlNodePtr contextNode;
11933 /* The context node for a compound traversal */
11934 xmlNodePtr outerContextNode;
11935 /* The final resulting node set wrt to all context nodes */
11936 xmlNodeSetPtr outSeq;
11937 /*
11938 * The temporary resulting node set wrt 1 context node.
11939 * Used to feed predicate evaluation.
11940 */
11941 xmlNodeSetPtr seq;
11942 xmlNodePtr cur;
11943 /* First predicate operator */
11944 xmlXPathStepOpPtr predOp;
11945 int maxPos; /* The requested position() (when a "[n]" predicate) */
11946 int hasPredicateRange, hasAxisRange, pos, size, newSize;
11947 int breakOnFirstHit;
11948
11949 xmlXPathTraversalFunction next = NULL;
11950 /* compound axis traversal */
11951 xmlXPathTraversalFunctionExt outerNext = NULL;
11952 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
11953 xmlXPathNodeSetMergeFunction mergeAndClear;
11954 xmlNodePtr oldContextNode;
11955 xmlXPathContextPtr xpctxt = ctxt->context;
11956
11957
11958 CHECK_TYPE0(XPATH_NODESET);
11959 obj = valuePop(ctxt);
11960 /*
11961 * Setup namespaces.
11962 */
11963 if (prefix != NULL) {
11964 URI = xmlXPathNsLookup(xpctxt, prefix);
11965 if (URI == NULL) {
11966 xmlXPathReleaseObject(xpctxt, obj);
11967 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11968 }
11969 }
11970 /*
11971 * Setup axis.
11972 *
11973 * MAYBE FUTURE TODO: merging optimizations:
11974 * - If the nodes to be traversed wrt to the initial nodes and
11975 * the current axis cannot overlap, then we could avoid searching
11976 * for duplicates during the merge.
11977 * But the question is how/when to evaluate if they cannot overlap.
11978 * Example: if we know that for two initial nodes, the one is
11979 * not in the ancestor-or-self axis of the other, then we could safely
11980 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
11981 * the descendant-or-self axis.
11982 */
11983 mergeAndClear = xmlXPathNodeSetMergeAndClear;
11984 switch (axis) {
11985 case AXIS_ANCESTOR:
11986 first = NULL;
11987 next = xmlXPathNextAncestor;
11988 break;
11989 case AXIS_ANCESTOR_OR_SELF:
11990 first = NULL;
11991 next = xmlXPathNextAncestorOrSelf;
11992 break;
11993 case AXIS_ATTRIBUTE:
11994 first = NULL;
11995 last = NULL;
11996 next = xmlXPathNextAttribute;
11997 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11998 break;
11999 case AXIS_CHILD:
12000 last = NULL;
12001 if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
12002 /*
12003 * This iterator will give us only nodes which can
12004 * hold element nodes.
12005 */
12006 outerNext = xmlXPathNextDescendantOrSelfElemParent;
12007 }
12008 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12009 (type == NODE_TYPE_NODE))
12010 {
12011 /*
12012 * Optimization if an element node type is 'element'.
12013 */
12014 next = xmlXPathNextChildElement;
12015 } else
12016 next = xmlXPathNextChild;
12017 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12018 break;
12019 case AXIS_DESCENDANT:
12020 last = NULL;
12021 next = xmlXPathNextDescendant;
12022 break;
12023 case AXIS_DESCENDANT_OR_SELF:
12024 last = NULL;
12025 next = xmlXPathNextDescendantOrSelf;
12026 break;
12027 case AXIS_FOLLOWING:
12028 last = NULL;
12029 next = xmlXPathNextFollowing;
12030 break;
12031 case AXIS_FOLLOWING_SIBLING:
12032 last = NULL;
12033 next = xmlXPathNextFollowingSibling;
12034 break;
12035 case AXIS_NAMESPACE:
12036 first = NULL;
12037 last = NULL;
12038 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12039 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12040 break;
12041 case AXIS_PARENT:
12042 first = NULL;
12043 next = xmlXPathNextParent;
12044 break;
12045 case AXIS_PRECEDING:
12046 first = NULL;
12047 next = xmlXPathNextPrecedingInternal;
12048 break;
12049 case AXIS_PRECEDING_SIBLING:
12050 first = NULL;
12051 next = xmlXPathNextPrecedingSibling;
12052 break;
12053 case AXIS_SELF:
12054 first = NULL;
12055 last = NULL;
12056 next = xmlXPathNextSelf;
12057 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12058 break;
12059 }
12060
12061 #ifdef DEBUG_STEP
12062 xmlXPathDebugDumpStepAxis(op,
12063 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12064 #endif
12065
12066 if (next == NULL) {
12067 xmlXPathReleaseObject(xpctxt, obj);
12068 return(0);
12069 }
12070 contextSeq = obj->nodesetval;
12071 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12072 xmlXPathReleaseObject(xpctxt, obj);
12073 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12074 return(0);
12075 }
12076 /*
12077 * Predicate optimization ---------------------------------------------
12078 * If this step has a last predicate, which contains a position(),
12079 * then we'll optimize (although not exactly "position()", but only
12080 * the short-hand form, i.e., "[n]".
12081 *
12082 * Example - expression "/foo[parent::bar][1]":
12083 *
12084 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12085 * ROOT -- op->ch1
12086 * PREDICATE -- op->ch2 (predOp)
12087 * PREDICATE -- predOp->ch1 = [parent::bar]
12088 * SORT
12089 * COLLECT 'parent' 'name' 'node' bar
12090 * NODE
12091 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12092 *
12093 */
12094 maxPos = 0;
12095 predOp = NULL;
12096 hasPredicateRange = 0;
12097 hasAxisRange = 0;
12098 if (op->ch2 != -1) {
12099 /*
12100 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12101 */
12102 predOp = &ctxt->comp->steps[op->ch2];
12103 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12104 if (predOp->ch1 != -1) {
12105 /*
12106 * Use the next inner predicate operator.
12107 */
12108 predOp = &ctxt->comp->steps[predOp->ch1];
12109 hasPredicateRange = 1;
12110 } else {
12111 /*
12112 * There's no other predicate than the [n] predicate.
12113 */
12114 predOp = NULL;
12115 hasAxisRange = 1;
12116 }
12117 }
12118 }
12119 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12120 /*
12121 * Axis traversal -----------------------------------------------------
12122 */
12123 /*
12124 * 2.3 Node Tests
12125 * - For the attribute axis, the principal node type is attribute.
12126 * - For the namespace axis, the principal node type is namespace.
12127 * - For other axes, the principal node type is element.
12128 *
12129 * A node test * is true for any node of the
12130 * principal node type. For example, child::* will
12131 * select all element children of the context node
12132 */
12133 oldContextNode = xpctxt->node;
12134 addNode = xmlXPathNodeSetAddUnique;
12135 outSeq = NULL;
12136 seq = NULL;
12137 outerContextNode = NULL;
12138 contextNode = NULL;
12139 contextIdx = 0;
12140
12141
12142 while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
12143 if (outerNext != NULL) {
12144 /*
12145 * This is a compound traversal.
12146 */
12147 if (contextNode == NULL) {
12148 /*
12149 * Set the context for the outer traversal.
12150 */
12151 outerContextNode = contextSeq->nodeTab[contextIdx++];
12152 contextNode = outerNext(NULL, outerContextNode);
12153 } else
12154 contextNode = outerNext(contextNode, outerContextNode);
12155 if (contextNode == NULL)
12156 continue;
12157 /*
12158 * Set the context for the main traversal.
12159 */
12160 xpctxt->node = contextNode;
12161 } else
12162 xpctxt->node = contextSeq->nodeTab[contextIdx++];
12163
12164 if (seq == NULL) {
12165 seq = xmlXPathNodeSetCreate(NULL);
12166 if (seq == NULL) {
12167 total = 0;
12168 goto error;
12169 }
12170 }
12171 /*
12172 * Traverse the axis and test the nodes.
12173 */
12174 pos = 0;
12175 cur = NULL;
12176 hasNsNodes = 0;
12177 do {
12178 cur = next(ctxt, cur);
12179 if (cur == NULL)
12180 break;
12181
12182 /*
12183 * QUESTION TODO: What does the "first" and "last" stuff do?
12184 */
12185 if ((first != NULL) && (*first != NULL)) {
12186 if (*first == cur)
12187 break;
12188 if (((total % 256) == 0) &&
12189 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12190 (xmlXPathCmpNodesExt(*first, cur) >= 0))
12191 #else
12192 (xmlXPathCmpNodes(*first, cur) >= 0))
12193 #endif
12194 {
12195 break;
12196 }
12197 }
12198 if ((last != NULL) && (*last != NULL)) {
12199 if (*last == cur)
12200 break;
12201 if (((total % 256) == 0) &&
12202 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12203 (xmlXPathCmpNodesExt(cur, *last) >= 0))
12204 #else
12205 (xmlXPathCmpNodes(cur, *last) >= 0))
12206 #endif
12207 {
12208 break;
12209 }
12210 }
12211
12212 total++;
12213
12214 #ifdef DEBUG_STEP
12215 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12216 #endif
12217
12218 switch (test) {
12219 case NODE_TEST_NONE:
12220 total = 0;
12221 STRANGE
12222 goto error;
12223 case NODE_TEST_TYPE:
12224 /*
12225 * TODO: Don't we need to use
12226 * xmlXPathNodeSetAddNs() for namespace nodes here?
12227 * Surprisingly, some c14n tests fail, if we do this.
12228 */
12229 if (type == NODE_TYPE_NODE) {
12230 switch (cur->type) {
12231 case XML_DOCUMENT_NODE:
12232 case XML_HTML_DOCUMENT_NODE:
12233 #ifdef LIBXML_DOCB_ENABLED
12234 case XML_DOCB_DOCUMENT_NODE:
12235 #endif
12236 case XML_ELEMENT_NODE:
12237 case XML_ATTRIBUTE_NODE:
12238 case XML_PI_NODE:
12239 case XML_COMMENT_NODE:
12240 case XML_CDATA_SECTION_NODE:
12241 case XML_TEXT_NODE:
12242 case XML_NAMESPACE_DECL:
12243 XP_TEST_HIT
12244 break;
12245 default:
12246 break;
12247 }
12248 } else if (cur->type == type) {
12249 if (type == XML_NAMESPACE_DECL)
12250 XP_TEST_HIT_NS
12251 else
12252 XP_TEST_HIT
12253 } else if ((type == NODE_TYPE_TEXT) &&
12254 (cur->type == XML_CDATA_SECTION_NODE))
12255 {
12256 XP_TEST_HIT
12257 }
12258 break;
12259 case NODE_TEST_PI:
12260 if ((cur->type == XML_PI_NODE) &&
12261 ((name == NULL) || xmlStrEqual(name, cur->name)))
12262 {
12263 XP_TEST_HIT
12264 }
12265 break;
12266 case NODE_TEST_ALL:
12267 if (axis == AXIS_ATTRIBUTE) {
12268 if (cur->type == XML_ATTRIBUTE_NODE)
12269 {
12270 XP_TEST_HIT
12271 }
12272 } else if (axis == AXIS_NAMESPACE) {
12273 if (cur->type == XML_NAMESPACE_DECL)
12274 {
12275 XP_TEST_HIT_NS
12276 }
12277 } else {
12278 if (cur->type == XML_ELEMENT_NODE) {
12279 if (prefix == NULL)
12280 {
12281 XP_TEST_HIT
12282
12283 } else if ((cur->ns != NULL) &&
12284 (xmlStrEqual(URI, cur->ns->href)))
12285 {
12286 XP_TEST_HIT
12287 }
12288 }
12289 }
12290 break;
12291 case NODE_TEST_NS:{
12292 TODO;
12293 break;
12294 }
12295 case NODE_TEST_NAME:
12296 if (axis == AXIS_ATTRIBUTE) {
12297 if (cur->type != XML_ATTRIBUTE_NODE)
12298 break;
12299 } else if (axis == AXIS_NAMESPACE) {
12300 if (cur->type != XML_NAMESPACE_DECL)
12301 break;
12302 } else {
12303 if (cur->type != XML_ELEMENT_NODE)
12304 break;
12305 }
12306 switch (cur->type) {
12307 case XML_ELEMENT_NODE:
12308 if (xmlStrEqual(name, cur->name)) {
12309 if (prefix == NULL) {
12310 if (cur->ns == NULL)
12311 {
12312 XP_TEST_HIT
12313 }
12314 } else {
12315 if ((cur->ns != NULL) &&
12316 (xmlStrEqual(URI, cur->ns->href)))
12317 {
12318 XP_TEST_HIT
12319 }
12320 }
12321 }
12322 break;
12323 case XML_ATTRIBUTE_NODE:{
12324 xmlAttrPtr attr = (xmlAttrPtr) cur;
12325
12326 if (xmlStrEqual(name, attr->name)) {
12327 if (prefix == NULL) {
12328 if ((attr->ns == NULL) ||
12329 (attr->ns->prefix == NULL))
12330 {
12331 XP_TEST_HIT
12332 }
12333 } else {
12334 if ((attr->ns != NULL) &&
12335 (xmlStrEqual(URI,
12336 attr->ns->href)))
12337 {
12338 XP_TEST_HIT
12339 }
12340 }
12341 }
12342 break;
12343 }
12344 case XML_NAMESPACE_DECL:
12345 if (cur->type == XML_NAMESPACE_DECL) {
12346 xmlNsPtr ns = (xmlNsPtr) cur;
12347
12348 if ((ns->prefix != NULL) && (name != NULL)
12349 && (xmlStrEqual(ns->prefix, name)))
12350 {
12351 XP_TEST_HIT_NS
12352 }
12353 }
12354 break;
12355 default:
12356 break;
12357 }
12358 break;
12359 } /* switch(test) */
12360 } while (cur != NULL);
12361
12362 goto apply_predicates;
12363
12364 axis_range_end: /* ----------------------------------------------------- */
12365 /*
12366 * We have a "/foo[n]", and position() = n was reached.
12367 * Note that we can have as well "/foo/::parent::foo[1]", so
12368 * a duplicate-aware merge is still needed.
12369 * Merge with the result.
12370 */
12371 if (outSeq == NULL) {
12372 outSeq = seq;
12373 seq = NULL;
12374 } else
12375 outSeq = mergeAndClear(outSeq, seq, 0);
12376 /*
12377 * Break if only a true/false result was requested.
12378 */
12379 if (toBool)
12380 break;
12381 continue;
12382
12383 first_hit: /* ---------------------------------------------------------- */
12384 /*
12385 * Break if only a true/false result was requested and
12386 * no predicates existed and a node test succeeded.
12387 */
12388 if (outSeq == NULL) {
12389 outSeq = seq;
12390 seq = NULL;
12391 } else
12392 outSeq = mergeAndClear(outSeq, seq, 0);
12393 break;
12394
12395 #ifdef DEBUG_STEP
12396 if (seq != NULL)
12397 nbMatches += seq->nodeNr;
12398 #endif
12399
12400 apply_predicates: /* --------------------------------------------------- */
12401 /*
12402 * Apply predicates.
12403 */
12404 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12405 /*
12406 * E.g. when we have a "/foo[some expression][n]".
12407 */
12408 /*
12409 * QUESTION TODO: The old predicate evaluation took into
12410 * account location-sets.
12411 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12412 * Do we expect such a set here?
12413 * All what I learned now from the evaluation semantics
12414 * does not indicate that a location-set will be processed
12415 * here, so this looks OK.
12416 */
12417 /*
12418 * Iterate over all predicates, starting with the outermost
12419 * predicate.
12420 * TODO: Problem: we cannot execute the inner predicates first
12421 * since we cannot go back *up* the operator tree!
12422 * Options we have:
12423 * 1) Use of recursive functions (like is it currently done
12424 * via xmlXPathCompOpEval())
12425 * 2) Add a predicate evaluation information stack to the
12426 * context struct
12427 * 3) Change the way the operators are linked; we need a
12428 * "parent" field on xmlXPathStepOp
12429 *
12430 * For the moment, I'll try to solve this with a recursive
12431 * function: xmlXPathCompOpEvalPredicate().
12432 */
12433 size = seq->nodeNr;
12434 if (hasPredicateRange != 0)
12435 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12436 predOp, seq, size, maxPos, maxPos, hasNsNodes);
12437 else
12438 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12439 predOp, seq, size, hasNsNodes);
12440
12441 if (ctxt->error != XPATH_EXPRESSION_OK) {
12442 total = 0;
12443 goto error;
12444 }
12445 /*
12446 * Add the filtered set of nodes to the result node set.
12447 */
12448 if (newSize == 0) {
12449 /*
12450 * The predicates filtered all nodes out.
12451 */
12452 xmlXPathNodeSetClear(seq, hasNsNodes);
12453 } else if (seq->nodeNr > 0) {
12454 /*
12455 * Add to result set.
12456 */
12457 if (outSeq == NULL) {
12458 if (size != newSize) {
12459 /*
12460 * We need to merge and clear here, since
12461 * the sequence will contained NULLed entries.
12462 */
12463 outSeq = mergeAndClear(NULL, seq, 1);
12464 } else {
12465 outSeq = seq;
12466 seq = NULL;
12467 }
12468 } else
12469 outSeq = mergeAndClear(outSeq, seq,
12470 (size != newSize) ? 1: 0);
12471 /*
12472 * Break if only a true/false result was requested.
12473 */
12474 if (toBool)
12475 break;
12476 }
12477 } else if (seq->nodeNr > 0) {
12478 /*
12479 * Add to result set.
12480 */
12481 if (outSeq == NULL) {
12482 outSeq = seq;
12483 seq = NULL;
12484 } else {
12485 outSeq = mergeAndClear(outSeq, seq, 0);
12486 }
12487 }
12488 }
12489
12490 error:
12491 if ((obj->boolval) && (obj->user != NULL)) {
12492 /*
12493 * QUESTION TODO: What does this do and why?
12494 * TODO: Do we have to do this also for the "error"
12495 * cleanup further down?
12496 */
12497 ctxt->value->boolval = 1;
12498 ctxt->value->user = obj->user;
12499 obj->user = NULL;
12500 obj->boolval = 0;
12501 }
12502 xmlXPathReleaseObject(xpctxt, obj);
12503
12504 /*
12505 * Ensure we return at least an emtpy set.
12506 */
12507 if (outSeq == NULL) {
12508 if ((seq != NULL) && (seq->nodeNr == 0))
12509 outSeq = seq;
12510 else
12511 outSeq = xmlXPathNodeSetCreate(NULL);
12512 /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12513 }
12514 if ((seq != NULL) && (seq != outSeq)) {
12515 xmlXPathFreeNodeSet(seq);
12516 }
12517 /*
12518 * Hand over the result. Better to push the set also in
12519 * case of errors.
12520 */
12521 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12522 /*
12523 * Reset the context node.
12524 */
12525 xpctxt->node = oldContextNode;
12526
12527 #ifdef DEBUG_STEP
12528 xmlGenericError(xmlGenericErrorContext,
12529 "\nExamined %d nodes, found %d nodes at that step\n",
12530 total, nbMatches);
12531 #endif
12532
12533 return(total);
12534 }
12535
12536 static int
12537 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12538 xmlXPathStepOpPtr op, xmlNodePtr * first);
12539
12540 /**
12541 * xmlXPathCompOpEvalFirst:
12542 * @ctxt: the XPath parser context with the compiled expression
12543 * @op: an XPath compiled operation
12544 * @first: the first elem found so far
12545 *
12546 * Evaluate the Precompiled XPath operation searching only the first
12547 * element in document order
12548 *
12549 * Returns the number of examined objects.
12550 */
12551 static int
12552 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12553 xmlXPathStepOpPtr op, xmlNodePtr * first)
12554 {
12555 int total = 0, cur;
12556 xmlXPathCompExprPtr comp;
12557 xmlXPathObjectPtr arg1, arg2;
12558
12559 CHECK_ERROR0;
12560 comp = ctxt->comp;
12561 switch (op->op) {
12562 case XPATH_OP_END:
12563 return (0);
12564 case XPATH_OP_UNION:
12565 total =
12566 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12567 first);
12568 CHECK_ERROR0;
12569 if ((ctxt->value != NULL)
12570 && (ctxt->value->type == XPATH_NODESET)
12571 && (ctxt->value->nodesetval != NULL)
12572 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12573 /*
12574 * limit tree traversing to first node in the result
12575 */
12576 /*
12577 * OPTIMIZE TODO: This implicitely sorts
12578 * the result, even if not needed. E.g. if the argument
12579 * of the count() function, no sorting is needed.
12580 * OPTIMIZE TODO: How do we know if the node-list wasn't
12581 * aready sorted?
12582 */
12583 if (ctxt->value->nodesetval->nodeNr > 1)
12584 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12585 *first = ctxt->value->nodesetval->nodeTab[0];
12586 }
12587 cur =
12588 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12589 first);
12590 CHECK_ERROR0;
12591 CHECK_TYPE0(XPATH_NODESET);
12592 arg2 = valuePop(ctxt);
12593
12594 CHECK_TYPE0(XPATH_NODESET);
12595 arg1 = valuePop(ctxt);
12596
12597 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12598 arg2->nodesetval);
12599 valuePush(ctxt, arg1);
12600 xmlXPathReleaseObject(ctxt->context, arg2);
12601 /* optimizer */
12602 if (total > cur)
12603 xmlXPathCompSwap(op);
12604 return (total + cur);
12605 case XPATH_OP_ROOT:
12606 xmlXPathRoot(ctxt);
12607 return (0);
12608 case XPATH_OP_NODE:
12609 if (op->ch1 != -1)
12610 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12611 CHECK_ERROR0;
12612 if (op->ch2 != -1)
12613 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12614 CHECK_ERROR0;
12615 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12616 ctxt->context->node));
12617 return (total);
12618 case XPATH_OP_RESET:
12619 if (op->ch1 != -1)
12620 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12621 CHECK_ERROR0;
12622 if (op->ch2 != -1)
12623 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12624 CHECK_ERROR0;
12625 ctxt->context->node = NULL;
12626 return (total);
12627 case XPATH_OP_COLLECT:{
12628 if (op->ch1 == -1)
12629 return (total);
12630
12631 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12632 CHECK_ERROR0;
12633
12634 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12635 return (total);
12636 }
12637 case XPATH_OP_VALUE:
12638 valuePush(ctxt,
12639 xmlXPathCacheObjectCopy(ctxt->context,
12640 (xmlXPathObjectPtr) op->value4));
12641 return (0);
12642 case XPATH_OP_SORT:
12643 if (op->ch1 != -1)
12644 total +=
12645 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12646 first);
12647 CHECK_ERROR0;
12648 if ((ctxt->value != NULL)
12649 && (ctxt->value->type == XPATH_NODESET)
12650 && (ctxt->value->nodesetval != NULL)
12651 && (ctxt->value->nodesetval->nodeNr > 1))
12652 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12653 return (total);
12654 #ifdef XP_OPTIMIZED_FILTER_FIRST
12655 case XPATH_OP_FILTER:
12656 total =+ xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12657 return (total);
12658 #endif
12659 default:
12660 return (xmlXPathCompOpEval(ctxt, op));
12661 }
12662 }
12663
12664 /**
12665 * xmlXPathCompOpEvalLast:
12666 * @ctxt: the XPath parser context with the compiled expression
12667 * @op: an XPath compiled operation
12668 * @last: the last elem found so far
12669 *
12670 * Evaluate the Precompiled XPath operation searching only the last
12671 * element in document order
12672 *
12673 * Returns the number of nodes traversed
12674 */
12675 static int
12676 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12677 xmlNodePtr * last)
12678 {
12679 int total = 0, cur;
12680 xmlXPathCompExprPtr comp;
12681 xmlXPathObjectPtr arg1, arg2;
12682 xmlNodePtr bak;
12683 xmlDocPtr bakd;
12684 int pp;
12685 int cs;
12686
12687 CHECK_ERROR0;
12688 comp = ctxt->comp;
12689 switch (op->op) {
12690 case XPATH_OP_END:
12691 return (0);
12692 case XPATH_OP_UNION:
12693 bakd = ctxt->context->doc;
12694 bak = ctxt->context->node;
12695 pp = ctxt->context->proximityPosition;
12696 cs = ctxt->context->contextSize;
12697 total =
12698 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12699 CHECK_ERROR0;
12700 if ((ctxt->value != NULL)
12701 && (ctxt->value->type == XPATH_NODESET)
12702 && (ctxt->value->nodesetval != NULL)
12703 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12704 /*
12705 * limit tree traversing to first node in the result
12706 */
12707 if (ctxt->value->nodesetval->nodeNr > 1)
12708 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12709 *last =
12710 ctxt->value->nodesetval->nodeTab[ctxt->value->
12711 nodesetval->nodeNr -
12712 1];
12713 }
12714 ctxt->context->doc = bakd;
12715 ctxt->context->node = bak;
12716 ctxt->context->proximityPosition = pp;
12717 ctxt->context->contextSize = cs;
12718 cur =
12719 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12720 CHECK_ERROR0;
12721 if ((ctxt->value != NULL)
12722 && (ctxt->value->type == XPATH_NODESET)
12723 && (ctxt->value->nodesetval != NULL)
12724 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12725 }
12726 CHECK_TYPE0(XPATH_NODESET);
12727 arg2 = valuePop(ctxt);
12728
12729 CHECK_TYPE0(XPATH_NODESET);
12730 arg1 = valuePop(ctxt);
12731
12732 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12733 arg2->nodesetval);
12734 valuePush(ctxt, arg1);
12735 xmlXPathReleaseObject(ctxt->context, arg2);
12736 /* optimizer */
12737 if (total > cur)
12738 xmlXPathCompSwap(op);
12739 return (total + cur);
12740 case XPATH_OP_ROOT:
12741 xmlXPathRoot(ctxt);
12742 return (0);
12743 case XPATH_OP_NODE:
12744 if (op->ch1 != -1)
12745 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12746 CHECK_ERROR0;
12747 if (op->ch2 != -1)
12748 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12749 CHECK_ERROR0;
12750 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12751 ctxt->context->node));
12752 return (total);
12753 case XPATH_OP_RESET:
12754 if (op->ch1 != -1)
12755 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12756 CHECK_ERROR0;
12757 if (op->ch2 != -1)
12758 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12759 CHECK_ERROR0;
12760 ctxt->context->node = NULL;
12761 return (total);
12762 case XPATH_OP_COLLECT:{
12763 if (op->ch1 == -1)
12764 return (0);
12765
12766 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12767 CHECK_ERROR0;
12768
12769 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12770 return (total);
12771 }
12772 case XPATH_OP_VALUE:
12773 valuePush(ctxt,
12774 xmlXPathCacheObjectCopy(ctxt->context,
12775 (xmlXPathObjectPtr) op->value4));
12776 return (0);
12777 case XPATH_OP_SORT:
12778 if (op->ch1 != -1)
12779 total +=
12780 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12781 last);
12782 CHECK_ERROR0;
12783 if ((ctxt->value != NULL)
12784 && (ctxt->value->type == XPATH_NODESET)
12785 && (ctxt->value->nodesetval != NULL)
12786 && (ctxt->value->nodesetval->nodeNr > 1))
12787 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12788 return (total);
12789 default:
12790 return (xmlXPathCompOpEval(ctxt, op));
12791 }
12792 }
12793
12794 #ifdef XP_OPTIMIZED_FILTER_FIRST
12795 static int
12796 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12797 xmlXPathStepOpPtr op, xmlNodePtr * first)
12798 {
12799 int total = 0;
12800 xmlXPathCompExprPtr comp;
12801 xmlXPathObjectPtr res;
12802 xmlXPathObjectPtr obj;
12803 xmlNodeSetPtr oldset;
12804 xmlNodePtr oldnode;
12805 xmlDocPtr oldDoc;
12806 int i;
12807
12808 CHECK_ERROR0;
12809 comp = ctxt->comp;
12810 /*
12811 * Optimization for ()[last()] selection i.e. the last elem
12812 */
12813 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12814 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12815 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12816 int f = comp->steps[op->ch2].ch1;
12817
12818 if ((f != -1) &&
12819 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12820 (comp->steps[f].value5 == NULL) &&
12821 (comp->steps[f].value == 0) &&
12822 (comp->steps[f].value4 != NULL) &&
12823 (xmlStrEqual
12824 (comp->steps[f].value4, BAD_CAST "last"))) {
12825 xmlNodePtr last = NULL;
12826
12827 total +=
12828 xmlXPathCompOpEvalLast(ctxt,
12829 &comp->steps[op->ch1],
12830 &last);
12831 CHECK_ERROR0;
12832 /*
12833 * The nodeset should be in document order,
12834 * Keep only the last value
12835 */
12836 if ((ctxt->value != NULL) &&
12837 (ctxt->value->type == XPATH_NODESET) &&
12838 (ctxt->value->nodesetval != NULL) &&
12839 (ctxt->value->nodesetval->nodeTab != NULL) &&
12840 (ctxt->value->nodesetval->nodeNr > 1)) {
12841 ctxt->value->nodesetval->nodeTab[0] =
12842 ctxt->value->nodesetval->nodeTab[ctxt->
12843 value->
12844 nodesetval->
12845 nodeNr -
12846 1];
12847 ctxt->value->nodesetval->nodeNr = 1;
12848 *first = *(ctxt->value->nodesetval->nodeTab);
12849 }
12850 return (total);
12851 }
12852 }
12853
12854 if (op->ch1 != -1)
12855 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12856 CHECK_ERROR0;
12857 if (op->ch2 == -1)
12858 return (total);
12859 if (ctxt->value == NULL)
12860 return (total);
12861
12862 #ifdef LIBXML_XPTR_ENABLED
12863 oldnode = ctxt->context->node;
12864 /*
12865 * Hum are we filtering the result of an XPointer expression
12866 */
12867 if (ctxt->value->type == XPATH_LOCATIONSET) {
12868 xmlXPathObjectPtr tmp = NULL;
12869 xmlLocationSetPtr newlocset = NULL;
12870 xmlLocationSetPtr oldlocset;
12871
12872 /*
12873 * Extract the old locset, and then evaluate the result of the
12874 * expression for all the element in the locset. use it to grow
12875 * up a new locset.
12876 */
12877 CHECK_TYPE0(XPATH_LOCATIONSET);
12878 obj = valuePop(ctxt);
12879 oldlocset = obj->user;
12880 ctxt->context->node = NULL;
12881
12882 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12883 ctxt->context->contextSize = 0;
12884 ctxt->context->proximityPosition = 0;
12885 if (op->ch2 != -1)
12886 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12887 res = valuePop(ctxt);
12888 if (res != NULL) {
12889 xmlXPathReleaseObject(ctxt->context, res);
12890 }
12891 valuePush(ctxt, obj);
12892 CHECK_ERROR0;
12893 return (total);
12894 }
12895 newlocset = xmlXPtrLocationSetCreate(NULL);
12896
12897 for (i = 0; i < oldlocset->locNr; i++) {
12898 /*
12899 * Run the evaluation with a node list made of a
12900 * single item in the nodelocset.
12901 */
12902 ctxt->context->node = oldlocset->locTab[i]->user;
12903 ctxt->context->contextSize = oldlocset->locNr;
12904 ctxt->context->proximityPosition = i + 1;
12905 if (tmp == NULL) {
12906 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12907 ctxt->context->node);
12908 } else {
12909 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12910 ctxt->context->node);
12911 }
12912 valuePush(ctxt, tmp);
12913 if (op->ch2 != -1)
12914 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12915 if (ctxt->error != XPATH_EXPRESSION_OK) {
12916 xmlXPathFreeObject(obj);
12917 return(0);
12918 }
12919 /*
12920 * The result of the evaluation need to be tested to
12921 * decided whether the filter succeeded or not
12922 */
12923 res = valuePop(ctxt);
12924 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12925 xmlXPtrLocationSetAdd(newlocset,
12926 xmlXPathCacheObjectCopy(ctxt->context,
12927 oldlocset->locTab[i]));
12928 }
12929 /*
12930 * Cleanup
12931 */
12932 if (res != NULL) {
12933 xmlXPathReleaseObject(ctxt->context, res);
12934 }
12935 if (ctxt->value == tmp) {
12936 valuePop(ctxt);
12937 xmlXPathNodeSetClear(tmp->nodesetval, 1);
12938 /*
12939 * REVISIT TODO: Don't create a temporary nodeset
12940 * for everly iteration.
12941 */
12942 /* OLD: xmlXPathFreeObject(res); */
12943 } else
12944 tmp = NULL;
12945 ctxt->context->node = NULL;
12946 /*
12947 * Only put the first node in the result, then leave.
12948 */
12949 if (newlocset->locNr > 0) {
12950 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
12951 break;
12952 }
12953 }
12954 if (tmp != NULL) {
12955 xmlXPathReleaseObject(ctxt->context, tmp);
12956 }
12957 /*
12958 * The result is used as the new evaluation locset.
12959 */
12960 xmlXPathReleaseObject(ctxt->context, obj);
12961 ctxt->context->node = NULL;
12962 ctxt->context->contextSize = -1;
12963 ctxt->context->proximityPosition = -1;
12964 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12965 ctxt->context->node = oldnode;
12966 return (total);
12967 }
12968 #endif /* LIBXML_XPTR_ENABLED */
12969
12970 /*
12971 * Extract the old set, and then evaluate the result of the
12972 * expression for all the element in the set. use it to grow
12973 * up a new set.
12974 */
12975 CHECK_TYPE0(XPATH_NODESET);
12976 obj = valuePop(ctxt);
12977 oldset = obj->nodesetval;
12978
12979 oldnode = ctxt->context->node;
12980 oldDoc = ctxt->context->doc;
12981 ctxt->context->node = NULL;
12982
12983 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
12984 ctxt->context->contextSize = 0;
12985 ctxt->context->proximityPosition = 0;
12986 /* QUESTION TODO: Why was this code commented out?
12987 if (op->ch2 != -1)
12988 total +=
12989 xmlXPathCompOpEval(ctxt,
12990 &comp->steps[op->ch2]);
12991 CHECK_ERROR0;
12992 res = valuePop(ctxt);
12993 if (res != NULL)
12994 xmlXPathFreeObject(res);
12995 */
12996 valuePush(ctxt, obj);
12997 ctxt->context->node = oldnode;
12998 CHECK_ERROR0;
12999 } else {
13000 xmlNodeSetPtr newset;
13001 xmlXPathObjectPtr tmp = NULL;
13002 /*
13003 * Initialize the new set.
13004 * Also set the xpath document in case things like
13005 * key() evaluation are attempted on the predicate
13006 */
13007 newset = xmlXPathNodeSetCreate(NULL);
13008 /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13009
13010 for (i = 0; i < oldset->nodeNr; i++) {
13011 /*
13012 * Run the evaluation with a node list made of
13013 * a single item in the nodeset.
13014 */
13015 ctxt->context->node = oldset->nodeTab[i];
13016 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13017 (oldset->nodeTab[i]->doc != NULL))
13018 ctxt->context->doc = oldset->nodeTab[i]->doc;
13019 if (tmp == NULL) {
13020 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13021 ctxt->context->node);
13022 } else {
13023 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13024 ctxt->context->node);
13025 }
13026 valuePush(ctxt, tmp);
13027 ctxt->context->contextSize = oldset->nodeNr;
13028 ctxt->context->proximityPosition = i + 1;
13029 if (op->ch2 != -1)
13030 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13031 if (ctxt->error != XPATH_EXPRESSION_OK) {
13032 xmlXPathFreeNodeSet(newset);
13033 xmlXPathFreeObject(obj);
13034 return(0);
13035 }
13036 /*
13037 * The result of the evaluation needs to be tested to
13038 * decide whether the filter succeeded or not
13039 */
13040 res = valuePop(ctxt);
13041 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13042 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13043 }
13044 /*
13045 * Cleanup
13046 */
13047 if (res != NULL) {
13048 xmlXPathReleaseObject(ctxt->context, res);
13049 }
13050 if (ctxt->value == tmp) {
13051 valuePop(ctxt);
13052 /*
13053 * Don't free the temporary nodeset
13054 * in order to avoid massive recreation inside this
13055 * loop.
13056 */
13057 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13058 } else
13059 tmp = NULL;
13060 ctxt->context->node = NULL;
13061 /*
13062 * Only put the first node in the result, then leave.
13063 */
13064 if (newset->nodeNr > 0) {
13065 *first = *(newset->nodeTab);
13066 break;
13067 }
13068 }
13069 if (tmp != NULL) {
13070 xmlXPathReleaseObject(ctxt->context, tmp);
13071 }
13072 /*
13073 * The result is used as the new evaluation set.
13074 */
13075 xmlXPathReleaseObject(ctxt->context, obj);
13076 ctxt->context->node = NULL;
13077 ctxt->context->contextSize = -1;
13078 ctxt->context->proximityPosition = -1;
13079 /* may want to move this past the '}' later */
13080 ctxt->context->doc = oldDoc;
13081 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13082 }
13083 ctxt->context->node = oldnode;
13084 return(total);
13085 }
13086 #endif /* XP_OPTIMIZED_FILTER_FIRST */
13087
13088 /**
13089 * xmlXPathCompOpEval:
13090 * @ctxt: the XPath parser context with the compiled expression
13091 * @op: an XPath compiled operation
13092 *
13093 * Evaluate the Precompiled XPath operation
13094 * Returns the number of nodes traversed
13095 */
13096 static int
13097 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13098 {
13099 int total = 0;
13100 int equal, ret;
13101 xmlXPathCompExprPtr comp;
13102 xmlXPathObjectPtr arg1, arg2;
13103 xmlNodePtr bak;
13104 xmlDocPtr bakd;
13105 int pp;
13106 int cs;
13107
13108 CHECK_ERROR0;
13109 comp = ctxt->comp;
13110 switch (op->op) {
13111 case XPATH_OP_END:
13112 return (0);
13113 case XPATH_OP_AND:
13114 bakd = ctxt->context->doc;
13115 bak = ctxt->context->node;
13116 pp = ctxt->context->proximityPosition;
13117 cs = ctxt->context->contextSize;
13118 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13119 CHECK_ERROR0;
13120 xmlXPathBooleanFunction(ctxt, 1);
13121 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13122 return (total);
13123 arg2 = valuePop(ctxt);
13124 ctxt->context->doc = bakd;
13125 ctxt->context->node = bak;
13126 ctxt->context->proximityPosition = pp;
13127 ctxt->context->contextSize = cs;
13128 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13129 if (ctxt->error) {
13130 xmlXPathFreeObject(arg2);
13131 return(0);
13132 }
13133 xmlXPathBooleanFunction(ctxt, 1);
13134 arg1 = valuePop(ctxt);
13135 arg1->boolval &= arg2->boolval;
13136 valuePush(ctxt, arg1);
13137 xmlXPathReleaseObject(ctxt->context, arg2);
13138 return (total);
13139 case XPATH_OP_OR:
13140 bakd = ctxt->context->doc;
13141 bak = ctxt->context->node;
13142 pp = ctxt->context->proximityPosition;
13143 cs = ctxt->context->contextSize;
13144 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13145 CHECK_ERROR0;
13146 xmlXPathBooleanFunction(ctxt, 1);
13147 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13148 return (total);
13149 arg2 = valuePop(ctxt);
13150 ctxt->context->doc = bakd;
13151 ctxt->context->node = bak;
13152 ctxt->context->proximityPosition = pp;
13153 ctxt->context->contextSize = cs;
13154 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13155 if (ctxt->error) {
13156 xmlXPathFreeObject(arg2);
13157 return(0);
13158 }
13159 xmlXPathBooleanFunction(ctxt, 1);
13160 arg1 = valuePop(ctxt);
13161 arg1->boolval |= arg2->boolval;
13162 valuePush(ctxt, arg1);
13163 xmlXPathReleaseObject(ctxt->context, arg2);
13164 return (total);
13165 case XPATH_OP_EQUAL:
13166 bakd = ctxt->context->doc;
13167 bak = ctxt->context->node;
13168 pp = ctxt->context->proximityPosition;
13169 cs = ctxt->context->contextSize;
13170 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13171 CHECK_ERROR0;
13172 ctxt->context->doc = bakd;
13173 ctxt->context->node = bak;
13174 ctxt->context->proximityPosition = pp;
13175 ctxt->context->contextSize = cs;
13176 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13177 CHECK_ERROR0;
13178 if (op->value)
13179 equal = xmlXPathEqualValues(ctxt);
13180 else
13181 equal = xmlXPathNotEqualValues(ctxt);
13182 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13183 return (total);
13184 case XPATH_OP_CMP:
13185 bakd = ctxt->context->doc;
13186 bak = ctxt->context->node;
13187 pp = ctxt->context->proximityPosition;
13188 cs = ctxt->context->contextSize;
13189 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13190 CHECK_ERROR0;
13191 ctxt->context->doc = bakd;
13192 ctxt->context->node = bak;
13193 ctxt->context->proximityPosition = pp;
13194 ctxt->context->contextSize = cs;
13195 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13196 CHECK_ERROR0;
13197 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13198 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13199 return (total);
13200 case XPATH_OP_PLUS:
13201 bakd = ctxt->context->doc;
13202 bak = ctxt->context->node;
13203 pp = ctxt->context->proximityPosition;
13204 cs = ctxt->context->contextSize;
13205 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13206 CHECK_ERROR0;
13207 if (op->ch2 != -1) {
13208 ctxt->context->doc = bakd;
13209 ctxt->context->node = bak;
13210 ctxt->context->proximityPosition = pp;
13211 ctxt->context->contextSize = cs;
13212 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13213 }
13214 CHECK_ERROR0;
13215 if (op->value == 0)
13216 xmlXPathSubValues(ctxt);
13217 else if (op->value == 1)
13218 xmlXPathAddValues(ctxt);
13219 else if (op->value == 2)
13220 xmlXPathValueFlipSign(ctxt);
13221 else if (op->value == 3) {
13222 CAST_TO_NUMBER;
13223 CHECK_TYPE0(XPATH_NUMBER);
13224 }
13225 return (total);
13226 case XPATH_OP_MULT:
13227 bakd = ctxt->context->doc;
13228 bak = ctxt->context->node;
13229 pp = ctxt->context->proximityPosition;
13230 cs = ctxt->context->contextSize;
13231 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13232 CHECK_ERROR0;
13233 ctxt->context->doc = bakd;
13234 ctxt->context->node = bak;
13235 ctxt->context->proximityPosition = pp;
13236 ctxt->context->contextSize = cs;
13237 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13238 CHECK_ERROR0;
13239 if (op->value == 0)
13240 xmlXPathMultValues(ctxt);
13241 else if (op->value == 1)
13242 xmlXPathDivValues(ctxt);
13243 else if (op->value == 2)
13244 xmlXPathModValues(ctxt);
13245 return (total);
13246 case XPATH_OP_UNION:
13247 bakd = ctxt->context->doc;
13248 bak = ctxt->context->node;
13249 pp = ctxt->context->proximityPosition;
13250 cs = ctxt->context->contextSize;
13251 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13252 CHECK_ERROR0;
13253 ctxt->context->doc = bakd;
13254 ctxt->context->node = bak;
13255 ctxt->context->proximityPosition = pp;
13256 ctxt->context->contextSize = cs;
13257 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13258 CHECK_ERROR0;
13259 CHECK_TYPE0(XPATH_NODESET);
13260 arg2 = valuePop(ctxt);
13261
13262 CHECK_TYPE0(XPATH_NODESET);
13263 arg1 = valuePop(ctxt);
13264
13265 if ((arg1->nodesetval == NULL) ||
13266 ((arg2->nodesetval != NULL) &&
13267 (arg2->nodesetval->nodeNr != 0)))
13268 {
13269 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13270 arg2->nodesetval);
13271 }
13272
13273 valuePush(ctxt, arg1);
13274 xmlXPathReleaseObject(ctxt->context, arg2);
13275 return (total);
13276 case XPATH_OP_ROOT:
13277 xmlXPathRoot(ctxt);
13278 return (total);
13279 case XPATH_OP_NODE:
13280 if (op->ch1 != -1)
13281 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13282 CHECK_ERROR0;
13283 if (op->ch2 != -1)
13284 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13285 CHECK_ERROR0;
13286 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13287 ctxt->context->node));
13288 return (total);
13289 case XPATH_OP_RESET:
13290 if (op->ch1 != -1)
13291 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13292 CHECK_ERROR0;
13293 if (op->ch2 != -1)
13294 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13295 CHECK_ERROR0;
13296 ctxt->context->node = NULL;
13297 return (total);
13298 case XPATH_OP_COLLECT:{
13299 if (op->ch1 == -1)
13300 return (total);
13301
13302 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13303 CHECK_ERROR0;
13304
13305 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13306 return (total);
13307 }
13308 case XPATH_OP_VALUE:
13309 valuePush(ctxt,
13310 xmlXPathCacheObjectCopy(ctxt->context,
13311 (xmlXPathObjectPtr) op->value4));
13312 return (total);
13313 case XPATH_OP_VARIABLE:{
13314 xmlXPathObjectPtr val;
13315
13316 if (op->ch1 != -1)
13317 total +=
13318 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13319 if (op->value5 == NULL) {
13320 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13321 if (val == NULL) {
13322 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13323 return(0);
13324 }
13325 valuePush(ctxt, val);
13326 } else {
13327 const xmlChar *URI;
13328
13329 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13330 if (URI == NULL) {
13331 xmlGenericError(xmlGenericErrorContext,
13332 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13333 (char *) op->value4, (char *)op->value5);
13334 return (total);
13335 }
13336 val = xmlXPathVariableLookupNS(ctxt->context,
13337 op->value4, URI);
13338 if (val == NULL) {
13339 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13340 return(0);
13341 }
13342 valuePush(ctxt, val);
13343 }
13344 return (total);
13345 }
13346 case XPATH_OP_FUNCTION:{
13347 xmlXPathFunction func;
13348 const xmlChar *oldFunc, *oldFuncURI;
13349 int i;
13350
13351 if (op->ch1 != -1)
13352 total +=
13353 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13354 if (ctxt->valueNr < op->value) {
13355 xmlGenericError(xmlGenericErrorContext,
13356 "xmlXPathCompOpEval: parameter error\n");
13357 ctxt->error = XPATH_INVALID_OPERAND;
13358 return (total);
13359 }
13360 for (i = 0; i < op->value; i++)
13361 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13362 xmlGenericError(xmlGenericErrorContext,
13363 "xmlXPathCompOpEval: parameter error\n");
13364 ctxt->error = XPATH_INVALID_OPERAND;
13365 return (total);
13366 }
13367 if (op->cache != NULL)
13368 XML_CAST_FPTR(func) = op->cache;
13369 else {
13370 const xmlChar *URI = NULL;
13371
13372 if (op->value5 == NULL)
13373 func =
13374 xmlXPathFunctionLookup(ctxt->context,
13375 op->value4);
13376 else {
13377 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13378 if (URI == NULL) {
13379 xmlGenericError(xmlGenericErrorContext,
13380 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13381 (char *)op->value4, (char *)op->value5);
13382 return (total);
13383 }
13384 func = xmlXPathFunctionLookupNS(ctxt->context,
13385 op->value4, URI);
13386 }
13387 if (func == NULL) {
13388 xmlGenericError(xmlGenericErrorContext,
13389 "xmlXPathCompOpEval: function %s not found\n",
13390 (char *)op->value4);
13391 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13392 }
13393 op->cache = XML_CAST_FPTR(func);
13394 op->cacheURI = (void *) URI;
13395 }
13396 oldFunc = ctxt->context->function;
13397 oldFuncURI = ctxt->context->functionURI;
13398 ctxt->context->function = op->value4;
13399 ctxt->context->functionURI = op->cacheURI;
13400 func(ctxt, op->value);
13401 ctxt->context->function = oldFunc;
13402 ctxt->context->functionURI = oldFuncURI;
13403 return (total);
13404 }
13405 case XPATH_OP_ARG:
13406 bakd = ctxt->context->doc;
13407 bak = ctxt->context->node;
13408 pp = ctxt->context->proximityPosition;
13409 cs = ctxt->context->contextSize;
13410 if (op->ch1 != -1)
13411 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13412 ctxt->context->contextSize = cs;
13413 ctxt->context->proximityPosition = pp;
13414 ctxt->context->node = bak;
13415 ctxt->context->doc = bakd;
13416 CHECK_ERROR0;
13417 if (op->ch2 != -1) {
13418 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13419 ctxt->context->doc = bakd;
13420 ctxt->context->node = bak;
13421 CHECK_ERROR0;
13422 }
13423 return (total);
13424 case XPATH_OP_PREDICATE:
13425 case XPATH_OP_FILTER:{
13426 xmlXPathObjectPtr res;
13427 xmlXPathObjectPtr obj, tmp;
13428 xmlNodeSetPtr newset = NULL;
13429 xmlNodeSetPtr oldset;
13430 xmlNodePtr oldnode;
13431 xmlDocPtr oldDoc;
13432 int i;
13433
13434 /*
13435 * Optimization for ()[1] selection i.e. the first elem
13436 */
13437 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13438 #ifdef XP_OPTIMIZED_FILTER_FIRST
13439 /*
13440 * FILTER TODO: Can we assume that the inner processing
13441 * will result in an ordered list if we have an
13442 * XPATH_OP_FILTER?
13443 * What about an additional field or flag on
13444 * xmlXPathObject like @sorted ? This way we wouln'd need
13445 * to assume anything, so it would be more robust and
13446 * easier to optimize.
13447 */
13448 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13449 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13450 #else
13451 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13452 #endif
13453 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13454 xmlXPathObjectPtr val;
13455
13456 val = comp->steps[op->ch2].value4;
13457 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13458 (val->floatval == 1.0)) {
13459 xmlNodePtr first = NULL;
13460
13461 total +=
13462 xmlXPathCompOpEvalFirst(ctxt,
13463 &comp->steps[op->ch1],
13464 &first);
13465 CHECK_ERROR0;
13466 /*
13467 * The nodeset should be in document order,
13468 * Keep only the first value
13469 */
13470 if ((ctxt->value != NULL) &&
13471 (ctxt->value->type == XPATH_NODESET) &&
13472 (ctxt->value->nodesetval != NULL) &&
13473 (ctxt->value->nodesetval->nodeNr > 1))
13474 ctxt->value->nodesetval->nodeNr = 1;
13475 return (total);
13476 }
13477 }
13478 /*
13479 * Optimization for ()[last()] selection i.e. the last elem
13480 */
13481 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13482 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13483 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13484 int f = comp->steps[op->ch2].ch1;
13485
13486 if ((f != -1) &&
13487 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13488 (comp->steps[f].value5 == NULL) &&
13489 (comp->steps[f].value == 0) &&
13490 (comp->steps[f].value4 != NULL) &&
13491 (xmlStrEqual
13492 (comp->steps[f].value4, BAD_CAST "last"))) {
13493 xmlNodePtr last = NULL;
13494
13495 total +=
13496 xmlXPathCompOpEvalLast(ctxt,
13497 &comp->steps[op->ch1],
13498 &last);
13499 CHECK_ERROR0;
13500 /*
13501 * The nodeset should be in document order,
13502 * Keep only the last value
13503 */
13504 if ((ctxt->value != NULL) &&
13505 (ctxt->value->type == XPATH_NODESET) &&
13506 (ctxt->value->nodesetval != NULL) &&
13507 (ctxt->value->nodesetval->nodeTab != NULL) &&
13508 (ctxt->value->nodesetval->nodeNr > 1)) {
13509 ctxt->value->nodesetval->nodeTab[0] =
13510 ctxt->value->nodesetval->nodeTab[ctxt->
13511 value->
13512 nodesetval->
13513 nodeNr -
13514 1];
13515 ctxt->value->nodesetval->nodeNr = 1;
13516 }
13517 return (total);
13518 }
13519 }
13520 /*
13521 * Process inner predicates first.
13522 * Example "index[parent::book][1]":
13523 * ...
13524 * PREDICATE <-- we are here "[1]"
13525 * PREDICATE <-- process "[parent::book]" first
13526 * SORT
13527 * COLLECT 'parent' 'name' 'node' book
13528 * NODE
13529 * ELEM Object is a number : 1
13530 */
13531 if (op->ch1 != -1)
13532 total +=
13533 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13534 CHECK_ERROR0;
13535 if (op->ch2 == -1)
13536 return (total);
13537 if (ctxt->value == NULL)
13538 return (total);
13539
13540 oldnode = ctxt->context->node;
13541
13542 #ifdef LIBXML_XPTR_ENABLED
13543 /*
13544 * Hum are we filtering the result of an XPointer expression
13545 */
13546 if (ctxt->value->type == XPATH_LOCATIONSET) {
13547 xmlLocationSetPtr newlocset = NULL;
13548 xmlLocationSetPtr oldlocset;
13549
13550 /*
13551 * Extract the old locset, and then evaluate the result of the
13552 * expression for all the element in the locset. use it to grow
13553 * up a new locset.
13554 */
13555 CHECK_TYPE0(XPATH_LOCATIONSET);
13556 obj = valuePop(ctxt);
13557 oldlocset = obj->user;
13558 ctxt->context->node = NULL;
13559
13560 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13561 ctxt->context->contextSize = 0;
13562 ctxt->context->proximityPosition = 0;
13563 if (op->ch2 != -1)
13564 total +=
13565 xmlXPathCompOpEval(ctxt,
13566 &comp->steps[op->ch2]);
13567 res = valuePop(ctxt);
13568 if (res != NULL) {
13569 xmlXPathReleaseObject(ctxt->context, res);
13570 }
13571 valuePush(ctxt, obj);
13572 CHECK_ERROR0;
13573 return (total);
13574 }
13575 newlocset = xmlXPtrLocationSetCreate(NULL);
13576
13577 for (i = 0; i < oldlocset->locNr; i++) {
13578 /*
13579 * Run the evaluation with a node list made of a
13580 * single item in the nodelocset.
13581 */
13582 ctxt->context->node = oldlocset->locTab[i]->user;
13583 ctxt->context->contextSize = oldlocset->locNr;
13584 ctxt->context->proximityPosition = i + 1;
13585 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13586 ctxt->context->node);
13587 valuePush(ctxt, tmp);
13588
13589 if (op->ch2 != -1)
13590 total +=
13591 xmlXPathCompOpEval(ctxt,
13592 &comp->steps[op->ch2]);
13593 if (ctxt->error != XPATH_EXPRESSION_OK) {
13594 xmlXPathFreeObject(obj);
13595 return(0);
13596 }
13597
13598 /*
13599 * The result of the evaluation need to be tested to
13600 * decided whether the filter succeeded or not
13601 */
13602 res = valuePop(ctxt);
13603 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13604 xmlXPtrLocationSetAdd(newlocset,
13605 xmlXPathObjectCopy
13606 (oldlocset->locTab[i]));
13607 }
13608
13609 /*
13610 * Cleanup
13611 */
13612 if (res != NULL) {
13613 xmlXPathReleaseObject(ctxt->context, res);
13614 }
13615 if (ctxt->value == tmp) {
13616 res = valuePop(ctxt);
13617 xmlXPathReleaseObject(ctxt->context, res);
13618 }
13619
13620 ctxt->context->node = NULL;
13621 }
13622
13623 /*
13624 * The result is used as the new evaluation locset.
13625 */
13626 xmlXPathReleaseObject(ctxt->context, obj);
13627 ctxt->context->node = NULL;
13628 ctxt->context->contextSize = -1;
13629 ctxt->context->proximityPosition = -1;
13630 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13631 ctxt->context->node = oldnode;
13632 return (total);
13633 }
13634 #endif /* LIBXML_XPTR_ENABLED */
13635
13636 /*
13637 * Extract the old set, and then evaluate the result of the
13638 * expression for all the element in the set. use it to grow
13639 * up a new set.
13640 */
13641 CHECK_TYPE0(XPATH_NODESET);
13642 obj = valuePop(ctxt);
13643 oldset = obj->nodesetval;
13644
13645 oldnode = ctxt->context->node;
13646 oldDoc = ctxt->context->doc;
13647 ctxt->context->node = NULL;
13648
13649 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13650 ctxt->context->contextSize = 0;
13651 ctxt->context->proximityPosition = 0;
13652 /*
13653 if (op->ch2 != -1)
13654 total +=
13655 xmlXPathCompOpEval(ctxt,
13656 &comp->steps[op->ch2]);
13657 CHECK_ERROR0;
13658 res = valuePop(ctxt);
13659 if (res != NULL)
13660 xmlXPathFreeObject(res);
13661 */
13662 valuePush(ctxt, obj);
13663 ctxt->context->node = oldnode;
13664 CHECK_ERROR0;
13665 } else {
13666 tmp = NULL;
13667 /*
13668 * Initialize the new set.
13669 * Also set the xpath document in case things like
13670 * key() evaluation are attempted on the predicate
13671 */
13672 newset = xmlXPathNodeSetCreate(NULL);
13673 /*
13674 * SPEC XPath 1.0:
13675 * "For each node in the node-set to be filtered, the
13676 * PredicateExpr is evaluated with that node as the
13677 * context node, with the number of nodes in the
13678 * node-set as the context size, and with the proximity
13679 * position of the node in the node-set with respect to
13680 * the axis as the context position;"
13681 * @oldset is the node-set" to be filtered.
13682 *
13683 * SPEC XPath 1.0:
13684 * "only predicates change the context position and
13685 * context size (see [2.4 Predicates])."
13686 * Example:
13687 * node-set context pos
13688 * nA 1
13689 * nB 2
13690 * nC 3
13691 * After applying predicate [position() > 1] :
13692 * node-set context pos
13693 * nB 1
13694 * nC 2
13695 *
13696 * removed the first node in the node-set, then
13697 * the context position of the
13698 */
13699 for (i = 0; i < oldset->nodeNr; i++) {
13700 /*
13701 * Run the evaluation with a node list made of
13702 * a single item in the nodeset.
13703 */
13704 ctxt->context->node = oldset->nodeTab[i];
13705 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13706 (oldset->nodeTab[i]->doc != NULL))
13707 ctxt->context->doc = oldset->nodeTab[i]->doc;
13708 if (tmp == NULL) {
13709 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13710 ctxt->context->node);
13711 } else {
13712 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13713 ctxt->context->node);
13714 }
13715 valuePush(ctxt, tmp);
13716 ctxt->context->contextSize = oldset->nodeNr;
13717 ctxt->context->proximityPosition = i + 1;
13718 /*
13719 * Evaluate the predicate against the context node.
13720 * Can/should we optimize position() predicates
13721 * here (e.g. "[1]")?
13722 */
13723 if (op->ch2 != -1)
13724 total +=
13725 xmlXPathCompOpEval(ctxt,
13726 &comp->steps[op->ch2]);
13727 if (ctxt->error != XPATH_EXPRESSION_OK) {
13728 xmlXPathFreeNodeSet(newset);
13729 xmlXPathFreeObject(obj);
13730 return(0);
13731 }
13732
13733 /*
13734 * The result of the evaluation needs to be tested to
13735 * decide whether the filter succeeded or not
13736 */
13737 /*
13738 * OPTIMIZE TODO: Can we use
13739 * xmlXPathNodeSetAdd*Unique()* instead?
13740 */
13741 res = valuePop(ctxt);
13742 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13743 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13744 }
13745
13746 /*
13747 * Cleanup
13748 */
13749 if (res != NULL) {
13750 xmlXPathReleaseObject(ctxt->context, res);
13751 }
13752 if (ctxt->value == tmp) {
13753 valuePop(ctxt);
13754 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13755 /*
13756 * Don't free the temporary nodeset
13757 * in order to avoid massive recreation inside this
13758 * loop.
13759 */
13760 } else
13761 tmp = NULL;
13762 ctxt->context->node = NULL;
13763 }
13764 if (tmp != NULL)
13765 xmlXPathReleaseObject(ctxt->context, tmp);
13766 /*
13767 * The result is used as the new evaluation set.
13768 */
13769 xmlXPathReleaseObject(ctxt->context, obj);
13770 ctxt->context->node = NULL;
13771 ctxt->context->contextSize = -1;
13772 ctxt->context->proximityPosition = -1;
13773 /* may want to move this past the '}' later */
13774 ctxt->context->doc = oldDoc;
13775 valuePush(ctxt,
13776 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13777 }
13778 ctxt->context->node = oldnode;
13779 return (total);
13780 }
13781 case XPATH_OP_SORT:
13782 if (op->ch1 != -1)
13783 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13784 CHECK_ERROR0;
13785 if ((ctxt->value != NULL) &&
13786 (ctxt->value->type == XPATH_NODESET) &&
13787 (ctxt->value->nodesetval != NULL) &&
13788 (ctxt->value->nodesetval->nodeNr > 1))
13789 {
13790 xmlXPathNodeSetSort(ctxt->value->nodesetval);
13791 }
13792 return (total);
13793 #ifdef LIBXML_XPTR_ENABLED
13794 case XPATH_OP_RANGETO:{
13795 xmlXPathObjectPtr range;
13796 xmlXPathObjectPtr res, obj;
13797 xmlXPathObjectPtr tmp;
13798 xmlLocationSetPtr newlocset = NULL;
13799 xmlLocationSetPtr oldlocset;
13800 xmlNodeSetPtr oldset;
13801 int i, j;
13802
13803 if (op->ch1 != -1)
13804 total +=
13805 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13806 if (op->ch2 == -1)
13807 return (total);
13808
13809 if (ctxt->value->type == XPATH_LOCATIONSET) {
13810 /*
13811 * Extract the old locset, and then evaluate the result of the
13812 * expression for all the element in the locset. use it to grow
13813 * up a new locset.
13814 */
13815 CHECK_TYPE0(XPATH_LOCATIONSET);
13816 obj = valuePop(ctxt);
13817 oldlocset = obj->user;
13818
13819 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13820 ctxt->context->node = NULL;
13821 ctxt->context->contextSize = 0;
13822 ctxt->context->proximityPosition = 0;
13823 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13824 res = valuePop(ctxt);
13825 if (res != NULL) {
13826 xmlXPathReleaseObject(ctxt->context, res);
13827 }
13828 valuePush(ctxt, obj);
13829 CHECK_ERROR0;
13830 return (total);
13831 }
13832 newlocset = xmlXPtrLocationSetCreate(NULL);
13833
13834 for (i = 0; i < oldlocset->locNr; i++) {
13835 /*
13836 * Run the evaluation with a node list made of a
13837 * single item in the nodelocset.
13838 */
13839 ctxt->context->node = oldlocset->locTab[i]->user;
13840 ctxt->context->contextSize = oldlocset->locNr;
13841 ctxt->context->proximityPosition = i + 1;
13842 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13843 ctxt->context->node);
13844 valuePush(ctxt, tmp);
13845
13846 if (op->ch2 != -1)
13847 total +=
13848 xmlXPathCompOpEval(ctxt,
13849 &comp->steps[op->ch2]);
13850 if (ctxt->error != XPATH_EXPRESSION_OK) {
13851 xmlXPathFreeObject(obj);
13852 return(0);
13853 }
13854
13855 res = valuePop(ctxt);
13856 if (res->type == XPATH_LOCATIONSET) {
13857 xmlLocationSetPtr rloc =
13858 (xmlLocationSetPtr)res->user;
13859 for (j=0; j<rloc->locNr; j++) {
13860 range = xmlXPtrNewRange(
13861 oldlocset->locTab[i]->user,
13862 oldlocset->locTab[i]->index,
13863 rloc->locTab[j]->user2,
13864 rloc->locTab[j]->index2);
13865 if (range != NULL) {
13866 xmlXPtrLocationSetAdd(newlocset, range);
13867 }
13868 }
13869 } else {
13870 range = xmlXPtrNewRangeNodeObject(
13871 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13872 if (range != NULL) {
13873 xmlXPtrLocationSetAdd(newlocset,range);
13874 }
13875 }
13876
13877 /*
13878 * Cleanup
13879 */
13880 if (res != NULL) {
13881 xmlXPathReleaseObject(ctxt->context, res);
13882 }
13883 if (ctxt->value == tmp) {
13884 res = valuePop(ctxt);
13885 xmlXPathReleaseObject(ctxt->context, res);
13886 }
13887
13888 ctxt->context->node = NULL;
13889 }
13890 } else { /* Not a location set */
13891 CHECK_TYPE0(XPATH_NODESET);
13892 obj = valuePop(ctxt);
13893 oldset = obj->nodesetval;
13894 ctxt->context->node = NULL;
13895
13896 newlocset = xmlXPtrLocationSetCreate(NULL);
13897
13898 if (oldset != NULL) {
13899 for (i = 0; i < oldset->nodeNr; i++) {
13900 /*
13901 * Run the evaluation with a node list made of a single item
13902 * in the nodeset.
13903 */
13904 ctxt->context->node = oldset->nodeTab[i];
13905 /*
13906 * OPTIMIZE TODO: Avoid recreation for every iteration.
13907 */
13908 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13909 ctxt->context->node);
13910 valuePush(ctxt, tmp);
13911
13912 if (op->ch2 != -1)
13913 total +=
13914 xmlXPathCompOpEval(ctxt,
13915 &comp->steps[op->ch2]);
13916 if (ctxt->error != XPATH_EXPRESSION_OK) {
13917 xmlXPathFreeObject(obj);
13918 return(0);
13919 }
13920
13921 res = valuePop(ctxt);
13922 range =
13923 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13924 res);
13925 if (range != NULL) {
13926 xmlXPtrLocationSetAdd(newlocset, range);
13927 }
13928
13929 /*
13930 * Cleanup
13931 */
13932 if (res != NULL) {
13933 xmlXPathReleaseObject(ctxt->context, res);
13934 }
13935 if (ctxt->value == tmp) {
13936 res = valuePop(ctxt);
13937 xmlXPathReleaseObject(ctxt->context, res);
13938 }
13939
13940 ctxt->context->node = NULL;
13941 }
13942 }
13943 }
13944
13945 /*
13946 * The result is used as the new evaluation set.
13947 */
13948 xmlXPathReleaseObject(ctxt->context, obj);
13949 ctxt->context->node = NULL;
13950 ctxt->context->contextSize = -1;
13951 ctxt->context->proximityPosition = -1;
13952 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13953 return (total);
13954 }
13955 #endif /* LIBXML_XPTR_ENABLED */
13956 }
13957 xmlGenericError(xmlGenericErrorContext,
13958 "XPath: unknown precompiled operation %d\n", op->op);
13959 return (total);
13960 }
13961
13962 /**
13963 * xmlXPathCompOpEvalToBoolean:
13964 * @ctxt: the XPath parser context
13965 *
13966 * Evaluates if the expression evaluates to true.
13967 *
13968 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13969 */
13970 static int
13971 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13972 xmlXPathStepOpPtr op,
13973 int isPredicate)
13974 {
13975 xmlXPathObjectPtr resObj = NULL;
13976
13977 start:
13978 /* comp = ctxt->comp; */
13979 switch (op->op) {
13980 case XPATH_OP_END:
13981 return (0);
13982 case XPATH_OP_VALUE:
13983 resObj = (xmlXPathObjectPtr) op->value4;
13984 if (isPredicate)
13985 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13986 return(xmlXPathCastToBoolean(resObj));
13987 case XPATH_OP_SORT:
13988 /*
13989 * We don't need sorting for boolean results. Skip this one.
13990 */
13991 if (op->ch1 != -1) {
13992 op = &ctxt->comp->steps[op->ch1];
13993 goto start;
13994 }
13995 return(0);
13996 case XPATH_OP_COLLECT:
13997 if (op->ch1 == -1)
13998 return(0);
13999
14000 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14001 if (ctxt->error != XPATH_EXPRESSION_OK)
14002 return(-1);
14003
14004 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14005 if (ctxt->error != XPATH_EXPRESSION_OK)
14006 return(-1);
14007
14008 resObj = valuePop(ctxt);
14009 if (resObj == NULL)
14010 return(-1);
14011 break;
14012 default:
14013 /*
14014 * Fallback to call xmlXPathCompOpEval().
14015 */
14016 xmlXPathCompOpEval(ctxt, op);
14017 if (ctxt->error != XPATH_EXPRESSION_OK)
14018 return(-1);
14019
14020 resObj = valuePop(ctxt);
14021 if (resObj == NULL)
14022 return(-1);
14023 break;
14024 }
14025
14026 if (resObj) {
14027 int res;
14028
14029 if (resObj->type == XPATH_BOOLEAN) {
14030 res = resObj->boolval;
14031 } else if (isPredicate) {
14032 /*
14033 * For predicates a result of type "number" is handled
14034 * differently:
14035 * SPEC XPath 1.0:
14036 * "If the result is a number, the result will be converted
14037 * to true if the number is equal to the context position
14038 * and will be converted to false otherwise;"
14039 */
14040 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14041 } else {
14042 res = xmlXPathCastToBoolean(resObj);
14043 }
14044 xmlXPathReleaseObject(ctxt->context, resObj);
14045 return(res);
14046 }
14047
14048 return(0);
14049 }
14050
14051 #ifdef XPATH_STREAMING
14052 /**
14053 * xmlXPathRunStreamEval:
14054 * @ctxt: the XPath parser context with the compiled expression
14055 *
14056 * Evaluate the Precompiled Streamable XPath expression in the given context.
14057 */
14058 static int
14059 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14060 xmlXPathObjectPtr *resultSeq, int toBool)
14061 {
14062 int max_depth, min_depth;
14063 int from_root;
14064 int ret, depth;
14065 int eval_all_nodes;
14066 xmlNodePtr cur = NULL, limit = NULL;
14067 xmlStreamCtxtPtr patstream = NULL;
14068
14069 int nb_nodes = 0;
14070
14071 if ((ctxt == NULL) || (comp == NULL))
14072 return(-1);
14073 max_depth = xmlPatternMaxDepth(comp);
14074 if (max_depth == -1)
14075 return(-1);
14076 if (max_depth == -2)
14077 max_depth = 10000;
14078 min_depth = xmlPatternMinDepth(comp);
14079 if (min_depth == -1)
14080 return(-1);
14081 from_root = xmlPatternFromRoot(comp);
14082 if (from_root < 0)
14083 return(-1);
14084 #if 0
14085 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14086 #endif
14087
14088 if (! toBool) {
14089 if (resultSeq == NULL)
14090 return(-1);
14091 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14092 if (*resultSeq == NULL)
14093 return(-1);
14094 }
14095
14096 /*
14097 * handle the special cases of "/" amd "." being matched
14098 */
14099 if (min_depth == 0) {
14100 if (from_root) {
14101 /* Select "/" */
14102 if (toBool)
14103 return(1);
14104 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14105 (xmlNodePtr) ctxt->doc);
14106 } else {
14107 /* Select "self::node()" */
14108 if (toBool)
14109 return(1);
14110 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14111 }
14112 }
14113 if (max_depth == 0) {
14114 return(0);
14115 }
14116
14117 if (from_root) {
14118 cur = (xmlNodePtr)ctxt->doc;
14119 } else if (ctxt->node != NULL) {
14120 switch (ctxt->node->type) {
14121 case XML_ELEMENT_NODE:
14122 case XML_DOCUMENT_NODE:
14123 case XML_DOCUMENT_FRAG_NODE:
14124 case XML_HTML_DOCUMENT_NODE:
14125 #ifdef LIBXML_DOCB_ENABLED
14126 case XML_DOCB_DOCUMENT_NODE:
14127 #endif
14128 cur = ctxt->node;
14129 break;
14130 case XML_ATTRIBUTE_NODE:
14131 case XML_TEXT_NODE:
14132 case XML_CDATA_SECTION_NODE:
14133 case XML_ENTITY_REF_NODE:
14134 case XML_ENTITY_NODE:
14135 case XML_PI_NODE:
14136 case XML_COMMENT_NODE:
14137 case XML_NOTATION_NODE:
14138 case XML_DTD_NODE:
14139 case XML_DOCUMENT_TYPE_NODE:
14140 case XML_ELEMENT_DECL:
14141 case XML_ATTRIBUTE_DECL:
14142 case XML_ENTITY_DECL:
14143 case XML_NAMESPACE_DECL:
14144 case XML_XINCLUDE_START:
14145 case XML_XINCLUDE_END:
14146 break;
14147 }
14148 limit = cur;
14149 }
14150 if (cur == NULL) {
14151 return(0);
14152 }
14153
14154 patstream = xmlPatternGetStreamCtxt(comp);
14155 if (patstream == NULL) {
14156 /*
14157 * QUESTION TODO: Is this an error?
14158 */
14159 return(0);
14160 }
14161
14162 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14163
14164 if (from_root) {
14165 ret = xmlStreamPush(patstream, NULL, NULL);
14166 if (ret < 0) {
14167 } else if (ret == 1) {
14168 if (toBool)
14169 goto return_1;
14170 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14171 }
14172 }
14173 depth = 0;
14174 goto scan_children;
14175 next_node:
14176 do {
14177 nb_nodes++;
14178
14179 switch (cur->type) {
14180 case XML_ELEMENT_NODE:
14181 case XML_TEXT_NODE:
14182 case XML_CDATA_SECTION_NODE:
14183 case XML_COMMENT_NODE:
14184 case XML_PI_NODE:
14185 if (cur->type == XML_ELEMENT_NODE) {
14186 ret = xmlStreamPush(patstream, cur->name,
14187 (cur->ns ? cur->ns->href : NULL));
14188 } else if (eval_all_nodes)
14189 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14190 else
14191 break;
14192
14193 if (ret < 0) {
14194 /* NOP. */
14195 } else if (ret == 1) {
14196 if (toBool)
14197 goto return_1;
14198 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14199 }
14200 if ((cur->children == NULL) || (depth >= max_depth)) {
14201 ret = xmlStreamPop(patstream);
14202 while (cur->next != NULL) {
14203 cur = cur->next;
14204 if ((cur->type != XML_ENTITY_DECL) &&
14205 (cur->type != XML_DTD_NODE))
14206 goto next_node;
14207 }
14208 }
14209 default:
14210 break;
14211 }
14212
14213 scan_children:
14214 if ((cur->children != NULL) && (depth < max_depth)) {
14215 /*
14216 * Do not descend on entities declarations
14217 */
14218 if (cur->children->type != XML_ENTITY_DECL) {
14219 cur = cur->children;
14220 depth++;
14221 /*
14222 * Skip DTDs
14223 */
14224 if (cur->type != XML_DTD_NODE)
14225 continue;
14226 }
14227 }
14228
14229 if (cur == limit)
14230 break;
14231
14232 while (cur->next != NULL) {
14233 cur = cur->next;
14234 if ((cur->type != XML_ENTITY_DECL) &&
14235 (cur->type != XML_DTD_NODE))
14236 goto next_node;
14237 }
14238
14239 do {
14240 cur = cur->parent;
14241 depth--;
14242 if ((cur == NULL) || (cur == limit))
14243 goto done;
14244 if (cur->type == XML_ELEMENT_NODE) {
14245 ret = xmlStreamPop(patstream);
14246 } else if ((eval_all_nodes) &&
14247 ((cur->type == XML_TEXT_NODE) ||
14248 (cur->type == XML_CDATA_SECTION_NODE) ||
14249 (cur->type == XML_COMMENT_NODE) ||
14250 (cur->type == XML_PI_NODE)))
14251 {
14252 ret = xmlStreamPop(patstream);
14253 }
14254 if (cur->next != NULL) {
14255 cur = cur->next;
14256 break;
14257 }
14258 } while (cur != NULL);
14259
14260 } while ((cur != NULL) && (depth >= 0));
14261
14262 done:
14263
14264 #if 0
14265 printf("stream eval: checked %d nodes selected %d\n",
14266 nb_nodes, retObj->nodesetval->nodeNr);
14267 #endif
14268
14269 if (patstream)
14270 xmlFreeStreamCtxt(patstream);
14271 return(0);
14272
14273 return_1:
14274 if (patstream)
14275 xmlFreeStreamCtxt(patstream);
14276 return(1);
14277 }
14278 #endif /* XPATH_STREAMING */
14279
14280 /**
14281 * xmlXPathRunEval:
14282 * @ctxt: the XPath parser context with the compiled expression
14283 * @toBool: evaluate to a boolean result
14284 *
14285 * Evaluate the Precompiled XPath expression in the given context.
14286 */
14287 static int
14288 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14289 {
14290 xmlXPathCompExprPtr comp;
14291
14292 if ((ctxt == NULL) || (ctxt->comp == NULL))
14293 return(-1);
14294
14295 if (ctxt->valueTab == NULL) {
14296 /* Allocate the value stack */
14297 ctxt->valueTab = (xmlXPathObjectPtr *)
14298 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14299 if (ctxt->valueTab == NULL) {
14300 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14301 xmlFree(ctxt);
14302 }
14303 ctxt->valueNr = 0;
14304 ctxt->valueMax = 10;
14305 ctxt->value = NULL;
14306 }
14307 #ifdef XPATH_STREAMING
14308 if (ctxt->comp->stream) {
14309 int res;
14310
14311 if (toBool) {
14312 /*
14313 * Evaluation to boolean result.
14314 */
14315 res = xmlXPathRunStreamEval(ctxt->context,
14316 ctxt->comp->stream, NULL, 1);
14317 if (res != -1)
14318 return(res);
14319 } else {
14320 xmlXPathObjectPtr resObj = NULL;
14321
14322 /*
14323 * Evaluation to a sequence.
14324 */
14325 res = xmlXPathRunStreamEval(ctxt->context,
14326 ctxt->comp->stream, &resObj, 0);
14327
14328 if ((res != -1) && (resObj != NULL)) {
14329 valuePush(ctxt, resObj);
14330 return(0);
14331 }
14332 if (resObj != NULL)
14333 xmlXPathReleaseObject(ctxt->context, resObj);
14334 }
14335 /*
14336 * QUESTION TODO: This falls back to normal XPath evaluation
14337 * if res == -1. Is this intended?
14338 */
14339 }
14340 #endif
14341 comp = ctxt->comp;
14342 if (comp->last < 0) {
14343 xmlGenericError(xmlGenericErrorContext,
14344 "xmlXPathRunEval: last is less than zero\n");
14345 return(-1);
14346 }
14347 if (toBool)
14348 return(xmlXPathCompOpEvalToBoolean(ctxt,
14349 &comp->steps[comp->last], 0));
14350 else
14351 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14352
14353 return(0);
14354 }
14355
14356 /************************************************************************
14357 * *
14358 * Public interfaces *
14359 * *
14360 ************************************************************************/
14361
14362 /**
14363 * xmlXPathEvalPredicate:
14364 * @ctxt: the XPath context
14365 * @res: the Predicate Expression evaluation result
14366 *
14367 * Evaluate a predicate result for the current node.
14368 * A PredicateExpr is evaluated by evaluating the Expr and converting
14369 * the result to a boolean. If the result is a number, the result will
14370 * be converted to true if the number is equal to the position of the
14371 * context node in the context node list (as returned by the position
14372 * function) and will be converted to false otherwise; if the result
14373 * is not a number, then the result will be converted as if by a call
14374 * to the boolean function.
14375 *
14376 * Returns 1 if predicate is true, 0 otherwise
14377 */
14378 int
14379 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14380 if ((ctxt == NULL) || (res == NULL)) return(0);
14381 switch (res->type) {
14382 case XPATH_BOOLEAN:
14383 return(res->boolval);
14384 case XPATH_NUMBER:
14385 return(res->floatval == ctxt->proximityPosition);
14386 case XPATH_NODESET:
14387 case XPATH_XSLT_TREE:
14388 if (res->nodesetval == NULL)
14389 return(0);
14390 return(res->nodesetval->nodeNr != 0);
14391 case XPATH_STRING:
14392 return((res->stringval != NULL) &&
14393 (xmlStrlen(res->stringval) != 0));
14394 default:
14395 STRANGE
14396 }
14397 return(0);
14398 }
14399
14400 /**
14401 * xmlXPathEvaluatePredicateResult:
14402 * @ctxt: the XPath Parser context
14403 * @res: the Predicate Expression evaluation result
14404 *
14405 * Evaluate a predicate result for the current node.
14406 * A PredicateExpr is evaluated by evaluating the Expr and converting
14407 * the result to a boolean. If the result is a number, the result will
14408 * be converted to true if the number is equal to the position of the
14409 * context node in the context node list (as returned by the position
14410 * function) and will be converted to false otherwise; if the result
14411 * is not a number, then the result will be converted as if by a call
14412 * to the boolean function.
14413 *
14414 * Returns 1 if predicate is true, 0 otherwise
14415 */
14416 int
14417 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14418 xmlXPathObjectPtr res) {
14419 if ((ctxt == NULL) || (res == NULL)) return(0);
14420 switch (res->type) {
14421 case XPATH_BOOLEAN:
14422 return(res->boolval);
14423 case XPATH_NUMBER:
14424 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14425 return((res->floatval == ctxt->context->proximityPosition) &&
14426 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14427 #else
14428 return(res->floatval == ctxt->context->proximityPosition);
14429 #endif
14430 case XPATH_NODESET:
14431 case XPATH_XSLT_TREE:
14432 if (res->nodesetval == NULL)
14433 return(0);
14434 return(res->nodesetval->nodeNr != 0);
14435 case XPATH_STRING:
14436 return((res->stringval != NULL) && (res->stringval[0] != 0));
14437 #ifdef LIBXML_XPTR_ENABLED
14438 case XPATH_LOCATIONSET:{
14439 xmlLocationSetPtr ptr = res->user;
14440 if (ptr == NULL)
14441 return(0);
14442 return (ptr->locNr != 0);
14443 }
14444 #endif
14445 default:
14446 STRANGE
14447 }
14448 return(0);
14449 }
14450
14451 #ifdef XPATH_STREAMING
14452 /**
14453 * xmlXPathTryStreamCompile:
14454 * @ctxt: an XPath context
14455 * @str: the XPath expression
14456 *
14457 * Try to compile the XPath expression as a streamable subset.
14458 *
14459 * Returns the compiled expression or NULL if failed to compile.
14460 */
14461 static xmlXPathCompExprPtr
14462 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14463 /*
14464 * Optimization: use streaming patterns when the XPath expression can
14465 * be compiled to a stream lookup
14466 */
14467 xmlPatternPtr stream;
14468 xmlXPathCompExprPtr comp;
14469 xmlDictPtr dict = NULL;
14470 const xmlChar **namespaces = NULL;
14471 xmlNsPtr ns;
14472 int i, j;
14473
14474 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14475 (!xmlStrchr(str, '@'))) {
14476 const xmlChar *tmp;
14477
14478 /*
14479 * We don't try to handle expressions using the verbose axis
14480 * specifiers ("::"), just the simplied form at this point.
14481 * Additionally, if there is no list of namespaces available and
14482 * there's a ":" in the expression, indicating a prefixed QName,
14483 * then we won't try to compile either. xmlPatterncompile() needs
14484 * to have a list of namespaces at compilation time in order to
14485 * compile prefixed name tests.
14486 */
14487 tmp = xmlStrchr(str, ':');
14488 if ((tmp != NULL) &&
14489 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14490 return(NULL);
14491
14492 if (ctxt != NULL) {
14493 dict = ctxt->dict;
14494 if (ctxt->nsNr > 0) {
14495 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14496 if (namespaces == NULL) {
14497 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14498 return(NULL);
14499 }
14500 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14501 ns = ctxt->namespaces[j];
14502 namespaces[i++] = ns->href;
14503 namespaces[i++] = ns->prefix;
14504 }
14505 namespaces[i++] = NULL;
14506 namespaces[i] = NULL;
14507 }
14508 }
14509
14510 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14511 &namespaces[0]);
14512 if (namespaces != NULL) {
14513 xmlFree((xmlChar **)namespaces);
14514 }
14515 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14516 comp = xmlXPathNewCompExpr();
14517 if (comp == NULL) {
14518 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14519 return(NULL);
14520 }
14521 comp->stream = stream;
14522 comp->dict = dict;
14523 if (comp->dict)
14524 xmlDictReference(comp->dict);
14525 return(comp);
14526 }
14527 xmlFreePattern(stream);
14528 }
14529 return(NULL);
14530 }
14531 #endif /* XPATH_STREAMING */
14532
14533 static int
14534 xmlXPathCanRewriteDosExpression(xmlChar *expr)
14535 {
14536 if (expr == NULL)
14537 return(0);
14538 do {
14539 if ((*expr == '/') && (*(++expr) == '/'))
14540 return(1);
14541 } while (*expr++);
14542 return(0);
14543 }
14544 static void
14545 xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14546 {
14547 /*
14548 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14549 * internal representation.
14550 */
14551 if (op->ch1 != -1) {
14552 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14553 ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
14554 ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14555 ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14556 {
14557 /*
14558 * This is a "child::foo"
14559 */
14560 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14561
14562 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14563 (prevop->ch1 != -1) &&
14564 ((xmlXPathAxisVal) prevop->value ==
14565 AXIS_DESCENDANT_OR_SELF) &&
14566 (prevop->ch2 == -1) &&
14567 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14568 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
14569 (comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
14570 {
14571 /*
14572 * This is a "/descendant-or-self::node()" without predicates.
14573 * Eliminate it.
14574 */
14575 op->ch1 = prevop->ch1;
14576 op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
14577 }
14578 }
14579 if (op->ch1 != -1)
14580 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14581 }
14582 if (op->ch2 != -1)
14583 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14584 }
14585
14586 /**
14587 * xmlXPathCtxtCompile:
14588 * @ctxt: an XPath context
14589 * @str: the XPath expression
14590 *
14591 * Compile an XPath expression
14592 *
14593 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14594 * the caller has to free the object.
14595 */
14596 xmlXPathCompExprPtr
14597 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14598 xmlXPathParserContextPtr pctxt;
14599 xmlXPathCompExprPtr comp;
14600
14601 #ifdef XPATH_STREAMING
14602 comp = xmlXPathTryStreamCompile(ctxt, str);
14603 if (comp != NULL)
14604 return(comp);
14605 #endif
14606
14607 xmlXPathInit();
14608
14609 pctxt = xmlXPathNewParserContext(str, ctxt);
14610 if (pctxt == NULL)
14611 return NULL;
14612 xmlXPathCompileExpr(pctxt, 1);
14613
14614 if( pctxt->error != XPATH_EXPRESSION_OK )
14615 {
14616 xmlXPathFreeParserContext(pctxt);
14617 return(NULL);
14618 }
14619
14620 if (*pctxt->cur != 0) {
14621 /*
14622 * aleksey: in some cases this line prints *second* error message
14623 * (see bug #78858) and probably this should be fixed.
14624 * However, we are not sure that all error messages are printed
14625 * out in other places. It's not critical so we leave it as-is for now
14626 */
14627 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14628 comp = NULL;
14629 } else {
14630 comp = pctxt->comp;
14631 pctxt->comp = NULL;
14632 }
14633 xmlXPathFreeParserContext(pctxt);
14634
14635 if (comp != NULL) {
14636 comp->expr = xmlStrdup(str);
14637 #ifdef DEBUG_EVAL_COUNTS
14638 comp->string = xmlStrdup(str);
14639 comp->nb = 0;
14640 #endif
14641 if ((comp->expr != NULL) &&
14642 (comp->nbStep > 2) &&
14643 (comp->last >= 0) &&
14644 (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14645 {
14646 xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
14647 }
14648 }
14649 return(comp);
14650 }
14651
14652 /**
14653 * xmlXPathCompile:
14654 * @str: the XPath expression
14655 *
14656 * Compile an XPath expression
14657 *
14658 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14659 * the caller has to free the object.
14660 */
14661 xmlXPathCompExprPtr
14662 xmlXPathCompile(const xmlChar *str) {
14663 return(xmlXPathCtxtCompile(NULL, str));
14664 }
14665
14666 /**
14667 * xmlXPathCompiledEvalInternal:
14668 * @comp: the compiled XPath expression
14669 * @ctxt: the XPath context
14670 * @resObj: the resulting XPath object or NULL
14671 * @toBool: 1 if only a boolean result is requested
14672 *
14673 * Evaluate the Precompiled XPath expression in the given context.
14674 * The caller has to free @resObj.
14675 *
14676 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14677 * the caller has to free the object.
14678 */
14679 static int
14680 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14681 xmlXPathContextPtr ctxt,
14682 xmlXPathObjectPtr *resObj,
14683 int toBool)
14684 {
14685 xmlXPathParserContextPtr pctxt;
14686 #ifndef LIBXML_THREAD_ENABLED
14687 static int reentance = 0;
14688 #endif
14689 int res;
14690
14691 CHECK_CTXT_NEG(ctxt)
14692
14693 if (comp == NULL)
14694 return(-1);
14695 xmlXPathInit();
14696
14697 #ifndef LIBXML_THREAD_ENABLED
14698 reentance++;
14699 if (reentance > 1)
14700 xmlXPathDisableOptimizer = 1;
14701 #endif
14702
14703 #ifdef DEBUG_EVAL_COUNTS
14704 comp->nb++;
14705 if ((comp->string != NULL) && (comp->nb > 100)) {
14706 fprintf(stderr, "100 x %s\n", comp->string);
14707 comp->nb = 0;
14708 }
14709 #endif
14710 pctxt = xmlXPathCompParserContext(comp, ctxt);
14711 res = xmlXPathRunEval(pctxt, toBool);
14712
14713 if (resObj) {
14714 if (pctxt->value == NULL) {
14715 xmlGenericError(xmlGenericErrorContext,
14716 "xmlXPathCompiledEval: evaluation failed\n");
14717 *resObj = NULL;
14718 } else {
14719 *resObj = valuePop(pctxt);
14720 }
14721 }
14722
14723 /*
14724 * Pop all remaining objects from the stack.
14725 */
14726 if (pctxt->valueNr > 0) {
14727 xmlXPathObjectPtr tmp;
14728 int stack = 0;
14729
14730 do {
14731 tmp = valuePop(pctxt);
14732 if (tmp != NULL) {
14733 stack++;
14734 xmlXPathReleaseObject(ctxt, tmp);
14735 }
14736 } while (tmp != NULL);
14737 if ((stack != 0) &&
14738 ((toBool) || ((resObj) && (*resObj))))
14739 {
14740 xmlGenericError(xmlGenericErrorContext,
14741 "xmlXPathCompiledEval: %d objects left on the stack.\n",
14742 stack);
14743 }
14744 }
14745
14746 if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14747 xmlXPathFreeObject(*resObj);
14748 *resObj = NULL;
14749 }
14750 pctxt->comp = NULL;
14751 xmlXPathFreeParserContext(pctxt);
14752 #ifndef LIBXML_THREAD_ENABLED
14753 reentance--;
14754 #endif
14755
14756 return(res);
14757 }
14758
14759 /**
14760 * xmlXPathCompiledEval:
14761 * @comp: the compiled XPath expression
14762 * @ctx: the XPath context
14763 *
14764 * Evaluate the Precompiled XPath expression in the given context.
14765 *
14766 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14767 * the caller has to free the object.
14768 */
14769 xmlXPathObjectPtr
14770 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14771 {
14772 xmlXPathObjectPtr res = NULL;
14773
14774 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14775 return(res);
14776 }
14777
14778 /**
14779 * xmlXPathCompiledEvalToBoolean:
14780 * @comp: the compiled XPath expression
14781 * @ctxt: the XPath context
14782 *
14783 * Applies the XPath boolean() function on the result of the given
14784 * compiled expression.
14785 *
14786 * Returns 1 if the expression evaluated to true, 0 if to false and
14787 * -1 in API and internal errors.
14788 */
14789 int
14790 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14791 xmlXPathContextPtr ctxt)
14792 {
14793 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14794 }
14795
14796 /**
14797 * xmlXPathEvalExpr:
14798 * @ctxt: the XPath Parser context
14799 *
14800 * Parse and evaluate an XPath expression in the given context,
14801 * then push the result on the context stack
14802 */
14803 void
14804 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14805 #ifdef XPATH_STREAMING
14806 xmlXPathCompExprPtr comp;
14807 #endif
14808
14809 if (ctxt == NULL) return;
14810
14811 #ifdef XPATH_STREAMING
14812 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14813 if (comp != NULL) {
14814 if (ctxt->comp != NULL)
14815 xmlXPathFreeCompExpr(ctxt->comp);
14816 ctxt->comp = comp;
14817 if (ctxt->cur != NULL)
14818 while (*ctxt->cur != 0) ctxt->cur++;
14819 } else
14820 #endif
14821 {
14822 xmlXPathCompileExpr(ctxt, 1);
14823 /*
14824 * In this scenario the expression string will sit in ctxt->base.
14825 */
14826 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14827 (ctxt->comp != NULL) &&
14828 (ctxt->base != NULL) &&
14829 (ctxt->comp->nbStep > 2) &&
14830 (ctxt->comp->last >= 0) &&
14831 (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
14832 {
14833 xmlXPathRewriteDOSExpression(ctxt->comp,
14834 &ctxt->comp->steps[ctxt->comp->last]);
14835 }
14836 }
14837 CHECK_ERROR;
14838 xmlXPathRunEval(ctxt, 0);
14839 }
14840
14841 /**
14842 * xmlXPathEval:
14843 * @str: the XPath expression
14844 * @ctx: the XPath context
14845 *
14846 * Evaluate the XPath Location Path in the given context.
14847 *
14848 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14849 * the caller has to free the object.
14850 */
14851 xmlXPathObjectPtr
14852 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14853 xmlXPathParserContextPtr ctxt;
14854 xmlXPathObjectPtr res, tmp, init = NULL;
14855 int stack = 0;
14856
14857 CHECK_CTXT(ctx)
14858
14859 xmlXPathInit();
14860
14861 ctxt = xmlXPathNewParserContext(str, ctx);
14862 if (ctxt == NULL)
14863 return NULL;
14864 xmlXPathEvalExpr(ctxt);
14865
14866 if (ctxt->value == NULL) {
14867 xmlGenericError(xmlGenericErrorContext,
14868 "xmlXPathEval: evaluation failed\n");
14869 res = NULL;
14870 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
14871 #ifdef XPATH_STREAMING
14872 && (ctxt->comp->stream == NULL)
14873 #endif
14874 ) {
14875 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14876 res = NULL;
14877 } else {
14878 res = valuePop(ctxt);
14879 }
14880
14881 do {
14882 tmp = valuePop(ctxt);
14883 if (tmp != NULL) {
14884 if (tmp != init)
14885 stack++;
14886 xmlXPathReleaseObject(ctx, tmp);
14887 }
14888 } while (tmp != NULL);
14889 if ((stack != 0) && (res != NULL)) {
14890 xmlGenericError(xmlGenericErrorContext,
14891 "xmlXPathEval: %d object left on the stack\n",
14892 stack);
14893 }
14894 if (ctxt->error != XPATH_EXPRESSION_OK) {
14895 xmlXPathFreeObject(res);
14896 res = NULL;
14897 }
14898
14899 xmlXPathFreeParserContext(ctxt);
14900 return(res);
14901 }
14902
14903 /**
14904 * xmlXPathEvalExpression:
14905 * @str: the XPath expression
14906 * @ctxt: the XPath context
14907 *
14908 * Evaluate the XPath expression in the given context.
14909 *
14910 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14911 * the caller has to free the object.
14912 */
14913 xmlXPathObjectPtr
14914 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14915 xmlXPathParserContextPtr pctxt;
14916 xmlXPathObjectPtr res, tmp;
14917 int stack = 0;
14918
14919 CHECK_CTXT(ctxt)
14920
14921 xmlXPathInit();
14922
14923 pctxt = xmlXPathNewParserContext(str, ctxt);
14924 if (pctxt == NULL)
14925 return NULL;
14926 xmlXPathEvalExpr(pctxt);
14927
14928 if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
14929 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14930 res = NULL;
14931 } else {
14932 res = valuePop(pctxt);
14933 }
14934 do {
14935 tmp = valuePop(pctxt);
14936 if (tmp != NULL) {
14937 xmlXPathReleaseObject(ctxt, tmp);
14938 stack++;
14939 }
14940 } while (tmp != NULL);
14941 if ((stack != 0) && (res != NULL)) {
14942 xmlGenericError(xmlGenericErrorContext,
14943 "xmlXPathEvalExpression: %d object left on the stack\n",
14944 stack);
14945 }
14946 xmlXPathFreeParserContext(pctxt);
14947 return(res);
14948 }
14949
14950 /************************************************************************
14951 * *
14952 * Extra functions not pertaining to the XPath spec *
14953 * *
14954 ************************************************************************/
14955 /**
14956 * xmlXPathEscapeUriFunction:
14957 * @ctxt: the XPath Parser context
14958 * @nargs: the number of arguments
14959 *
14960 * Implement the escape-uri() XPath function
14961 * string escape-uri(string $str, bool $escape-reserved)
14962 *
14963 * This function applies the URI escaping rules defined in section 2 of [RFC
14964 * 2396] to the string supplied as $uri-part, which typically represents all
14965 * or part of a URI. The effect of the function is to replace any special
14966 * character in the string by an escape sequence of the form %xx%yy...,
14967 * where xxyy... is the hexadecimal representation of the octets used to
14968 * represent the character in UTF-8.
14969 *
14970 * The set of characters that are escaped depends on the setting of the
14971 * boolean argument $escape-reserved.
14972 *
14973 * If $escape-reserved is true, all characters are escaped other than lower
14974 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14975 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14976 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14977 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14978 * A-F).
14979 *
14980 * If $escape-reserved is false, the behavior differs in that characters
14981 * referred to in [RFC 2396] as reserved characters are not escaped. These
14982 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14983 *
14984 * [RFC 2396] does not define whether escaped URIs should use lower case or
14985 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14986 * compared using string comparison functions, this function must always use
14987 * the upper-case letters A-F.
14988 *
14989 * Generally, $escape-reserved should be set to true when escaping a string
14990 * that is to form a single part of a URI, and to false when escaping an
14991 * entire URI or URI reference.
14992 *
14993 * In the case of non-ascii characters, the string is encoded according to
14994 * utf-8 and then converted according to RFC 2396.
14995 *
14996 * Examples
14997 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14998 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14999 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15000 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15001 *
15002 */
15003 static void
15004 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15005 xmlXPathObjectPtr str;
15006 int escape_reserved;
15007 xmlBufferPtr target;
15008 xmlChar *cptr;
15009 xmlChar escape[4];
15010
15011 CHECK_ARITY(2);
15012
15013 escape_reserved = xmlXPathPopBoolean(ctxt);
15014
15015 CAST_TO_STRING;
15016 str = valuePop(ctxt);
15017
15018 target = xmlBufferCreate();
15019
15020 escape[0] = '%';
15021 escape[3] = 0;
15022
15023 if (target) {
15024 for (cptr = str->stringval; *cptr; cptr++) {
15025 if ((*cptr >= 'A' && *cptr <= 'Z') ||
15026 (*cptr >= 'a' && *cptr <= 'z') ||
15027 (*cptr >= '0' && *cptr <= '9') ||
15028 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
15029 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
15030 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
15031 (*cptr == '%' &&
15032 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15033 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15034 (cptr[1] >= '0' && cptr[1] <= '9')) &&
15035 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15036 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15037 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15038 (!escape_reserved &&
15039 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15040 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15041 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15042 *cptr == ','))) {
15043 xmlBufferAdd(target, cptr, 1);
15044 } else {
15045 if ((*cptr >> 4) < 10)
15046 escape[1] = '0' + (*cptr >> 4);
15047 else
15048 escape[1] = 'A' - 10 + (*cptr >> 4);
15049 if ((*cptr & 0xF) < 10)
15050 escape[2] = '0' + (*cptr & 0xF);
15051 else
15052 escape[2] = 'A' - 10 + (*cptr & 0xF);
15053
15054 xmlBufferAdd(target, &escape[0], 3);
15055 }
15056 }
15057 }
15058 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15059 xmlBufferContent(target)));
15060 xmlBufferFree(target);
15061 xmlXPathReleaseObject(ctxt->context, str);
15062 }
15063
15064 /**
15065 * xmlXPathRegisterAllFunctions:
15066 * @ctxt: the XPath context
15067 *
15068 * Registers all default XPath functions in this context
15069 */
15070 void
15071 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15072 {
15073 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15074 xmlXPathBooleanFunction);
15075 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15076 xmlXPathCeilingFunction);
15077 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15078 xmlXPathCountFunction);
15079 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15080 xmlXPathConcatFunction);
15081 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15082 xmlXPathContainsFunction);
15083 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15084 xmlXPathIdFunction);
15085 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15086 xmlXPathFalseFunction);
15087 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15088 xmlXPathFloorFunction);
15089 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15090 xmlXPathLastFunction);
15091 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15092 xmlXPathLangFunction);
15093 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15094 xmlXPathLocalNameFunction);
15095 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15096 xmlXPathNotFunction);
15097 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15098 xmlXPathNameFunction);
15099 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15100 xmlXPathNamespaceURIFunction);
15101 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15102 xmlXPathNormalizeFunction);
15103 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15104 xmlXPathNumberFunction);
15105 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15106 xmlXPathPositionFunction);
15107 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15108 xmlXPathRoundFunction);
15109 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15110 xmlXPathStringFunction);
15111 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15112 xmlXPathStringLengthFunction);
15113 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15114 xmlXPathStartsWithFunction);
15115 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15116 xmlXPathSubstringFunction);
15117 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15118 xmlXPathSubstringBeforeFunction);
15119 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15120 xmlXPathSubstringAfterFunction);
15121 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15122 xmlXPathSumFunction);
15123 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15124 xmlXPathTrueFunction);
15125 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15126 xmlXPathTranslateFunction);
15127
15128 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15129 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15130 xmlXPathEscapeUriFunction);
15131 }
15132
15133 #endif /* LIBXML_XPATH_ENABLED */
15134 #define bottom_xpath
15135 #include "elfgcchack.h"