VirtualBox

source: vbox/trunk/src/libs/libxml2-2.6.31/xpath.c@ 39954

Last change on this file since 39954 was 39921, checked in by vboxsync, 13 years ago

libxml-2.6.31 upstream fixes

  • Property svn:eol-style set to native
File size: 411.3 KB
Line 
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: [email protected]
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 */
115double xmlXPathNAN = 0;
116double xmlXPathPINF = 1;
117double xmlXPathNINF = -1;
118static double xmlXPathNZERO = 0; /* not exported from headers */
119static int xmlXPathInitialized = 0;
120
121/**
122 * xmlXPathInit:
123 *
124 * Initialize the XPath environment
125 */
126void
127xmlXPathInit(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 */
148int
149xmlXPathIsNaN(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 */
163int
164xmlXPathIsInf(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 */
180static int
181xmlXPathGetSign(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/* #define DEBUG */
191/* #define DEBUG_STEP */
192/* #define DEBUG_STEP_NTH */
193/* #define DEBUG_EXPR */
194/* #define DEBUG_EVAL_COUNTS */
195
196static xmlNs xmlXPathXMLNamespaceStruct = {
197 NULL,
198 XML_NAMESPACE_DECL,
199 XML_XML_NAMESPACE,
200 BAD_CAST "xml",
201 NULL,
202 NULL
203};
204static 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 */
210static 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 */
231static 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 */
266static void
267xmlXPathErrMemory(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 */
308static void
309xmlXPathPErrMemory(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 */
326void
327xmlXPathErr(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 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 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 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 */
386void
387xmlXPatherror(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 */
403typedef struct _xmlPointerList xmlPointerList;
404typedef xmlPointerList *xmlPointerListPtr;
405struct _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*/
414static int
415xmlPointerListAddSize(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 */
453static xmlPointerListPtr
454xmlPointerListCreate(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 */
478static void
479xmlPointerListFree(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
498typedef 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
523typedef 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
539typedef 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
548typedef 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
557typedef struct _xmlXPathStepOp xmlXPathStepOp;
558typedef xmlXPathStepOp *xmlXPathStepOpPtr;
559struct _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
573struct _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 ************************************************************************/
594static void
595xmlXPathFreeValueTree(xmlNodeSetPtr obj);
596static void
597xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
598static int
599xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
600 xmlXPathStepOpPtr op, xmlNodePtr *first);
601static int
602xmlXPathCompOpEvalToBoolean(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 */
619static xmlXPathCompExprPtr
620xmlXPathNewCompExpr(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 */
652void
653xmlXPathFreeCompExpr(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 */
718static int
719xmlXPathCompExprAdd(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 */
773static void
774xmlXPathCompSwap(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) \
800xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
801
802#define PUSH_UNARY_EXPR(op, ch, val, val2) \
803xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
804
805#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
806xmlXPathCompExprAdd(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
819typedef struct _xmlXPathContextCache xmlXPathContextCache;
820typedef xmlXPathContextCache *xmlXPathContextCachePtr;
821struct _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
873static void
874xmlXPathDebugDumpNode(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, 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, 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}
897static void
898xmlXPathDebugDumpNodeList(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, 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
920static void
921xmlXPathDebugDumpNodeSet(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, 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, shift);
940 fprintf(output, "%d", i + 1);
941 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
942 }
943 }
944}
945
946static void
947xmlXPathDebugDumpValueTree(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, shift);
957 fprintf(output, "Value Tree is NULL !\n");
958 return;
959
960 }
961
962 fprintf(output, shift);
963 fprintf(output, "%d", i + 1);
964 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
965}
966#if defined(LIBXML_XPTR_ENABLED)
967static void
968xmlXPathDebugDumpLocationSet(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, shift);
978 fprintf(output, "LocationSet is NULL !\n");
979 return;
980
981 }
982
983 for (i = 0;i < cur->locNr;i++) {
984 fprintf(output, 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 */
999void
1000xmlXPathDebugDumpObject(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, 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, 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, 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, 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
1104static void
1105xmlXPathDebugDumpStepOp(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, 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");
1274finish:
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 */
1289void
1290xmlXPathDebugDumpCompExpr(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, 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*/
1314static int xmlXPathDebugObjCounterUndefined = 0;
1315static int xmlXPathDebugObjCounterNodeset = 0;
1316static int xmlXPathDebugObjCounterBool = 0;
1317static int xmlXPathDebugObjCounterNumber = 0;
1318static int xmlXPathDebugObjCounterString = 0;
1319static int xmlXPathDebugObjCounterPoint = 0;
1320static int xmlXPathDebugObjCounterRange = 0;
1321static int xmlXPathDebugObjCounterLocset = 0;
1322static int xmlXPathDebugObjCounterUsers = 0;
1323static int xmlXPathDebugObjCounterXSLTTree = 0;
1324static int xmlXPathDebugObjCounterAll = 0;
1325
1326static int xmlXPathDebugObjTotalUndefined = 0;
1327static int xmlXPathDebugObjTotalNodeset = 0;
1328static int xmlXPathDebugObjTotalBool = 0;
1329static int xmlXPathDebugObjTotalNumber = 0;
1330static int xmlXPathDebugObjTotalString = 0;
1331static int xmlXPathDebugObjTotalPoint = 0;
1332static int xmlXPathDebugObjTotalRange = 0;
1333static int xmlXPathDebugObjTotalLocset = 0;
1334static int xmlXPathDebugObjTotalUsers = 0;
1335static int xmlXPathDebugObjTotalXSLTTree = 0;
1336static int xmlXPathDebugObjTotalAll = 0;
1337
1338static int xmlXPathDebugObjMaxUndefined = 0;
1339static int xmlXPathDebugObjMaxNodeset = 0;
1340static int xmlXPathDebugObjMaxBool = 0;
1341static int xmlXPathDebugObjMaxNumber = 0;
1342static int xmlXPathDebugObjMaxString = 0;
1343static int xmlXPathDebugObjMaxPoint = 0;
1344static int xmlXPathDebugObjMaxRange = 0;
1345static int xmlXPathDebugObjMaxLocset = 0;
1346static int xmlXPathDebugObjMaxUsers = 0;
1347static int xmlXPathDebugObjMaxXSLTTree = 0;
1348static int xmlXPathDebugObjMaxAll = 0;
1349
1350/* REVISIT TODO: Make this static when committing */
1351static void
1352xmlXPathDebugObjUsageReset(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
1423static void
1424xmlXPathDebugObjUsageRequested(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
1577static void
1578xmlXPathDebugObjUsageReleased(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 */
1666static void
1667xmlXPathDebugObjUsageDisplay(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 */
1790static xmlXPathContextCachePtr
1791xmlXPathNewCache(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
1809static void
1810xmlXPathCacheFreeObjectList(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
1837static void
1838xmlXPathFreeCache(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 */
1877int
1878xmlXPathContextSetCache(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 */
1920static xmlXPathObjectPtr
1921xmlXPathCacheWrapNodeSet(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 */
1957static xmlXPathObjectPtr
1958xmlXPathCacheWrapString(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 */
2009static xmlXPathObjectPtr
2010xmlXPathCacheNewNodeSet(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 */
2073static xmlXPathObjectPtr
2074xmlXPathCacheNewCString(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 */
2122static xmlXPathObjectPtr
2123xmlXPathCacheNewString(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 */
2176static xmlXPathObjectPtr
2177xmlXPathCacheNewBoolean(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 */
2224static xmlXPathObjectPtr
2225xmlXPathCacheNewFloat(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
2274static xmlXPathObjectPtr
2275xmlXPathCacheConvertString(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 */
2322static xmlXPathObjectPtr
2323xmlXPathCacheObjectCopy(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 */
2357static xmlXPathObjectPtr
2358xmlXPathCacheConvertBoolean(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 */
2381static xmlXPathObjectPtr
2382xmlXPathCacheConvertNumber(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 */
2408xmlXPathObjectPtr
2409valuePop(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 */
2433int
2434valuePush(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 ctxt->error = XPATH_MEMORY_ERROR;
2446 return (0);
2447 }
2448 ctxt->valueMax *= 2;
2449 ctxt->valueTab = tmp;
2450 }
2451 ctxt->valueTab[ctxt->valueNr] = value;
2452 ctxt->value = value;
2453 return (ctxt->valueNr++);
2454}
2455
2456/**
2457 * xmlXPathPopBoolean:
2458 * @ctxt: an XPath parser context
2459 *
2460 * Pops a boolean from the stack, handling conversion if needed.
2461 * Check error with #xmlXPathCheckError.
2462 *
2463 * Returns the boolean
2464 */
2465int
2466xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2467 xmlXPathObjectPtr obj;
2468 int ret;
2469
2470 obj = valuePop(ctxt);
2471 if (obj == NULL) {
2472 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2473 return(0);
2474 }
2475 if (obj->type != XPATH_BOOLEAN)
2476 ret = xmlXPathCastToBoolean(obj);
2477 else
2478 ret = obj->boolval;
2479 xmlXPathReleaseObject(ctxt->context, obj);
2480 return(ret);
2481}
2482
2483/**
2484 * xmlXPathPopNumber:
2485 * @ctxt: an XPath parser context
2486 *
2487 * Pops a number from the stack, handling conversion if needed.
2488 * Check error with #xmlXPathCheckError.
2489 *
2490 * Returns the number
2491 */
2492double
2493xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2494 xmlXPathObjectPtr obj;
2495 double ret;
2496
2497 obj = valuePop(ctxt);
2498 if (obj == NULL) {
2499 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2500 return(0);
2501 }
2502 if (obj->type != XPATH_NUMBER)
2503 ret = xmlXPathCastToNumber(obj);
2504 else
2505 ret = obj->floatval;
2506 xmlXPathReleaseObject(ctxt->context, obj);
2507 return(ret);
2508}
2509
2510/**
2511 * xmlXPathPopString:
2512 * @ctxt: an XPath parser context
2513 *
2514 * Pops a string from the stack, handling conversion if needed.
2515 * Check error with #xmlXPathCheckError.
2516 *
2517 * Returns the string
2518 */
2519xmlChar *
2520xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2521 xmlXPathObjectPtr obj;
2522 xmlChar * ret;
2523
2524 obj = valuePop(ctxt);
2525 if (obj == NULL) {
2526 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2527 return(NULL);
2528 }
2529 ret = xmlXPathCastToString(obj); /* this does required strdup */
2530 /* TODO: needs refactoring somewhere else */
2531 if (obj->stringval == ret)
2532 obj->stringval = NULL;
2533 xmlXPathReleaseObject(ctxt->context, obj);
2534 return(ret);
2535}
2536
2537/**
2538 * xmlXPathPopNodeSet:
2539 * @ctxt: an XPath parser context
2540 *
2541 * Pops a node-set from the stack, handling conversion if needed.
2542 * Check error with #xmlXPathCheckError.
2543 *
2544 * Returns the node-set
2545 */
2546xmlNodeSetPtr
2547xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2548 xmlXPathObjectPtr obj;
2549 xmlNodeSetPtr ret;
2550
2551 if (ctxt == NULL) return(NULL);
2552 if (ctxt->value == NULL) {
2553 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2554 return(NULL);
2555 }
2556 if (!xmlXPathStackIsNodeSet(ctxt)) {
2557 xmlXPathSetTypeError(ctxt);
2558 return(NULL);
2559 }
2560 obj = valuePop(ctxt);
2561 ret = obj->nodesetval;
2562#if 0
2563 /* to fix memory leak of not clearing obj->user */
2564 if (obj->boolval && obj->user != NULL)
2565 xmlFreeNodeList((xmlNodePtr) obj->user);
2566#endif
2567 obj->nodesetval = NULL;
2568 xmlXPathReleaseObject(ctxt->context, obj);
2569 return(ret);
2570}
2571
2572/**
2573 * xmlXPathPopExternal:
2574 * @ctxt: an XPath parser context
2575 *
2576 * Pops an external object from the stack, handling conversion if needed.
2577 * Check error with #xmlXPathCheckError.
2578 *
2579 * Returns the object
2580 */
2581void *
2582xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2583 xmlXPathObjectPtr obj;
2584 void * ret;
2585
2586 if ((ctxt == NULL) || (ctxt->value == NULL)) {
2587 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2588 return(NULL);
2589 }
2590 if (ctxt->value->type != XPATH_USERS) {
2591 xmlXPathSetTypeError(ctxt);
2592 return(NULL);
2593 }
2594 obj = valuePop(ctxt);
2595 ret = obj->user;
2596 obj->user = NULL;
2597 xmlXPathReleaseObject(ctxt->context, obj);
2598 return(ret);
2599}
2600
2601/*
2602 * Macros for accessing the content. Those should be used only by the parser,
2603 * and not exported.
2604 *
2605 * Dirty macros, i.e. one need to make assumption on the context to use them
2606 *
2607 * CUR_PTR return the current pointer to the xmlChar to be parsed.
2608 * CUR returns the current xmlChar value, i.e. a 8 bit value
2609 * in ISO-Latin or UTF-8.
2610 * This should be used internally by the parser
2611 * only to compare to ASCII values otherwise it would break when
2612 * running with UTF-8 encoding.
2613 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
2614 * to compare on ASCII based substring.
2615 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2616 * strings within the parser.
2617 * CURRENT Returns the current char value, with the full decoding of
2618 * UTF-8 if we are using this mode. It returns an int.
2619 * NEXT Skip to the next character, this does the proper decoding
2620 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
2621 * It returns the pointer to the current xmlChar.
2622 */
2623
2624#define CUR (*ctxt->cur)
2625#define SKIP(val) ctxt->cur += (val)
2626#define NXT(val) ctxt->cur[(val)]
2627#define CUR_PTR ctxt->cur
2628#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2629
2630#define COPY_BUF(l,b,i,v) \
2631 if (l == 1) b[i++] = (xmlChar) v; \
2632 else i += xmlCopyChar(l,&b[i],v)
2633
2634#define NEXTL(l) ctxt->cur += l
2635
2636#define SKIP_BLANKS \
2637 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2638
2639#define CURRENT (*ctxt->cur)
2640#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
2641
2642
2643#ifndef DBL_DIG
2644#define DBL_DIG 16
2645#endif
2646#ifndef DBL_EPSILON
2647#define DBL_EPSILON 1E-9
2648#endif
2649
2650#define UPPER_DOUBLE 1E9
2651#define LOWER_DOUBLE 1E-5
2652#define LOWER_DOUBLE_EXP 5
2653
2654#define INTEGER_DIGITS DBL_DIG
2655#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
2656#define EXPONENT_DIGITS (3 + 2)
2657
2658/**
2659 * xmlXPathFormatNumber:
2660 * @number: number to format
2661 * @buffer: output buffer
2662 * @buffersize: size of output buffer
2663 *
2664 * Convert the number into a string representation.
2665 */
2666static void
2667xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2668{
2669 switch (xmlXPathIsInf(number)) {
2670 case 1:
2671 if (buffersize > (int)sizeof("Infinity"))
2672 snprintf(buffer, buffersize, "Infinity");
2673 break;
2674 case -1:
2675 if (buffersize > (int)sizeof("-Infinity"))
2676 snprintf(buffer, buffersize, "-Infinity");
2677 break;
2678 default:
2679 if (xmlXPathIsNaN(number)) {
2680 if (buffersize > (int)sizeof("NaN"))
2681 snprintf(buffer, buffersize, "NaN");
2682 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
2683 snprintf(buffer, buffersize, "0");
2684 } else if (number == ((int) number)) {
2685 char work[30];
2686 char *ptr, *cur;
2687 int value = (int) number;
2688
2689 ptr = &buffer[0];
2690 if (value == 0) {
2691 *ptr++ = '0';
2692 } else {
2693 snprintf(work, 29, "%d", value);
2694 cur = &work[0];
2695 while ((*cur) && (ptr - buffer < buffersize)) {
2696 *ptr++ = *cur++;
2697 }
2698 }
2699 if (ptr - buffer < buffersize) {
2700 *ptr = 0;
2701 } else if (buffersize > 0) {
2702 ptr--;
2703 *ptr = 0;
2704 }
2705 } else {
2706 /*
2707 For the dimension of work,
2708 DBL_DIG is number of significant digits
2709 EXPONENT is only needed for "scientific notation"
2710 3 is sign, decimal point, and terminating zero
2711 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2712 Note that this dimension is slightly (a few characters)
2713 larger than actually necessary.
2714 */
2715 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2716 int integer_place, fraction_place;
2717 char *ptr;
2718 char *after_fraction;
2719 double absolute_value;
2720 int size;
2721
2722 absolute_value = fabs(number);
2723
2724 /*
2725 * First choose format - scientific or regular floating point.
2726 * In either case, result is in work, and after_fraction points
2727 * just past the fractional part.
2728 */
2729 if ( ((absolute_value > UPPER_DOUBLE) ||
2730 (absolute_value < LOWER_DOUBLE)) &&
2731 (absolute_value != 0.0) ) {
2732 /* Use scientific notation */
2733 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2734 fraction_place = DBL_DIG - 1;
2735 size = snprintf(work, sizeof(work),"%*.*e",
2736 integer_place, fraction_place, number);
2737 while ((size > 0) && (work[size] != 'e')) size--;
2738
2739 }
2740 else {
2741 /* Use regular notation */
2742 if (absolute_value > 0.0) {
2743 integer_place = (int)log10(absolute_value);
2744 if (integer_place > 0)
2745 fraction_place = DBL_DIG - integer_place - 1;
2746 else
2747 fraction_place = DBL_DIG - integer_place;
2748 } else {
2749 fraction_place = 1;
2750 }
2751 size = snprintf(work, sizeof(work), "%0.*f",
2752 fraction_place, number);
2753 }
2754
2755 /* Remove fractional trailing zeroes */
2756 after_fraction = work + size;
2757 ptr = after_fraction;
2758 while (*(--ptr) == '0')
2759 ;
2760 if (*ptr != '.')
2761 ptr++;
2762 while ((*ptr++ = *after_fraction++) != 0);
2763
2764 /* Finally copy result back to caller */
2765 size = strlen(work) + 1;
2766 if (size > buffersize) {
2767 work[buffersize - 1] = 0;
2768 size = buffersize;
2769 }
2770 memmove(buffer, work, size);
2771 }
2772 break;
2773 }
2774}
2775
2776
2777/************************************************************************
2778 * *
2779 * Routines to handle NodeSets *
2780 * *
2781 ************************************************************************/
2782
2783/**
2784 * xmlXPathOrderDocElems:
2785 * @doc: an input document
2786 *
2787 * Call this routine to speed up XPath computation on static documents.
2788 * This stamps all the element nodes with the document order
2789 * Like for line information, the order is kept in the element->content
2790 * field, the value stored is actually - the node number (starting at -1)
2791 * to be able to differentiate from line numbers.
2792 *
2793 * Returns the number of elements found in the document or -1 in case
2794 * of error.
2795 */
2796long
2797xmlXPathOrderDocElems(xmlDocPtr doc) {
2798 long count = 0;
2799 xmlNodePtr cur;
2800
2801 if (doc == NULL)
2802 return(-1);
2803 cur = doc->children;
2804 while (cur != NULL) {
2805 if (cur->type == XML_ELEMENT_NODE) {
2806 cur->content = (void *) (-(++count));
2807 if (cur->children != NULL) {
2808 cur = cur->children;
2809 continue;
2810 }
2811 }
2812 if (cur->next != NULL) {
2813 cur = cur->next;
2814 continue;
2815 }
2816 do {
2817 cur = cur->parent;
2818 if (cur == NULL)
2819 break;
2820 if (cur == (xmlNodePtr) doc) {
2821 cur = NULL;
2822 break;
2823 }
2824 if (cur->next != NULL) {
2825 cur = cur->next;
2826 break;
2827 }
2828 } while (cur != NULL);
2829 }
2830 return(count);
2831}
2832
2833/**
2834 * xmlXPathCmpNodes:
2835 * @node1: the first node
2836 * @node2: the second node
2837 *
2838 * Compare two nodes w.r.t document order
2839 *
2840 * Returns -2 in case of error 1 if first point < second point, 0 if
2841 * it's the same node, -1 otherwise
2842 */
2843int
2844xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2845 int depth1, depth2;
2846 int attr1 = 0, attr2 = 0;
2847 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
2848 xmlNodePtr cur, root;
2849
2850 if ((node1 == NULL) || (node2 == NULL))
2851 return(-2);
2852 /*
2853 * a couple of optimizations which will avoid computations in most cases
2854 */
2855 if (node1 == node2) /* trivial case */
2856 return(0);
2857 if (node1->type == XML_ATTRIBUTE_NODE) {
2858 attr1 = 1;
2859 attrNode1 = node1;
2860 node1 = node1->parent;
2861 }
2862 if (node2->type == XML_ATTRIBUTE_NODE) {
2863 attr2 = 1;
2864 attrNode2 = node2;
2865 node2 = node2->parent;
2866 }
2867 if (node1 == node2) {
2868 if (attr1 == attr2) {
2869 /* not required, but we keep attributes in order */
2870 if (attr1 != 0) {
2871 cur = attrNode2->prev;
2872 while (cur != NULL) {
2873 if (cur == attrNode1)
2874 return (1);
2875 cur = cur->prev;
2876 }
2877 return (-1);
2878 }
2879 return(0);
2880 }
2881 if (attr2 == 1)
2882 return(1);
2883 return(-1);
2884 }
2885 if ((node1->type == XML_NAMESPACE_DECL) ||
2886 (node2->type == XML_NAMESPACE_DECL))
2887 return(1);
2888 if (node1 == node2->prev)
2889 return(1);
2890 if (node1 == node2->next)
2891 return(-1);
2892
2893 /*
2894 * Speedup using document order if availble.
2895 */
2896 if ((node1->type == XML_ELEMENT_NODE) &&
2897 (node2->type == XML_ELEMENT_NODE) &&
2898 (0 > (long) node1->content) &&
2899 (0 > (long) node2->content) &&
2900 (node1->doc == node2->doc)) {
2901 long l1, l2;
2902
2903 l1 = -((long) node1->content);
2904 l2 = -((long) node2->content);
2905 if (l1 < l2)
2906 return(1);
2907 if (l1 > l2)
2908 return(-1);
2909 }
2910
2911 /*
2912 * compute depth to root
2913 */
2914 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2915 if (cur == node1)
2916 return(1);
2917 depth2++;
2918 }
2919 root = cur;
2920 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2921 if (cur == node2)
2922 return(-1);
2923 depth1++;
2924 }
2925 /*
2926 * Distinct document (or distinct entities :-( ) case.
2927 */
2928 if (root != cur) {
2929 return(-2);
2930 }
2931 /*
2932 * get the nearest common ancestor.
2933 */
2934 while (depth1 > depth2) {
2935 depth1--;
2936 node1 = node1->parent;
2937 }
2938 while (depth2 > depth1) {
2939 depth2--;
2940 node2 = node2->parent;
2941 }
2942 while (node1->parent != node2->parent) {
2943 node1 = node1->parent;
2944 node2 = node2->parent;
2945 /* should not happen but just in case ... */
2946 if ((node1 == NULL) || (node2 == NULL))
2947 return(-2);
2948 }
2949 /*
2950 * Find who's first.
2951 */
2952 if (node1 == node2->prev)
2953 return(1);
2954 if (node1 == node2->next)
2955 return(-1);
2956 /*
2957 * Speedup using document order if availble.
2958 */
2959 if ((node1->type == XML_ELEMENT_NODE) &&
2960 (node2->type == XML_ELEMENT_NODE) &&
2961 (0 > (long) node1->content) &&
2962 (0 > (long) node2->content) &&
2963 (node1->doc == node2->doc)) {
2964 long l1, l2;
2965
2966 l1 = -((long) node1->content);
2967 l2 = -((long) node2->content);
2968 if (l1 < l2)
2969 return(1);
2970 if (l1 > l2)
2971 return(-1);
2972 }
2973
2974 for (cur = node1->next;cur != NULL;cur = cur->next)
2975 if (cur == node2)
2976 return(1);
2977 return(-1); /* assume there is no sibling list corruption */
2978}
2979
2980#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
2981/**
2982 * xmlXPathCmpNodesExt:
2983 * @node1: the first node
2984 * @node2: the second node
2985 *
2986 * Compare two nodes w.r.t document order.
2987 * This one is optimized for handling of non-element nodes.
2988 *
2989 * Returns -2 in case of error 1 if first point < second point, 0 if
2990 * it's the same node, -1 otherwise
2991 */
2992static int
2993xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
2994 int depth1, depth2;
2995 int misc = 0, precedence1 = 0, precedence2 = 0;
2996 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
2997 xmlNodePtr cur, root;
2998 long l1, l2;
2999
3000 if ((node1 == NULL) || (node2 == NULL))
3001 return(-2);
3002
3003 if (node1 == node2)
3004 return(0);
3005
3006 /*
3007 * a couple of optimizations which will avoid computations in most cases
3008 */
3009 switch (node1->type) {
3010 case XML_ELEMENT_NODE:
3011 if (node2->type == XML_ELEMENT_NODE) {
3012 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
3013 (0 > (long) node2->content) &&
3014 (node1->doc == node2->doc))
3015 {
3016 l1 = -((long) node1->content);
3017 l2 = -((long) node2->content);
3018 if (l1 < l2)
3019 return(1);
3020 if (l1 > l2)
3021 return(-1);
3022 } else
3023 goto turtle_comparison;
3024 }
3025 break;
3026 case XML_ATTRIBUTE_NODE:
3027 precedence1 = 1; /* element is owner */
3028 miscNode1 = node1;
3029 node1 = node1->parent;
3030 misc = 1;
3031 break;
3032 case XML_TEXT_NODE:
3033 case XML_CDATA_SECTION_NODE:
3034 case XML_COMMENT_NODE:
3035 case XML_PI_NODE: {
3036 miscNode1 = node1;
3037 /*
3038 * Find nearest element node.
3039 */
3040 if (node1->prev != NULL) {
3041 do {
3042 node1 = node1->prev;
3043 if (node1->type == XML_ELEMENT_NODE) {
3044 precedence1 = 3; /* element in prev-sibl axis */
3045 break;
3046 }
3047 if (node1->prev == NULL) {
3048 precedence1 = 2; /* element is parent */
3049 /*
3050 * URGENT TODO: Are there any cases, where the
3051 * parent of such a node is not an element node?
3052 */
3053 node1 = node1->parent;
3054 break;
3055 }
3056 } while (1);
3057 } else {
3058 precedence1 = 2; /* element is parent */
3059 node1 = node1->parent;
3060 }
3061 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
3062 (0 <= (long) node1->content)) {
3063 /*
3064 * Fallback for whatever case.
3065 */
3066 node1 = miscNode1;
3067 precedence1 = 0;
3068 } else
3069 misc = 1;
3070 }
3071 break;
3072 case XML_NAMESPACE_DECL:
3073 /*
3074 * TODO: why do we return 1 for namespace nodes?
3075 */
3076 return(1);
3077 default:
3078 break;
3079 }
3080 switch (node2->type) {
3081 case XML_ELEMENT_NODE:
3082 break;
3083 case XML_ATTRIBUTE_NODE:
3084 precedence2 = 1; /* element is owner */
3085 miscNode2 = node2;
3086 node2 = node2->parent;
3087 misc = 1;
3088 break;
3089 case XML_TEXT_NODE:
3090 case XML_CDATA_SECTION_NODE:
3091 case XML_COMMENT_NODE:
3092 case XML_PI_NODE: {
3093 miscNode2 = node2;
3094 if (node2->prev != NULL) {
3095 do {
3096 node2 = node2->prev;
3097 if (node2->type == XML_ELEMENT_NODE) {
3098 precedence2 = 3; /* element in prev-sibl axis */
3099 break;
3100 }
3101 if (node2->prev == NULL) {
3102 precedence2 = 2; /* element is parent */
3103 node2 = node2->parent;
3104 break;
3105 }
3106 } while (1);
3107 } else {
3108 precedence2 = 2; /* element is parent */
3109 node2 = node2->parent;
3110 }
3111 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3112 (0 <= (long) node1->content))
3113 {
3114 node2 = miscNode2;
3115 precedence2 = 0;
3116 } else
3117 misc = 1;
3118 }
3119 break;
3120 case XML_NAMESPACE_DECL:
3121 return(1);
3122 default:
3123 break;
3124 }
3125 if (misc) {
3126 if (node1 == node2) {
3127 if (precedence1 == precedence2) {
3128 /*
3129 * The ugly case; but normally there aren't many
3130 * adjacent non-element nodes around.
3131 */
3132 cur = miscNode2->prev;
3133 while (cur != NULL) {
3134 if (cur == miscNode1)
3135 return(1);
3136 if (cur->type == XML_ELEMENT_NODE)
3137 return(-1);
3138 cur = cur->prev;
3139 }
3140 return (-1);
3141 } else {
3142 /*
3143 * Evaluate based on higher precedence wrt to the element.
3144 * TODO: This assumes attributes are sorted before content.
3145 * Is this 100% correct?
3146 */
3147 if (precedence1 < precedence2)
3148 return(1);
3149 else
3150 return(-1);
3151 }
3152 }
3153 /*
3154 * Special case: One of the helper-elements is contained by the other.
3155 * <foo>
3156 * <node2>
3157 * <node1>Text-1(precedence1 == 2)</node1>
3158 * </node2>
3159 * Text-6(precedence2 == 3)
3160 * </foo>
3161 */
3162 if ((precedence2 == 3) && (precedence1 > 1)) {
3163 cur = node1->parent;
3164 while (cur) {
3165 if (cur == node2)
3166 return(1);
3167 cur = cur->parent;
3168 }
3169 }
3170 if ((precedence1 == 3) && (precedence2 > 1)) {
3171 cur = node2->parent;
3172 while (cur) {
3173 if (cur == node1)
3174 return(-1);
3175 cur = cur->parent;
3176 }
3177 }
3178 }
3179
3180 /*
3181 * Speedup using document order if availble.
3182 */
3183 if ((node1->type == XML_ELEMENT_NODE) &&
3184 (node2->type == XML_ELEMENT_NODE) &&
3185 (0 > (long) node1->content) &&
3186 (0 > (long) node2->content) &&
3187 (node1->doc == node2->doc)) {
3188
3189 l1 = -((long) node1->content);
3190 l2 = -((long) node2->content);
3191 if (l1 < l2)
3192 return(1);
3193 if (l1 > l2)
3194 return(-1);
3195 }
3196
3197turtle_comparison:
3198
3199 if (node1 == node2->prev)
3200 return(1);
3201 if (node1 == node2->next)
3202 return(-1);
3203 /*
3204 * compute depth to root
3205 */
3206 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3207 if (cur == node1)
3208 return(1);
3209 depth2++;
3210 }
3211 root = cur;
3212 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3213 if (cur == node2)
3214 return(-1);
3215 depth1++;
3216 }
3217 /*
3218 * Distinct document (or distinct entities :-( ) case.
3219 */
3220 if (root != cur) {
3221 return(-2);
3222 }
3223 /*
3224 * get the nearest common ancestor.
3225 */
3226 while (depth1 > depth2) {
3227 depth1--;
3228 node1 = node1->parent;
3229 }
3230 while (depth2 > depth1) {
3231 depth2--;
3232 node2 = node2->parent;
3233 }
3234 while (node1->parent != node2->parent) {
3235 node1 = node1->parent;
3236 node2 = node2->parent;
3237 /* should not happen but just in case ... */
3238 if ((node1 == NULL) || (node2 == NULL))
3239 return(-2);
3240 }
3241 /*
3242 * Find who's first.
3243 */
3244 if (node1 == node2->prev)
3245 return(1);
3246 if (node1 == node2->next)
3247 return(-1);
3248 /*
3249 * Speedup using document order if availble.
3250 */
3251 if ((node1->type == XML_ELEMENT_NODE) &&
3252 (node2->type == XML_ELEMENT_NODE) &&
3253 (0 > (long) node1->content) &&
3254 (0 > (long) node2->content) &&
3255 (node1->doc == node2->doc)) {
3256
3257 l1 = -((long) node1->content);
3258 l2 = -((long) node2->content);
3259 if (l1 < l2)
3260 return(1);
3261 if (l1 > l2)
3262 return(-1);
3263 }
3264
3265 for (cur = node1->next;cur != NULL;cur = cur->next)
3266 if (cur == node2)
3267 return(1);
3268 return(-1); /* assume there is no sibling list corruption */
3269}
3270#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
3271
3272/**
3273 * xmlXPathNodeSetSort:
3274 * @set: the node set
3275 *
3276 * Sort the node set in document order
3277 */
3278void
3279xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3280 int i, j, incr, len;
3281 xmlNodePtr tmp;
3282
3283 if (set == NULL)
3284 return;
3285
3286 /* Use Shell's sort to sort the node-set */
3287 len = set->nodeNr;
3288 for (incr = len / 2; incr > 0; incr /= 2) {
3289 for (i = incr; i < len; i++) {
3290 j = i - incr;
3291 while (j >= 0) {
3292#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3293 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3294 set->nodeTab[j + incr]) == -1)
3295#else
3296 if (xmlXPathCmpNodes(set->nodeTab[j],
3297 set->nodeTab[j + incr]) == -1)
3298#endif
3299 {
3300 tmp = set->nodeTab[j];
3301 set->nodeTab[j] = set->nodeTab[j + incr];
3302 set->nodeTab[j + incr] = tmp;
3303 j -= incr;
3304 } else
3305 break;
3306 }
3307 }
3308 }
3309}
3310
3311#define XML_NODESET_DEFAULT 10
3312/**
3313 * xmlXPathNodeSetDupNs:
3314 * @node: the parent node of the namespace XPath node
3315 * @ns: the libxml namespace declaration node.
3316 *
3317 * Namespace node in libxml don't match the XPath semantic. In a node set
3318 * the namespace nodes are duplicated and the next pointer is set to the
3319 * parent node in the XPath semantic.
3320 *
3321 * Returns the newly created object.
3322 */
3323static xmlNodePtr
3324xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3325 xmlNsPtr cur;
3326
3327 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3328 return(NULL);
3329 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3330 return((xmlNodePtr) ns);
3331
3332 /*
3333 * Allocate a new Namespace and fill the fields.
3334 */
3335 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3336 if (cur == NULL) {
3337 xmlXPathErrMemory(NULL, "duplicating namespace\n");
3338 return(NULL);
3339 }
3340 memset(cur, 0, sizeof(xmlNs));
3341 cur->type = XML_NAMESPACE_DECL;
3342 if (ns->href != NULL)
3343 cur->href = xmlStrdup(ns->href);
3344 if (ns->prefix != NULL)
3345 cur->prefix = xmlStrdup(ns->prefix);
3346 cur->next = (xmlNsPtr) node;
3347 return((xmlNodePtr) cur);
3348}
3349
3350/**
3351 * xmlXPathNodeSetFreeNs:
3352 * @ns: the XPath namespace node found in a nodeset.
3353 *
3354 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3355 * the namespace nodes are duplicated and the next pointer is set to the
3356 * parent node in the XPath semantic. Check if such a node needs to be freed
3357 */
3358void
3359xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3360 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3361 return;
3362
3363 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3364 if (ns->href != NULL)
3365 xmlFree((xmlChar *)ns->href);
3366 if (ns->prefix != NULL)
3367 xmlFree((xmlChar *)ns->prefix);
3368 xmlFree(ns);
3369 }
3370}
3371
3372/**
3373 * xmlXPathNodeSetCreate:
3374 * @val: an initial xmlNodePtr, or NULL
3375 *
3376 * Create a new xmlNodeSetPtr of type double and of value @val
3377 *
3378 * Returns the newly created object.
3379 */
3380xmlNodeSetPtr
3381xmlXPathNodeSetCreate(xmlNodePtr val) {
3382 xmlNodeSetPtr ret;
3383
3384 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3385 if (ret == NULL) {
3386 xmlXPathErrMemory(NULL, "creating nodeset\n");
3387 return(NULL);
3388 }
3389 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3390 if (val != NULL) {
3391 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3392 sizeof(xmlNodePtr));
3393 if (ret->nodeTab == NULL) {
3394 xmlXPathErrMemory(NULL, "creating nodeset\n");
3395 xmlFree(ret);
3396 return(NULL);
3397 }
3398 memset(ret->nodeTab, 0 ,
3399 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3400 ret->nodeMax = XML_NODESET_DEFAULT;
3401 if (val->type == XML_NAMESPACE_DECL) {
3402 xmlNsPtr ns = (xmlNsPtr) val;
3403
3404 ret->nodeTab[ret->nodeNr++] =
3405 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3406 } else
3407 ret->nodeTab[ret->nodeNr++] = val;
3408 }
3409 return(ret);
3410}
3411
3412/**
3413 * xmlXPathNodeSetCreateSize:
3414 * @size: the initial size of the set
3415 *
3416 * Create a new xmlNodeSetPtr of type double and of value @val
3417 *
3418 * Returns the newly created object.
3419 */
3420static xmlNodeSetPtr
3421xmlXPathNodeSetCreateSize(int size) {
3422 xmlNodeSetPtr ret;
3423
3424 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3425 if (ret == NULL) {
3426 xmlXPathErrMemory(NULL, "creating nodeset\n");
3427 return(NULL);
3428 }
3429 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3430 if (size < XML_NODESET_DEFAULT)
3431 size = XML_NODESET_DEFAULT;
3432 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3433 if (ret->nodeTab == NULL) {
3434 xmlXPathErrMemory(NULL, "creating nodeset\n");
3435 xmlFree(ret);
3436 return(NULL);
3437 }
3438 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3439 ret->nodeMax = size;
3440 return(ret);
3441}
3442
3443/**
3444 * xmlXPathNodeSetContains:
3445 * @cur: the node-set
3446 * @val: the node
3447 *
3448 * checks whether @cur contains @val
3449 *
3450 * Returns true (1) if @cur contains @val, false (0) otherwise
3451 */
3452int
3453xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3454 int i;
3455
3456 if ((cur == NULL) || (val == NULL)) return(0);
3457 if (val->type == XML_NAMESPACE_DECL) {
3458 for (i = 0; i < cur->nodeNr; i++) {
3459 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3460 xmlNsPtr ns1, ns2;
3461
3462 ns1 = (xmlNsPtr) val;
3463 ns2 = (xmlNsPtr) cur->nodeTab[i];
3464 if (ns1 == ns2)
3465 return(1);
3466 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3467 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3468 return(1);
3469 }
3470 }
3471 } else {
3472 for (i = 0; i < cur->nodeNr; i++) {
3473 if (cur->nodeTab[i] == val)
3474 return(1);
3475 }
3476 }
3477 return(0);
3478}
3479
3480/**
3481 * xmlXPathNodeSetAddNs:
3482 * @cur: the initial node set
3483 * @node: the hosting node
3484 * @ns: a the namespace node
3485 *
3486 * add a new namespace node to an existing NodeSet
3487 */
3488void
3489xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3490 int i;
3491
3492
3493 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3494 (ns->type != XML_NAMESPACE_DECL) ||
3495 (node->type != XML_ELEMENT_NODE))
3496 return;
3497
3498 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3499 /*
3500 * prevent duplicates
3501 */
3502 for (i = 0;i < cur->nodeNr;i++) {
3503 if ((cur->nodeTab[i] != NULL) &&
3504 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3505 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3506 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3507 return;
3508 }
3509
3510 /*
3511 * grow the nodeTab if needed
3512 */
3513 if (cur->nodeMax == 0) {
3514 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3515 sizeof(xmlNodePtr));
3516 if (cur->nodeTab == NULL) {
3517 xmlXPathErrMemory(NULL, "growing nodeset\n");
3518 return;
3519 }
3520 memset(cur->nodeTab, 0 ,
3521 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3522 cur->nodeMax = XML_NODESET_DEFAULT;
3523 } else if (cur->nodeNr == cur->nodeMax) {
3524 xmlNodePtr *temp;
3525
3526 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3527 sizeof(xmlNodePtr));
3528 if (temp == NULL) {
3529 xmlXPathErrMemory(NULL, "growing nodeset\n");
3530 return;
3531 }
3532 cur->nodeMax *= 2;
3533 cur->nodeTab = temp;
3534 }
3535 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3536}
3537
3538/**
3539 * xmlXPathNodeSetAdd:
3540 * @cur: the initial node set
3541 * @val: a new xmlNodePtr
3542 *
3543 * add a new xmlNodePtr to an existing NodeSet
3544 */
3545void
3546xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3547 int i;
3548
3549 if ((cur == NULL) || (val == NULL)) return;
3550
3551#if 0
3552 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3553 return; /* an XSLT fake node */
3554#endif
3555
3556 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3557 /*
3558 * prevent duplcates
3559 */
3560 for (i = 0;i < cur->nodeNr;i++)
3561 if (cur->nodeTab[i] == val) return;
3562
3563 /*
3564 * grow the nodeTab if needed
3565 */
3566 if (cur->nodeMax == 0) {
3567 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3568 sizeof(xmlNodePtr));
3569 if (cur->nodeTab == NULL) {
3570 xmlXPathErrMemory(NULL, "growing nodeset\n");
3571 return;
3572 }
3573 memset(cur->nodeTab, 0 ,
3574 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3575 cur->nodeMax = XML_NODESET_DEFAULT;
3576 } else if (cur->nodeNr == cur->nodeMax) {
3577 xmlNodePtr *temp;
3578
3579 cur->nodeMax *= 2;
3580 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3581 sizeof(xmlNodePtr));
3582 if (temp == NULL) {
3583 xmlXPathErrMemory(NULL, "growing nodeset\n");
3584 return;
3585 }
3586 cur->nodeTab = temp;
3587 }
3588 if (val->type == XML_NAMESPACE_DECL) {
3589 xmlNsPtr ns = (xmlNsPtr) val;
3590
3591 cur->nodeTab[cur->nodeNr++] =
3592 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3593 } else
3594 cur->nodeTab[cur->nodeNr++] = val;
3595}
3596
3597/**
3598 * xmlXPathNodeSetAddUnique:
3599 * @cur: the initial node set
3600 * @val: a new xmlNodePtr
3601 *
3602 * add a new xmlNodePtr to an existing NodeSet, optimized version
3603 * when we are sure the node is not already in the set.
3604 */
3605void
3606xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3607 if ((cur == NULL) || (val == NULL)) return;
3608
3609#if 0
3610 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3611 return; /* an XSLT fake node */
3612#endif
3613
3614 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3615 /*
3616 * grow the nodeTab if needed
3617 */
3618 if (cur->nodeMax == 0) {
3619 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3620 sizeof(xmlNodePtr));
3621 if (cur->nodeTab == NULL) {
3622 xmlXPathErrMemory(NULL, "growing nodeset\n");
3623 return;
3624 }
3625 memset(cur->nodeTab, 0 ,
3626 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3627 cur->nodeMax = XML_NODESET_DEFAULT;
3628 } else if (cur->nodeNr == cur->nodeMax) {
3629 xmlNodePtr *temp;
3630
3631 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3632 sizeof(xmlNodePtr));
3633 if (temp == NULL) {
3634 xmlXPathErrMemory(NULL, "growing nodeset\n");
3635 return;
3636 }
3637 cur->nodeTab = temp;
3638 cur->nodeMax *= 2;
3639 }
3640 if (val->type == XML_NAMESPACE_DECL) {
3641 xmlNsPtr ns = (xmlNsPtr) val;
3642
3643 cur->nodeTab[cur->nodeNr++] =
3644 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3645 } else
3646 cur->nodeTab[cur->nodeNr++] = val;
3647}
3648
3649/**
3650 * xmlXPathNodeSetMerge:
3651 * @val1: the first NodeSet or NULL
3652 * @val2: the second NodeSet
3653 *
3654 * Merges two nodesets, all nodes from @val2 are added to @val1
3655 * if @val1 is NULL, a new set is created and copied from @val2
3656 *
3657 * Returns @val1 once extended or NULL in case of error.
3658 */
3659xmlNodeSetPtr
3660xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3661 int i, j, initNr, skip;
3662 xmlNodePtr n1, n2;
3663
3664 if (val2 == NULL) return(val1);
3665 if (val1 == NULL) {
3666 val1 = xmlXPathNodeSetCreate(NULL);
3667#if 0
3668 /*
3669 * TODO: The optimization won't work in every case, since
3670 * those nasty namespace nodes need to be added with
3671 * xmlXPathNodeSetDupNs() to the set; thus a pure
3672 * memcpy is not possible.
3673 * If there was a flag on the nodesetval, indicating that
3674 * some temporary nodes are in, that would be helpfull.
3675 */
3676 /*
3677 * Optimization: Create an equally sized node-set
3678 * and memcpy the content.
3679 */
3680 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3681 if (val1 == NULL)
3682 return(NULL);
3683 if (val2->nodeNr != 0) {
3684 if (val2->nodeNr == 1)
3685 *(val1->nodeTab) = *(val2->nodeTab);
3686 else {
3687 memcpy(val1->nodeTab, val2->nodeTab,
3688 val2->nodeNr * sizeof(xmlNodePtr));
3689 }
3690 val1->nodeNr = val2->nodeNr;
3691 }
3692 return(val1);
3693#endif
3694 }
3695
3696 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3697 initNr = val1->nodeNr;
3698
3699 for (i = 0;i < val2->nodeNr;i++) {
3700 n2 = val2->nodeTab[i];
3701 /*
3702 * check against duplicates
3703 */
3704 skip = 0;
3705 for (j = 0; j < initNr; j++) {
3706 n1 = val1->nodeTab[j];
3707 if (n1 == n2) {
3708 skip = 1;
3709 break;
3710 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3711 (n2->type == XML_NAMESPACE_DECL)) {
3712 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3713 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3714 ((xmlNsPtr) n2)->prefix)))
3715 {
3716 skip = 1;
3717 break;
3718 }
3719 }
3720 }
3721 if (skip)
3722 continue;
3723
3724 /*
3725 * grow the nodeTab if needed
3726 */
3727 if (val1->nodeMax == 0) {
3728 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3729 sizeof(xmlNodePtr));
3730 if (val1->nodeTab == NULL) {
3731 xmlXPathErrMemory(NULL, "merging nodeset\n");
3732 return(NULL);
3733 }
3734 memset(val1->nodeTab, 0 ,
3735 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3736 val1->nodeMax = XML_NODESET_DEFAULT;
3737 } else if (val1->nodeNr == val1->nodeMax) {
3738 xmlNodePtr *temp;
3739
3740 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3741 sizeof(xmlNodePtr));
3742 if (temp == NULL) {
3743 xmlXPathErrMemory(NULL, "merging nodeset\n");
3744 return(NULL);
3745 }
3746 val1->nodeTab = temp;
3747 val1->nodeMax *= 2;
3748 }
3749 if (n2->type == XML_NAMESPACE_DECL) {
3750 xmlNsPtr ns = (xmlNsPtr) n2;
3751
3752 val1->nodeTab[val1->nodeNr++] =
3753 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3754 } else
3755 val1->nodeTab[val1->nodeNr++] = n2;
3756 }
3757
3758 return(val1);
3759}
3760
3761#if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3762/**
3763 * xmlXPathNodeSetMergeUnique:
3764 * @val1: the first NodeSet or NULL
3765 * @val2: the second NodeSet
3766 *
3767 * Merges two nodesets, all nodes from @val2 are added to @val1
3768 * if @val1 is NULL, a new set is created and copied from @val2
3769 *
3770 * Returns @val1 once extended or NULL in case of error.
3771 */
3772static xmlNodeSetPtr
3773xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3774 int i;
3775
3776 if (val2 == NULL) return(val1);
3777 if (val1 == NULL) {
3778 val1 = xmlXPathNodeSetCreate(NULL);
3779 }
3780
3781 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3782
3783 for (i = 0;i < val2->nodeNr;i++) {
3784 /*
3785 * grow the nodeTab if needed
3786 */
3787 if (val1->nodeMax == 0) {
3788 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3789 sizeof(xmlNodePtr));
3790 if (val1->nodeTab == NULL) {
3791 xmlXPathErrMemory(NULL, "merging nodeset\n");
3792 return(NULL);
3793 }
3794 memset(val1->nodeTab, 0 ,
3795 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3796 val1->nodeMax = XML_NODESET_DEFAULT;
3797 } else if (val1->nodeNr == val1->nodeMax) {
3798 xmlNodePtr *temp;
3799
3800 val1->nodeMax *= 2;
3801 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3802 sizeof(xmlNodePtr));
3803 if (temp == NULL) {
3804 xmlXPathErrMemory(NULL, "merging nodeset\n");
3805 return(NULL);
3806 }
3807 val1->nodeTab = temp;
3808 }
3809 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3810 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
3811
3812 val1->nodeTab[val1->nodeNr++] =
3813 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3814 } else
3815 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
3816 }
3817
3818 return(val1);
3819}
3820#endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3821
3822/**
3823 * xmlXPathNodeSetMergeAndClear:
3824 * @set1: the first NodeSet or NULL
3825 * @set2: the second NodeSet
3826 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3827 *
3828 * Merges two nodesets, all nodes from @set2 are added to @set1
3829 * if @set1 is NULL, a new set is created and copied from @set2.
3830 * Checks for duplicate nodes. Clears set2.
3831 *
3832 * Returns @set1 once extended or NULL in case of error.
3833 */
3834static xmlNodeSetPtr
3835xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3836 int hasNullEntries)
3837{
3838 if ((set1 == NULL) && (hasNullEntries == 0)) {
3839 /*
3840 * Note that doing a memcpy of the list, namespace nodes are
3841 * just assigned to set1, since set2 is cleared anyway.
3842 */
3843 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3844 if (set1 == NULL)
3845 return(NULL);
3846 if (set2->nodeNr != 0) {
3847 memcpy(set1->nodeTab, set2->nodeTab,
3848 set2->nodeNr * sizeof(xmlNodePtr));
3849 set1->nodeNr = set2->nodeNr;
3850 }
3851 } else {
3852 int i, j, initNbSet1;
3853 xmlNodePtr n1, n2;
3854
3855 if (set1 == NULL)
3856 set1 = xmlXPathNodeSetCreate(NULL);
3857
3858 initNbSet1 = set1->nodeNr;
3859 for (i = 0;i < set2->nodeNr;i++) {
3860 n2 = set2->nodeTab[i];
3861 /*
3862 * Skip NULLed entries.
3863 */
3864 if (n2 == NULL)
3865 continue;
3866 /*
3867 * Skip duplicates.
3868 */
3869 for (j = 0; j < initNbSet1; j++) {
3870 n1 = set1->nodeTab[j];
3871 if (n1 == n2) {
3872 goto skip_node;
3873 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3874 (n2->type == XML_NAMESPACE_DECL))
3875 {
3876 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3877 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3878 ((xmlNsPtr) n2)->prefix)))
3879 {
3880 /*
3881 * Free the namespace node.
3882 */
3883 set2->nodeTab[i] = NULL;
3884 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3885 goto skip_node;
3886 }
3887 }
3888 }
3889 /*
3890 * grow the nodeTab if needed
3891 */
3892 if (set1->nodeMax == 0) {
3893 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3894 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3895 if (set1->nodeTab == NULL) {
3896 xmlXPathErrMemory(NULL, "merging nodeset\n");
3897 return(NULL);
3898 }
3899 memset(set1->nodeTab, 0,
3900 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3901 set1->nodeMax = XML_NODESET_DEFAULT;
3902 } else if (set1->nodeNr >= set1->nodeMax) {
3903 xmlNodePtr *temp;
3904
3905 temp = (xmlNodePtr *) xmlRealloc(
3906 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3907 if (temp == NULL) {
3908 xmlXPathErrMemory(NULL, "merging nodeset\n");
3909 return(NULL);
3910 }
3911 set1->nodeTab = temp;
3912 set1->nodeMax *= 2;
3913 }
3914 if (n2->type == XML_NAMESPACE_DECL) {
3915 xmlNsPtr ns = (xmlNsPtr) n2;
3916
3917 set1->nodeTab[set1->nodeNr++] =
3918 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3919 } else
3920 set1->nodeTab[set1->nodeNr++] = n2;
3921skip_node:
3922 {}
3923 }
3924 }
3925 set2->nodeNr = 0;
3926 return(set1);
3927}
3928
3929/**
3930 * xmlXPathNodeSetMergeAndClearNoDupls:
3931 * @set1: the first NodeSet or NULL
3932 * @set2: the second NodeSet
3933 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3934 *
3935 * Merges two nodesets, all nodes from @set2 are added to @set1
3936 * if @set1 is NULL, a new set is created and copied from @set2.
3937 * Doesn't chack for duplicate nodes. Clears set2.
3938 *
3939 * Returns @set1 once extended or NULL in case of error.
3940 */
3941static xmlNodeSetPtr
3942xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3943 int hasNullEntries)
3944{
3945 if (set2 == NULL)
3946 return(set1);
3947 if ((set1 == NULL) && (hasNullEntries == 0)) {
3948 /*
3949 * Note that doing a memcpy of the list, namespace nodes are
3950 * just assigned to set1, since set2 is cleared anyway.
3951 */
3952 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3953 if (set1 == NULL)
3954 return(NULL);
3955 if (set2->nodeNr != 0) {
3956 memcpy(set1->nodeTab, set2->nodeTab,
3957 set2->nodeNr * sizeof(xmlNodePtr));
3958 set1->nodeNr = set2->nodeNr;
3959 }
3960 } else {
3961 int i;
3962 xmlNodePtr n2;
3963
3964 if (set1 == NULL)
3965 set1 = xmlXPathNodeSetCreate(NULL);
3966
3967 for (i = 0;i < set2->nodeNr;i++) {
3968 n2 = set2->nodeTab[i];
3969 /*
3970 * Skip NULLed entries.
3971 */
3972 if (n2 == NULL)
3973 continue;
3974 if (set1->nodeMax == 0) {
3975 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3976 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3977 if (set1->nodeTab == NULL) {
3978 xmlXPathErrMemory(NULL, "merging nodeset\n");
3979 return(NULL);
3980 }
3981 memset(set1->nodeTab, 0,
3982 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3983 set1->nodeMax = XML_NODESET_DEFAULT;
3984 } else if (set1->nodeNr >= set1->nodeMax) {
3985 xmlNodePtr *temp;
3986
3987 temp = (xmlNodePtr *) xmlRealloc(
3988 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3989 if (temp == NULL) {
3990 xmlXPathErrMemory(NULL, "merging nodeset\n");
3991 return(NULL);
3992 }
3993 set1->nodeTab = temp;
3994 set1->nodeMax *= 2;
3995 }
3996 set1->nodeTab[set1->nodeNr++] = n2;
3997 }
3998 }
3999 set2->nodeNr = 0;
4000 return(set1);
4001}
4002
4003/**
4004 * xmlXPathNodeSetDel:
4005 * @cur: the initial node set
4006 * @val: an xmlNodePtr
4007 *
4008 * Removes an xmlNodePtr from an existing NodeSet
4009 */
4010void
4011xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4012 int i;
4013
4014 if (cur == NULL) return;
4015 if (val == NULL) return;
4016
4017 /*
4018 * find node in nodeTab
4019 */
4020 for (i = 0;i < cur->nodeNr;i++)
4021 if (cur->nodeTab[i] == val) break;
4022
4023 if (i >= cur->nodeNr) { /* not found */
4024#ifdef DEBUG
4025 xmlGenericError(xmlGenericErrorContext,
4026 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4027 val->name);
4028#endif
4029 return;
4030 }
4031 if ((cur->nodeTab[i] != NULL) &&
4032 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4033 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4034 cur->nodeNr--;
4035 for (;i < cur->nodeNr;i++)
4036 cur->nodeTab[i] = cur->nodeTab[i + 1];
4037 cur->nodeTab[cur->nodeNr] = NULL;
4038}
4039
4040/**
4041 * xmlXPathNodeSetRemove:
4042 * @cur: the initial node set
4043 * @val: the index to remove
4044 *
4045 * Removes an entry from an existing NodeSet list.
4046 */
4047void
4048xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4049 if (cur == NULL) return;
4050 if (val >= cur->nodeNr) return;
4051 if ((cur->nodeTab[val] != NULL) &&
4052 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4053 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4054 cur->nodeNr--;
4055 for (;val < cur->nodeNr;val++)
4056 cur->nodeTab[val] = cur->nodeTab[val + 1];
4057 cur->nodeTab[cur->nodeNr] = NULL;
4058}
4059
4060/**
4061 * xmlXPathFreeNodeSet:
4062 * @obj: the xmlNodeSetPtr to free
4063 *
4064 * Free the NodeSet compound (not the actual nodes !).
4065 */
4066void
4067xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4068 if (obj == NULL) return;
4069 if (obj->nodeTab != NULL) {
4070 int i;
4071
4072 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4073 for (i = 0;i < obj->nodeNr;i++)
4074 if ((obj->nodeTab[i] != NULL) &&
4075 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4076 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4077 xmlFree(obj->nodeTab);
4078 }
4079 xmlFree(obj);
4080}
4081
4082/**
4083 * xmlXPathNodeSetClear:
4084 * @set: the node set to clear
4085 *
4086 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4087 * are feed), but does *not* free the list itself. Sets the length of the
4088 * list to 0.
4089 */
4090static void
4091xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4092{
4093 if ((set == NULL) || (set->nodeNr <= 0))
4094 return;
4095 else if (hasNsNodes) {
4096 int i;
4097 xmlNodePtr node;
4098
4099 for (i = 0; i < set->nodeNr; i++) {
4100 node = set->nodeTab[i];
4101 if ((node != NULL) &&
4102 (node->type == XML_NAMESPACE_DECL))
4103 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4104 }
4105 }
4106 set->nodeNr = 0;
4107}
4108
4109/**
4110 * xmlXPathNodeSetClearFromPos:
4111 * @set: the node set to be cleared
4112 * @pos: the start position to clear from
4113 *
4114 * Clears the list from temporary XPath objects (e.g. namespace nodes
4115 * are feed) starting with the entry at @pos, but does *not* free the list
4116 * itself. Sets the length of the list to @pos.
4117 */
4118static void
4119xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4120{
4121 if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4122 return;
4123 else if ((hasNsNodes)) {
4124 int i;
4125 xmlNodePtr node;
4126
4127 for (i = pos; i < set->nodeNr; i++) {
4128 node = set->nodeTab[i];
4129 if ((node != NULL) &&
4130 (node->type == XML_NAMESPACE_DECL))
4131 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4132 }
4133 }
4134 set->nodeNr = pos;
4135}
4136
4137/**
4138 * xmlXPathFreeValueTree:
4139 * @obj: the xmlNodeSetPtr to free
4140 *
4141 * Free the NodeSet compound and the actual tree, this is different
4142 * from xmlXPathFreeNodeSet()
4143 */
4144static void
4145xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4146 int i;
4147
4148 if (obj == NULL) return;
4149
4150 if (obj->nodeTab != NULL) {
4151 for (i = 0;i < obj->nodeNr;i++) {
4152 if (obj->nodeTab[i] != NULL) {
4153 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4154 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4155 } else {
4156 xmlFreeNodeList(obj->nodeTab[i]);
4157 }
4158 }
4159 }
4160 xmlFree(obj->nodeTab);
4161 }
4162 xmlFree(obj);
4163}
4164
4165#if defined(DEBUG) || defined(DEBUG_STEP)
4166/**
4167 * xmlGenericErrorContextNodeSet:
4168 * @output: a FILE * for the output
4169 * @obj: the xmlNodeSetPtr to display
4170 *
4171 * Quick display of a NodeSet
4172 */
4173void
4174xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4175 int i;
4176
4177 if (output == NULL) output = xmlGenericErrorContext;
4178 if (obj == NULL) {
4179 fprintf(output, "NodeSet == NULL !\n");
4180 return;
4181 }
4182 if (obj->nodeNr == 0) {
4183 fprintf(output, "NodeSet is empty\n");
4184 return;
4185 }
4186 if (obj->nodeTab == NULL) {
4187 fprintf(output, " nodeTab == NULL !\n");
4188 return;
4189 }
4190 for (i = 0; i < obj->nodeNr; i++) {
4191 if (obj->nodeTab[i] == NULL) {
4192 fprintf(output, " NULL !\n");
4193 return;
4194 }
4195 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4196 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4197 fprintf(output, " /");
4198 else if (obj->nodeTab[i]->name == NULL)
4199 fprintf(output, " noname!");
4200 else fprintf(output, " %s", obj->nodeTab[i]->name);
4201 }
4202 fprintf(output, "\n");
4203}
4204#endif
4205
4206/**
4207 * xmlXPathNewNodeSet:
4208 * @val: the NodePtr value
4209 *
4210 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4211 * it with the single Node @val
4212 *
4213 * Returns the newly created object.
4214 */
4215xmlXPathObjectPtr
4216xmlXPathNewNodeSet(xmlNodePtr val) {
4217 xmlXPathObjectPtr ret;
4218
4219 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4220 if (ret == NULL) {
4221 xmlXPathErrMemory(NULL, "creating nodeset\n");
4222 return(NULL);
4223 }
4224 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4225 ret->type = XPATH_NODESET;
4226 ret->boolval = 0;
4227 ret->nodesetval = xmlXPathNodeSetCreate(val);
4228 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4229#ifdef XP_DEBUG_OBJ_USAGE
4230 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4231#endif
4232 return(ret);
4233}
4234
4235/**
4236 * xmlXPathNewValueTree:
4237 * @val: the NodePtr value
4238 *
4239 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4240 * it with the tree root @val
4241 *
4242 * Returns the newly created object.
4243 */
4244xmlXPathObjectPtr
4245xmlXPathNewValueTree(xmlNodePtr val) {
4246 xmlXPathObjectPtr ret;
4247
4248 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4249 if (ret == NULL) {
4250 xmlXPathErrMemory(NULL, "creating result value tree\n");
4251 return(NULL);
4252 }
4253 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4254 ret->type = XPATH_XSLT_TREE;
4255 ret->boolval = 1;
4256 ret->user = (void *) val;
4257 ret->nodesetval = xmlXPathNodeSetCreate(val);
4258#ifdef XP_DEBUG_OBJ_USAGE
4259 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4260#endif
4261 return(ret);
4262}
4263
4264/**
4265 * xmlXPathNewNodeSetList:
4266 * @val: an existing NodeSet
4267 *
4268 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4269 * it with the Nodeset @val
4270 *
4271 * Returns the newly created object.
4272 */
4273xmlXPathObjectPtr
4274xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4275{
4276 xmlXPathObjectPtr ret;
4277 int i;
4278
4279 if (val == NULL)
4280 ret = NULL;
4281 else if (val->nodeTab == NULL)
4282 ret = xmlXPathNewNodeSet(NULL);
4283 else {
4284 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4285 for (i = 1; i < val->nodeNr; ++i)
4286 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
4287 }
4288
4289 return (ret);
4290}
4291
4292/**
4293 * xmlXPathWrapNodeSet:
4294 * @val: the NodePtr value
4295 *
4296 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4297 *
4298 * Returns the newly created object.
4299 */
4300xmlXPathObjectPtr
4301xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4302 xmlXPathObjectPtr ret;
4303
4304 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4305 if (ret == NULL) {
4306 xmlXPathErrMemory(NULL, "creating node set object\n");
4307 return(NULL);
4308 }
4309 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4310 ret->type = XPATH_NODESET;
4311 ret->nodesetval = val;
4312#ifdef XP_DEBUG_OBJ_USAGE
4313 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4314#endif
4315 return(ret);
4316}
4317
4318/**
4319 * xmlXPathFreeNodeSetList:
4320 * @obj: an existing NodeSetList object
4321 *
4322 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4323 * the list contrary to xmlXPathFreeObject().
4324 */
4325void
4326xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4327 if (obj == NULL) return;
4328#ifdef XP_DEBUG_OBJ_USAGE
4329 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4330#endif
4331 xmlFree(obj);
4332}
4333
4334/**
4335 * xmlXPathDifference:
4336 * @nodes1: a node-set
4337 * @nodes2: a node-set
4338 *
4339 * Implements the EXSLT - Sets difference() function:
4340 * node-set set:difference (node-set, node-set)
4341 *
4342 * Returns the difference between the two node sets, or nodes1 if
4343 * nodes2 is empty
4344 */
4345xmlNodeSetPtr
4346xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4347 xmlNodeSetPtr ret;
4348 int i, l1;
4349 xmlNodePtr cur;
4350
4351 if (xmlXPathNodeSetIsEmpty(nodes2))
4352 return(nodes1);
4353
4354 ret = xmlXPathNodeSetCreate(NULL);
4355 if (xmlXPathNodeSetIsEmpty(nodes1))
4356 return(ret);
4357
4358 l1 = xmlXPathNodeSetGetLength(nodes1);
4359
4360 for (i = 0; i < l1; i++) {
4361 cur = xmlXPathNodeSetItem(nodes1, i);
4362 if (!xmlXPathNodeSetContains(nodes2, cur))
4363 xmlXPathNodeSetAddUnique(ret, cur);
4364 }
4365 return(ret);
4366}
4367
4368/**
4369 * xmlXPathIntersection:
4370 * @nodes1: a node-set
4371 * @nodes2: a node-set
4372 *
4373 * Implements the EXSLT - Sets intersection() function:
4374 * node-set set:intersection (node-set, node-set)
4375 *
4376 * Returns a node set comprising the nodes that are within both the
4377 * node sets passed as arguments
4378 */
4379xmlNodeSetPtr
4380xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4381 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4382 int i, l1;
4383 xmlNodePtr cur;
4384
4385 if (xmlXPathNodeSetIsEmpty(nodes1))
4386 return(ret);
4387 if (xmlXPathNodeSetIsEmpty(nodes2))
4388 return(ret);
4389
4390 l1 = xmlXPathNodeSetGetLength(nodes1);
4391
4392 for (i = 0; i < l1; i++) {
4393 cur = xmlXPathNodeSetItem(nodes1, i);
4394 if (xmlXPathNodeSetContains(nodes2, cur))
4395 xmlXPathNodeSetAddUnique(ret, cur);
4396 }
4397 return(ret);
4398}
4399
4400/**
4401 * xmlXPathDistinctSorted:
4402 * @nodes: a node-set, sorted by document order
4403 *
4404 * Implements the EXSLT - Sets distinct() function:
4405 * node-set set:distinct (node-set)
4406 *
4407 * Returns a subset of the nodes contained in @nodes, or @nodes if
4408 * it is empty
4409 */
4410xmlNodeSetPtr
4411xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4412 xmlNodeSetPtr ret;
4413 xmlHashTablePtr hash;
4414 int i, l;
4415 xmlChar * strval;
4416 xmlNodePtr cur;
4417
4418 if (xmlXPathNodeSetIsEmpty(nodes))
4419 return(nodes);
4420
4421 ret = xmlXPathNodeSetCreate(NULL);
4422 l = xmlXPathNodeSetGetLength(nodes);
4423 hash = xmlHashCreate (l);
4424 for (i = 0; i < l; i++) {
4425 cur = xmlXPathNodeSetItem(nodes, i);
4426 strval = xmlXPathCastNodeToString(cur);
4427 if (xmlHashLookup(hash, strval) == NULL) {
4428 xmlHashAddEntry(hash, strval, strval);
4429 xmlXPathNodeSetAddUnique(ret, cur);
4430 } else {
4431 xmlFree(strval);
4432 }
4433 }
4434 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4435 return(ret);
4436}
4437
4438/**
4439 * xmlXPathDistinct:
4440 * @nodes: a node-set
4441 *
4442 * Implements the EXSLT - Sets distinct() function:
4443 * node-set set:distinct (node-set)
4444 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4445 * is called with the sorted node-set
4446 *
4447 * Returns a subset of the nodes contained in @nodes, or @nodes if
4448 * it is empty
4449 */
4450xmlNodeSetPtr
4451xmlXPathDistinct (xmlNodeSetPtr nodes) {
4452 if (xmlXPathNodeSetIsEmpty(nodes))
4453 return(nodes);
4454
4455 xmlXPathNodeSetSort(nodes);
4456 return(xmlXPathDistinctSorted(nodes));
4457}
4458
4459/**
4460 * xmlXPathHasSameNodes:
4461 * @nodes1: a node-set
4462 * @nodes2: a node-set
4463 *
4464 * Implements the EXSLT - Sets has-same-nodes function:
4465 * boolean set:has-same-node(node-set, node-set)
4466 *
4467 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4468 * otherwise
4469 */
4470int
4471xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4472 int i, l;
4473 xmlNodePtr cur;
4474
4475 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4476 xmlXPathNodeSetIsEmpty(nodes2))
4477 return(0);
4478
4479 l = xmlXPathNodeSetGetLength(nodes1);
4480 for (i = 0; i < l; i++) {
4481 cur = xmlXPathNodeSetItem(nodes1, i);
4482 if (xmlXPathNodeSetContains(nodes2, cur))
4483 return(1);
4484 }
4485 return(0);
4486}
4487
4488/**
4489 * xmlXPathNodeLeadingSorted:
4490 * @nodes: a node-set, sorted by document order
4491 * @node: a node
4492 *
4493 * Implements the EXSLT - Sets leading() function:
4494 * node-set set:leading (node-set, node-set)
4495 *
4496 * Returns the nodes in @nodes that precede @node in document order,
4497 * @nodes if @node is NULL or an empty node-set if @nodes
4498 * doesn't contain @node
4499 */
4500xmlNodeSetPtr
4501xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4502 int i, l;
4503 xmlNodePtr cur;
4504 xmlNodeSetPtr ret;
4505
4506 if (node == NULL)
4507 return(nodes);
4508
4509 ret = xmlXPathNodeSetCreate(NULL);
4510 if (xmlXPathNodeSetIsEmpty(nodes) ||
4511 (!xmlXPathNodeSetContains(nodes, node)))
4512 return(ret);
4513
4514 l = xmlXPathNodeSetGetLength(nodes);
4515 for (i = 0; i < l; i++) {
4516 cur = xmlXPathNodeSetItem(nodes, i);
4517 if (cur == node)
4518 break;
4519 xmlXPathNodeSetAddUnique(ret, cur);
4520 }
4521 return(ret);
4522}
4523
4524/**
4525 * xmlXPathNodeLeading:
4526 * @nodes: a node-set
4527 * @node: a node
4528 *
4529 * Implements the EXSLT - Sets leading() function:
4530 * node-set set:leading (node-set, node-set)
4531 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4532 * is called.
4533 *
4534 * Returns the nodes in @nodes that precede @node in document order,
4535 * @nodes if @node is NULL or an empty node-set if @nodes
4536 * doesn't contain @node
4537 */
4538xmlNodeSetPtr
4539xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4540 xmlXPathNodeSetSort(nodes);
4541 return(xmlXPathNodeLeadingSorted(nodes, node));
4542}
4543
4544/**
4545 * xmlXPathLeadingSorted:
4546 * @nodes1: a node-set, sorted by document order
4547 * @nodes2: a node-set, sorted by document order
4548 *
4549 * Implements the EXSLT - Sets leading() function:
4550 * node-set set:leading (node-set, node-set)
4551 *
4552 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4553 * in document order, @nodes1 if @nodes2 is NULL or empty or
4554 * an empty node-set if @nodes1 doesn't contain @nodes2
4555 */
4556xmlNodeSetPtr
4557xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4558 if (xmlXPathNodeSetIsEmpty(nodes2))
4559 return(nodes1);
4560 return(xmlXPathNodeLeadingSorted(nodes1,
4561 xmlXPathNodeSetItem(nodes2, 1)));
4562}
4563
4564/**
4565 * xmlXPathLeading:
4566 * @nodes1: a node-set
4567 * @nodes2: a node-set
4568 *
4569 * Implements the EXSLT - Sets leading() function:
4570 * node-set set:leading (node-set, node-set)
4571 * @nodes1 and @nodes2 are sorted by document order, then
4572 * #exslSetsLeadingSorted is called.
4573 *
4574 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4575 * in document order, @nodes1 if @nodes2 is NULL or empty or
4576 * an empty node-set if @nodes1 doesn't contain @nodes2
4577 */
4578xmlNodeSetPtr
4579xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4580 if (xmlXPathNodeSetIsEmpty(nodes2))
4581 return(nodes1);
4582 if (xmlXPathNodeSetIsEmpty(nodes1))
4583 return(xmlXPathNodeSetCreate(NULL));
4584 xmlXPathNodeSetSort(nodes1);
4585 xmlXPathNodeSetSort(nodes2);
4586 return(xmlXPathNodeLeadingSorted(nodes1,
4587 xmlXPathNodeSetItem(nodes2, 1)));
4588}
4589
4590/**
4591 * xmlXPathNodeTrailingSorted:
4592 * @nodes: a node-set, sorted by document order
4593 * @node: a node
4594 *
4595 * Implements the EXSLT - Sets trailing() function:
4596 * node-set set:trailing (node-set, node-set)
4597 *
4598 * Returns the nodes in @nodes that follow @node in document order,
4599 * @nodes if @node is NULL or an empty node-set if @nodes
4600 * doesn't contain @node
4601 */
4602xmlNodeSetPtr
4603xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4604 int i, l;
4605 xmlNodePtr cur;
4606 xmlNodeSetPtr ret;
4607
4608 if (node == NULL)
4609 return(nodes);
4610
4611 ret = xmlXPathNodeSetCreate(NULL);
4612 if (xmlXPathNodeSetIsEmpty(nodes) ||
4613 (!xmlXPathNodeSetContains(nodes, node)))
4614 return(ret);
4615
4616 l = xmlXPathNodeSetGetLength(nodes);
4617 for (i = l - 1; i >= 0; i--) {
4618 cur = xmlXPathNodeSetItem(nodes, i);
4619 if (cur == node)
4620 break;
4621 xmlXPathNodeSetAddUnique(ret, cur);
4622 }
4623 xmlXPathNodeSetSort(ret); /* bug 413451 */
4624 return(ret);
4625}
4626
4627/**
4628 * xmlXPathNodeTrailing:
4629 * @nodes: a node-set
4630 * @node: a node
4631 *
4632 * Implements the EXSLT - Sets trailing() function:
4633 * node-set set:trailing (node-set, node-set)
4634 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4635 * is called.
4636 *
4637 * Returns the nodes in @nodes that follow @node in document order,
4638 * @nodes if @node is NULL or an empty node-set if @nodes
4639 * doesn't contain @node
4640 */
4641xmlNodeSetPtr
4642xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4643 xmlXPathNodeSetSort(nodes);
4644 return(xmlXPathNodeTrailingSorted(nodes, node));
4645}
4646
4647/**
4648 * xmlXPathTrailingSorted:
4649 * @nodes1: a node-set, sorted by document order
4650 * @nodes2: a node-set, sorted by document order
4651 *
4652 * Implements the EXSLT - Sets trailing() function:
4653 * node-set set:trailing (node-set, node-set)
4654 *
4655 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4656 * in document order, @nodes1 if @nodes2 is NULL or empty or
4657 * an empty node-set if @nodes1 doesn't contain @nodes2
4658 */
4659xmlNodeSetPtr
4660xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4661 if (xmlXPathNodeSetIsEmpty(nodes2))
4662 return(nodes1);
4663 return(xmlXPathNodeTrailingSorted(nodes1,
4664 xmlXPathNodeSetItem(nodes2, 0)));
4665}
4666
4667/**
4668 * xmlXPathTrailing:
4669 * @nodes1: a node-set
4670 * @nodes2: a node-set
4671 *
4672 * Implements the EXSLT - Sets trailing() function:
4673 * node-set set:trailing (node-set, node-set)
4674 * @nodes1 and @nodes2 are sorted by document order, then
4675 * #xmlXPathTrailingSorted is called.
4676 *
4677 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4678 * in document order, @nodes1 if @nodes2 is NULL or empty or
4679 * an empty node-set if @nodes1 doesn't contain @nodes2
4680 */
4681xmlNodeSetPtr
4682xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4683 if (xmlXPathNodeSetIsEmpty(nodes2))
4684 return(nodes1);
4685 if (xmlXPathNodeSetIsEmpty(nodes1))
4686 return(xmlXPathNodeSetCreate(NULL));
4687 xmlXPathNodeSetSort(nodes1);
4688 xmlXPathNodeSetSort(nodes2);
4689 return(xmlXPathNodeTrailingSorted(nodes1,
4690 xmlXPathNodeSetItem(nodes2, 0)));
4691}
4692
4693/************************************************************************
4694 * *
4695 * Routines to handle extra functions *
4696 * *
4697 ************************************************************************/
4698
4699/**
4700 * xmlXPathRegisterFunc:
4701 * @ctxt: the XPath context
4702 * @name: the function name
4703 * @f: the function implementation or NULL
4704 *
4705 * Register a new function. If @f is NULL it unregisters the function
4706 *
4707 * Returns 0 in case of success, -1 in case of error
4708 */
4709int
4710xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4711 xmlXPathFunction f) {
4712 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4713}
4714
4715/**
4716 * xmlXPathRegisterFuncNS:
4717 * @ctxt: the XPath context
4718 * @name: the function name
4719 * @ns_uri: the function namespace URI
4720 * @f: the function implementation or NULL
4721 *
4722 * Register a new function. If @f is NULL it unregisters the function
4723 *
4724 * Returns 0 in case of success, -1 in case of error
4725 */
4726int
4727xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4728 const xmlChar *ns_uri, xmlXPathFunction f) {
4729 if (ctxt == NULL)
4730 return(-1);
4731 if (name == NULL)
4732 return(-1);
4733
4734 if (ctxt->funcHash == NULL)
4735 ctxt->funcHash = xmlHashCreate(0);
4736 if (ctxt->funcHash == NULL)
4737 return(-1);
4738 if (f == NULL)
4739 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4740 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
4741}
4742
4743/**
4744 * xmlXPathRegisterFuncLookup:
4745 * @ctxt: the XPath context
4746 * @f: the lookup function
4747 * @funcCtxt: the lookup data
4748 *
4749 * Registers an external mechanism to do function lookup.
4750 */
4751void
4752xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4753 xmlXPathFuncLookupFunc f,
4754 void *funcCtxt) {
4755 if (ctxt == NULL)
4756 return;
4757 ctxt->funcLookupFunc = f;
4758 ctxt->funcLookupData = funcCtxt;
4759}
4760
4761/**
4762 * xmlXPathFunctionLookup:
4763 * @ctxt: the XPath context
4764 * @name: the function name
4765 *
4766 * Search in the Function array of the context for the given
4767 * function.
4768 *
4769 * Returns the xmlXPathFunction or NULL if not found
4770 */
4771xmlXPathFunction
4772xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4773 if (ctxt == NULL)
4774 return (NULL);
4775
4776 if (ctxt->funcLookupFunc != NULL) {
4777 xmlXPathFunction ret;
4778 xmlXPathFuncLookupFunc f;
4779
4780 f = ctxt->funcLookupFunc;
4781 ret = f(ctxt->funcLookupData, name, NULL);
4782 if (ret != NULL)
4783 return(ret);
4784 }
4785 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4786}
4787
4788/**
4789 * xmlXPathFunctionLookupNS:
4790 * @ctxt: the XPath context
4791 * @name: the function name
4792 * @ns_uri: the function namespace URI
4793 *
4794 * Search in the Function array of the context for the given
4795 * function.
4796 *
4797 * Returns the xmlXPathFunction or NULL if not found
4798 */
4799xmlXPathFunction
4800xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4801 const xmlChar *ns_uri) {
4802 xmlXPathFunction ret;
4803
4804 if (ctxt == NULL)
4805 return(NULL);
4806 if (name == NULL)
4807 return(NULL);
4808
4809 if (ctxt->funcLookupFunc != NULL) {
4810 xmlXPathFuncLookupFunc f;
4811
4812 f = ctxt->funcLookupFunc;
4813 ret = f(ctxt->funcLookupData, name, ns_uri);
4814 if (ret != NULL)
4815 return(ret);
4816 }
4817
4818 if (ctxt->funcHash == NULL)
4819 return(NULL);
4820
4821 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4822 return(ret);
4823}
4824
4825/**
4826 * xmlXPathRegisteredFuncsCleanup:
4827 * @ctxt: the XPath context
4828 *
4829 * Cleanup the XPath context data associated to registered functions
4830 */
4831void
4832xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4833 if (ctxt == NULL)
4834 return;
4835
4836 xmlHashFree(ctxt->funcHash, NULL);
4837 ctxt->funcHash = NULL;
4838}
4839
4840/************************************************************************
4841 * *
4842 * Routines to handle Variables *
4843 * *
4844 ************************************************************************/
4845
4846/**
4847 * xmlXPathRegisterVariable:
4848 * @ctxt: the XPath context
4849 * @name: the variable name
4850 * @value: the variable value or NULL
4851 *
4852 * Register a new variable value. If @value is NULL it unregisters
4853 * the variable
4854 *
4855 * Returns 0 in case of success, -1 in case of error
4856 */
4857int
4858xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4859 xmlXPathObjectPtr value) {
4860 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4861}
4862
4863/**
4864 * xmlXPathRegisterVariableNS:
4865 * @ctxt: the XPath context
4866 * @name: the variable name
4867 * @ns_uri: the variable namespace URI
4868 * @value: the variable value or NULL
4869 *
4870 * Register a new variable value. If @value is NULL it unregisters
4871 * the variable
4872 *
4873 * Returns 0 in case of success, -1 in case of error
4874 */
4875int
4876xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4877 const xmlChar *ns_uri,
4878 xmlXPathObjectPtr value) {
4879 if (ctxt == NULL)
4880 return(-1);
4881 if (name == NULL)
4882 return(-1);
4883
4884 if (ctxt->varHash == NULL)
4885 ctxt->varHash = xmlHashCreate(0);
4886 if (ctxt->varHash == NULL)
4887 return(-1);
4888 if (value == NULL)
4889 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4890 (xmlHashDeallocator)xmlXPathFreeObject));
4891 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4892 (void *) value,
4893 (xmlHashDeallocator)xmlXPathFreeObject));
4894}
4895
4896/**
4897 * xmlXPathRegisterVariableLookup:
4898 * @ctxt: the XPath context
4899 * @f: the lookup function
4900 * @data: the lookup data
4901 *
4902 * register an external mechanism to do variable lookup
4903 */
4904void
4905xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4906 xmlXPathVariableLookupFunc f, void *data) {
4907 if (ctxt == NULL)
4908 return;
4909 ctxt->varLookupFunc = f;
4910 ctxt->varLookupData = data;
4911}
4912
4913/**
4914 * xmlXPathVariableLookup:
4915 * @ctxt: the XPath context
4916 * @name: the variable name
4917 *
4918 * Search in the Variable array of the context for the given
4919 * variable value.
4920 *
4921 * Returns a copy of the value or NULL if not found
4922 */
4923xmlXPathObjectPtr
4924xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4925 if (ctxt == NULL)
4926 return(NULL);
4927
4928 if (ctxt->varLookupFunc != NULL) {
4929 xmlXPathObjectPtr ret;
4930
4931 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4932 (ctxt->varLookupData, name, NULL);
4933 return(ret);
4934 }
4935 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4936}
4937
4938/**
4939 * xmlXPathVariableLookupNS:
4940 * @ctxt: the XPath context
4941 * @name: the variable name
4942 * @ns_uri: the variable namespace URI
4943 *
4944 * Search in the Variable array of the context for the given
4945 * variable value.
4946 *
4947 * Returns the a copy of the value or NULL if not found
4948 */
4949xmlXPathObjectPtr
4950xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4951 const xmlChar *ns_uri) {
4952 if (ctxt == NULL)
4953 return(NULL);
4954
4955 if (ctxt->varLookupFunc != NULL) {
4956 xmlXPathObjectPtr ret;
4957
4958 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4959 (ctxt->varLookupData, name, ns_uri);
4960 if (ret != NULL) return(ret);
4961 }
4962
4963 if (ctxt->varHash == NULL)
4964 return(NULL);
4965 if (name == NULL)
4966 return(NULL);
4967
4968 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
4969 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
4970}
4971
4972/**
4973 * xmlXPathRegisteredVariablesCleanup:
4974 * @ctxt: the XPath context
4975 *
4976 * Cleanup the XPath context data associated to registered variables
4977 */
4978void
4979xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4980 if (ctxt == NULL)
4981 return;
4982
4983 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
4984 ctxt->varHash = NULL;
4985}
4986
4987/**
4988 * xmlXPathRegisterNs:
4989 * @ctxt: the XPath context
4990 * @prefix: the namespace prefix
4991 * @ns_uri: the namespace name
4992 *
4993 * Register a new namespace. If @ns_uri is NULL it unregisters
4994 * the namespace
4995 *
4996 * Returns 0 in case of success, -1 in case of error
4997 */
4998int
4999xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5000 const xmlChar *ns_uri) {
5001 if (ctxt == NULL)
5002 return(-1);
5003 if (prefix == NULL)
5004 return(-1);
5005
5006 if (ctxt->nsHash == NULL)
5007 ctxt->nsHash = xmlHashCreate(10);
5008 if (ctxt->nsHash == NULL)
5009 return(-1);
5010 if (ns_uri == NULL)
5011 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5012 (xmlHashDeallocator)xmlFree));
5013 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5014 (xmlHashDeallocator)xmlFree));
5015}
5016
5017/**
5018 * xmlXPathNsLookup:
5019 * @ctxt: the XPath context
5020 * @prefix: the namespace prefix value
5021 *
5022 * Search in the namespace declaration array of the context for the given
5023 * namespace name associated to the given prefix
5024 *
5025 * Returns the value or NULL if not found
5026 */
5027const xmlChar *
5028xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5029 if (ctxt == NULL)
5030 return(NULL);
5031 if (prefix == NULL)
5032 return(NULL);
5033
5034#ifdef XML_XML_NAMESPACE
5035 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5036 return(XML_XML_NAMESPACE);
5037#endif
5038
5039 if (ctxt->namespaces != NULL) {
5040 int i;
5041
5042 for (i = 0;i < ctxt->nsNr;i++) {
5043 if ((ctxt->namespaces[i] != NULL) &&
5044 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5045 return(ctxt->namespaces[i]->href);
5046 }
5047 }
5048
5049 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5050}
5051
5052/**
5053 * xmlXPathRegisteredNsCleanup:
5054 * @ctxt: the XPath context
5055 *
5056 * Cleanup the XPath context data associated to registered variables
5057 */
5058void
5059xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5060 if (ctxt == NULL)
5061 return;
5062
5063 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
5064 ctxt->nsHash = NULL;
5065}
5066
5067/************************************************************************
5068 * *
5069 * Routines to handle Values *
5070 * *
5071 ************************************************************************/
5072
5073/* Allocations are terrible, one needs to optimize all this !!! */
5074
5075/**
5076 * xmlXPathNewFloat:
5077 * @val: the double value
5078 *
5079 * Create a new xmlXPathObjectPtr of type double and of value @val
5080 *
5081 * Returns the newly created object.
5082 */
5083xmlXPathObjectPtr
5084xmlXPathNewFloat(double val) {
5085 xmlXPathObjectPtr ret;
5086
5087 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5088 if (ret == NULL) {
5089 xmlXPathErrMemory(NULL, "creating float object\n");
5090 return(NULL);
5091 }
5092 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5093 ret->type = XPATH_NUMBER;
5094 ret->floatval = val;
5095#ifdef XP_DEBUG_OBJ_USAGE
5096 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5097#endif
5098 return(ret);
5099}
5100
5101/**
5102 * xmlXPathNewBoolean:
5103 * @val: the boolean value
5104 *
5105 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5106 *
5107 * Returns the newly created object.
5108 */
5109xmlXPathObjectPtr
5110xmlXPathNewBoolean(int val) {
5111 xmlXPathObjectPtr ret;
5112
5113 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5114 if (ret == NULL) {
5115 xmlXPathErrMemory(NULL, "creating boolean object\n");
5116 return(NULL);
5117 }
5118 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5119 ret->type = XPATH_BOOLEAN;
5120 ret->boolval = (val != 0);
5121#ifdef XP_DEBUG_OBJ_USAGE
5122 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5123#endif
5124 return(ret);
5125}
5126
5127/**
5128 * xmlXPathNewString:
5129 * @val: the xmlChar * value
5130 *
5131 * Create a new xmlXPathObjectPtr of type string and of value @val
5132 *
5133 * Returns the newly created object.
5134 */
5135xmlXPathObjectPtr
5136xmlXPathNewString(const xmlChar *val) {
5137 xmlXPathObjectPtr ret;
5138
5139 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5140 if (ret == NULL) {
5141 xmlXPathErrMemory(NULL, "creating string object\n");
5142 return(NULL);
5143 }
5144 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5145 ret->type = XPATH_STRING;
5146 if (val != NULL)
5147 ret->stringval = xmlStrdup(val);
5148 else
5149 ret->stringval = xmlStrdup((const xmlChar *)"");
5150#ifdef XP_DEBUG_OBJ_USAGE
5151 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5152#endif
5153 return(ret);
5154}
5155
5156/**
5157 * xmlXPathWrapString:
5158 * @val: the xmlChar * value
5159 *
5160 * Wraps the @val string into an XPath object.
5161 *
5162 * Returns the newly created object.
5163 */
5164xmlXPathObjectPtr
5165xmlXPathWrapString (xmlChar *val) {
5166 xmlXPathObjectPtr ret;
5167
5168 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5169 if (ret == NULL) {
5170 xmlXPathErrMemory(NULL, "creating string object\n");
5171 return(NULL);
5172 }
5173 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5174 ret->type = XPATH_STRING;
5175 ret->stringval = val;
5176#ifdef XP_DEBUG_OBJ_USAGE
5177 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5178#endif
5179 return(ret);
5180}
5181
5182/**
5183 * xmlXPathNewCString:
5184 * @val: the char * value
5185 *
5186 * Create a new xmlXPathObjectPtr of type string and of value @val
5187 *
5188 * Returns the newly created object.
5189 */
5190xmlXPathObjectPtr
5191xmlXPathNewCString(const char *val) {
5192 xmlXPathObjectPtr ret;
5193
5194 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5195 if (ret == NULL) {
5196 xmlXPathErrMemory(NULL, "creating string object\n");
5197 return(NULL);
5198 }
5199 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5200 ret->type = XPATH_STRING;
5201 ret->stringval = xmlStrdup(BAD_CAST val);
5202#ifdef XP_DEBUG_OBJ_USAGE
5203 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5204#endif
5205 return(ret);
5206}
5207
5208/**
5209 * xmlXPathWrapCString:
5210 * @val: the char * value
5211 *
5212 * Wraps a string into an XPath object.
5213 *
5214 * Returns the newly created object.
5215 */
5216xmlXPathObjectPtr
5217xmlXPathWrapCString (char * val) {
5218 return(xmlXPathWrapString((xmlChar *)(val)));
5219}
5220
5221/**
5222 * xmlXPathWrapExternal:
5223 * @val: the user data
5224 *
5225 * Wraps the @val data into an XPath object.
5226 *
5227 * Returns the newly created object.
5228 */
5229xmlXPathObjectPtr
5230xmlXPathWrapExternal (void *val) {
5231 xmlXPathObjectPtr ret;
5232
5233 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5234 if (ret == NULL) {
5235 xmlXPathErrMemory(NULL, "creating user object\n");
5236 return(NULL);
5237 }
5238 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5239 ret->type = XPATH_USERS;
5240 ret->user = val;
5241#ifdef XP_DEBUG_OBJ_USAGE
5242 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5243#endif
5244 return(ret);
5245}
5246
5247/**
5248 * xmlXPathObjectCopy:
5249 * @val: the original object
5250 *
5251 * allocate a new copy of a given object
5252 *
5253 * Returns the newly created object.
5254 */
5255xmlXPathObjectPtr
5256xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5257 xmlXPathObjectPtr ret;
5258
5259 if (val == NULL)
5260 return(NULL);
5261
5262 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5263 if (ret == NULL) {
5264 xmlXPathErrMemory(NULL, "copying object\n");
5265 return(NULL);
5266 }
5267 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5268#ifdef XP_DEBUG_OBJ_USAGE
5269 xmlXPathDebugObjUsageRequested(NULL, val->type);
5270#endif
5271 switch (val->type) {
5272 case XPATH_BOOLEAN:
5273 case XPATH_NUMBER:
5274 case XPATH_POINT:
5275 case XPATH_RANGE:
5276 break;
5277 case XPATH_STRING:
5278 ret->stringval = xmlStrdup(val->stringval);
5279 break;
5280 case XPATH_XSLT_TREE:
5281#if 0
5282/*
5283 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5284 this previous handling is no longer correct, and can cause some serious
5285 problems (ref. bug 145547)
5286*/
5287 if ((val->nodesetval != NULL) &&
5288 (val->nodesetval->nodeTab != NULL)) {
5289 xmlNodePtr cur, tmp;
5290 xmlDocPtr top;
5291
5292 ret->boolval = 1;
5293 top = xmlNewDoc(NULL);
5294 top->name = (char *)
5295 xmlStrdup(val->nodesetval->nodeTab[0]->name);
5296 ret->user = top;
5297 if (top != NULL) {
5298 top->doc = top;
5299 cur = val->nodesetval->nodeTab[0]->children;
5300 while (cur != NULL) {
5301 tmp = xmlDocCopyNode(cur, top, 1);
5302 xmlAddChild((xmlNodePtr) top, tmp);
5303 cur = cur->next;
5304 }
5305 }
5306
5307 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5308 } else
5309 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5310 /* Deallocate the copied tree value */
5311 break;
5312#endif
5313 case XPATH_NODESET:
5314 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5315 /* Do not deallocate the copied tree value */
5316 ret->boolval = 0;
5317 break;
5318 case XPATH_LOCATIONSET:
5319#ifdef LIBXML_XPTR_ENABLED
5320 {
5321 xmlLocationSetPtr loc = val->user;
5322 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5323 break;
5324 }
5325#endif
5326 case XPATH_USERS:
5327 ret->user = val->user;
5328 break;
5329 case XPATH_UNDEFINED:
5330 xmlGenericError(xmlGenericErrorContext,
5331 "xmlXPathObjectCopy: unsupported type %d\n",
5332 val->type);
5333 break;
5334 }
5335 return(ret);
5336}
5337
5338/**
5339 * xmlXPathFreeObject:
5340 * @obj: the object to free
5341 *
5342 * Free up an xmlXPathObjectPtr object.
5343 */
5344void
5345xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5346 if (obj == NULL) return;
5347 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5348 if (obj->boolval) {
5349#if 0
5350 if (obj->user != NULL) {
5351 xmlXPathFreeNodeSet(obj->nodesetval);
5352 xmlFreeNodeList((xmlNodePtr) obj->user);
5353 } else
5354#endif
5355 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5356 if (obj->nodesetval != NULL)
5357 xmlXPathFreeValueTree(obj->nodesetval);
5358 } else {
5359 if (obj->nodesetval != NULL)
5360 xmlXPathFreeNodeSet(obj->nodesetval);
5361 }
5362#ifdef LIBXML_XPTR_ENABLED
5363 } else if (obj->type == XPATH_LOCATIONSET) {
5364 if (obj->user != NULL)
5365 xmlXPtrFreeLocationSet(obj->user);
5366#endif
5367 } else if (obj->type == XPATH_STRING) {
5368 if (obj->stringval != NULL)
5369 xmlFree(obj->stringval);
5370 }
5371#ifdef XP_DEBUG_OBJ_USAGE
5372 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5373#endif
5374 xmlFree(obj);
5375}
5376
5377/**
5378 * xmlXPathReleaseObject:
5379 * @obj: the xmlXPathObjectPtr to free or to cache
5380 *
5381 * Depending on the state of the cache this frees the given
5382 * XPath object or stores it in the cache.
5383 */
5384static void
5385xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5386{
5387#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5388 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5389 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5390
5391#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5392
5393 if (obj == NULL)
5394 return;
5395 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5396 xmlXPathFreeObject(obj);
5397 } else {
5398 xmlXPathContextCachePtr cache =
5399 (xmlXPathContextCachePtr) ctxt->cache;
5400
5401 switch (obj->type) {
5402 case XPATH_NODESET:
5403 case XPATH_XSLT_TREE:
5404 if (obj->nodesetval != NULL) {
5405 if (obj->boolval) {
5406 /*
5407 * It looks like the @boolval is used for
5408 * evaluation if this an XSLT Result Tree Fragment.
5409 * TODO: Check if this assumption is correct.
5410 */
5411 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5412 xmlXPathFreeValueTree(obj->nodesetval);
5413 obj->nodesetval = NULL;
5414 } else if ((obj->nodesetval->nodeMax <= 40) &&
5415 (XP_CACHE_WANTS(cache->nodesetObjs,
5416 cache->maxNodeset)))
5417 {
5418 XP_CACHE_ADD(cache->nodesetObjs, obj);
5419 goto obj_cached;
5420 } else {
5421 xmlXPathFreeNodeSet(obj->nodesetval);
5422 obj->nodesetval = NULL;
5423 }
5424 }
5425 break;
5426 case XPATH_STRING:
5427 if (obj->stringval != NULL)
5428 xmlFree(obj->stringval);
5429
5430 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5431 XP_CACHE_ADD(cache->stringObjs, obj);
5432 goto obj_cached;
5433 }
5434 break;
5435 case XPATH_BOOLEAN:
5436 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5437 XP_CACHE_ADD(cache->booleanObjs, obj);
5438 goto obj_cached;
5439 }
5440 break;
5441 case XPATH_NUMBER:
5442 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5443 XP_CACHE_ADD(cache->numberObjs, obj);
5444 goto obj_cached;
5445 }
5446 break;
5447#ifdef LIBXML_XPTR_ENABLED
5448 case XPATH_LOCATIONSET:
5449 if (obj->user != NULL) {
5450 xmlXPtrFreeLocationSet(obj->user);
5451 }
5452 goto free_obj;
5453#endif
5454 default:
5455 goto free_obj;
5456 }
5457
5458 /*
5459 * Fallback to adding to the misc-objects slot.
5460 */
5461 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5462 XP_CACHE_ADD(cache->miscObjs, obj);
5463 } else
5464 goto free_obj;
5465
5466obj_cached:
5467
5468#ifdef XP_DEBUG_OBJ_USAGE
5469 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5470#endif
5471
5472 if (obj->nodesetval != NULL) {
5473 xmlNodeSetPtr tmpset = obj->nodesetval;
5474
5475 /*
5476 * TODO: Due to those nasty ns-nodes, we need to traverse
5477 * the list and free the ns-nodes.
5478 * URGENT TODO: Check if it's actually slowing things down.
5479 * Maybe we shouldn't try to preserve the list.
5480 */
5481 if (tmpset->nodeNr > 1) {
5482 int i;
5483 xmlNodePtr node;
5484
5485 for (i = 0; i < tmpset->nodeNr; i++) {
5486 node = tmpset->nodeTab[i];
5487 if ((node != NULL) &&
5488 (node->type == XML_NAMESPACE_DECL))
5489 {
5490 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5491 }
5492 }
5493 } else if (tmpset->nodeNr == 1) {
5494 if ((tmpset->nodeTab[0] != NULL) &&
5495 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5496 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5497 }
5498 tmpset->nodeNr = 0;
5499 memset(obj, 0, sizeof(xmlXPathObject));
5500 obj->nodesetval = tmpset;
5501 } else
5502 memset(obj, 0, sizeof(xmlXPathObject));
5503
5504 return;
5505
5506free_obj:
5507 /*
5508 * Cache is full; free the object.
5509 */
5510 if (obj->nodesetval != NULL)
5511 xmlXPathFreeNodeSet(obj->nodesetval);
5512#ifdef XP_DEBUG_OBJ_USAGE
5513 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5514#endif
5515 xmlFree(obj);
5516 }
5517 return;
5518}
5519
5520
5521/************************************************************************
5522 * *
5523 * Type Casting Routines *
5524 * *
5525 ************************************************************************/
5526
5527/**
5528 * xmlXPathCastBooleanToString:
5529 * @val: a boolean
5530 *
5531 * Converts a boolean to its string value.
5532 *
5533 * Returns a newly allocated string.
5534 */
5535xmlChar *
5536xmlXPathCastBooleanToString (int val) {
5537 xmlChar *ret;
5538 if (val)
5539 ret = xmlStrdup((const xmlChar *) "true");
5540 else
5541 ret = xmlStrdup((const xmlChar *) "false");
5542 return(ret);
5543}
5544
5545/**
5546 * xmlXPathCastNumberToString:
5547 * @val: a number
5548 *
5549 * Converts a number to its string value.
5550 *
5551 * Returns a newly allocated string.
5552 */
5553xmlChar *
5554xmlXPathCastNumberToString (double val) {
5555 xmlChar *ret;
5556 switch (xmlXPathIsInf(val)) {
5557 case 1:
5558 ret = xmlStrdup((const xmlChar *) "Infinity");
5559 break;
5560 case -1:
5561 ret = xmlStrdup((const xmlChar *) "-Infinity");
5562 break;
5563 default:
5564 if (xmlXPathIsNaN(val)) {
5565 ret = xmlStrdup((const xmlChar *) "NaN");
5566 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5567 ret = xmlStrdup((const xmlChar *) "0");
5568 } else {
5569 /* could be improved */
5570 char buf[100];
5571 xmlXPathFormatNumber(val, buf, 99);
5572 buf[99] = 0;
5573 ret = xmlStrdup((const xmlChar *) buf);
5574 }
5575 }
5576 return(ret);
5577}
5578
5579/**
5580 * xmlXPathCastNodeToString:
5581 * @node: a node
5582 *
5583 * Converts a node to its string value.
5584 *
5585 * Returns a newly allocated string.
5586 */
5587xmlChar *
5588xmlXPathCastNodeToString (xmlNodePtr node) {
5589xmlChar *ret;
5590 if ((ret = xmlNodeGetContent(node)) == NULL)
5591 ret = xmlStrdup((const xmlChar *) "");
5592 return(ret);
5593}
5594
5595/**
5596 * xmlXPathCastNodeSetToString:
5597 * @ns: a node-set
5598 *
5599 * Converts a node-set to its string value.
5600 *
5601 * Returns a newly allocated string.
5602 */
5603xmlChar *
5604xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5605 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5606 return(xmlStrdup((const xmlChar *) ""));
5607
5608 if (ns->nodeNr > 1)
5609 xmlXPathNodeSetSort(ns);
5610 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5611}
5612
5613/**
5614 * xmlXPathCastToString:
5615 * @val: an XPath object
5616 *
5617 * Converts an existing object to its string() equivalent
5618 *
5619 * Returns the allocated string value of the object, NULL in case of error.
5620 * It's up to the caller to free the string memory with xmlFree().
5621 */
5622xmlChar *
5623xmlXPathCastToString(xmlXPathObjectPtr val) {
5624 xmlChar *ret = NULL;
5625
5626 if (val == NULL)
5627 return(xmlStrdup((const xmlChar *) ""));
5628 switch (val->type) {
5629 case XPATH_UNDEFINED:
5630#ifdef DEBUG_EXPR
5631 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5632#endif
5633 ret = xmlStrdup((const xmlChar *) "");
5634 break;
5635 case XPATH_NODESET:
5636 case XPATH_XSLT_TREE:
5637 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5638 break;
5639 case XPATH_STRING:
5640 return(xmlStrdup(val->stringval));
5641 case XPATH_BOOLEAN:
5642 ret = xmlXPathCastBooleanToString(val->boolval);
5643 break;
5644 case XPATH_NUMBER: {
5645 ret = xmlXPathCastNumberToString(val->floatval);
5646 break;
5647 }
5648 case XPATH_USERS:
5649 case XPATH_POINT:
5650 case XPATH_RANGE:
5651 case XPATH_LOCATIONSET:
5652 TODO
5653 ret = xmlStrdup((const xmlChar *) "");
5654 break;
5655 }
5656 return(ret);
5657}
5658
5659/**
5660 * xmlXPathConvertString:
5661 * @val: an XPath object
5662 *
5663 * Converts an existing object to its string() equivalent
5664 *
5665 * Returns the new object, the old one is freed (or the operation
5666 * is done directly on @val)
5667 */
5668xmlXPathObjectPtr
5669xmlXPathConvertString(xmlXPathObjectPtr val) {
5670 xmlChar *res = NULL;
5671
5672 if (val == NULL)
5673 return(xmlXPathNewCString(""));
5674
5675 switch (val->type) {
5676 case XPATH_UNDEFINED:
5677#ifdef DEBUG_EXPR
5678 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5679#endif
5680 break;
5681 case XPATH_NODESET:
5682 case XPATH_XSLT_TREE:
5683 res = xmlXPathCastNodeSetToString(val->nodesetval);
5684 break;
5685 case XPATH_STRING:
5686 return(val);
5687 case XPATH_BOOLEAN:
5688 res = xmlXPathCastBooleanToString(val->boolval);
5689 break;
5690 case XPATH_NUMBER:
5691 res = xmlXPathCastNumberToString(val->floatval);
5692 break;
5693 case XPATH_USERS:
5694 case XPATH_POINT:
5695 case XPATH_RANGE:
5696 case XPATH_LOCATIONSET:
5697 TODO;
5698 break;
5699 }
5700 xmlXPathFreeObject(val);
5701 if (res == NULL)
5702 return(xmlXPathNewCString(""));
5703 return(xmlXPathWrapString(res));
5704}
5705
5706/**
5707 * xmlXPathCastBooleanToNumber:
5708 * @val: a boolean
5709 *
5710 * Converts a boolean to its number value
5711 *
5712 * Returns the number value
5713 */
5714double
5715xmlXPathCastBooleanToNumber(int val) {
5716 if (val)
5717 return(1.0);
5718 return(0.0);
5719}
5720
5721/**
5722 * xmlXPathCastStringToNumber:
5723 * @val: a string
5724 *
5725 * Converts a string to its number value
5726 *
5727 * Returns the number value
5728 */
5729double
5730xmlXPathCastStringToNumber(const xmlChar * val) {
5731 return(xmlXPathStringEvalNumber(val));
5732}
5733
5734/**
5735 * xmlXPathCastNodeToNumber:
5736 * @node: a node
5737 *
5738 * Converts a node to its number value
5739 *
5740 * Returns the number value
5741 */
5742double
5743xmlXPathCastNodeToNumber (xmlNodePtr node) {
5744 xmlChar *strval;
5745 double ret;
5746
5747 if (node == NULL)
5748 return(xmlXPathNAN);
5749 strval = xmlXPathCastNodeToString(node);
5750 if (strval == NULL)
5751 return(xmlXPathNAN);
5752 ret = xmlXPathCastStringToNumber(strval);
5753 xmlFree(strval);
5754
5755 return(ret);
5756}
5757
5758/**
5759 * xmlXPathCastNodeSetToNumber:
5760 * @ns: a node-set
5761 *
5762 * Converts a node-set to its number value
5763 *
5764 * Returns the number value
5765 */
5766double
5767xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5768 xmlChar *str;
5769 double ret;
5770
5771 if (ns == NULL)
5772 return(xmlXPathNAN);
5773 str = xmlXPathCastNodeSetToString(ns);
5774 ret = xmlXPathCastStringToNumber(str);
5775 xmlFree(str);
5776 return(ret);
5777}
5778
5779/**
5780 * xmlXPathCastToNumber:
5781 * @val: an XPath object
5782 *
5783 * Converts an XPath object to its number value
5784 *
5785 * Returns the number value
5786 */
5787double
5788xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5789 double ret = 0.0;
5790
5791 if (val == NULL)
5792 return(xmlXPathNAN);
5793 switch (val->type) {
5794 case XPATH_UNDEFINED:
5795#ifdef DEGUB_EXPR
5796 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5797#endif
5798 ret = xmlXPathNAN;
5799 break;
5800 case XPATH_NODESET:
5801 case XPATH_XSLT_TREE:
5802 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5803 break;
5804 case XPATH_STRING:
5805 ret = xmlXPathCastStringToNumber(val->stringval);
5806 break;
5807 case XPATH_NUMBER:
5808 ret = val->floatval;
5809 break;
5810 case XPATH_BOOLEAN:
5811 ret = xmlXPathCastBooleanToNumber(val->boolval);
5812 break;
5813 case XPATH_USERS:
5814 case XPATH_POINT:
5815 case XPATH_RANGE:
5816 case XPATH_LOCATIONSET:
5817 TODO;
5818 ret = xmlXPathNAN;
5819 break;
5820 }
5821 return(ret);
5822}
5823
5824/**
5825 * xmlXPathConvertNumber:
5826 * @val: an XPath object
5827 *
5828 * Converts an existing object to its number() equivalent
5829 *
5830 * Returns the new object, the old one is freed (or the operation
5831 * is done directly on @val)
5832 */
5833xmlXPathObjectPtr
5834xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5835 xmlXPathObjectPtr ret;
5836
5837 if (val == NULL)
5838 return(xmlXPathNewFloat(0.0));
5839 if (val->type == XPATH_NUMBER)
5840 return(val);
5841 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5842 xmlXPathFreeObject(val);
5843 return(ret);
5844}
5845
5846/**
5847 * xmlXPathCastNumberToBoolean:
5848 * @val: a number
5849 *
5850 * Converts a number to its boolean value
5851 *
5852 * Returns the boolean value
5853 */
5854int
5855xmlXPathCastNumberToBoolean (double val) {
5856 if (xmlXPathIsNaN(val) || (val == 0.0))
5857 return(0);
5858 return(1);
5859}
5860
5861/**
5862 * xmlXPathCastStringToBoolean:
5863 * @val: a string
5864 *
5865 * Converts a string to its boolean value
5866 *
5867 * Returns the boolean value
5868 */
5869int
5870xmlXPathCastStringToBoolean (const xmlChar *val) {
5871 if ((val == NULL) || (xmlStrlen(val) == 0))
5872 return(0);
5873 return(1);
5874}
5875
5876/**
5877 * xmlXPathCastNodeSetToBoolean:
5878 * @ns: a node-set
5879 *
5880 * Converts a node-set to its boolean value
5881 *
5882 * Returns the boolean value
5883 */
5884int
5885xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5886 if ((ns == NULL) || (ns->nodeNr == 0))
5887 return(0);
5888 return(1);
5889}
5890
5891/**
5892 * xmlXPathCastToBoolean:
5893 * @val: an XPath object
5894 *
5895 * Converts an XPath object to its boolean value
5896 *
5897 * Returns the boolean value
5898 */
5899int
5900xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5901 int ret = 0;
5902
5903 if (val == NULL)
5904 return(0);
5905 switch (val->type) {
5906 case XPATH_UNDEFINED:
5907#ifdef DEBUG_EXPR
5908 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
5909#endif
5910 ret = 0;
5911 break;
5912 case XPATH_NODESET:
5913 case XPATH_XSLT_TREE:
5914 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5915 break;
5916 case XPATH_STRING:
5917 ret = xmlXPathCastStringToBoolean(val->stringval);
5918 break;
5919 case XPATH_NUMBER:
5920 ret = xmlXPathCastNumberToBoolean(val->floatval);
5921 break;
5922 case XPATH_BOOLEAN:
5923 ret = val->boolval;
5924 break;
5925 case XPATH_USERS:
5926 case XPATH_POINT:
5927 case XPATH_RANGE:
5928 case XPATH_LOCATIONSET:
5929 TODO;
5930 ret = 0;
5931 break;
5932 }
5933 return(ret);
5934}
5935
5936
5937/**
5938 * xmlXPathConvertBoolean:
5939 * @val: an XPath object
5940 *
5941 * Converts an existing object to its boolean() equivalent
5942 *
5943 * Returns the new object, the old one is freed (or the operation
5944 * is done directly on @val)
5945 */
5946xmlXPathObjectPtr
5947xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
5948 xmlXPathObjectPtr ret;
5949
5950 if (val == NULL)
5951 return(xmlXPathNewBoolean(0));
5952 if (val->type == XPATH_BOOLEAN)
5953 return(val);
5954 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
5955 xmlXPathFreeObject(val);
5956 return(ret);
5957}
5958
5959/************************************************************************
5960 * *
5961 * Routines to handle XPath contexts *
5962 * *
5963 ************************************************************************/
5964
5965/**
5966 * xmlXPathNewContext:
5967 * @doc: the XML document
5968 *
5969 * Create a new xmlXPathContext
5970 *
5971 * Returns the xmlXPathContext just allocated. The caller will need to free it.
5972 */
5973xmlXPathContextPtr
5974xmlXPathNewContext(xmlDocPtr doc) {
5975 xmlXPathContextPtr ret;
5976
5977 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
5978 if (ret == NULL) {
5979 xmlXPathErrMemory(NULL, "creating context\n");
5980 return(NULL);
5981 }
5982 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
5983 ret->doc = doc;
5984 ret->node = NULL;
5985
5986 ret->varHash = NULL;
5987
5988 ret->nb_types = 0;
5989 ret->max_types = 0;
5990 ret->types = NULL;
5991
5992 ret->funcHash = xmlHashCreate(0);
5993
5994 ret->nb_axis = 0;
5995 ret->max_axis = 0;
5996 ret->axis = NULL;
5997
5998 ret->nsHash = NULL;
5999 ret->user = NULL;
6000
6001 ret->contextSize = -1;
6002 ret->proximityPosition = -1;
6003
6004#ifdef XP_DEFAULT_CACHE_ON
6005 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6006 xmlXPathFreeContext(ret);
6007 return(NULL);
6008 }
6009#endif
6010
6011 xmlXPathRegisterAllFunctions(ret);
6012
6013 return(ret);
6014}
6015
6016/**
6017 * xmlXPathFreeContext:
6018 * @ctxt: the context to free
6019 *
6020 * Free up an xmlXPathContext
6021 */
6022void
6023xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6024 if (ctxt == NULL) return;
6025
6026 if (ctxt->cache != NULL)
6027 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6028 xmlXPathRegisteredNsCleanup(ctxt);
6029 xmlXPathRegisteredFuncsCleanup(ctxt);
6030 xmlXPathRegisteredVariablesCleanup(ctxt);
6031 xmlResetError(&ctxt->lastError);
6032 xmlFree(ctxt);
6033}
6034
6035/************************************************************************
6036 * *
6037 * Routines to handle XPath parser contexts *
6038 * *
6039 ************************************************************************/
6040
6041#define CHECK_CTXT(ctxt) \
6042 if (ctxt == NULL) { \
6043 __xmlRaiseError(NULL, NULL, NULL, \
6044 NULL, NULL, XML_FROM_XPATH, \
6045 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6046 __FILE__, __LINE__, \
6047 NULL, NULL, NULL, 0, 0, \
6048 "NULL context pointer\n"); \
6049 return(NULL); \
6050 } \
6051
6052#define CHECK_CTXT_NEG(ctxt) \
6053 if (ctxt == NULL) { \
6054 __xmlRaiseError(NULL, NULL, NULL, \
6055 NULL, NULL, XML_FROM_XPATH, \
6056 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6057 __FILE__, __LINE__, \
6058 NULL, NULL, NULL, 0, 0, \
6059 "NULL context pointer\n"); \
6060 return(-1); \
6061 } \
6062
6063
6064#define CHECK_CONTEXT(ctxt) \
6065 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
6066 (ctxt->doc->children == NULL)) { \
6067 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
6068 return(NULL); \
6069 }
6070
6071
6072/**
6073 * xmlXPathNewParserContext:
6074 * @str: the XPath expression
6075 * @ctxt: the XPath context
6076 *
6077 * Create a new xmlXPathParserContext
6078 *
6079 * Returns the xmlXPathParserContext just allocated.
6080 */
6081xmlXPathParserContextPtr
6082xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6083 xmlXPathParserContextPtr ret;
6084
6085 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6086 if (ret == NULL) {
6087 xmlXPathErrMemory(ctxt, "creating parser context\n");
6088 return(NULL);
6089 }
6090 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6091 ret->cur = ret->base = str;
6092 ret->context = ctxt;
6093
6094 ret->comp = xmlXPathNewCompExpr();
6095 if (ret->comp == NULL) {
6096 xmlFree(ret->valueTab);
6097 xmlFree(ret);
6098 return(NULL);
6099 }
6100 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6101 ret->comp->dict = ctxt->dict;
6102 xmlDictReference(ret->comp->dict);
6103 }
6104
6105 return(ret);
6106}
6107
6108/**
6109 * xmlXPathCompParserContext:
6110 * @comp: the XPath compiled expression
6111 * @ctxt: the XPath context
6112 *
6113 * Create a new xmlXPathParserContext when processing a compiled expression
6114 *
6115 * Returns the xmlXPathParserContext just allocated.
6116 */
6117static xmlXPathParserContextPtr
6118xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6119 xmlXPathParserContextPtr ret;
6120
6121 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6122 if (ret == NULL) {
6123 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6124 return(NULL);
6125 }
6126 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6127
6128 /* Allocate the value stack */
6129 ret->valueTab = (xmlXPathObjectPtr *)
6130 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6131 if (ret->valueTab == NULL) {
6132 xmlFree(ret);
6133 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6134 return(NULL);
6135 }
6136 ret->valueNr = 0;
6137 ret->valueMax = 10;
6138 ret->value = NULL;
6139
6140 ret->context = ctxt;
6141 ret->comp = comp;
6142
6143 return(ret);
6144}
6145
6146/**
6147 * xmlXPathFreeParserContext:
6148 * @ctxt: the context to free
6149 *
6150 * Free up an xmlXPathParserContext
6151 */
6152void
6153xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6154 if (ctxt->valueTab != NULL) {
6155 xmlFree(ctxt->valueTab);
6156 }
6157 if (ctxt->comp != NULL) {
6158#ifdef XPATH_STREAMING
6159 if (ctxt->comp->stream != NULL) {
6160 xmlFreePatternList(ctxt->comp->stream);
6161 ctxt->comp->stream = NULL;
6162 }
6163#endif
6164 xmlXPathFreeCompExpr(ctxt->comp);
6165 }
6166 xmlFree(ctxt);
6167}
6168
6169/************************************************************************
6170 * *
6171 * The implicit core function library *
6172 * *
6173 ************************************************************************/
6174
6175/**
6176 * xmlXPathNodeValHash:
6177 * @node: a node pointer
6178 *
6179 * Function computing the beginning of the string value of the node,
6180 * used to speed up comparisons
6181 *
6182 * Returns an int usable as a hash
6183 */
6184static unsigned int
6185xmlXPathNodeValHash(xmlNodePtr node) {
6186 int len = 2;
6187 const xmlChar * string = NULL;
6188 xmlNodePtr tmp = NULL;
6189 unsigned int ret = 0;
6190
6191 if (node == NULL)
6192 return(0);
6193
6194 if (node->type == XML_DOCUMENT_NODE) {
6195 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6196 if (tmp == NULL)
6197 node = node->children;
6198 else
6199 node = tmp;
6200
6201 if (node == NULL)
6202 return(0);
6203 }
6204
6205 switch (node->type) {
6206 case XML_COMMENT_NODE:
6207 case XML_PI_NODE:
6208 case XML_CDATA_SECTION_NODE:
6209 case XML_TEXT_NODE:
6210 string = node->content;
6211 if (string == NULL)
6212 return(0);
6213 if (string[0] == 0)
6214 return(0);
6215 return(((unsigned int) string[0]) +
6216 (((unsigned int) string[1]) << 8));
6217 case XML_NAMESPACE_DECL:
6218 string = ((xmlNsPtr)node)->href;
6219 if (string == NULL)
6220 return(0);
6221 if (string[0] == 0)
6222 return(0);
6223 return(((unsigned int) string[0]) +
6224 (((unsigned int) string[1]) << 8));
6225 case XML_ATTRIBUTE_NODE:
6226 tmp = ((xmlAttrPtr) node)->children;
6227 break;
6228 case XML_ELEMENT_NODE:
6229 tmp = node->children;
6230 break;
6231 default:
6232 return(0);
6233 }
6234 while (tmp != NULL) {
6235 switch (tmp->type) {
6236 case XML_COMMENT_NODE:
6237 case XML_PI_NODE:
6238 case XML_CDATA_SECTION_NODE:
6239 case XML_TEXT_NODE:
6240 string = tmp->content;
6241 break;
6242 case XML_NAMESPACE_DECL:
6243 string = ((xmlNsPtr)tmp)->href;
6244 break;
6245 default:
6246 break;
6247 }
6248 if ((string != NULL) && (string[0] != 0)) {
6249 if (len == 1) {
6250 return(ret + (((unsigned int) string[0]) << 8));
6251 }
6252 if (string[1] == 0) {
6253 len = 1;
6254 ret = (unsigned int) string[0];
6255 } else {
6256 return(((unsigned int) string[0]) +
6257 (((unsigned int) string[1]) << 8));
6258 }
6259 }
6260 /*
6261 * Skip to next node
6262 */
6263 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6264 if (tmp->children->type != XML_ENTITY_DECL) {
6265 tmp = tmp->children;
6266 continue;
6267 }
6268 }
6269 if (tmp == node)
6270 break;
6271
6272 if (tmp->next != NULL) {
6273 tmp = tmp->next;
6274 continue;
6275 }
6276
6277 do {
6278 tmp = tmp->parent;
6279 if (tmp == NULL)
6280 break;
6281 if (tmp == node) {
6282 tmp = NULL;
6283 break;
6284 }
6285 if (tmp->next != NULL) {
6286 tmp = tmp->next;
6287 break;
6288 }
6289 } while (tmp != NULL);
6290 }
6291 return(ret);
6292}
6293
6294/**
6295 * xmlXPathStringHash:
6296 * @string: a string
6297 *
6298 * Function computing the beginning of the string value of the node,
6299 * used to speed up comparisons
6300 *
6301 * Returns an int usable as a hash
6302 */
6303static unsigned int
6304xmlXPathStringHash(const xmlChar * string) {
6305 if (string == NULL)
6306 return((unsigned int) 0);
6307 if (string[0] == 0)
6308 return(0);
6309 return(((unsigned int) string[0]) +
6310 (((unsigned int) string[1]) << 8));
6311}
6312
6313/**
6314 * xmlXPathCompareNodeSetFloat:
6315 * @ctxt: the XPath Parser context
6316 * @inf: less than (1) or greater than (0)
6317 * @strict: is the comparison strict
6318 * @arg: the node set
6319 * @f: the value
6320 *
6321 * Implement the compare operation between a nodeset and a number
6322 * @ns < @val (1, 1, ...
6323 * @ns <= @val (1, 0, ...
6324 * @ns > @val (0, 1, ...
6325 * @ns >= @val (0, 0, ...
6326 *
6327 * If one object to be compared is a node-set and the other is a number,
6328 * then the comparison will be true if and only if there is a node in the
6329 * node-set such that the result of performing the comparison on the number
6330 * to be compared and on the result of converting the string-value of that
6331 * node to a number using the number function is true.
6332 *
6333 * Returns 0 or 1 depending on the results of the test.
6334 */
6335static int
6336xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6337 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6338 int i, ret = 0;
6339 xmlNodeSetPtr ns;
6340 xmlChar *str2;
6341
6342 if ((f == NULL) || (arg == NULL) ||
6343 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6344 xmlXPathReleaseObject(ctxt->context, arg);
6345 xmlXPathReleaseObject(ctxt->context, f);
6346 return(0);
6347 }
6348 ns = arg->nodesetval;
6349 if (ns != NULL) {
6350 for (i = 0;i < ns->nodeNr;i++) {
6351 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6352 if (str2 != NULL) {
6353 valuePush(ctxt,
6354 xmlXPathCacheNewString(ctxt->context, str2));
6355 xmlFree(str2);
6356 xmlXPathNumberFunction(ctxt, 1);
6357 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6358 ret = xmlXPathCompareValues(ctxt, inf, strict);
6359 if (ret)
6360 break;
6361 }
6362 }
6363 }
6364 xmlXPathReleaseObject(ctxt->context, arg);
6365 xmlXPathReleaseObject(ctxt->context, f);
6366 return(ret);
6367}
6368
6369/**
6370 * xmlXPathCompareNodeSetString:
6371 * @ctxt: the XPath Parser context
6372 * @inf: less than (1) or greater than (0)
6373 * @strict: is the comparison strict
6374 * @arg: the node set
6375 * @s: the value
6376 *
6377 * Implement the compare operation between a nodeset and a string
6378 * @ns < @val (1, 1, ...
6379 * @ns <= @val (1, 0, ...
6380 * @ns > @val (0, 1, ...
6381 * @ns >= @val (0, 0, ...
6382 *
6383 * If one object to be compared is a node-set and the other is a string,
6384 * then the comparison will be true if and only if there is a node in
6385 * the node-set such that the result of performing the comparison on the
6386 * string-value of the node and the other string is true.
6387 *
6388 * Returns 0 or 1 depending on the results of the test.
6389 */
6390static int
6391xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6392 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6393 int i, ret = 0;
6394 xmlNodeSetPtr ns;
6395 xmlChar *str2;
6396
6397 if ((s == NULL) || (arg == NULL) ||
6398 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6399 xmlXPathReleaseObject(ctxt->context, arg);
6400 xmlXPathReleaseObject(ctxt->context, s);
6401 return(0);
6402 }
6403 ns = arg->nodesetval;
6404 if (ns != NULL) {
6405 for (i = 0;i < ns->nodeNr;i++) {
6406 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6407 if (str2 != NULL) {
6408 valuePush(ctxt,
6409 xmlXPathCacheNewString(ctxt->context, str2));
6410 xmlFree(str2);
6411 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6412 ret = xmlXPathCompareValues(ctxt, inf, strict);
6413 if (ret)
6414 break;
6415 }
6416 }
6417 }
6418 xmlXPathReleaseObject(ctxt->context, arg);
6419 xmlXPathReleaseObject(ctxt->context, s);
6420 return(ret);
6421}
6422
6423/**
6424 * xmlXPathCompareNodeSets:
6425 * @inf: less than (1) or greater than (0)
6426 * @strict: is the comparison strict
6427 * @arg1: the first node set object
6428 * @arg2: the second node set object
6429 *
6430 * Implement the compare operation on nodesets:
6431 *
6432 * If both objects to be compared are node-sets, then the comparison
6433 * will be true if and only if there is a node in the first node-set
6434 * and a node in the second node-set such that the result of performing
6435 * the comparison on the string-values of the two nodes is true.
6436 * ....
6437 * When neither object to be compared is a node-set and the operator
6438 * is <=, <, >= or >, then the objects are compared by converting both
6439 * objects to numbers and comparing the numbers according to IEEE 754.
6440 * ....
6441 * The number function converts its argument to a number as follows:
6442 * - a string that consists of optional whitespace followed by an
6443 * optional minus sign followed by a Number followed by whitespace
6444 * is converted to the IEEE 754 number that is nearest (according
6445 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6446 * represented by the string; any other string is converted to NaN
6447 *
6448 * Conclusion all nodes need to be converted first to their string value
6449 * and then the comparison must be done when possible
6450 */
6451static int
6452xmlXPathCompareNodeSets(int inf, int strict,
6453 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6454 int i, j, init = 0;
6455 double val1;
6456 double *values2;
6457 int ret = 0;
6458 xmlNodeSetPtr ns1;
6459 xmlNodeSetPtr ns2;
6460
6461 if ((arg1 == NULL) ||
6462 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6463 xmlXPathFreeObject(arg2);
6464 return(0);
6465 }
6466 if ((arg2 == NULL) ||
6467 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6468 xmlXPathFreeObject(arg1);
6469 xmlXPathFreeObject(arg2);
6470 return(0);
6471 }
6472
6473 ns1 = arg1->nodesetval;
6474 ns2 = arg2->nodesetval;
6475
6476 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6477 xmlXPathFreeObject(arg1);
6478 xmlXPathFreeObject(arg2);
6479 return(0);
6480 }
6481 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6482 xmlXPathFreeObject(arg1);
6483 xmlXPathFreeObject(arg2);
6484 return(0);
6485 }
6486
6487 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6488 if (values2 == NULL) {
6489 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6490 xmlXPathFreeObject(arg1);
6491 xmlXPathFreeObject(arg2);
6492 return(0);
6493 }
6494 for (i = 0;i < ns1->nodeNr;i++) {
6495 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6496 if (xmlXPathIsNaN(val1))
6497 continue;
6498 for (j = 0;j < ns2->nodeNr;j++) {
6499 if (init == 0) {
6500 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6501 }
6502 if (xmlXPathIsNaN(values2[j]))
6503 continue;
6504 if (inf && strict)
6505 ret = (val1 < values2[j]);
6506 else if (inf && !strict)
6507 ret = (val1 <= values2[j]);
6508 else if (!inf && strict)
6509 ret = (val1 > values2[j]);
6510 else if (!inf && !strict)
6511 ret = (val1 >= values2[j]);
6512 if (ret)
6513 break;
6514 }
6515 if (ret)
6516 break;
6517 init = 1;
6518 }
6519 xmlFree(values2);
6520 xmlXPathFreeObject(arg1);
6521 xmlXPathFreeObject(arg2);
6522 return(ret);
6523}
6524
6525/**
6526 * xmlXPathCompareNodeSetValue:
6527 * @ctxt: the XPath Parser context
6528 * @inf: less than (1) or greater than (0)
6529 * @strict: is the comparison strict
6530 * @arg: the node set
6531 * @val: the value
6532 *
6533 * Implement the compare operation between a nodeset and a value
6534 * @ns < @val (1, 1, ...
6535 * @ns <= @val (1, 0, ...
6536 * @ns > @val (0, 1, ...
6537 * @ns >= @val (0, 0, ...
6538 *
6539 * If one object to be compared is a node-set and the other is a boolean,
6540 * then the comparison will be true if and only if the result of performing
6541 * the comparison on the boolean and on the result of converting
6542 * the node-set to a boolean using the boolean function is true.
6543 *
6544 * Returns 0 or 1 depending on the results of the test.
6545 */
6546static int
6547xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6548 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6549 if ((val == NULL) || (arg == NULL) ||
6550 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6551 return(0);
6552
6553 switch(val->type) {
6554 case XPATH_NUMBER:
6555 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6556 case XPATH_NODESET:
6557 case XPATH_XSLT_TREE:
6558 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6559 case XPATH_STRING:
6560 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6561 case XPATH_BOOLEAN:
6562 valuePush(ctxt, arg);
6563 xmlXPathBooleanFunction(ctxt, 1);
6564 valuePush(ctxt, val);
6565 return(xmlXPathCompareValues(ctxt, inf, strict));
6566 default:
6567 TODO
6568 }
6569 return(0);
6570}
6571
6572/**
6573 * xmlXPathEqualNodeSetString:
6574 * @arg: the nodeset object argument
6575 * @str: the string to compare to.
6576 * @neq: flag to show whether for '=' (0) or '!=' (1)
6577 *
6578 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6579 * If one object to be compared is a node-set and the other is a string,
6580 * then the comparison will be true if and only if there is a node in
6581 * the node-set such that the result of performing the comparison on the
6582 * string-value of the node and the other string is true.
6583 *
6584 * Returns 0 or 1 depending on the results of the test.
6585 */
6586static int
6587xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6588{
6589 int i;
6590 xmlNodeSetPtr ns;
6591 xmlChar *str2;
6592 unsigned int hash;
6593
6594 if ((str == NULL) || (arg == NULL) ||
6595 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6596 return (0);
6597 ns = arg->nodesetval;
6598 /*
6599 * A NULL nodeset compared with a string is always false
6600 * (since there is no node equal, and no node not equal)
6601 */
6602 if ((ns == NULL) || (ns->nodeNr <= 0) )
6603 return (0);
6604 hash = xmlXPathStringHash(str);
6605 for (i = 0; i < ns->nodeNr; i++) {
6606 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6607 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6608 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6609 xmlFree(str2);
6610 if (neq)
6611 continue;
6612 return (1);
6613 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6614 if (neq)
6615 continue;
6616 return (1);
6617 } else if (neq) {
6618 if (str2 != NULL)
6619 xmlFree(str2);
6620 return (1);
6621 }
6622 if (str2 != NULL)
6623 xmlFree(str2);
6624 } else if (neq)
6625 return (1);
6626 }
6627 return (0);
6628}
6629
6630/**
6631 * xmlXPathEqualNodeSetFloat:
6632 * @arg: the nodeset object argument
6633 * @f: the float to compare to
6634 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
6635 *
6636 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6637 * If one object to be compared is a node-set and the other is a number,
6638 * then the comparison will be true if and only if there is a node in
6639 * the node-set such that the result of performing the comparison on the
6640 * number to be compared and on the result of converting the string-value
6641 * of that node to a number using the number function is true.
6642 *
6643 * Returns 0 or 1 depending on the results of the test.
6644 */
6645static int
6646xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6647 xmlXPathObjectPtr arg, double f, int neq) {
6648 int i, ret=0;
6649 xmlNodeSetPtr ns;
6650 xmlChar *str2;
6651 xmlXPathObjectPtr val;
6652 double v;
6653
6654 if ((arg == NULL) ||
6655 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6656 return(0);
6657
6658 ns = arg->nodesetval;
6659 if (ns != NULL) {
6660 for (i=0;i<ns->nodeNr;i++) {
6661 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6662 if (str2 != NULL) {
6663 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6664 xmlFree(str2);
6665 xmlXPathNumberFunction(ctxt, 1);
6666 val = valuePop(ctxt);
6667 v = val->floatval;
6668 xmlXPathReleaseObject(ctxt->context, val);
6669 if (!xmlXPathIsNaN(v)) {
6670 if ((!neq) && (v==f)) {
6671 ret = 1;
6672 break;
6673 } else if ((neq) && (v!=f)) {
6674 ret = 1;
6675 break;
6676 }
6677 } else { /* NaN is unequal to any value */
6678 if (neq)
6679 ret = 1;
6680 }
6681 }
6682 }
6683 }
6684
6685 return(ret);
6686}
6687
6688
6689/**
6690 * xmlXPathEqualNodeSets:
6691 * @arg1: first nodeset object argument
6692 * @arg2: second nodeset object argument
6693 * @neq: flag to show whether to test '=' (0) or '!=' (1)
6694 *
6695 * Implement the equal / not equal operation on XPath nodesets:
6696 * @arg1 == @arg2 or @arg1 != @arg2
6697 * If both objects to be compared are node-sets, then the comparison
6698 * will be true if and only if there is a node in the first node-set and
6699 * a node in the second node-set such that the result of performing the
6700 * comparison on the string-values of the two nodes is true.
6701 *
6702 * (needless to say, this is a costly operation)
6703 *
6704 * Returns 0 or 1 depending on the results of the test.
6705 */
6706static int
6707xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6708 int i, j;
6709 unsigned int *hashs1;
6710 unsigned int *hashs2;
6711 xmlChar **values1;
6712 xmlChar **values2;
6713 int ret = 0;
6714 xmlNodeSetPtr ns1;
6715 xmlNodeSetPtr ns2;
6716
6717 if ((arg1 == NULL) ||
6718 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6719 return(0);
6720 if ((arg2 == NULL) ||
6721 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6722 return(0);
6723
6724 ns1 = arg1->nodesetval;
6725 ns2 = arg2->nodesetval;
6726
6727 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6728 return(0);
6729 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6730 return(0);
6731
6732 /*
6733 * for equal, check if there is a node pertaining to both sets
6734 */
6735 if (neq == 0)
6736 for (i = 0;i < ns1->nodeNr;i++)
6737 for (j = 0;j < ns2->nodeNr;j++)
6738 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6739 return(1);
6740
6741 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6742 if (values1 == NULL) {
6743 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6744 return(0);
6745 }
6746 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6747 if (hashs1 == NULL) {
6748 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6749 xmlFree(values1);
6750 return(0);
6751 }
6752 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6753 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6754 if (values2 == NULL) {
6755 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6756 xmlFree(hashs1);
6757 xmlFree(values1);
6758 return(0);
6759 }
6760 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6761 if (hashs2 == NULL) {
6762 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6763 xmlFree(hashs1);
6764 xmlFree(values1);
6765 xmlFree(values2);
6766 return(0);
6767 }
6768 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6769 for (i = 0;i < ns1->nodeNr;i++) {
6770 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6771 for (j = 0;j < ns2->nodeNr;j++) {
6772 if (i == 0)
6773 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6774 if (hashs1[i] != hashs2[j]) {
6775 if (neq) {
6776 ret = 1;
6777 break;
6778 }
6779 }
6780 else {
6781 if (values1[i] == NULL)
6782 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6783 if (values2[j] == NULL)
6784 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6785 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6786 if (ret)
6787 break;
6788 }
6789 }
6790 if (ret)
6791 break;
6792 }
6793 for (i = 0;i < ns1->nodeNr;i++)
6794 if (values1[i] != NULL)
6795 xmlFree(values1[i]);
6796 for (j = 0;j < ns2->nodeNr;j++)
6797 if (values2[j] != NULL)
6798 xmlFree(values2[j]);
6799 xmlFree(values1);
6800 xmlFree(values2);
6801 xmlFree(hashs1);
6802 xmlFree(hashs2);
6803 return(ret);
6804}
6805
6806static int
6807xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6808 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6809 int ret = 0;
6810 /*
6811 *At this point we are assured neither arg1 nor arg2
6812 *is a nodeset, so we can just pick the appropriate routine.
6813 */
6814 switch (arg1->type) {
6815 case XPATH_UNDEFINED:
6816#ifdef DEBUG_EXPR
6817 xmlGenericError(xmlGenericErrorContext,
6818 "Equal: undefined\n");
6819#endif
6820 break;
6821 case XPATH_BOOLEAN:
6822 switch (arg2->type) {
6823 case XPATH_UNDEFINED:
6824#ifdef DEBUG_EXPR
6825 xmlGenericError(xmlGenericErrorContext,
6826 "Equal: undefined\n");
6827#endif
6828 break;
6829 case XPATH_BOOLEAN:
6830#ifdef DEBUG_EXPR
6831 xmlGenericError(xmlGenericErrorContext,
6832 "Equal: %d boolean %d \n",
6833 arg1->boolval, arg2->boolval);
6834#endif
6835 ret = (arg1->boolval == arg2->boolval);
6836 break;
6837 case XPATH_NUMBER:
6838 ret = (arg1->boolval ==
6839 xmlXPathCastNumberToBoolean(arg2->floatval));
6840 break;
6841 case XPATH_STRING:
6842 if ((arg2->stringval == NULL) ||
6843 (arg2->stringval[0] == 0)) ret = 0;
6844 else
6845 ret = 1;
6846 ret = (arg1->boolval == ret);
6847 break;
6848 case XPATH_USERS:
6849 case XPATH_POINT:
6850 case XPATH_RANGE:
6851 case XPATH_LOCATIONSET:
6852 TODO
6853 break;
6854 case XPATH_NODESET:
6855 case XPATH_XSLT_TREE:
6856 break;
6857 }
6858 break;
6859 case XPATH_NUMBER:
6860 switch (arg2->type) {
6861 case XPATH_UNDEFINED:
6862#ifdef DEBUG_EXPR
6863 xmlGenericError(xmlGenericErrorContext,
6864 "Equal: undefined\n");
6865#endif
6866 break;
6867 case XPATH_BOOLEAN:
6868 ret = (arg2->boolval==
6869 xmlXPathCastNumberToBoolean(arg1->floatval));
6870 break;
6871 case XPATH_STRING:
6872 valuePush(ctxt, arg2);
6873 xmlXPathNumberFunction(ctxt, 1);
6874 arg2 = valuePop(ctxt);
6875 /* no break on purpose */
6876 case XPATH_NUMBER:
6877 /* Hand check NaN and Infinity equalities */
6878 if (xmlXPathIsNaN(arg1->floatval) ||
6879 xmlXPathIsNaN(arg2->floatval)) {
6880 ret = 0;
6881 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6882 if (xmlXPathIsInf(arg2->floatval) == 1)
6883 ret = 1;
6884 else
6885 ret = 0;
6886 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6887 if (xmlXPathIsInf(arg2->floatval) == -1)
6888 ret = 1;
6889 else
6890 ret = 0;
6891 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6892 if (xmlXPathIsInf(arg1->floatval) == 1)
6893 ret = 1;
6894 else
6895 ret = 0;
6896 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6897 if (xmlXPathIsInf(arg1->floatval) == -1)
6898 ret = 1;
6899 else
6900 ret = 0;
6901 } else {
6902 ret = (arg1->floatval == arg2->floatval);
6903 }
6904 break;
6905 case XPATH_USERS:
6906 case XPATH_POINT:
6907 case XPATH_RANGE:
6908 case XPATH_LOCATIONSET:
6909 TODO
6910 break;
6911 case XPATH_NODESET:
6912 case XPATH_XSLT_TREE:
6913 break;
6914 }
6915 break;
6916 case XPATH_STRING:
6917 switch (arg2->type) {
6918 case XPATH_UNDEFINED:
6919#ifdef DEBUG_EXPR
6920 xmlGenericError(xmlGenericErrorContext,
6921 "Equal: undefined\n");
6922#endif
6923 break;
6924 case XPATH_BOOLEAN:
6925 if ((arg1->stringval == NULL) ||
6926 (arg1->stringval[0] == 0)) ret = 0;
6927 else
6928 ret = 1;
6929 ret = (arg2->boolval == ret);
6930 break;
6931 case XPATH_STRING:
6932 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6933 break;
6934 case XPATH_NUMBER:
6935 valuePush(ctxt, arg1);
6936 xmlXPathNumberFunction(ctxt, 1);
6937 arg1 = valuePop(ctxt);
6938 /* Hand check NaN and Infinity equalities */
6939 if (xmlXPathIsNaN(arg1->floatval) ||
6940 xmlXPathIsNaN(arg2->floatval)) {
6941 ret = 0;
6942 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6943 if (xmlXPathIsInf(arg2->floatval) == 1)
6944 ret = 1;
6945 else
6946 ret = 0;
6947 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6948 if (xmlXPathIsInf(arg2->floatval) == -1)
6949 ret = 1;
6950 else
6951 ret = 0;
6952 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6953 if (xmlXPathIsInf(arg1->floatval) == 1)
6954 ret = 1;
6955 else
6956 ret = 0;
6957 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6958 if (xmlXPathIsInf(arg1->floatval) == -1)
6959 ret = 1;
6960 else
6961 ret = 0;
6962 } else {
6963 ret = (arg1->floatval == arg2->floatval);
6964 }
6965 break;
6966 case XPATH_USERS:
6967 case XPATH_POINT:
6968 case XPATH_RANGE:
6969 case XPATH_LOCATIONSET:
6970 TODO
6971 break;
6972 case XPATH_NODESET:
6973 case XPATH_XSLT_TREE:
6974 break;
6975 }
6976 break;
6977 case XPATH_USERS:
6978 case XPATH_POINT:
6979 case XPATH_RANGE:
6980 case XPATH_LOCATIONSET:
6981 TODO
6982 break;
6983 case XPATH_NODESET:
6984 case XPATH_XSLT_TREE:
6985 break;
6986 }
6987 xmlXPathReleaseObject(ctxt->context, arg1);
6988 xmlXPathReleaseObject(ctxt->context, arg2);
6989 return(ret);
6990}
6991
6992/**
6993 * xmlXPathEqualValues:
6994 * @ctxt: the XPath Parser context
6995 *
6996 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6997 *
6998 * Returns 0 or 1 depending on the results of the test.
6999 */
7000int
7001xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7002 xmlXPathObjectPtr arg1, arg2, argtmp;
7003 int ret = 0;
7004
7005 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7006 arg2 = valuePop(ctxt);
7007 arg1 = valuePop(ctxt);
7008 if ((arg1 == NULL) || (arg2 == NULL)) {
7009 if (arg1 != NULL)
7010 xmlXPathReleaseObject(ctxt->context, arg1);
7011 else
7012 xmlXPathReleaseObject(ctxt->context, arg2);
7013 XP_ERROR0(XPATH_INVALID_OPERAND);
7014 }
7015
7016 if (arg1 == arg2) {
7017#ifdef DEBUG_EXPR
7018 xmlGenericError(xmlGenericErrorContext,
7019 "Equal: by pointer\n");
7020#endif
7021 xmlXPathFreeObject(arg1);
7022 return(1);
7023 }
7024
7025 /*
7026 *If either argument is a nodeset, it's a 'special case'
7027 */
7028 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7029 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7030 /*
7031 *Hack it to assure arg1 is the nodeset
7032 */
7033 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7034 argtmp = arg2;
7035 arg2 = arg1;
7036 arg1 = argtmp;
7037 }
7038 switch (arg2->type) {
7039 case XPATH_UNDEFINED:
7040#ifdef DEBUG_EXPR
7041 xmlGenericError(xmlGenericErrorContext,
7042 "Equal: undefined\n");
7043#endif
7044 break;
7045 case XPATH_NODESET:
7046 case XPATH_XSLT_TREE:
7047 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7048 break;
7049 case XPATH_BOOLEAN:
7050 if ((arg1->nodesetval == NULL) ||
7051 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7052 else
7053 ret = 1;
7054 ret = (ret == arg2->boolval);
7055 break;
7056 case XPATH_NUMBER:
7057 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7058 break;
7059 case XPATH_STRING:
7060 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7061 break;
7062 case XPATH_USERS:
7063 case XPATH_POINT:
7064 case XPATH_RANGE:
7065 case XPATH_LOCATIONSET:
7066 TODO
7067 break;
7068 }
7069 xmlXPathReleaseObject(ctxt->context, arg1);
7070 xmlXPathReleaseObject(ctxt->context, arg2);
7071 return(ret);
7072 }
7073
7074 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7075}
7076
7077/**
7078 * xmlXPathNotEqualValues:
7079 * @ctxt: the XPath Parser context
7080 *
7081 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7082 *
7083 * Returns 0 or 1 depending on the results of the test.
7084 */
7085int
7086xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7087 xmlXPathObjectPtr arg1, arg2, argtmp;
7088 int ret = 0;
7089
7090 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7091 arg2 = valuePop(ctxt);
7092 arg1 = valuePop(ctxt);
7093 if ((arg1 == NULL) || (arg2 == NULL)) {
7094 if (arg1 != NULL)
7095 xmlXPathReleaseObject(ctxt->context, arg1);
7096 else
7097 xmlXPathReleaseObject(ctxt->context, arg2);
7098 XP_ERROR0(XPATH_INVALID_OPERAND);
7099 }
7100
7101 if (arg1 == arg2) {
7102#ifdef DEBUG_EXPR
7103 xmlGenericError(xmlGenericErrorContext,
7104 "NotEqual: by pointer\n");
7105#endif
7106 xmlXPathReleaseObject(ctxt->context, arg1);
7107 return(0);
7108 }
7109
7110 /*
7111 *If either argument is a nodeset, it's a 'special case'
7112 */
7113 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7114 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7115 /*
7116 *Hack it to assure arg1 is the nodeset
7117 */
7118 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7119 argtmp = arg2;
7120 arg2 = arg1;
7121 arg1 = argtmp;
7122 }
7123 switch (arg2->type) {
7124 case XPATH_UNDEFINED:
7125#ifdef DEBUG_EXPR
7126 xmlGenericError(xmlGenericErrorContext,
7127 "NotEqual: undefined\n");
7128#endif
7129 break;
7130 case XPATH_NODESET:
7131 case XPATH_XSLT_TREE:
7132 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7133 break;
7134 case XPATH_BOOLEAN:
7135 if ((arg1->nodesetval == NULL) ||
7136 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7137 else
7138 ret = 1;
7139 ret = (ret != arg2->boolval);
7140 break;
7141 case XPATH_NUMBER:
7142 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7143 break;
7144 case XPATH_STRING:
7145 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7146 break;
7147 case XPATH_USERS:
7148 case XPATH_POINT:
7149 case XPATH_RANGE:
7150 case XPATH_LOCATIONSET:
7151 TODO
7152 break;
7153 }
7154 xmlXPathReleaseObject(ctxt->context, arg1);
7155 xmlXPathReleaseObject(ctxt->context, arg2);
7156 return(ret);
7157 }
7158
7159 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7160}
7161
7162/**
7163 * xmlXPathCompareValues:
7164 * @ctxt: the XPath Parser context
7165 * @inf: less than (1) or greater than (0)
7166 * @strict: is the comparison strict
7167 *
7168 * Implement the compare operation on XPath objects:
7169 * @arg1 < @arg2 (1, 1, ...
7170 * @arg1 <= @arg2 (1, 0, ...
7171 * @arg1 > @arg2 (0, 1, ...
7172 * @arg1 >= @arg2 (0, 0, ...
7173 *
7174 * When neither object to be compared is a node-set and the operator is
7175 * <=, <, >=, >, then the objects are compared by converted both objects
7176 * to numbers and comparing the numbers according to IEEE 754. The <
7177 * comparison will be true if and only if the first number is less than the
7178 * second number. The <= comparison will be true if and only if the first
7179 * number is less than or equal to the second number. The > comparison
7180 * will be true if and only if the first number is greater than the second
7181 * number. The >= comparison will be true if and only if the first number
7182 * is greater than or equal to the second number.
7183 *
7184 * Returns 1 if the comparison succeeded, 0 if it failed
7185 */
7186int
7187xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7188 int ret = 0, arg1i = 0, arg2i = 0;
7189 xmlXPathObjectPtr arg1, arg2;
7190
7191 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7192 arg2 = valuePop(ctxt);
7193 arg1 = valuePop(ctxt);
7194 if ((arg1 == NULL) || (arg2 == NULL)) {
7195 if (arg1 != NULL)
7196 xmlXPathReleaseObject(ctxt->context, arg1);
7197 else
7198 xmlXPathReleaseObject(ctxt->context, arg2);
7199 XP_ERROR0(XPATH_INVALID_OPERAND);
7200 }
7201
7202 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7203 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7204 /*
7205 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7206 * are not freed from within this routine; they will be freed from the
7207 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7208 */
7209 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7210 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7211 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7212 } else {
7213 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7214 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7215 arg1, arg2);
7216 } else {
7217 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7218 arg2, arg1);
7219 }
7220 }
7221 return(ret);
7222 }
7223
7224 if (arg1->type != XPATH_NUMBER) {
7225 valuePush(ctxt, arg1);
7226 xmlXPathNumberFunction(ctxt, 1);
7227 arg1 = valuePop(ctxt);
7228 }
7229 if (arg1->type != XPATH_NUMBER) {
7230 xmlXPathFreeObject(arg1);
7231 xmlXPathFreeObject(arg2);
7232 XP_ERROR0(XPATH_INVALID_OPERAND);
7233 }
7234 if (arg2->type != XPATH_NUMBER) {
7235 valuePush(ctxt, arg2);
7236 xmlXPathNumberFunction(ctxt, 1);
7237 arg2 = valuePop(ctxt);
7238 }
7239 if (arg2->type != XPATH_NUMBER) {
7240 xmlXPathReleaseObject(ctxt->context, arg1);
7241 xmlXPathReleaseObject(ctxt->context, arg2);
7242 XP_ERROR0(XPATH_INVALID_OPERAND);
7243 }
7244 /*
7245 * Add tests for infinity and nan
7246 * => feedback on 3.4 for Inf and NaN
7247 */
7248 /* Hand check NaN and Infinity comparisons */
7249 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7250 ret=0;
7251 } else {
7252 arg1i=xmlXPathIsInf(arg1->floatval);
7253 arg2i=xmlXPathIsInf(arg2->floatval);
7254 if (inf && strict) {
7255 if ((arg1i == -1 && arg2i != -1) ||
7256 (arg2i == 1 && arg1i != 1)) {
7257 ret = 1;
7258 } else if (arg1i == 0 && arg2i == 0) {
7259 ret = (arg1->floatval < arg2->floatval);
7260 } else {
7261 ret = 0;
7262 }
7263 }
7264 else if (inf && !strict) {
7265 if (arg1i == -1 || arg2i == 1) {
7266 ret = 1;
7267 } else if (arg1i == 0 && arg2i == 0) {
7268 ret = (arg1->floatval <= arg2->floatval);
7269 } else {
7270 ret = 0;
7271 }
7272 }
7273 else if (!inf && strict) {
7274 if ((arg1i == 1 && arg2i != 1) ||
7275 (arg2i == -1 && arg1i != -1)) {
7276 ret = 1;
7277 } else if (arg1i == 0 && arg2i == 0) {
7278 ret = (arg1->floatval > arg2->floatval);
7279 } else {
7280 ret = 0;
7281 }
7282 }
7283 else if (!inf && !strict) {
7284 if (arg1i == 1 || arg2i == -1) {
7285 ret = 1;
7286 } else if (arg1i == 0 && arg2i == 0) {
7287 ret = (arg1->floatval >= arg2->floatval);
7288 } else {
7289 ret = 0;
7290 }
7291 }
7292 }
7293 xmlXPathReleaseObject(ctxt->context, arg1);
7294 xmlXPathReleaseObject(ctxt->context, arg2);
7295 return(ret);
7296}
7297
7298/**
7299 * xmlXPathValueFlipSign:
7300 * @ctxt: the XPath Parser context
7301 *
7302 * Implement the unary - operation on an XPath object
7303 * The numeric operators convert their operands to numbers as if
7304 * by calling the number function.
7305 */
7306void
7307xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7308 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7309 CAST_TO_NUMBER;
7310 CHECK_TYPE(XPATH_NUMBER);
7311 if (xmlXPathIsNaN(ctxt->value->floatval))
7312 ctxt->value->floatval=xmlXPathNAN;
7313 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7314 ctxt->value->floatval=xmlXPathNINF;
7315 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7316 ctxt->value->floatval=xmlXPathPINF;
7317 else if (ctxt->value->floatval == 0) {
7318 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7319 ctxt->value->floatval = xmlXPathNZERO;
7320 else
7321 ctxt->value->floatval = 0;
7322 }
7323 else
7324 ctxt->value->floatval = - ctxt->value->floatval;
7325}
7326
7327/**
7328 * xmlXPathAddValues:
7329 * @ctxt: the XPath Parser context
7330 *
7331 * Implement the add operation on XPath objects:
7332 * The numeric operators convert their operands to numbers as if
7333 * by calling the number function.
7334 */
7335void
7336xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7337 xmlXPathObjectPtr arg;
7338 double val;
7339
7340 arg = valuePop(ctxt);
7341 if (arg == NULL)
7342 XP_ERROR(XPATH_INVALID_OPERAND);
7343 val = xmlXPathCastToNumber(arg);
7344 xmlXPathReleaseObject(ctxt->context, arg);
7345 CAST_TO_NUMBER;
7346 CHECK_TYPE(XPATH_NUMBER);
7347 ctxt->value->floatval += val;
7348}
7349
7350/**
7351 * xmlXPathSubValues:
7352 * @ctxt: the XPath Parser context
7353 *
7354 * Implement the subtraction operation on XPath objects:
7355 * The numeric operators convert their operands to numbers as if
7356 * by calling the number function.
7357 */
7358void
7359xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7360 xmlXPathObjectPtr arg;
7361 double val;
7362
7363 arg = valuePop(ctxt);
7364 if (arg == NULL)
7365 XP_ERROR(XPATH_INVALID_OPERAND);
7366 val = xmlXPathCastToNumber(arg);
7367 xmlXPathReleaseObject(ctxt->context, arg);
7368 CAST_TO_NUMBER;
7369 CHECK_TYPE(XPATH_NUMBER);
7370 ctxt->value->floatval -= val;
7371}
7372
7373/**
7374 * xmlXPathMultValues:
7375 * @ctxt: the XPath Parser context
7376 *
7377 * Implement the multiply operation on XPath objects:
7378 * The numeric operators convert their operands to numbers as if
7379 * by calling the number function.
7380 */
7381void
7382xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7383 xmlXPathObjectPtr arg;
7384 double val;
7385
7386 arg = valuePop(ctxt);
7387 if (arg == NULL)
7388 XP_ERROR(XPATH_INVALID_OPERAND);
7389 val = xmlXPathCastToNumber(arg);
7390 xmlXPathReleaseObject(ctxt->context, arg);
7391 CAST_TO_NUMBER;
7392 CHECK_TYPE(XPATH_NUMBER);
7393 ctxt->value->floatval *= val;
7394}
7395
7396/**
7397 * xmlXPathDivValues:
7398 * @ctxt: the XPath Parser context
7399 *
7400 * Implement the div operation on XPath objects @arg1 / @arg2:
7401 * The numeric operators convert their operands to numbers as if
7402 * by calling the number function.
7403 */
7404void
7405xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7406 xmlXPathObjectPtr arg;
7407 double val;
7408
7409 arg = valuePop(ctxt);
7410 if (arg == NULL)
7411 XP_ERROR(XPATH_INVALID_OPERAND);
7412 val = xmlXPathCastToNumber(arg);
7413 xmlXPathReleaseObject(ctxt->context, arg);
7414 CAST_TO_NUMBER;
7415 CHECK_TYPE(XPATH_NUMBER);
7416 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7417 ctxt->value->floatval = xmlXPathNAN;
7418 else if (val == 0 && xmlXPathGetSign(val) != 0) {
7419 if (ctxt->value->floatval == 0)
7420 ctxt->value->floatval = xmlXPathNAN;
7421 else if (ctxt->value->floatval > 0)
7422 ctxt->value->floatval = xmlXPathNINF;
7423 else if (ctxt->value->floatval < 0)
7424 ctxt->value->floatval = xmlXPathPINF;
7425 }
7426 else if (val == 0) {
7427 if (ctxt->value->floatval == 0)
7428 ctxt->value->floatval = xmlXPathNAN;
7429 else if (ctxt->value->floatval > 0)
7430 ctxt->value->floatval = xmlXPathPINF;
7431 else if (ctxt->value->floatval < 0)
7432 ctxt->value->floatval = xmlXPathNINF;
7433 } else
7434 ctxt->value->floatval /= val;
7435}
7436
7437/**
7438 * xmlXPathModValues:
7439 * @ctxt: the XPath Parser context
7440 *
7441 * Implement the mod operation on XPath objects: @arg1 / @arg2
7442 * The numeric operators convert their operands to numbers as if
7443 * by calling the number function.
7444 */
7445void
7446xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7447 xmlXPathObjectPtr arg;
7448 double arg1, arg2;
7449
7450 arg = valuePop(ctxt);
7451 if (arg == NULL)
7452 XP_ERROR(XPATH_INVALID_OPERAND);
7453 arg2 = xmlXPathCastToNumber(arg);
7454 xmlXPathReleaseObject(ctxt->context, arg);
7455 CAST_TO_NUMBER;
7456 CHECK_TYPE(XPATH_NUMBER);
7457 arg1 = ctxt->value->floatval;
7458 if (arg2 == 0)
7459 ctxt->value->floatval = xmlXPathNAN;
7460 else {
7461 ctxt->value->floatval = fmod(arg1, arg2);
7462 }
7463}
7464
7465/************************************************************************
7466 * *
7467 * The traversal functions *
7468 * *
7469 ************************************************************************/
7470
7471/*
7472 * A traversal function enumerates nodes along an axis.
7473 * Initially it must be called with NULL, and it indicates
7474 * termination on the axis by returning NULL.
7475 */
7476typedef xmlNodePtr (*xmlXPathTraversalFunction)
7477 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7478
7479/*
7480 * xmlXPathTraversalFunctionExt:
7481 * A traversal function enumerates nodes along an axis.
7482 * Initially it must be called with NULL, and it indicates
7483 * termination on the axis by returning NULL.
7484 * The context node of the traversal is specified via @contextNode.
7485 */
7486typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7487 (xmlNodePtr cur, xmlNodePtr contextNode);
7488
7489/*
7490 * xmlXPathNodeSetMergeFunction:
7491 * Used for merging node sets in xmlXPathCollectAndTest().
7492 */
7493typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7494 (xmlNodeSetPtr, xmlNodeSetPtr, int);
7495
7496
7497/**
7498 * xmlXPathNextSelf:
7499 * @ctxt: the XPath Parser context
7500 * @cur: the current node in the traversal
7501 *
7502 * Traversal function for the "self" direction
7503 * The self axis contains just the context node itself
7504 *
7505 * Returns the next element following that axis
7506 */
7507xmlNodePtr
7508xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7509 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7510 if (cur == NULL)
7511 return(ctxt->context->node);
7512 return(NULL);
7513}
7514
7515/**
7516 * xmlXPathNextChild:
7517 * @ctxt: the XPath Parser context
7518 * @cur: the current node in the traversal
7519 *
7520 * Traversal function for the "child" direction
7521 * The child axis contains the children of the context node in document order.
7522 *
7523 * Returns the next element following that axis
7524 */
7525xmlNodePtr
7526xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7527 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7528 if (cur == NULL) {
7529 if (ctxt->context->node == NULL) return(NULL);
7530 switch (ctxt->context->node->type) {
7531 case XML_ELEMENT_NODE:
7532 case XML_TEXT_NODE:
7533 case XML_CDATA_SECTION_NODE:
7534 case XML_ENTITY_REF_NODE:
7535 case XML_ENTITY_NODE:
7536 case XML_PI_NODE:
7537 case XML_COMMENT_NODE:
7538 case XML_NOTATION_NODE:
7539 case XML_DTD_NODE:
7540 return(ctxt->context->node->children);
7541 case XML_DOCUMENT_NODE:
7542 case XML_DOCUMENT_TYPE_NODE:
7543 case XML_DOCUMENT_FRAG_NODE:
7544 case XML_HTML_DOCUMENT_NODE:
7545#ifdef LIBXML_DOCB_ENABLED
7546 case XML_DOCB_DOCUMENT_NODE:
7547#endif
7548 return(((xmlDocPtr) ctxt->context->node)->children);
7549 case XML_ELEMENT_DECL:
7550 case XML_ATTRIBUTE_DECL:
7551 case XML_ENTITY_DECL:
7552 case XML_ATTRIBUTE_NODE:
7553 case XML_NAMESPACE_DECL:
7554 case XML_XINCLUDE_START:
7555 case XML_XINCLUDE_END:
7556 return(NULL);
7557 }
7558 return(NULL);
7559 }
7560 if ((cur->type == XML_DOCUMENT_NODE) ||
7561 (cur->type == XML_HTML_DOCUMENT_NODE))
7562 return(NULL);
7563 return(cur->next);
7564}
7565
7566/**
7567 * xmlXPathNextChildElement:
7568 * @ctxt: the XPath Parser context
7569 * @cur: the current node in the traversal
7570 *
7571 * Traversal function for the "child" direction and nodes of type element.
7572 * The child axis contains the children of the context node in document order.
7573 *
7574 * Returns the next element following that axis
7575 */
7576static xmlNodePtr
7577xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7578 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7579 if (cur == NULL) {
7580 cur = ctxt->context->node;
7581 if (cur == NULL) return(NULL);
7582 /*
7583 * Get the first element child.
7584 */
7585 switch (cur->type) {
7586 case XML_ELEMENT_NODE:
7587 case XML_DOCUMENT_FRAG_NODE:
7588 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7589 case XML_ENTITY_NODE:
7590 cur = cur->children;
7591 if (cur != NULL) {
7592 if (cur->type == XML_ELEMENT_NODE)
7593 return(cur);
7594 do {
7595 cur = cur->next;
7596 } while ((cur != NULL) &&
7597 (cur->type != XML_ELEMENT_NODE));
7598 return(cur);
7599 }
7600 return(NULL);
7601 case XML_DOCUMENT_NODE:
7602 case XML_HTML_DOCUMENT_NODE:
7603#ifdef LIBXML_DOCB_ENABLED
7604 case XML_DOCB_DOCUMENT_NODE:
7605#endif
7606 return(xmlDocGetRootElement((xmlDocPtr) cur));
7607 default:
7608 return(NULL);
7609 }
7610 return(NULL);
7611 }
7612 /*
7613 * Get the next sibling element node.
7614 */
7615 switch (cur->type) {
7616 case XML_ELEMENT_NODE:
7617 case XML_TEXT_NODE:
7618 case XML_ENTITY_REF_NODE:
7619 case XML_ENTITY_NODE:
7620 case XML_CDATA_SECTION_NODE:
7621 case XML_PI_NODE:
7622 case XML_COMMENT_NODE:
7623 case XML_XINCLUDE_END:
7624 break;
7625 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7626 default:
7627 return(NULL);
7628 }
7629 if (cur->next != NULL) {
7630 if (cur->next->type == XML_ELEMENT_NODE)
7631 return(cur->next);
7632 cur = cur->next;
7633 do {
7634 cur = cur->next;
7635 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7636 return(cur);
7637 }
7638 return(NULL);
7639}
7640
7641/**
7642 * xmlXPathNextDescendantOrSelfElemParent:
7643 * @ctxt: the XPath Parser context
7644 * @cur: the current node in the traversal
7645 *
7646 * Traversal function for the "descendant-or-self" axis.
7647 * Additionally it returns only nodes which can be parents of
7648 * element nodes.
7649 *
7650 *
7651 * Returns the next element following that axis
7652 */
7653static xmlNodePtr
7654xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7655 xmlNodePtr contextNode)
7656{
7657 if (cur == NULL) {
7658 if (contextNode == NULL)
7659 return(NULL);
7660 switch (contextNode->type) {
7661 case XML_ELEMENT_NODE:
7662 case XML_XINCLUDE_START:
7663 case XML_DOCUMENT_FRAG_NODE:
7664 case XML_DOCUMENT_NODE:
7665#ifdef LIBXML_DOCB_ENABLED
7666 case XML_DOCB_DOCUMENT_NODE:
7667#endif
7668 case XML_HTML_DOCUMENT_NODE:
7669 return(contextNode);
7670 default:
7671 return(NULL);
7672 }
7673 return(NULL);
7674 } else {
7675 xmlNodePtr start = cur;
7676
7677 while (cur != NULL) {
7678 switch (cur->type) {
7679 case XML_ELEMENT_NODE:
7680 /* TODO: OK to have XInclude here? */
7681 case XML_XINCLUDE_START:
7682 case XML_DOCUMENT_FRAG_NODE:
7683 if (cur != start)
7684 return(cur);
7685 if (cur->children != NULL) {
7686 cur = cur->children;
7687 continue;
7688 }
7689 break;
7690 /* Not sure if we need those here. */
7691 case XML_DOCUMENT_NODE:
7692#ifdef LIBXML_DOCB_ENABLED
7693 case XML_DOCB_DOCUMENT_NODE:
7694#endif
7695 case XML_HTML_DOCUMENT_NODE:
7696 if (cur != start)
7697 return(cur);
7698 return(xmlDocGetRootElement((xmlDocPtr) cur));
7699 default:
7700 break;
7701 }
7702
7703next_sibling:
7704 if ((cur == NULL) || (cur == contextNode))
7705 return(NULL);
7706 if (cur->next != NULL) {
7707 cur = cur->next;
7708 } else {
7709 cur = cur->parent;
7710 goto next_sibling;
7711 }
7712 }
7713 }
7714 return(NULL);
7715}
7716
7717/**
7718 * xmlXPathNextDescendant:
7719 * @ctxt: the XPath Parser context
7720 * @cur: the current node in the traversal
7721 *
7722 * Traversal function for the "descendant" direction
7723 * the descendant axis contains the descendants of the context node in document
7724 * order; a descendant is a child or a child of a child and so on.
7725 *
7726 * Returns the next element following that axis
7727 */
7728xmlNodePtr
7729xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7730 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7731 if (cur == NULL) {
7732 if (ctxt->context->node == NULL)
7733 return(NULL);
7734 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7735 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7736 return(NULL);
7737
7738 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7739 return(ctxt->context->doc->children);
7740 return(ctxt->context->node->children);
7741 }
7742
7743 if (cur->children != NULL) {
7744 /*
7745 * Do not descend on entities declarations
7746 */
7747 if (cur->children->type != XML_ENTITY_DECL) {
7748 cur = cur->children;
7749 /*
7750 * Skip DTDs
7751 */
7752 if (cur->type != XML_DTD_NODE)
7753 return(cur);
7754 }
7755 }
7756
7757 if (cur == ctxt->context->node) return(NULL);
7758
7759 while (cur->next != NULL) {
7760 cur = cur->next;
7761 if ((cur->type != XML_ENTITY_DECL) &&
7762 (cur->type != XML_DTD_NODE))
7763 return(cur);
7764 }
7765
7766 do {
7767 cur = cur->parent;
7768 if (cur == NULL) break;
7769 if (cur == ctxt->context->node) return(NULL);
7770 if (cur->next != NULL) {
7771 cur = cur->next;
7772 return(cur);
7773 }
7774 } while (cur != NULL);
7775 return(cur);
7776}
7777
7778/**
7779 * xmlXPathNextDescendantOrSelf:
7780 * @ctxt: the XPath Parser context
7781 * @cur: the current node in the traversal
7782 *
7783 * Traversal function for the "descendant-or-self" direction
7784 * the descendant-or-self axis contains the context node and the descendants
7785 * of the context node in document order; thus the context node is the first
7786 * node on the axis, and the first child of the context node is the second node
7787 * on the axis
7788 *
7789 * Returns the next element following that axis
7790 */
7791xmlNodePtr
7792xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7793 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7794 if (cur == NULL) {
7795 if (ctxt->context->node == NULL)
7796 return(NULL);
7797 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7798 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7799 return(NULL);
7800 return(ctxt->context->node);
7801 }
7802
7803 return(xmlXPathNextDescendant(ctxt, cur));
7804}
7805
7806/**
7807 * xmlXPathNextParent:
7808 * @ctxt: the XPath Parser context
7809 * @cur: the current node in the traversal
7810 *
7811 * Traversal function for the "parent" direction
7812 * The parent axis contains the parent of the context node, if there is one.
7813 *
7814 * Returns the next element following that axis
7815 */
7816xmlNodePtr
7817xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7818 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7819 /*
7820 * the parent of an attribute or namespace node is the element
7821 * to which the attribute or namespace node is attached
7822 * Namespace handling !!!
7823 */
7824 if (cur == NULL) {
7825 if (ctxt->context->node == NULL) return(NULL);
7826 switch (ctxt->context->node->type) {
7827 case XML_ELEMENT_NODE:
7828 case XML_TEXT_NODE:
7829 case XML_CDATA_SECTION_NODE:
7830 case XML_ENTITY_REF_NODE:
7831 case XML_ENTITY_NODE:
7832 case XML_PI_NODE:
7833 case XML_COMMENT_NODE:
7834 case XML_NOTATION_NODE:
7835 case XML_DTD_NODE:
7836 case XML_ELEMENT_DECL:
7837 case XML_ATTRIBUTE_DECL:
7838 case XML_XINCLUDE_START:
7839 case XML_XINCLUDE_END:
7840 case XML_ENTITY_DECL:
7841 if (ctxt->context->node->parent == NULL)
7842 return((xmlNodePtr) ctxt->context->doc);
7843 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7844 ((ctxt->context->node->parent->name[0] == ' ') ||
7845 (xmlStrEqual(ctxt->context->node->parent->name,
7846 BAD_CAST "fake node libxslt"))))
7847 return(NULL);
7848 return(ctxt->context->node->parent);
7849 case XML_ATTRIBUTE_NODE: {
7850 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7851
7852 return(att->parent);
7853 }
7854 case XML_DOCUMENT_NODE:
7855 case XML_DOCUMENT_TYPE_NODE:
7856 case XML_DOCUMENT_FRAG_NODE:
7857 case XML_HTML_DOCUMENT_NODE:
7858#ifdef LIBXML_DOCB_ENABLED
7859 case XML_DOCB_DOCUMENT_NODE:
7860#endif
7861 return(NULL);
7862 case XML_NAMESPACE_DECL: {
7863 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7864
7865 if ((ns->next != NULL) &&
7866 (ns->next->type != XML_NAMESPACE_DECL))
7867 return((xmlNodePtr) ns->next);
7868 return(NULL);
7869 }
7870 }
7871 }
7872 return(NULL);
7873}
7874
7875/**
7876 * xmlXPathNextAncestor:
7877 * @ctxt: the XPath Parser context
7878 * @cur: the current node in the traversal
7879 *
7880 * Traversal function for the "ancestor" direction
7881 * the ancestor axis contains the ancestors of the context node; the ancestors
7882 * of the context node consist of the parent of context node and the parent's
7883 * parent and so on; the nodes are ordered in reverse document order; thus the
7884 * parent is the first node on the axis, and the parent's parent is the second
7885 * node on the axis
7886 *
7887 * Returns the next element following that axis
7888 */
7889xmlNodePtr
7890xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7891 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7892 /*
7893 * the parent of an attribute or namespace node is the element
7894 * to which the attribute or namespace node is attached
7895 * !!!!!!!!!!!!!
7896 */
7897 if (cur == NULL) {
7898 if (ctxt->context->node == NULL) return(NULL);
7899 switch (ctxt->context->node->type) {
7900 case XML_ELEMENT_NODE:
7901 case XML_TEXT_NODE:
7902 case XML_CDATA_SECTION_NODE:
7903 case XML_ENTITY_REF_NODE:
7904 case XML_ENTITY_NODE:
7905 case XML_PI_NODE:
7906 case XML_COMMENT_NODE:
7907 case XML_DTD_NODE:
7908 case XML_ELEMENT_DECL:
7909 case XML_ATTRIBUTE_DECL:
7910 case XML_ENTITY_DECL:
7911 case XML_NOTATION_NODE:
7912 case XML_XINCLUDE_START:
7913 case XML_XINCLUDE_END:
7914 if (ctxt->context->node->parent == NULL)
7915 return((xmlNodePtr) ctxt->context->doc);
7916 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7917 ((ctxt->context->node->parent->name[0] == ' ') ||
7918 (xmlStrEqual(ctxt->context->node->parent->name,
7919 BAD_CAST "fake node libxslt"))))
7920 return(NULL);
7921 return(ctxt->context->node->parent);
7922 case XML_ATTRIBUTE_NODE: {
7923 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
7924
7925 return(tmp->parent);
7926 }
7927 case XML_DOCUMENT_NODE:
7928 case XML_DOCUMENT_TYPE_NODE:
7929 case XML_DOCUMENT_FRAG_NODE:
7930 case XML_HTML_DOCUMENT_NODE:
7931#ifdef LIBXML_DOCB_ENABLED
7932 case XML_DOCB_DOCUMENT_NODE:
7933#endif
7934 return(NULL);
7935 case XML_NAMESPACE_DECL: {
7936 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7937
7938 if ((ns->next != NULL) &&
7939 (ns->next->type != XML_NAMESPACE_DECL))
7940 return((xmlNodePtr) ns->next);
7941 /* Bad, how did that namespace end up here ? */
7942 return(NULL);
7943 }
7944 }
7945 return(NULL);
7946 }
7947 if (cur == ctxt->context->doc->children)
7948 return((xmlNodePtr) ctxt->context->doc);
7949 if (cur == (xmlNodePtr) ctxt->context->doc)
7950 return(NULL);
7951 switch (cur->type) {
7952 case XML_ELEMENT_NODE:
7953 case XML_TEXT_NODE:
7954 case XML_CDATA_SECTION_NODE:
7955 case XML_ENTITY_REF_NODE:
7956 case XML_ENTITY_NODE:
7957 case XML_PI_NODE:
7958 case XML_COMMENT_NODE:
7959 case XML_NOTATION_NODE:
7960 case XML_DTD_NODE:
7961 case XML_ELEMENT_DECL:
7962 case XML_ATTRIBUTE_DECL:
7963 case XML_ENTITY_DECL:
7964 case XML_XINCLUDE_START:
7965 case XML_XINCLUDE_END:
7966 if (cur->parent == NULL)
7967 return(NULL);
7968 if ((cur->parent->type == XML_ELEMENT_NODE) &&
7969 ((cur->parent->name[0] == ' ') ||
7970 (xmlStrEqual(cur->parent->name,
7971 BAD_CAST "fake node libxslt"))))
7972 return(NULL);
7973 return(cur->parent);
7974 case XML_ATTRIBUTE_NODE: {
7975 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7976
7977 return(att->parent);
7978 }
7979 case XML_NAMESPACE_DECL: {
7980 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7981
7982 if ((ns->next != NULL) &&
7983 (ns->next->type != XML_NAMESPACE_DECL))
7984 return((xmlNodePtr) ns->next);
7985 /* Bad, how did that namespace end up here ? */
7986 return(NULL);
7987 }
7988 case XML_DOCUMENT_NODE:
7989 case XML_DOCUMENT_TYPE_NODE:
7990 case XML_DOCUMENT_FRAG_NODE:
7991 case XML_HTML_DOCUMENT_NODE:
7992#ifdef LIBXML_DOCB_ENABLED
7993 case XML_DOCB_DOCUMENT_NODE:
7994#endif
7995 return(NULL);
7996 }
7997 return(NULL);
7998}
7999
8000/**
8001 * xmlXPathNextAncestorOrSelf:
8002 * @ctxt: the XPath Parser context
8003 * @cur: the current node in the traversal
8004 *
8005 * Traversal function for the "ancestor-or-self" direction
8006 * he ancestor-or-self axis contains the context node and ancestors of
8007 * the context node in reverse document order; thus the context node is
8008 * the first node on the axis, and the context node's parent the second;
8009 * parent here is defined the same as with the parent axis.
8010 *
8011 * Returns the next element following that axis
8012 */
8013xmlNodePtr
8014xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8015 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8016 if (cur == NULL)
8017 return(ctxt->context->node);
8018 return(xmlXPathNextAncestor(ctxt, cur));
8019}
8020
8021/**
8022 * xmlXPathNextFollowingSibling:
8023 * @ctxt: the XPath Parser context
8024 * @cur: the current node in the traversal
8025 *
8026 * Traversal function for the "following-sibling" direction
8027 * The following-sibling axis contains the following siblings of the context
8028 * node in document order.
8029 *
8030 * Returns the next element following that axis
8031 */
8032xmlNodePtr
8033xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8034 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8035 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8036 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8037 return(NULL);
8038 if (cur == (xmlNodePtr) ctxt->context->doc)
8039 return(NULL);
8040 if (cur == NULL)
8041 return(ctxt->context->node->next);
8042 return(cur->next);
8043}
8044
8045/**
8046 * xmlXPathNextPrecedingSibling:
8047 * @ctxt: the XPath Parser context
8048 * @cur: the current node in the traversal
8049 *
8050 * Traversal function for the "preceding-sibling" direction
8051 * The preceding-sibling axis contains the preceding siblings of the context
8052 * node in reverse document order; the first preceding sibling is first on the
8053 * axis; the sibling preceding that node is the second on the axis and so on.
8054 *
8055 * Returns the next element following that axis
8056 */
8057xmlNodePtr
8058xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8059 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8060 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8061 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8062 return(NULL);
8063 if (cur == (xmlNodePtr) ctxt->context->doc)
8064 return(NULL);
8065 if (cur == NULL)
8066 return(ctxt->context->node->prev);
8067 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8068 cur = cur->prev;
8069 if (cur == NULL)
8070 return(ctxt->context->node->prev);
8071 }
8072 return(cur->prev);
8073}
8074
8075/**
8076 * xmlXPathNextFollowing:
8077 * @ctxt: the XPath Parser context
8078 * @cur: the current node in the traversal
8079 *
8080 * Traversal function for the "following" direction
8081 * The following axis contains all nodes in the same document as the context
8082 * node that are after the context node in document order, excluding any
8083 * descendants and excluding attribute nodes and namespace nodes; the nodes
8084 * are ordered in document order
8085 *
8086 * Returns the next element following that axis
8087 */
8088xmlNodePtr
8089xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8090 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8091 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
8092 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8093 return(cur->children);
8094
8095 if (cur == NULL) {
8096 cur = ctxt->context->node;
8097 if (cur->type == XML_NAMESPACE_DECL)
8098 return(NULL);
8099 if (cur->type == XML_ATTRIBUTE_NODE)
8100 cur = cur->parent;
8101 }
8102 if (cur == NULL) return(NULL) ; /* ERROR */
8103 if (cur->next != NULL) return(cur->next) ;
8104 do {
8105 cur = cur->parent;
8106 if (cur == NULL) break;
8107 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8108 if (cur->next != NULL) return(cur->next);
8109 } while (cur != NULL);
8110 return(cur);
8111}
8112
8113/*
8114 * xmlXPathIsAncestor:
8115 * @ancestor: the ancestor node
8116 * @node: the current node
8117 *
8118 * Check that @ancestor is a @node's ancestor
8119 *
8120 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8121 */
8122static int
8123xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8124 if ((ancestor == NULL) || (node == NULL)) return(0);
8125 /* nodes need to be in the same document */
8126 if (ancestor->doc != node->doc) return(0);
8127 /* avoid searching if ancestor or node is the root node */
8128 if (ancestor == (xmlNodePtr) node->doc) return(1);
8129 if (node == (xmlNodePtr) ancestor->doc) return(0);
8130 while (node->parent != NULL) {
8131 if (node->parent == ancestor)
8132 return(1);
8133 node = node->parent;
8134 }
8135 return(0);
8136}
8137
8138/**
8139 * xmlXPathNextPreceding:
8140 * @ctxt: the XPath Parser context
8141 * @cur: the current node in the traversal
8142 *
8143 * Traversal function for the "preceding" direction
8144 * the preceding axis contains all nodes in the same document as the context
8145 * node that are before the context node in document order, excluding any
8146 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8147 * ordered in reverse document order
8148 *
8149 * Returns the next element following that axis
8150 */
8151xmlNodePtr
8152xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8153{
8154 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8155 if (cur == NULL) {
8156 cur = ctxt->context->node;
8157 if (cur->type == XML_NAMESPACE_DECL)
8158 return(NULL);
8159 if (cur->type == XML_ATTRIBUTE_NODE)
8160 return(cur->parent);
8161 }
8162 if (cur == NULL)
8163 return (NULL);
8164 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8165 cur = cur->prev;
8166 do {
8167 if (cur->prev != NULL) {
8168 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8169 return (cur);
8170 }
8171
8172 cur = cur->parent;
8173 if (cur == NULL)
8174 return (NULL);
8175 if (cur == ctxt->context->doc->children)
8176 return (NULL);
8177 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8178 return (cur);
8179}
8180
8181/**
8182 * xmlXPathNextPrecedingInternal:
8183 * @ctxt: the XPath Parser context
8184 * @cur: the current node in the traversal
8185 *
8186 * Traversal function for the "preceding" direction
8187 * the preceding axis contains all nodes in the same document as the context
8188 * node that are before the context node in document order, excluding any
8189 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8190 * ordered in reverse document order
8191 * This is a faster implementation but internal only since it requires a
8192 * state kept in the parser context: ctxt->ancestor.
8193 *
8194 * Returns the next element following that axis
8195 */
8196static xmlNodePtr
8197xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8198 xmlNodePtr cur)
8199{
8200 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8201 if (cur == NULL) {
8202 cur = ctxt->context->node;
8203 if (cur == NULL)
8204 return (NULL);
8205 if (cur->type == XML_NAMESPACE_DECL)
8206 return (NULL);
8207 ctxt->ancestor = cur->parent;
8208 }
8209 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8210 cur = cur->prev;
8211 while (cur->prev == NULL) {
8212 cur = cur->parent;
8213 if (cur == NULL)
8214 return (NULL);
8215 if (cur == ctxt->context->doc->children)
8216 return (NULL);
8217 if (cur != ctxt->ancestor)
8218 return (cur);
8219 ctxt->ancestor = cur->parent;
8220 }
8221 cur = cur->prev;
8222 while (cur->last != NULL)
8223 cur = cur->last;
8224 return (cur);
8225}
8226
8227/**
8228 * xmlXPathNextNamespace:
8229 * @ctxt: the XPath Parser context
8230 * @cur: the current attribute in the traversal
8231 *
8232 * Traversal function for the "namespace" direction
8233 * the namespace axis contains the namespace nodes of the context node;
8234 * the order of nodes on this axis is implementation-defined; the axis will
8235 * be empty unless the context node is an element
8236 *
8237 * We keep the XML namespace node at the end of the list.
8238 *
8239 * Returns the next element following that axis
8240 */
8241xmlNodePtr
8242xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8243 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8244 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8245 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
8246 if (ctxt->context->tmpNsList != NULL)
8247 xmlFree(ctxt->context->tmpNsList);
8248 ctxt->context->tmpNsList =
8249 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8250 ctxt->context->tmpNsNr = 0;
8251 if (ctxt->context->tmpNsList != NULL) {
8252 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8253 ctxt->context->tmpNsNr++;
8254 }
8255 }
8256 return((xmlNodePtr) xmlXPathXMLNamespace);
8257 }
8258 if (ctxt->context->tmpNsNr > 0) {
8259 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8260 } else {
8261 if (ctxt->context->tmpNsList != NULL)
8262 xmlFree(ctxt->context->tmpNsList);
8263 ctxt->context->tmpNsList = NULL;
8264 return(NULL);
8265 }
8266}
8267
8268/**
8269 * xmlXPathNextAttribute:
8270 * @ctxt: the XPath Parser context
8271 * @cur: the current attribute in the traversal
8272 *
8273 * Traversal function for the "attribute" direction
8274 * TODO: support DTD inherited default attributes
8275 *
8276 * Returns the next element following that axis
8277 */
8278xmlNodePtr
8279xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8280 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8281 if (ctxt->context->node == NULL)
8282 return(NULL);
8283 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8284 return(NULL);
8285 if (cur == NULL) {
8286 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8287 return(NULL);
8288 return((xmlNodePtr)ctxt->context->node->properties);
8289 }
8290 return((xmlNodePtr)cur->next);
8291}
8292
8293/************************************************************************
8294 * *
8295 * NodeTest Functions *
8296 * *
8297 ************************************************************************/
8298
8299#define IS_FUNCTION 200
8300
8301
8302/************************************************************************
8303 * *
8304 * Implicit tree core function library *
8305 * *
8306 ************************************************************************/
8307
8308/**
8309 * xmlXPathRoot:
8310 * @ctxt: the XPath Parser context
8311 *
8312 * Initialize the context to the root of the document
8313 */
8314void
8315xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8316 if ((ctxt == NULL) || (ctxt->context == NULL))
8317 return;
8318 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
8319 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8320 ctxt->context->node));
8321}
8322
8323/************************************************************************
8324 * *
8325 * The explicit core function library *
8326 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8327 * *
8328 ************************************************************************/
8329
8330
8331/**
8332 * xmlXPathLastFunction:
8333 * @ctxt: the XPath Parser context
8334 * @nargs: the number of arguments
8335 *
8336 * Implement the last() XPath function
8337 * number last()
8338 * The last function returns the number of nodes in the context node list.
8339 */
8340void
8341xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8342 CHECK_ARITY(0);
8343 if (ctxt->context->contextSize >= 0) {
8344 valuePush(ctxt,
8345 xmlXPathCacheNewFloat(ctxt->context,
8346 (double) ctxt->context->contextSize));
8347#ifdef DEBUG_EXPR
8348 xmlGenericError(xmlGenericErrorContext,
8349 "last() : %d\n", ctxt->context->contextSize);
8350#endif
8351 } else {
8352 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8353 }
8354}
8355
8356/**
8357 * xmlXPathPositionFunction:
8358 * @ctxt: the XPath Parser context
8359 * @nargs: the number of arguments
8360 *
8361 * Implement the position() XPath function
8362 * number position()
8363 * The position function returns the position of the context node in the
8364 * context node list. The first position is 1, and so the last position
8365 * will be equal to last().
8366 */
8367void
8368xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8369 CHECK_ARITY(0);
8370 if (ctxt->context->proximityPosition >= 0) {
8371 valuePush(ctxt,
8372 xmlXPathCacheNewFloat(ctxt->context,
8373 (double) ctxt->context->proximityPosition));
8374#ifdef DEBUG_EXPR
8375 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8376 ctxt->context->proximityPosition);
8377#endif
8378 } else {
8379 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8380 }
8381}
8382
8383/**
8384 * xmlXPathCountFunction:
8385 * @ctxt: the XPath Parser context
8386 * @nargs: the number of arguments
8387 *
8388 * Implement the count() XPath function
8389 * number count(node-set)
8390 */
8391void
8392xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8393 xmlXPathObjectPtr cur;
8394
8395 CHECK_ARITY(1);
8396 if ((ctxt->value == NULL) ||
8397 ((ctxt->value->type != XPATH_NODESET) &&
8398 (ctxt->value->type != XPATH_XSLT_TREE)))
8399 XP_ERROR(XPATH_INVALID_TYPE);
8400 cur = valuePop(ctxt);
8401
8402 if ((cur == NULL) || (cur->nodesetval == NULL))
8403 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8404 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8405 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8406 (double) cur->nodesetval->nodeNr));
8407 } else {
8408 if ((cur->nodesetval->nodeNr != 1) ||
8409 (cur->nodesetval->nodeTab == NULL)) {
8410 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8411 } else {
8412 xmlNodePtr tmp;
8413 int i = 0;
8414
8415 tmp = cur->nodesetval->nodeTab[0];
8416 if (tmp != NULL) {
8417 tmp = tmp->children;
8418 while (tmp != NULL) {
8419 tmp = tmp->next;
8420 i++;
8421 }
8422 }
8423 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8424 }
8425 }
8426 xmlXPathReleaseObject(ctxt->context, cur);
8427}
8428
8429/**
8430 * xmlXPathGetElementsByIds:
8431 * @doc: the document
8432 * @ids: a whitespace separated list of IDs
8433 *
8434 * Selects elements by their unique ID.
8435 *
8436 * Returns a node-set of selected elements.
8437 */
8438static xmlNodeSetPtr
8439xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8440 xmlNodeSetPtr ret;
8441 const xmlChar *cur = ids;
8442 xmlChar *ID;
8443 xmlAttrPtr attr;
8444 xmlNodePtr elem = NULL;
8445
8446 if (ids == NULL) return(NULL);
8447
8448 ret = xmlXPathNodeSetCreate(NULL);
8449
8450 while (IS_BLANK_CH(*cur)) cur++;
8451 while (*cur != 0) {
8452 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8453 cur++;
8454
8455 ID = xmlStrndup(ids, cur - ids);
8456 if (ID != NULL) {
8457 /*
8458 * We used to check the fact that the value passed
8459 * was an NCName, but this generated much troubles for
8460 * me and Aleksey Sanin, people blatantly violated that
8461 * constaint, like Visa3D spec.
8462 * if (xmlValidateNCName(ID, 1) == 0)
8463 */
8464 attr = xmlGetID(doc, ID);
8465 if (attr != NULL) {
8466 if (attr->type == XML_ATTRIBUTE_NODE)
8467 elem = attr->parent;
8468 else if (attr->type == XML_ELEMENT_NODE)
8469 elem = (xmlNodePtr) attr;
8470 else
8471 elem = NULL;
8472 if (elem != NULL)
8473 xmlXPathNodeSetAdd(ret, elem);
8474 }
8475 xmlFree(ID);
8476 }
8477
8478 while (IS_BLANK_CH(*cur)) cur++;
8479 ids = cur;
8480 }
8481 return(ret);
8482}
8483
8484/**
8485 * xmlXPathIdFunction:
8486 * @ctxt: the XPath Parser context
8487 * @nargs: the number of arguments
8488 *
8489 * Implement the id() XPath function
8490 * node-set id(object)
8491 * The id function selects elements by their unique ID
8492 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8493 * then the result is the union of the result of applying id to the
8494 * string value of each of the nodes in the argument node-set. When the
8495 * argument to id is of any other type, the argument is converted to a
8496 * string as if by a call to the string function; the string is split
8497 * into a whitespace-separated list of tokens (whitespace is any sequence
8498 * of characters matching the production S); the result is a node-set
8499 * containing the elements in the same document as the context node that
8500 * have a unique ID equal to any of the tokens in the list.
8501 */
8502void
8503xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8504 xmlChar *tokens;
8505 xmlNodeSetPtr ret;
8506 xmlXPathObjectPtr obj;
8507
8508 CHECK_ARITY(1);
8509 obj = valuePop(ctxt);
8510 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8511 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8512 xmlNodeSetPtr ns;
8513 int i;
8514
8515 ret = xmlXPathNodeSetCreate(NULL);
8516
8517 if (obj->nodesetval != NULL) {
8518 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8519 tokens =
8520 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8521 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8522 ret = xmlXPathNodeSetMerge(ret, ns);
8523 xmlXPathFreeNodeSet(ns);
8524 if (tokens != NULL)
8525 xmlFree(tokens);
8526 }
8527 }
8528 xmlXPathReleaseObject(ctxt->context, obj);
8529 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8530 return;
8531 }
8532 obj = xmlXPathCacheConvertString(ctxt->context, obj);
8533 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8534 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8535 xmlXPathReleaseObject(ctxt->context, obj);
8536 return;
8537}
8538
8539/**
8540 * xmlXPathLocalNameFunction:
8541 * @ctxt: the XPath Parser context
8542 * @nargs: the number of arguments
8543 *
8544 * Implement the local-name() XPath function
8545 * string local-name(node-set?)
8546 * The local-name function returns a string containing the local part
8547 * of the name of the node in the argument node-set that is first in
8548 * document order. If the node-set is empty or the first node has no
8549 * name, an empty string is returned. If the argument is omitted it
8550 * defaults to the context node.
8551 */
8552void
8553xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8554 xmlXPathObjectPtr cur;
8555
8556 if (ctxt == NULL) return;
8557
8558 if (nargs == 0) {
8559 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8560 ctxt->context->node));
8561 nargs = 1;
8562 }
8563
8564 CHECK_ARITY(1);
8565 if ((ctxt->value == NULL) ||
8566 ((ctxt->value->type != XPATH_NODESET) &&
8567 (ctxt->value->type != XPATH_XSLT_TREE)))
8568 XP_ERROR(XPATH_INVALID_TYPE);
8569 cur = valuePop(ctxt);
8570
8571 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8572 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8573 } else {
8574 int i = 0; /* Should be first in document order !!!!! */
8575 switch (cur->nodesetval->nodeTab[i]->type) {
8576 case XML_ELEMENT_NODE:
8577 case XML_ATTRIBUTE_NODE:
8578 case XML_PI_NODE:
8579 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8580 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8581 else
8582 valuePush(ctxt,
8583 xmlXPathCacheNewString(ctxt->context,
8584 cur->nodesetval->nodeTab[i]->name));
8585 break;
8586 case XML_NAMESPACE_DECL:
8587 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8588 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8589 break;
8590 default:
8591 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8592 }
8593 }
8594 xmlXPathReleaseObject(ctxt->context, cur);
8595}
8596
8597/**
8598 * xmlXPathNamespaceURIFunction:
8599 * @ctxt: the XPath Parser context
8600 * @nargs: the number of arguments
8601 *
8602 * Implement the namespace-uri() XPath function
8603 * string namespace-uri(node-set?)
8604 * The namespace-uri function returns a string containing the
8605 * namespace URI of the expanded name of the node in the argument
8606 * node-set that is first in document order. If the node-set is empty,
8607 * the first node has no name, or the expanded name has no namespace
8608 * URI, an empty string is returned. If the argument is omitted it
8609 * defaults to the context node.
8610 */
8611void
8612xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8613 xmlXPathObjectPtr cur;
8614
8615 if (ctxt == NULL) return;
8616
8617 if (nargs == 0) {
8618 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8619 ctxt->context->node));
8620 nargs = 1;
8621 }
8622 CHECK_ARITY(1);
8623 if ((ctxt->value == NULL) ||
8624 ((ctxt->value->type != XPATH_NODESET) &&
8625 (ctxt->value->type != XPATH_XSLT_TREE)))
8626 XP_ERROR(XPATH_INVALID_TYPE);
8627 cur = valuePop(ctxt);
8628
8629 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8630 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8631 } else {
8632 int i = 0; /* Should be first in document order !!!!! */
8633 switch (cur->nodesetval->nodeTab[i]->type) {
8634 case XML_ELEMENT_NODE:
8635 case XML_ATTRIBUTE_NODE:
8636 if (cur->nodesetval->nodeTab[i]->ns == NULL)
8637 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8638 else
8639 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8640 cur->nodesetval->nodeTab[i]->ns->href));
8641 break;
8642 default:
8643 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8644 }
8645 }
8646 xmlXPathReleaseObject(ctxt->context, cur);
8647}
8648
8649/**
8650 * xmlXPathNameFunction:
8651 * @ctxt: the XPath Parser context
8652 * @nargs: the number of arguments
8653 *
8654 * Implement the name() XPath function
8655 * string name(node-set?)
8656 * The name function returns a string containing a QName representing
8657 * the name of the node in the argument node-set that is first in document
8658 * order. The QName must represent the name with respect to the namespace
8659 * declarations in effect on the node whose name is being represented.
8660 * Typically, this will be the form in which the name occurred in the XML
8661 * source. This need not be the case if there are namespace declarations
8662 * in effect on the node that associate multiple prefixes with the same
8663 * namespace. However, an implementation may include information about
8664 * the original prefix in its representation of nodes; in this case, an
8665 * implementation can ensure that the returned string is always the same
8666 * as the QName used in the XML source. If the argument it omitted it
8667 * defaults to the context node.
8668 * Libxml keep the original prefix so the "real qualified name" used is
8669 * returned.
8670 */
8671static void
8672xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8673{
8674 xmlXPathObjectPtr cur;
8675
8676 if (nargs == 0) {
8677 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8678 ctxt->context->node));
8679 nargs = 1;
8680 }
8681
8682 CHECK_ARITY(1);
8683 if ((ctxt->value == NULL) ||
8684 ((ctxt->value->type != XPATH_NODESET) &&
8685 (ctxt->value->type != XPATH_XSLT_TREE)))
8686 XP_ERROR(XPATH_INVALID_TYPE);
8687 cur = valuePop(ctxt);
8688
8689 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8690 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8691 } else {
8692 int i = 0; /* Should be first in document order !!!!! */
8693
8694 switch (cur->nodesetval->nodeTab[i]->type) {
8695 case XML_ELEMENT_NODE:
8696 case XML_ATTRIBUTE_NODE:
8697 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8698 valuePush(ctxt,
8699 xmlXPathCacheNewCString(ctxt->context, ""));
8700 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8701 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8702 valuePush(ctxt,
8703 xmlXPathCacheNewString(ctxt->context,
8704 cur->nodesetval->nodeTab[i]->name));
8705 } else {
8706 xmlChar *fullname;
8707
8708 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8709 cur->nodesetval->nodeTab[i]->ns->prefix,
8710 NULL, 0);
8711 if (fullname == cur->nodesetval->nodeTab[i]->name)
8712 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8713 if (fullname == NULL) {
8714 XP_ERROR(XPATH_MEMORY_ERROR);
8715 }
8716 valuePush(ctxt, xmlXPathCacheWrapString(
8717 ctxt->context, fullname));
8718 }
8719 break;
8720 default:
8721 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8722 cur->nodesetval->nodeTab[i]));
8723 xmlXPathLocalNameFunction(ctxt, 1);
8724 }
8725 }
8726 xmlXPathReleaseObject(ctxt->context, cur);
8727}
8728
8729
8730/**
8731 * xmlXPathStringFunction:
8732 * @ctxt: the XPath Parser context
8733 * @nargs: the number of arguments
8734 *
8735 * Implement the string() XPath function
8736 * string string(object?)
8737 * The string function converts an object to a string as follows:
8738 * - A node-set is converted to a string by returning the value of
8739 * the node in the node-set that is first in document order.
8740 * If the node-set is empty, an empty string is returned.
8741 * - A number is converted to a string as follows
8742 * + NaN is converted to the string NaN
8743 * + positive zero is converted to the string 0
8744 * + negative zero is converted to the string 0
8745 * + positive infinity is converted to the string Infinity
8746 * + negative infinity is converted to the string -Infinity
8747 * + if the number is an integer, the number is represented in
8748 * decimal form as a Number with no decimal point and no leading
8749 * zeros, preceded by a minus sign (-) if the number is negative
8750 * + otherwise, the number is represented in decimal form as a
8751 * Number including a decimal point with at least one digit
8752 * before the decimal point and at least one digit after the
8753 * decimal point, preceded by a minus sign (-) if the number
8754 * is negative; there must be no leading zeros before the decimal
8755 * point apart possibly from the one required digit immediately
8756 * before the decimal point; beyond the one required digit
8757 * after the decimal point there must be as many, but only as
8758 * many, more digits as are needed to uniquely distinguish the
8759 * number from all other IEEE 754 numeric values.
8760 * - The boolean false value is converted to the string false.
8761 * The boolean true value is converted to the string true.
8762 *
8763 * If the argument is omitted, it defaults to a node-set with the
8764 * context node as its only member.
8765 */
8766void
8767xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8768 xmlXPathObjectPtr cur;
8769
8770 if (ctxt == NULL) return;
8771 if (nargs == 0) {
8772 valuePush(ctxt,
8773 xmlXPathCacheWrapString(ctxt->context,
8774 xmlXPathCastNodeToString(ctxt->context->node)));
8775 return;
8776 }
8777
8778 CHECK_ARITY(1);
8779 cur = valuePop(ctxt);
8780 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8781 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8782}
8783
8784/**
8785 * xmlXPathStringLengthFunction:
8786 * @ctxt: the XPath Parser context
8787 * @nargs: the number of arguments
8788 *
8789 * Implement the string-length() XPath function
8790 * number string-length(string?)
8791 * The string-length returns the number of characters in the string
8792 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8793 * the context node converted to a string, in other words the value
8794 * of the context node.
8795 */
8796void
8797xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8798 xmlXPathObjectPtr cur;
8799
8800 if (nargs == 0) {
8801 if ((ctxt == NULL) || (ctxt->context == NULL))
8802 return;
8803 if (ctxt->context->node == NULL) {
8804 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8805 } else {
8806 xmlChar *content;
8807
8808 content = xmlXPathCastNodeToString(ctxt->context->node);
8809 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8810 xmlUTF8Strlen(content)));
8811 xmlFree(content);
8812 }
8813 return;
8814 }
8815 CHECK_ARITY(1);
8816 CAST_TO_STRING;
8817 CHECK_TYPE(XPATH_STRING);
8818 cur = valuePop(ctxt);
8819 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8820 xmlUTF8Strlen(cur->stringval)));
8821 xmlXPathReleaseObject(ctxt->context, cur);
8822}
8823
8824/**
8825 * xmlXPathConcatFunction:
8826 * @ctxt: the XPath Parser context
8827 * @nargs: the number of arguments
8828 *
8829 * Implement the concat() XPath function
8830 * string concat(string, string, string*)
8831 * The concat function returns the concatenation of its arguments.
8832 */
8833void
8834xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8835 xmlXPathObjectPtr cur, newobj;
8836 xmlChar *tmp;
8837
8838 if (ctxt == NULL) return;
8839 if (nargs < 2) {
8840 CHECK_ARITY(2);
8841 }
8842
8843 CAST_TO_STRING;
8844 cur = valuePop(ctxt);
8845 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8846 xmlXPathReleaseObject(ctxt->context, cur);
8847 return;
8848 }
8849 nargs--;
8850
8851 while (nargs > 0) {
8852 CAST_TO_STRING;
8853 newobj = valuePop(ctxt);
8854 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8855 xmlXPathReleaseObject(ctxt->context, newobj);
8856 xmlXPathReleaseObject(ctxt->context, cur);
8857 XP_ERROR(XPATH_INVALID_TYPE);
8858 }
8859 tmp = xmlStrcat(newobj->stringval, cur->stringval);
8860 newobj->stringval = cur->stringval;
8861 cur->stringval = tmp;
8862 xmlXPathReleaseObject(ctxt->context, newobj);
8863 nargs--;
8864 }
8865 valuePush(ctxt, cur);
8866}
8867
8868/**
8869 * xmlXPathContainsFunction:
8870 * @ctxt: the XPath Parser context
8871 * @nargs: the number of arguments
8872 *
8873 * Implement the contains() XPath function
8874 * boolean contains(string, string)
8875 * The contains function returns true if the first argument string
8876 * contains the second argument string, and otherwise returns false.
8877 */
8878void
8879xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8880 xmlXPathObjectPtr hay, needle;
8881
8882 CHECK_ARITY(2);
8883 CAST_TO_STRING;
8884 CHECK_TYPE(XPATH_STRING);
8885 needle = valuePop(ctxt);
8886 CAST_TO_STRING;
8887 hay = valuePop(ctxt);
8888
8889 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8890 xmlXPathReleaseObject(ctxt->context, hay);
8891 xmlXPathReleaseObject(ctxt->context, needle);
8892 XP_ERROR(XPATH_INVALID_TYPE);
8893 }
8894 if (xmlStrstr(hay->stringval, needle->stringval))
8895 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8896 else
8897 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8898 xmlXPathReleaseObject(ctxt->context, hay);
8899 xmlXPathReleaseObject(ctxt->context, needle);
8900}
8901
8902/**
8903 * xmlXPathStartsWithFunction:
8904 * @ctxt: the XPath Parser context
8905 * @nargs: the number of arguments
8906 *
8907 * Implement the starts-with() XPath function
8908 * boolean starts-with(string, string)
8909 * The starts-with function returns true if the first argument string
8910 * starts with the second argument string, and otherwise returns false.
8911 */
8912void
8913xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8914 xmlXPathObjectPtr hay, needle;
8915 int n;
8916
8917 CHECK_ARITY(2);
8918 CAST_TO_STRING;
8919 CHECK_TYPE(XPATH_STRING);
8920 needle = valuePop(ctxt);
8921 CAST_TO_STRING;
8922 hay = valuePop(ctxt);
8923
8924 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8925 xmlXPathReleaseObject(ctxt->context, hay);
8926 xmlXPathReleaseObject(ctxt->context, needle);
8927 XP_ERROR(XPATH_INVALID_TYPE);
8928 }
8929 n = xmlStrlen(needle->stringval);
8930 if (xmlStrncmp(hay->stringval, needle->stringval, n))
8931 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8932 else
8933 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8934 xmlXPathReleaseObject(ctxt->context, hay);
8935 xmlXPathReleaseObject(ctxt->context, needle);
8936}
8937
8938/**
8939 * xmlXPathSubstringFunction:
8940 * @ctxt: the XPath Parser context
8941 * @nargs: the number of arguments
8942 *
8943 * Implement the substring() XPath function
8944 * string substring(string, number, number?)
8945 * The substring function returns the substring of the first argument
8946 * starting at the position specified in the second argument with
8947 * length specified in the third argument. For example,
8948 * substring("12345",2,3) returns "234". If the third argument is not
8949 * specified, it returns the substring starting at the position specified
8950 * in the second argument and continuing to the end of the string. For
8951 * example, substring("12345",2) returns "2345". More precisely, each
8952 * character in the string (see [3.6 Strings]) is considered to have a
8953 * numeric position: the position of the first character is 1, the position
8954 * of the second character is 2 and so on. The returned substring contains
8955 * those characters for which the position of the character is greater than
8956 * or equal to the second argument and, if the third argument is specified,
8957 * less than the sum of the second and third arguments; the comparisons
8958 * and addition used for the above follow the standard IEEE 754 rules. Thus:
8959 * - substring("12345", 1.5, 2.6) returns "234"
8960 * - substring("12345", 0, 3) returns "12"
8961 * - substring("12345", 0 div 0, 3) returns ""
8962 * - substring("12345", 1, 0 div 0) returns ""
8963 * - substring("12345", -42, 1 div 0) returns "12345"
8964 * - substring("12345", -1 div 0, 1 div 0) returns ""
8965 */
8966void
8967xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8968 xmlXPathObjectPtr str, start, len;
8969 double le=0, in;
8970 int i, l, m;
8971 xmlChar *ret;
8972
8973 if (nargs < 2) {
8974 CHECK_ARITY(2);
8975 }
8976 if (nargs > 3) {
8977 CHECK_ARITY(3);
8978 }
8979 /*
8980 * take care of possible last (position) argument
8981 */
8982 if (nargs == 3) {
8983 CAST_TO_NUMBER;
8984 CHECK_TYPE(XPATH_NUMBER);
8985 len = valuePop(ctxt);
8986 le = len->floatval;
8987 xmlXPathReleaseObject(ctxt->context, len);
8988 }
8989
8990 CAST_TO_NUMBER;
8991 CHECK_TYPE(XPATH_NUMBER);
8992 start = valuePop(ctxt);
8993 in = start->floatval;
8994 xmlXPathReleaseObject(ctxt->context, start);
8995 CAST_TO_STRING;
8996 CHECK_TYPE(XPATH_STRING);
8997 str = valuePop(ctxt);
8998 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
8999
9000 /*
9001 * If last pos not present, calculate last position
9002 */
9003 if (nargs != 3) {
9004 le = (double)m;
9005 if (in < 1.0)
9006 in = 1.0;
9007 }
9008
9009 /* Need to check for the special cases where either
9010 * the index is NaN, the length is NaN, or both
9011 * arguments are infinity (relying on Inf + -Inf = NaN)
9012 */
9013 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
9014 /*
9015 * To meet the requirements of the spec, the arguments
9016 * must be converted to integer format before
9017 * initial index calculations are done
9018 *
9019 * First we go to integer form, rounding up
9020 * and checking for special cases
9021 */
9022 i = (int) in;
9023 if (((double)i)+0.5 <= in) i++;
9024
9025 if (xmlXPathIsInf(le) == 1) {
9026 l = m;
9027 if (i < 1)
9028 i = 1;
9029 }
9030 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9031 l = 0;
9032 else {
9033 l = (int) le;
9034 if (((double)l)+0.5 <= le) l++;
9035 }
9036
9037 /* Now we normalize inidices */
9038 i -= 1;
9039 l += i;
9040 if (i < 0)
9041 i = 0;
9042 if (l > m)
9043 l = m;
9044
9045 /* number of chars to copy */
9046 l -= i;
9047
9048 ret = xmlUTF8Strsub(str->stringval, i, l);
9049 }
9050 else {
9051 ret = NULL;
9052 }
9053 if (ret == NULL)
9054 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9055 else {
9056 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9057 xmlFree(ret);
9058 }
9059 xmlXPathReleaseObject(ctxt->context, str);
9060}
9061
9062/**
9063 * xmlXPathSubstringBeforeFunction:
9064 * @ctxt: the XPath Parser context
9065 * @nargs: the number of arguments
9066 *
9067 * Implement the substring-before() XPath function
9068 * string substring-before(string, string)
9069 * The substring-before function returns the substring of the first
9070 * argument string that precedes the first occurrence of the second
9071 * argument string in the first argument string, or the empty string
9072 * if the first argument string does not contain the second argument
9073 * string. For example, substring-before("1999/04/01","/") returns 1999.
9074 */
9075void
9076xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9077 xmlXPathObjectPtr str;
9078 xmlXPathObjectPtr find;
9079 xmlBufferPtr target;
9080 const xmlChar *point;
9081 int offset;
9082
9083 CHECK_ARITY(2);
9084 CAST_TO_STRING;
9085 find = valuePop(ctxt);
9086 CAST_TO_STRING;
9087 str = valuePop(ctxt);
9088
9089 target = xmlBufferCreate();
9090 if (target) {
9091 point = xmlStrstr(str->stringval, find->stringval);
9092 if (point) {
9093 offset = (int)(point - str->stringval);
9094 xmlBufferAdd(target, str->stringval, offset);
9095 }
9096 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9097 xmlBufferContent(target)));
9098 xmlBufferFree(target);
9099 }
9100 xmlXPathReleaseObject(ctxt->context, str);
9101 xmlXPathReleaseObject(ctxt->context, find);
9102}
9103
9104/**
9105 * xmlXPathSubstringAfterFunction:
9106 * @ctxt: the XPath Parser context
9107 * @nargs: the number of arguments
9108 *
9109 * Implement the substring-after() XPath function
9110 * string substring-after(string, string)
9111 * The substring-after function returns the substring of the first
9112 * argument string that follows the first occurrence of the second
9113 * argument string in the first argument string, or the empty stringi
9114 * if the first argument string does not contain the second argument
9115 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9116 * and substring-after("1999/04/01","19") returns 99/04/01.
9117 */
9118void
9119xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9120 xmlXPathObjectPtr str;
9121 xmlXPathObjectPtr find;
9122 xmlBufferPtr target;
9123 const xmlChar *point;
9124 int offset;
9125
9126 CHECK_ARITY(2);
9127 CAST_TO_STRING;
9128 find = valuePop(ctxt);
9129 CAST_TO_STRING;
9130 str = valuePop(ctxt);
9131
9132 target = xmlBufferCreate();
9133 if (target) {
9134 point = xmlStrstr(str->stringval, find->stringval);
9135 if (point) {
9136 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9137 xmlBufferAdd(target, &str->stringval[offset],
9138 xmlStrlen(str->stringval) - offset);
9139 }
9140 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9141 xmlBufferContent(target)));
9142 xmlBufferFree(target);
9143 }
9144 xmlXPathReleaseObject(ctxt->context, str);
9145 xmlXPathReleaseObject(ctxt->context, find);
9146}
9147
9148/**
9149 * xmlXPathNormalizeFunction:
9150 * @ctxt: the XPath Parser context
9151 * @nargs: the number of arguments
9152 *
9153 * Implement the normalize-space() XPath function
9154 * string normalize-space(string?)
9155 * The normalize-space function returns the argument string with white
9156 * space normalized by stripping leading and trailing whitespace
9157 * and replacing sequences of whitespace characters by a single
9158 * space. Whitespace characters are the same allowed by the S production
9159 * in XML. If the argument is omitted, it defaults to the context
9160 * node converted to a string, in other words the value of the context node.
9161 */
9162void
9163xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9164 xmlXPathObjectPtr obj = NULL;
9165 xmlChar *source = NULL;
9166 xmlBufferPtr target;
9167 xmlChar blank;
9168
9169 if (ctxt == NULL) return;
9170 if (nargs == 0) {
9171 /* Use current context node */
9172 valuePush(ctxt,
9173 xmlXPathCacheWrapString(ctxt->context,
9174 xmlXPathCastNodeToString(ctxt->context->node)));
9175 nargs = 1;
9176 }
9177
9178 CHECK_ARITY(1);
9179 CAST_TO_STRING;
9180 CHECK_TYPE(XPATH_STRING);
9181 obj = valuePop(ctxt);
9182 source = obj->stringval;
9183
9184 target = xmlBufferCreate();
9185 if (target && source) {
9186
9187 /* Skip leading whitespaces */
9188 while (IS_BLANK_CH(*source))
9189 source++;
9190
9191 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9192 blank = 0;
9193 while (*source) {
9194 if (IS_BLANK_CH(*source)) {
9195 blank = 0x20;
9196 } else {
9197 if (blank) {
9198 xmlBufferAdd(target, &blank, 1);
9199 blank = 0;
9200 }
9201 xmlBufferAdd(target, source, 1);
9202 }
9203 source++;
9204 }
9205 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9206 xmlBufferContent(target)));
9207 xmlBufferFree(target);
9208 }
9209 xmlXPathReleaseObject(ctxt->context, obj);
9210}
9211
9212/**
9213 * xmlXPathTranslateFunction:
9214 * @ctxt: the XPath Parser context
9215 * @nargs: the number of arguments
9216 *
9217 * Implement the translate() XPath function
9218 * string translate(string, string, string)
9219 * The translate function returns the first argument string with
9220 * occurrences of characters in the second argument string replaced
9221 * by the character at the corresponding position in the third argument
9222 * string. For example, translate("bar","abc","ABC") returns the string
9223 * BAr. If there is a character in the second argument string with no
9224 * character at a corresponding position in the third argument string
9225 * (because the second argument string is longer than the third argument
9226 * string), then occurrences of that character in the first argument
9227 * string are removed. For example, translate("--aaa--","abc-","ABC")
9228 * returns "AAA". If a character occurs more than once in second
9229 * argument string, then the first occurrence determines the replacement
9230 * character. If the third argument string is longer than the second
9231 * argument string, then excess characters are ignored.
9232 */
9233void
9234xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9235 xmlXPathObjectPtr str;
9236 xmlXPathObjectPtr from;
9237 xmlXPathObjectPtr to;
9238 xmlBufferPtr target;
9239 int offset, max;
9240 xmlChar ch;
9241 const xmlChar *point;
9242 xmlChar *cptr;
9243
9244 CHECK_ARITY(3);
9245
9246 CAST_TO_STRING;
9247 to = valuePop(ctxt);
9248 CAST_TO_STRING;
9249 from = valuePop(ctxt);
9250 CAST_TO_STRING;
9251 str = valuePop(ctxt);
9252
9253 target = xmlBufferCreate();
9254 if (target) {
9255 max = xmlUTF8Strlen(to->stringval);
9256 for (cptr = str->stringval; (ch=*cptr); ) {
9257 offset = xmlUTF8Strloc(from->stringval, cptr);
9258 if (offset >= 0) {
9259 if (offset < max) {
9260 point = xmlUTF8Strpos(to->stringval, offset);
9261 if (point)
9262 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
9263 }
9264 } else
9265 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9266
9267 /* Step to next character in input */
9268 cptr++;
9269 if ( ch & 0x80 ) {
9270 /* if not simple ascii, verify proper format */
9271 if ( (ch & 0xc0) != 0xc0 ) {
9272 xmlGenericError(xmlGenericErrorContext,
9273 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9274 /* not asserting an XPath error is probably better */
9275 break;
9276 }
9277 /* then skip over remaining bytes for this char */
9278 while ( (ch <<= 1) & 0x80 )
9279 if ( (*cptr++ & 0xc0) != 0x80 ) {
9280 xmlGenericError(xmlGenericErrorContext,
9281 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9282 /* not asserting an XPath error is probably better */
9283 break;
9284 }
9285 if (ch & 0x80) /* must have had error encountered */
9286 break;
9287 }
9288 }
9289 }
9290 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9291 xmlBufferContent(target)));
9292 xmlBufferFree(target);
9293 xmlXPathReleaseObject(ctxt->context, str);
9294 xmlXPathReleaseObject(ctxt->context, from);
9295 xmlXPathReleaseObject(ctxt->context, to);
9296}
9297
9298/**
9299 * xmlXPathBooleanFunction:
9300 * @ctxt: the XPath Parser context
9301 * @nargs: the number of arguments
9302 *
9303 * Implement the boolean() XPath function
9304 * boolean boolean(object)
9305 * The boolean function converts its argument to a boolean as follows:
9306 * - a number is true if and only if it is neither positive or
9307 * negative zero nor NaN
9308 * - a node-set is true if and only if it is non-empty
9309 * - a string is true if and only if its length is non-zero
9310 */
9311void
9312xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9313 xmlXPathObjectPtr cur;
9314
9315 CHECK_ARITY(1);
9316 cur = valuePop(ctxt);
9317 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9318 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9319 valuePush(ctxt, cur);
9320}
9321
9322/**
9323 * xmlXPathNotFunction:
9324 * @ctxt: the XPath Parser context
9325 * @nargs: the number of arguments
9326 *
9327 * Implement the not() XPath function
9328 * boolean not(boolean)
9329 * The not function returns true if its argument is false,
9330 * and false otherwise.
9331 */
9332void
9333xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9334 CHECK_ARITY(1);
9335 CAST_TO_BOOLEAN;
9336 CHECK_TYPE(XPATH_BOOLEAN);
9337 ctxt->value->boolval = ! ctxt->value->boolval;
9338}
9339
9340/**
9341 * xmlXPathTrueFunction:
9342 * @ctxt: the XPath Parser context
9343 * @nargs: the number of arguments
9344 *
9345 * Implement the true() XPath function
9346 * boolean true()
9347 */
9348void
9349xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9350 CHECK_ARITY(0);
9351 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9352}
9353
9354/**
9355 * xmlXPathFalseFunction:
9356 * @ctxt: the XPath Parser context
9357 * @nargs: the number of arguments
9358 *
9359 * Implement the false() XPath function
9360 * boolean false()
9361 */
9362void
9363xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9364 CHECK_ARITY(0);
9365 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9366}
9367
9368/**
9369 * xmlXPathLangFunction:
9370 * @ctxt: the XPath Parser context
9371 * @nargs: the number of arguments
9372 *
9373 * Implement the lang() XPath function
9374 * boolean lang(string)
9375 * The lang function returns true or false depending on whether the
9376 * language of the context node as specified by xml:lang attributes
9377 * is the same as or is a sublanguage of the language specified by
9378 * the argument string. The language of the context node is determined
9379 * by the value of the xml:lang attribute on the context node, or, if
9380 * the context node has no xml:lang attribute, by the value of the
9381 * xml:lang attribute on the nearest ancestor of the context node that
9382 * has an xml:lang attribute. If there is no such attribute, then lang
9383 * returns false. If there is such an attribute, then lang returns
9384 * true if the attribute value is equal to the argument ignoring case,
9385 * or if there is some suffix starting with - such that the attribute
9386 * value is equal to the argument ignoring that suffix of the attribute
9387 * value and ignoring case.
9388 */
9389void
9390xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9391 xmlXPathObjectPtr val = NULL;
9392 const xmlChar *theLang = NULL;
9393 const xmlChar *lang;
9394 int ret = 0;
9395 int i;
9396
9397 CHECK_ARITY(1);
9398 CAST_TO_STRING;
9399 CHECK_TYPE(XPATH_STRING);
9400 val = valuePop(ctxt);
9401 lang = val->stringval;
9402 theLang = xmlNodeGetLang(ctxt->context->node);
9403 if ((theLang != NULL) && (lang != NULL)) {
9404 for (i = 0;lang[i] != 0;i++)
9405 if (toupper(lang[i]) != toupper(theLang[i]))
9406 goto not_equal;
9407 if ((theLang[i] == 0) || (theLang[i] == '-'))
9408 ret = 1;
9409 }
9410not_equal:
9411 if (theLang != NULL)
9412 xmlFree((void *)theLang);
9413
9414 xmlXPathReleaseObject(ctxt->context, val);
9415 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9416}
9417
9418/**
9419 * xmlXPathNumberFunction:
9420 * @ctxt: the XPath Parser context
9421 * @nargs: the number of arguments
9422 *
9423 * Implement the number() XPath function
9424 * number number(object?)
9425 */
9426void
9427xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9428 xmlXPathObjectPtr cur;
9429 double res;
9430
9431 if (ctxt == NULL) return;
9432 if (nargs == 0) {
9433 if (ctxt->context->node == NULL) {
9434 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9435 } else {
9436 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9437
9438 res = xmlXPathStringEvalNumber(content);
9439 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9440 xmlFree(content);
9441 }
9442 return;
9443 }
9444
9445 CHECK_ARITY(1);
9446 cur = valuePop(ctxt);
9447 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9448}
9449
9450/**
9451 * xmlXPathSumFunction:
9452 * @ctxt: the XPath Parser context
9453 * @nargs: the number of arguments
9454 *
9455 * Implement the sum() XPath function
9456 * number sum(node-set)
9457 * The sum function returns the sum of the values of the nodes in
9458 * the argument node-set.
9459 */
9460void
9461xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9462 xmlXPathObjectPtr cur;
9463 int i;
9464 double res = 0.0;
9465
9466 CHECK_ARITY(1);
9467 if ((ctxt->value == NULL) ||
9468 ((ctxt->value->type != XPATH_NODESET) &&
9469 (ctxt->value->type != XPATH_XSLT_TREE)))
9470 XP_ERROR(XPATH_INVALID_TYPE);
9471 cur = valuePop(ctxt);
9472
9473 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9474 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9475 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9476 }
9477 }
9478 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9479 xmlXPathReleaseObject(ctxt->context, cur);
9480}
9481
9482/*
9483 * To assure working code on multiple platforms, we want to only depend
9484 * upon the characteristic truncation of converting a floating point value
9485 * to an integer. Unfortunately, because of the different storage sizes
9486 * of our internal floating point value (double) and integer (int), we
9487 * can't directly convert (see bug 301162). This macro is a messy
9488 * 'workaround'
9489 */
9490#define XTRUNC(f, v) \
9491 f = fmod((v), INT_MAX); \
9492 f = (v) - (f) + (double)((int)(f));
9493
9494/**
9495 * xmlXPathFloorFunction:
9496 * @ctxt: the XPath Parser context
9497 * @nargs: the number of arguments
9498 *
9499 * Implement the floor() XPath function
9500 * number floor(number)
9501 * The floor function returns the largest (closest to positive infinity)
9502 * number that is not greater than the argument and that is an integer.
9503 */
9504void
9505xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9506 double f;
9507
9508 CHECK_ARITY(1);
9509 CAST_TO_NUMBER;
9510 CHECK_TYPE(XPATH_NUMBER);
9511
9512 XTRUNC(f, ctxt->value->floatval);
9513 if (f != ctxt->value->floatval) {
9514 if (ctxt->value->floatval > 0)
9515 ctxt->value->floatval = f;
9516 else
9517 ctxt->value->floatval = f - 1;
9518 }
9519}
9520
9521/**
9522 * xmlXPathCeilingFunction:
9523 * @ctxt: the XPath Parser context
9524 * @nargs: the number of arguments
9525 *
9526 * Implement the ceiling() XPath function
9527 * number ceiling(number)
9528 * The ceiling function returns the smallest (closest to negative infinity)
9529 * number that is not less than the argument and that is an integer.
9530 */
9531void
9532xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9533 double f;
9534
9535 CHECK_ARITY(1);
9536 CAST_TO_NUMBER;
9537 CHECK_TYPE(XPATH_NUMBER);
9538
9539#if 0
9540 ctxt->value->floatval = ceil(ctxt->value->floatval);
9541#else
9542 XTRUNC(f, ctxt->value->floatval);
9543 if (f != ctxt->value->floatval) {
9544 if (ctxt->value->floatval > 0)
9545 ctxt->value->floatval = f + 1;
9546 else {
9547 if (ctxt->value->floatval < 0 && f == 0)
9548 ctxt->value->floatval = xmlXPathNZERO;
9549 else
9550 ctxt->value->floatval = f;
9551 }
9552
9553 }
9554#endif
9555}
9556
9557/**
9558 * xmlXPathRoundFunction:
9559 * @ctxt: the XPath Parser context
9560 * @nargs: the number of arguments
9561 *
9562 * Implement the round() XPath function
9563 * number round(number)
9564 * The round function returns the number that is closest to the
9565 * argument and that is an integer. If there are two such numbers,
9566 * then the one that is even is returned.
9567 */
9568void
9569xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9570 double f;
9571
9572 CHECK_ARITY(1);
9573 CAST_TO_NUMBER;
9574 CHECK_TYPE(XPATH_NUMBER);
9575
9576 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9577 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9578 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
9579 (ctxt->value->floatval == 0.0))
9580 return;
9581
9582 XTRUNC(f, ctxt->value->floatval);
9583 if (ctxt->value->floatval < 0) {
9584 if (ctxt->value->floatval < f - 0.5)
9585 ctxt->value->floatval = f - 1;
9586 else
9587 ctxt->value->floatval = f;
9588 if (ctxt->value->floatval == 0)
9589 ctxt->value->floatval = xmlXPathNZERO;
9590 } else {
9591 if (ctxt->value->floatval < f + 0.5)
9592 ctxt->value->floatval = f;
9593 else
9594 ctxt->value->floatval = f + 1;
9595 }
9596}
9597
9598/************************************************************************
9599 * *
9600 * The Parser *
9601 * *
9602 ************************************************************************/
9603
9604/*
9605 * a few forward declarations since we use a recursive call based
9606 * implementation.
9607 */
9608static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9609static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9610static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9611static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9612static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9613 int qualified);
9614
9615/**
9616 * xmlXPathCurrentChar:
9617 * @ctxt: the XPath parser context
9618 * @cur: pointer to the beginning of the char
9619 * @len: pointer to the length of the char read
9620 *
9621 * The current char value, if using UTF-8 this may actually span multiple
9622 * bytes in the input buffer.
9623 *
9624 * Returns the current char value and its length
9625 */
9626
9627static int
9628xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9629 unsigned char c;
9630 unsigned int val;
9631 const xmlChar *cur;
9632
9633 if (ctxt == NULL)
9634 return(0);
9635 cur = ctxt->cur;
9636
9637 /*
9638 * We are supposed to handle UTF8, check it's valid
9639 * From rfc2044: encoding of the Unicode values on UTF-8:
9640 *
9641 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9642 * 0000 0000-0000 007F 0xxxxxxx
9643 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
9644 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
9645 *
9646 * Check for the 0x110000 limit too
9647 */
9648 c = *cur;
9649 if (c & 0x80) {
9650 if ((cur[1] & 0xc0) != 0x80)
9651 goto encoding_error;
9652 if ((c & 0xe0) == 0xe0) {
9653
9654 if ((cur[2] & 0xc0) != 0x80)
9655 goto encoding_error;
9656 if ((c & 0xf0) == 0xf0) {
9657 if (((c & 0xf8) != 0xf0) ||
9658 ((cur[3] & 0xc0) != 0x80))
9659 goto encoding_error;
9660 /* 4-byte code */
9661 *len = 4;
9662 val = (cur[0] & 0x7) << 18;
9663 val |= (cur[1] & 0x3f) << 12;
9664 val |= (cur[2] & 0x3f) << 6;
9665 val |= cur[3] & 0x3f;
9666 } else {
9667 /* 3-byte code */
9668 *len = 3;
9669 val = (cur[0] & 0xf) << 12;
9670 val |= (cur[1] & 0x3f) << 6;
9671 val |= cur[2] & 0x3f;
9672 }
9673 } else {
9674 /* 2-byte code */
9675 *len = 2;
9676 val = (cur[0] & 0x1f) << 6;
9677 val |= cur[1] & 0x3f;
9678 }
9679 if (!IS_CHAR(val)) {
9680 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9681 }
9682 return(val);
9683 } else {
9684 /* 1-byte code */
9685 *len = 1;
9686 return((int) *cur);
9687 }
9688encoding_error:
9689 /*
9690 * If we detect an UTF8 error that probably means that the
9691 * input encoding didn't get properly advertised in the
9692 * declaration header. Report the error and switch the encoding
9693 * to ISO-Latin-1 (if you don't like this policy, just declare the
9694 * encoding !)
9695 */
9696 *len = 0;
9697 XP_ERROR0(XPATH_ENCODING_ERROR);
9698}
9699
9700/**
9701 * xmlXPathParseNCName:
9702 * @ctxt: the XPath Parser context
9703 *
9704 * parse an XML namespace non qualified name.
9705 *
9706 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9707 *
9708 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9709 * CombiningChar | Extender
9710 *
9711 * Returns the namespace name or NULL
9712 */
9713
9714xmlChar *
9715xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9716 const xmlChar *in;
9717 xmlChar *ret;
9718 int count = 0;
9719
9720 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9721 /*
9722 * Accelerator for simple ASCII names
9723 */
9724 in = ctxt->cur;
9725 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9726 ((*in >= 0x41) && (*in <= 0x5A)) ||
9727 (*in == '_')) {
9728 in++;
9729 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9730 ((*in >= 0x41) && (*in <= 0x5A)) ||
9731 ((*in >= 0x30) && (*in <= 0x39)) ||
9732 (*in == '_') || (*in == '.') ||
9733 (*in == '-'))
9734 in++;
9735 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9736 (*in == '[') || (*in == ']') || (*in == ':') ||
9737 (*in == '@') || (*in == '*')) {
9738 count = in - ctxt->cur;
9739 if (count == 0)
9740 return(NULL);
9741 ret = xmlStrndup(ctxt->cur, count);
9742 ctxt->cur = in;
9743 return(ret);
9744 }
9745 }
9746 return(xmlXPathParseNameComplex(ctxt, 0));
9747}
9748
9749
9750/**
9751 * xmlXPathParseQName:
9752 * @ctxt: the XPath Parser context
9753 * @prefix: a xmlChar **
9754 *
9755 * parse an XML qualified name
9756 *
9757 * [NS 5] QName ::= (Prefix ':')? LocalPart
9758 *
9759 * [NS 6] Prefix ::= NCName
9760 *
9761 * [NS 7] LocalPart ::= NCName
9762 *
9763 * Returns the function returns the local part, and prefix is updated
9764 * to get the Prefix if any.
9765 */
9766
9767static xmlChar *
9768xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9769 xmlChar *ret = NULL;
9770
9771 *prefix = NULL;
9772 ret = xmlXPathParseNCName(ctxt);
9773 if (CUR == ':') {
9774 *prefix = ret;
9775 NEXT;
9776 ret = xmlXPathParseNCName(ctxt);
9777 }
9778 return(ret);
9779}
9780
9781/**
9782 * xmlXPathParseName:
9783 * @ctxt: the XPath Parser context
9784 *
9785 * parse an XML name
9786 *
9787 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9788 * CombiningChar | Extender
9789 *
9790 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9791 *
9792 * Returns the namespace name or NULL
9793 */
9794
9795xmlChar *
9796xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9797 const xmlChar *in;
9798 xmlChar *ret;
9799 int count = 0;
9800
9801 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9802 /*
9803 * Accelerator for simple ASCII names
9804 */
9805 in = ctxt->cur;
9806 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9807 ((*in >= 0x41) && (*in <= 0x5A)) ||
9808 (*in == '_') || (*in == ':')) {
9809 in++;
9810 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9811 ((*in >= 0x41) && (*in <= 0x5A)) ||
9812 ((*in >= 0x30) && (*in <= 0x39)) ||
9813 (*in == '_') || (*in == '-') ||
9814 (*in == ':') || (*in == '.'))
9815 in++;
9816 if ((*in > 0) && (*in < 0x80)) {
9817 count = in - ctxt->cur;
9818 ret = xmlStrndup(ctxt->cur, count);
9819 ctxt->cur = in;
9820 return(ret);
9821 }
9822 }
9823 return(xmlXPathParseNameComplex(ctxt, 1));
9824}
9825
9826static xmlChar *
9827xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9828 xmlChar buf[XML_MAX_NAMELEN + 5];
9829 int len = 0, l;
9830 int c;
9831
9832 /*
9833 * Handler for more complex cases
9834 */
9835 c = CUR_CHAR(l);
9836 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9837 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9838 (c == '*') || /* accelerators */
9839 (!IS_LETTER(c) && (c != '_') &&
9840 ((qualified) && (c != ':')))) {
9841 return(NULL);
9842 }
9843
9844 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9845 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9846 (c == '.') || (c == '-') ||
9847 (c == '_') || ((qualified) && (c == ':')) ||
9848 (IS_COMBINING(c)) ||
9849 (IS_EXTENDER(c)))) {
9850 COPY_BUF(l,buf,len,c);
9851 NEXTL(l);
9852 c = CUR_CHAR(l);
9853 if (len >= XML_MAX_NAMELEN) {
9854 /*
9855 * Okay someone managed to make a huge name, so he's ready to pay
9856 * for the processing speed.
9857 */
9858 xmlChar *buffer;
9859 int max = len * 2;
9860
9861 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
9862 if (buffer == NULL) {
9863 XP_ERRORNULL(XPATH_MEMORY_ERROR);
9864 }
9865 memcpy(buffer, buf, len);
9866 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9867 (c == '.') || (c == '-') ||
9868 (c == '_') || ((qualified) && (c == ':')) ||
9869 (IS_COMBINING(c)) ||
9870 (IS_EXTENDER(c))) {
9871 if (len + 10 > max) {
9872 max *= 2;
9873 buffer = (xmlChar *) xmlRealloc(buffer,
9874 max * sizeof(xmlChar));
9875 if (buffer == NULL) {
9876 XP_ERRORNULL(XPATH_MEMORY_ERROR);
9877 }
9878 }
9879 COPY_BUF(l,buffer,len,c);
9880 NEXTL(l);
9881 c = CUR_CHAR(l);
9882 }
9883 buffer[len] = 0;
9884 return(buffer);
9885 }
9886 }
9887 if (len == 0)
9888 return(NULL);
9889 return(xmlStrndup(buf, len));
9890}
9891
9892#define MAX_FRAC 20
9893
9894/*
9895 * These are used as divisors for the fractional part of a number.
9896 * Since the table includes 1.0 (representing '0' fractional digits),
9897 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
9898 */
9899static double my_pow10[MAX_FRAC+1] = {
9900 1.0, 10.0, 100.0, 1000.0, 10000.0,
9901 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
9902 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
9903 100000000000000.0,
9904 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
9905 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
9906};
9907
9908/**
9909 * xmlXPathStringEvalNumber:
9910 * @str: A string to scan
9911 *
9912 * [30a] Float ::= Number ('e' Digits?)?
9913 *
9914 * [30] Number ::= Digits ('.' Digits?)?
9915 * | '.' Digits
9916 * [31] Digits ::= [0-9]+
9917 *
9918 * Compile a Number in the string
9919 * In complement of the Number expression, this function also handles
9920 * negative values : '-' Number.
9921 *
9922 * Returns the double value.
9923 */
9924double
9925xmlXPathStringEvalNumber(const xmlChar *str) {
9926 const xmlChar *cur = str;
9927 double ret;
9928 int ok = 0;
9929 int isneg = 0;
9930 int exponent = 0;
9931 int is_exponent_negative = 0;
9932#ifdef __GNUC__
9933 unsigned long tmp = 0;
9934 double temp;
9935#endif
9936 if (cur == NULL) return(0);
9937 while (IS_BLANK_CH(*cur)) cur++;
9938 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9939 return(xmlXPathNAN);
9940 }
9941 if (*cur == '-') {
9942 isneg = 1;
9943 cur++;
9944 }
9945
9946#ifdef __GNUC__
9947 /*
9948 * tmp/temp is a workaround against a gcc compiler bug
9949 * http://veillard.com/gcc.bug
9950 */
9951 ret = 0;
9952 while ((*cur >= '0') && (*cur <= '9')) {
9953 ret = ret * 10;
9954 tmp = (*cur - '0');
9955 ok = 1;
9956 cur++;
9957 temp = (double) tmp;
9958 ret = ret + temp;
9959 }
9960#else
9961 ret = 0;
9962 while ((*cur >= '0') && (*cur <= '9')) {
9963 ret = ret * 10 + (*cur - '0');
9964 ok = 1;
9965 cur++;
9966 }
9967#endif
9968
9969 if (*cur == '.') {
9970 int v, frac = 0;
9971 double fraction = 0;
9972
9973 cur++;
9974 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
9975 return(xmlXPathNAN);
9976 }
9977 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
9978 v = (*cur - '0');
9979 fraction = fraction * 10 + v;
9980 frac = frac + 1;
9981 cur++;
9982 }
9983 fraction /= my_pow10[frac];
9984 ret = ret + fraction;
9985 while ((*cur >= '0') && (*cur <= '9'))
9986 cur++;
9987 }
9988 if ((*cur == 'e') || (*cur == 'E')) {
9989 cur++;
9990 if (*cur == '-') {
9991 is_exponent_negative = 1;
9992 cur++;
9993 } else if (*cur == '+') {
9994 cur++;
9995 }
9996 while ((*cur >= '0') && (*cur <= '9')) {
9997 exponent = exponent * 10 + (*cur - '0');
9998 cur++;
9999 }
10000 }
10001 while (IS_BLANK_CH(*cur)) cur++;
10002 if (*cur != 0) return(xmlXPathNAN);
10003 if (isneg) ret = -ret;
10004 if (is_exponent_negative) exponent = -exponent;
10005 ret *= pow(10.0, (double)exponent);
10006 return(ret);
10007}
10008
10009/**
10010 * xmlXPathCompNumber:
10011 * @ctxt: the XPath Parser context
10012 *
10013 * [30] Number ::= Digits ('.' Digits?)?
10014 * | '.' Digits
10015 * [31] Digits ::= [0-9]+
10016 *
10017 * Compile a Number, then push it on the stack
10018 *
10019 */
10020static void
10021xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10022{
10023 double ret = 0.0;
10024 double mult = 1;
10025 int ok = 0;
10026 int exponent = 0;
10027 int is_exponent_negative = 0;
10028#ifdef __GNUC__
10029 unsigned long tmp = 0;
10030 double temp;
10031#endif
10032
10033 CHECK_ERROR;
10034 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10035 XP_ERROR(XPATH_NUMBER_ERROR);
10036 }
10037#ifdef __GNUC__
10038 /*
10039 * tmp/temp is a workaround against a gcc compiler bug
10040 * http://veillard.com/gcc.bug
10041 */
10042 ret = 0;
10043 while ((CUR >= '0') && (CUR <= '9')) {
10044 ret = ret * 10;
10045 tmp = (CUR - '0');
10046 ok = 1;
10047 NEXT;
10048 temp = (double) tmp;
10049 ret = ret + temp;
10050 }
10051#else
10052 ret = 0;
10053 while ((CUR >= '0') && (CUR <= '9')) {
10054 ret = ret * 10 + (CUR - '0');
10055 ok = 1;
10056 NEXT;
10057 }
10058#endif
10059 if (CUR == '.') {
10060 NEXT;
10061 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10062 XP_ERROR(XPATH_NUMBER_ERROR);
10063 }
10064 while ((CUR >= '0') && (CUR <= '9')) {
10065 mult /= 10;
10066 ret = ret + (CUR - '0') * mult;
10067 NEXT;
10068 }
10069 }
10070 if ((CUR == 'e') || (CUR == 'E')) {
10071 NEXT;
10072 if (CUR == '-') {
10073 is_exponent_negative = 1;
10074 NEXT;
10075 } else if (CUR == '+') {
10076 NEXT;
10077 }
10078 while ((CUR >= '0') && (CUR <= '9')) {
10079 exponent = exponent * 10 + (CUR - '0');
10080 NEXT;
10081 }
10082 if (is_exponent_negative)
10083 exponent = -exponent;
10084 ret *= pow(10.0, (double) exponent);
10085 }
10086 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10087 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10088}
10089
10090/**
10091 * xmlXPathParseLiteral:
10092 * @ctxt: the XPath Parser context
10093 *
10094 * Parse a Literal
10095 *
10096 * [29] Literal ::= '"' [^"]* '"'
10097 * | "'" [^']* "'"
10098 *
10099 * Returns the value found or NULL in case of error
10100 */
10101static xmlChar *
10102xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10103 const xmlChar *q;
10104 xmlChar *ret = NULL;
10105
10106 if (CUR == '"') {
10107 NEXT;
10108 q = CUR_PTR;
10109 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10110 NEXT;
10111 if (!IS_CHAR_CH(CUR)) {
10112 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10113 } else {
10114 ret = xmlStrndup(q, CUR_PTR - q);
10115 NEXT;
10116 }
10117 } else if (CUR == '\'') {
10118 NEXT;
10119 q = CUR_PTR;
10120 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10121 NEXT;
10122 if (!IS_CHAR_CH(CUR)) {
10123 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10124 } else {
10125 ret = xmlStrndup(q, CUR_PTR - q);
10126 NEXT;
10127 }
10128 } else {
10129 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10130 }
10131 return(ret);
10132}
10133
10134/**
10135 * xmlXPathCompLiteral:
10136 * @ctxt: the XPath Parser context
10137 *
10138 * Parse a Literal and push it on the stack.
10139 *
10140 * [29] Literal ::= '"' [^"]* '"'
10141 * | "'" [^']* "'"
10142 *
10143 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10144 */
10145static void
10146xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10147 const xmlChar *q;
10148 xmlChar *ret = NULL;
10149
10150 if (CUR == '"') {
10151 NEXT;
10152 q = CUR_PTR;
10153 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10154 NEXT;
10155 if (!IS_CHAR_CH(CUR)) {
10156 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10157 } else {
10158 ret = xmlStrndup(q, CUR_PTR - q);
10159 NEXT;
10160 }
10161 } else if (CUR == '\'') {
10162 NEXT;
10163 q = CUR_PTR;
10164 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10165 NEXT;
10166 if (!IS_CHAR_CH(CUR)) {
10167 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10168 } else {
10169 ret = xmlStrndup(q, CUR_PTR - q);
10170 NEXT;
10171 }
10172 } else {
10173 XP_ERROR(XPATH_START_LITERAL_ERROR);
10174 }
10175 if (ret == NULL) return;
10176 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10177 xmlXPathCacheNewString(ctxt->context, ret), NULL);
10178 xmlFree(ret);
10179}
10180
10181/**
10182 * xmlXPathCompVariableReference:
10183 * @ctxt: the XPath Parser context
10184 *
10185 * Parse a VariableReference, evaluate it and push it on the stack.
10186 *
10187 * The variable bindings consist of a mapping from variable names
10188 * to variable values. The value of a variable is an object, which can be
10189 * of any of the types that are possible for the value of an expression,
10190 * and may also be of additional types not specified here.
10191 *
10192 * Early evaluation is possible since:
10193 * The variable bindings [...] used to evaluate a subexpression are
10194 * always the same as those used to evaluate the containing expression.
10195 *
10196 * [36] VariableReference ::= '$' QName
10197 */
10198static void
10199xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10200 xmlChar *name;
10201 xmlChar *prefix;
10202
10203 SKIP_BLANKS;
10204 if (CUR != '$') {
10205 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10206 }
10207 NEXT;
10208 name = xmlXPathParseQName(ctxt, &prefix);
10209 if (name == NULL) {
10210 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10211 }
10212 ctxt->comp->last = -1;
10213 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10214 name, prefix);
10215 SKIP_BLANKS;
10216 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10217 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
10218 }
10219}
10220
10221/**
10222 * xmlXPathIsNodeType:
10223 * @name: a name string
10224 *
10225 * Is the name given a NodeType one.
10226 *
10227 * [38] NodeType ::= 'comment'
10228 * | 'text'
10229 * | 'processing-instruction'
10230 * | 'node'
10231 *
10232 * Returns 1 if true 0 otherwise
10233 */
10234int
10235xmlXPathIsNodeType(const xmlChar *name) {
10236 if (name == NULL)
10237 return(0);
10238
10239 if (xmlStrEqual(name, BAD_CAST "node"))
10240 return(1);
10241 if (xmlStrEqual(name, BAD_CAST "text"))
10242 return(1);
10243 if (xmlStrEqual(name, BAD_CAST "comment"))
10244 return(1);
10245 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10246 return(1);
10247 return(0);
10248}
10249
10250/**
10251 * xmlXPathCompFunctionCall:
10252 * @ctxt: the XPath Parser context
10253 *
10254 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10255 * [17] Argument ::= Expr
10256 *
10257 * Compile a function call, the evaluation of all arguments are
10258 * pushed on the stack
10259 */
10260static void
10261xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10262 xmlChar *name;
10263 xmlChar *prefix;
10264 int nbargs = 0;
10265 int sort = 1;
10266
10267 name = xmlXPathParseQName(ctxt, &prefix);
10268 if (name == NULL) {
10269 XP_ERROR(XPATH_EXPR_ERROR);
10270 }
10271 SKIP_BLANKS;
10272#ifdef DEBUG_EXPR
10273 if (prefix == NULL)
10274 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10275 name);
10276 else
10277 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10278 prefix, name);
10279#endif
10280
10281 if (CUR != '(') {
10282 XP_ERROR(XPATH_EXPR_ERROR);
10283 }
10284 NEXT;
10285 SKIP_BLANKS;
10286
10287 /*
10288 * Optimization for count(): we don't need the node-set to be sorted.
10289 */
10290 if ((prefix == NULL) && (name[0] == 'c') &&
10291 xmlStrEqual(name, BAD_CAST "count"))
10292 {
10293 sort = 0;
10294 }
10295 ctxt->comp->last = -1;
10296 if (CUR != ')') {
10297 while (CUR != 0) {
10298 int op1 = ctxt->comp->last;
10299 ctxt->comp->last = -1;
10300 xmlXPathCompileExpr(ctxt, sort);
10301 CHECK_ERROR;
10302 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10303 nbargs++;
10304 if (CUR == ')') break;
10305 if (CUR != ',') {
10306 XP_ERROR(XPATH_EXPR_ERROR);
10307 }
10308 NEXT;
10309 SKIP_BLANKS;
10310 }
10311 }
10312 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10313 name, prefix);
10314 NEXT;
10315 SKIP_BLANKS;
10316}
10317
10318/**
10319 * xmlXPathCompPrimaryExpr:
10320 * @ctxt: the XPath Parser context
10321 *
10322 * [15] PrimaryExpr ::= VariableReference
10323 * | '(' Expr ')'
10324 * | Literal
10325 * | Number
10326 * | FunctionCall
10327 *
10328 * Compile a primary expression.
10329 */
10330static void
10331xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10332 SKIP_BLANKS;
10333 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10334 else if (CUR == '(') {
10335 NEXT;
10336 SKIP_BLANKS;
10337 xmlXPathCompileExpr(ctxt, 1);
10338 CHECK_ERROR;
10339 if (CUR != ')') {
10340 XP_ERROR(XPATH_EXPR_ERROR);
10341 }
10342 NEXT;
10343 SKIP_BLANKS;
10344 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10345 xmlXPathCompNumber(ctxt);
10346 } else if ((CUR == '\'') || (CUR == '"')) {
10347 xmlXPathCompLiteral(ctxt);
10348 } else {
10349 xmlXPathCompFunctionCall(ctxt);
10350 }
10351 SKIP_BLANKS;
10352}
10353
10354/**
10355 * xmlXPathCompFilterExpr:
10356 * @ctxt: the XPath Parser context
10357 *
10358 * [20] FilterExpr ::= PrimaryExpr
10359 * | FilterExpr Predicate
10360 *
10361 * Compile a filter expression.
10362 * Square brackets are used to filter expressions in the same way that
10363 * they are used in location paths. It is an error if the expression to
10364 * be filtered does not evaluate to a node-set. The context node list
10365 * used for evaluating the expression in square brackets is the node-set
10366 * to be filtered listed in document order.
10367 */
10368
10369static void
10370xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10371 xmlXPathCompPrimaryExpr(ctxt);
10372 CHECK_ERROR;
10373 SKIP_BLANKS;
10374
10375 while (CUR == '[') {
10376 xmlXPathCompPredicate(ctxt, 1);
10377 SKIP_BLANKS;
10378 }
10379
10380
10381}
10382
10383/**
10384 * xmlXPathScanName:
10385 * @ctxt: the XPath Parser context
10386 *
10387 * Trickery: parse an XML name but without consuming the input flow
10388 * Needed to avoid insanity in the parser state.
10389 *
10390 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10391 * CombiningChar | Extender
10392 *
10393 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10394 *
10395 * [6] Names ::= Name (S Name)*
10396 *
10397 * Returns the Name parsed or NULL
10398 */
10399
10400static xmlChar *
10401xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10402 int len = 0, l;
10403 int c;
10404 const xmlChar *cur;
10405 xmlChar *ret;
10406
10407 cur = ctxt->cur;
10408
10409 c = CUR_CHAR(l);
10410 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10411 (!IS_LETTER(c) && (c != '_') &&
10412 (c != ':'))) {
10413 return(NULL);
10414 }
10415
10416 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10417 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10418 (c == '.') || (c == '-') ||
10419 (c == '_') || (c == ':') ||
10420 (IS_COMBINING(c)) ||
10421 (IS_EXTENDER(c)))) {
10422 len += l;
10423 NEXTL(l);
10424 c = CUR_CHAR(l);
10425 }
10426 ret = xmlStrndup(cur, ctxt->cur - cur);
10427 ctxt->cur = cur;
10428 return(ret);
10429}
10430
10431/**
10432 * xmlXPathCompPathExpr:
10433 * @ctxt: the XPath Parser context
10434 *
10435 * [19] PathExpr ::= LocationPath
10436 * | FilterExpr
10437 * | FilterExpr '/' RelativeLocationPath
10438 * | FilterExpr '//' RelativeLocationPath
10439 *
10440 * Compile a path expression.
10441 * The / operator and // operators combine an arbitrary expression
10442 * and a relative location path. It is an error if the expression
10443 * does not evaluate to a node-set.
10444 * The / operator does composition in the same way as when / is
10445 * used in a location path. As in location paths, // is short for
10446 * /descendant-or-self::node()/.
10447 */
10448
10449static void
10450xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10451 int lc = 1; /* Should we branch to LocationPath ? */
10452 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10453
10454 SKIP_BLANKS;
10455 if ((CUR == '$') || (CUR == '(') ||
10456 (IS_ASCII_DIGIT(CUR)) ||
10457 (CUR == '\'') || (CUR == '"') ||
10458 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10459 lc = 0;
10460 } else if (CUR == '*') {
10461 /* relative or absolute location path */
10462 lc = 1;
10463 } else if (CUR == '/') {
10464 /* relative or absolute location path */
10465 lc = 1;
10466 } else if (CUR == '@') {
10467 /* relative abbreviated attribute location path */
10468 lc = 1;
10469 } else if (CUR == '.') {
10470 /* relative abbreviated attribute location path */
10471 lc = 1;
10472 } else {
10473 /*
10474 * Problem is finding if we have a name here whether it's:
10475 * - a nodetype
10476 * - a function call in which case it's followed by '('
10477 * - an axis in which case it's followed by ':'
10478 * - a element name
10479 * We do an a priori analysis here rather than having to
10480 * maintain parsed token content through the recursive function
10481 * calls. This looks uglier but makes the code easier to
10482 * read/write/debug.
10483 */
10484 SKIP_BLANKS;
10485 name = xmlXPathScanName(ctxt);
10486 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10487#ifdef DEBUG_STEP
10488 xmlGenericError(xmlGenericErrorContext,
10489 "PathExpr: Axis\n");
10490#endif
10491 lc = 1;
10492 xmlFree(name);
10493 } else if (name != NULL) {
10494 int len =xmlStrlen(name);
10495
10496
10497 while (NXT(len) != 0) {
10498 if (NXT(len) == '/') {
10499 /* element name */
10500#ifdef DEBUG_STEP
10501 xmlGenericError(xmlGenericErrorContext,
10502 "PathExpr: AbbrRelLocation\n");
10503#endif
10504 lc = 1;
10505 break;
10506 } else if (IS_BLANK_CH(NXT(len))) {
10507 /* ignore blanks */
10508 ;
10509 } else if (NXT(len) == ':') {
10510#ifdef DEBUG_STEP
10511 xmlGenericError(xmlGenericErrorContext,
10512 "PathExpr: AbbrRelLocation\n");
10513#endif
10514 lc = 1;
10515 break;
10516 } else if ((NXT(len) == '(')) {
10517 /* Note Type or Function */
10518 if (xmlXPathIsNodeType(name)) {
10519#ifdef DEBUG_STEP
10520 xmlGenericError(xmlGenericErrorContext,
10521 "PathExpr: Type search\n");
10522#endif
10523 lc = 1;
10524 } else {
10525#ifdef DEBUG_STEP
10526 xmlGenericError(xmlGenericErrorContext,
10527 "PathExpr: function call\n");
10528#endif
10529 lc = 0;
10530 }
10531 break;
10532 } else if ((NXT(len) == '[')) {
10533 /* element name */
10534#ifdef DEBUG_STEP
10535 xmlGenericError(xmlGenericErrorContext,
10536 "PathExpr: AbbrRelLocation\n");
10537#endif
10538 lc = 1;
10539 break;
10540 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10541 (NXT(len) == '=')) {
10542 lc = 1;
10543 break;
10544 } else {
10545 lc = 1;
10546 break;
10547 }
10548 len++;
10549 }
10550 if (NXT(len) == 0) {
10551#ifdef DEBUG_STEP
10552 xmlGenericError(xmlGenericErrorContext,
10553 "PathExpr: AbbrRelLocation\n");
10554#endif
10555 /* element name */
10556 lc = 1;
10557 }
10558 xmlFree(name);
10559 } else {
10560 /* make sure all cases are covered explicitly */
10561 XP_ERROR(XPATH_EXPR_ERROR);
10562 }
10563 }
10564
10565 if (lc) {
10566 if (CUR == '/') {
10567 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10568 } else {
10569 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10570 }
10571 xmlXPathCompLocationPath(ctxt);
10572 } else {
10573 xmlXPathCompFilterExpr(ctxt);
10574 CHECK_ERROR;
10575 if ((CUR == '/') && (NXT(1) == '/')) {
10576 SKIP(2);
10577 SKIP_BLANKS;
10578
10579 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10580 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10581 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10582
10583 xmlXPathCompRelativeLocationPath(ctxt);
10584 } else if (CUR == '/') {
10585 xmlXPathCompRelativeLocationPath(ctxt);
10586 }
10587 }
10588 SKIP_BLANKS;
10589}
10590
10591/**
10592 * xmlXPathCompUnionExpr:
10593 * @ctxt: the XPath Parser context
10594 *
10595 * [18] UnionExpr ::= PathExpr
10596 * | UnionExpr '|' PathExpr
10597 *
10598 * Compile an union expression.
10599 */
10600
10601static void
10602xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10603 xmlXPathCompPathExpr(ctxt);
10604 CHECK_ERROR;
10605 SKIP_BLANKS;
10606 while (CUR == '|') {
10607 int op1 = ctxt->comp->last;
10608 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10609
10610 NEXT;
10611 SKIP_BLANKS;
10612 xmlXPathCompPathExpr(ctxt);
10613
10614 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10615
10616 SKIP_BLANKS;
10617 }
10618}
10619
10620/**
10621 * xmlXPathCompUnaryExpr:
10622 * @ctxt: the XPath Parser context
10623 *
10624 * [27] UnaryExpr ::= UnionExpr
10625 * | '-' UnaryExpr
10626 *
10627 * Compile an unary expression.
10628 */
10629
10630static void
10631xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10632 int minus = 0;
10633 int found = 0;
10634
10635 SKIP_BLANKS;
10636 while (CUR == '-') {
10637 minus = 1 - minus;
10638 found = 1;
10639 NEXT;
10640 SKIP_BLANKS;
10641 }
10642
10643 xmlXPathCompUnionExpr(ctxt);
10644 CHECK_ERROR;
10645 if (found) {
10646 if (minus)
10647 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10648 else
10649 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10650 }
10651}
10652
10653/**
10654 * xmlXPathCompMultiplicativeExpr:
10655 * @ctxt: the XPath Parser context
10656 *
10657 * [26] MultiplicativeExpr ::= UnaryExpr
10658 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10659 * | MultiplicativeExpr 'div' UnaryExpr
10660 * | MultiplicativeExpr 'mod' UnaryExpr
10661 * [34] MultiplyOperator ::= '*'
10662 *
10663 * Compile an Additive expression.
10664 */
10665
10666static void
10667xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10668 xmlXPathCompUnaryExpr(ctxt);
10669 CHECK_ERROR;
10670 SKIP_BLANKS;
10671 while ((CUR == '*') ||
10672 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10673 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10674 int op = -1;
10675 int op1 = ctxt->comp->last;
10676
10677 if (CUR == '*') {
10678 op = 0;
10679 NEXT;
10680 } else if (CUR == 'd') {
10681 op = 1;
10682 SKIP(3);
10683 } else if (CUR == 'm') {
10684 op = 2;
10685 SKIP(3);
10686 }
10687 SKIP_BLANKS;
10688 xmlXPathCompUnaryExpr(ctxt);
10689 CHECK_ERROR;
10690 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10691 SKIP_BLANKS;
10692 }
10693}
10694
10695/**
10696 * xmlXPathCompAdditiveExpr:
10697 * @ctxt: the XPath Parser context
10698 *
10699 * [25] AdditiveExpr ::= MultiplicativeExpr
10700 * | AdditiveExpr '+' MultiplicativeExpr
10701 * | AdditiveExpr '-' MultiplicativeExpr
10702 *
10703 * Compile an Additive expression.
10704 */
10705
10706static void
10707xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10708
10709 xmlXPathCompMultiplicativeExpr(ctxt);
10710 CHECK_ERROR;
10711 SKIP_BLANKS;
10712 while ((CUR == '+') || (CUR == '-')) {
10713 int plus;
10714 int op1 = ctxt->comp->last;
10715
10716 if (CUR == '+') plus = 1;
10717 else plus = 0;
10718 NEXT;
10719 SKIP_BLANKS;
10720 xmlXPathCompMultiplicativeExpr(ctxt);
10721 CHECK_ERROR;
10722 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10723 SKIP_BLANKS;
10724 }
10725}
10726
10727/**
10728 * xmlXPathCompRelationalExpr:
10729 * @ctxt: the XPath Parser context
10730 *
10731 * [24] RelationalExpr ::= AdditiveExpr
10732 * | RelationalExpr '<' AdditiveExpr
10733 * | RelationalExpr '>' AdditiveExpr
10734 * | RelationalExpr '<=' AdditiveExpr
10735 * | RelationalExpr '>=' AdditiveExpr
10736 *
10737 * A <= B > C is allowed ? Answer from James, yes with
10738 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10739 * which is basically what got implemented.
10740 *
10741 * Compile a Relational expression, then push the result
10742 * on the stack
10743 */
10744
10745static void
10746xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10747 xmlXPathCompAdditiveExpr(ctxt);
10748 CHECK_ERROR;
10749 SKIP_BLANKS;
10750 while ((CUR == '<') ||
10751 (CUR == '>') ||
10752 ((CUR == '<') && (NXT(1) == '=')) ||
10753 ((CUR == '>') && (NXT(1) == '='))) {
10754 int inf, strict;
10755 int op1 = ctxt->comp->last;
10756
10757 if (CUR == '<') inf = 1;
10758 else inf = 0;
10759 if (NXT(1) == '=') strict = 0;
10760 else strict = 1;
10761 NEXT;
10762 if (!strict) NEXT;
10763 SKIP_BLANKS;
10764 xmlXPathCompAdditiveExpr(ctxt);
10765 CHECK_ERROR;
10766 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10767 SKIP_BLANKS;
10768 }
10769}
10770
10771/**
10772 * xmlXPathCompEqualityExpr:
10773 * @ctxt: the XPath Parser context
10774 *
10775 * [23] EqualityExpr ::= RelationalExpr
10776 * | EqualityExpr '=' RelationalExpr
10777 * | EqualityExpr '!=' RelationalExpr
10778 *
10779 * A != B != C is allowed ? Answer from James, yes with
10780 * (RelationalExpr = RelationalExpr) = RelationalExpr
10781 * (RelationalExpr != RelationalExpr) != RelationalExpr
10782 * which is basically what got implemented.
10783 *
10784 * Compile an Equality expression.
10785 *
10786 */
10787static void
10788xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10789 xmlXPathCompRelationalExpr(ctxt);
10790 CHECK_ERROR;
10791 SKIP_BLANKS;
10792 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10793 int eq;
10794 int op1 = ctxt->comp->last;
10795
10796 if (CUR == '=') eq = 1;
10797 else eq = 0;
10798 NEXT;
10799 if (!eq) NEXT;
10800 SKIP_BLANKS;
10801 xmlXPathCompRelationalExpr(ctxt);
10802 CHECK_ERROR;
10803 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10804 SKIP_BLANKS;
10805 }
10806}
10807
10808/**
10809 * xmlXPathCompAndExpr:
10810 * @ctxt: the XPath Parser context
10811 *
10812 * [22] AndExpr ::= EqualityExpr
10813 * | AndExpr 'and' EqualityExpr
10814 *
10815 * Compile an AND expression.
10816 *
10817 */
10818static void
10819xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10820 xmlXPathCompEqualityExpr(ctxt);
10821 CHECK_ERROR;
10822 SKIP_BLANKS;
10823 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10824 int op1 = ctxt->comp->last;
10825 SKIP(3);
10826 SKIP_BLANKS;
10827 xmlXPathCompEqualityExpr(ctxt);
10828 CHECK_ERROR;
10829 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10830 SKIP_BLANKS;
10831 }
10832}
10833
10834/**
10835 * xmlXPathCompileExpr:
10836 * @ctxt: the XPath Parser context
10837 *
10838 * [14] Expr ::= OrExpr
10839 * [21] OrExpr ::= AndExpr
10840 * | OrExpr 'or' AndExpr
10841 *
10842 * Parse and compile an expression
10843 */
10844static void
10845xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10846 xmlXPathCompAndExpr(ctxt);
10847 CHECK_ERROR;
10848 SKIP_BLANKS;
10849 while ((CUR == 'o') && (NXT(1) == 'r')) {
10850 int op1 = ctxt->comp->last;
10851 SKIP(2);
10852 SKIP_BLANKS;
10853 xmlXPathCompAndExpr(ctxt);
10854 CHECK_ERROR;
10855 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10856 op1 = ctxt->comp->nbStep;
10857 SKIP_BLANKS;
10858 }
10859 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10860 /* more ops could be optimized too */
10861 /*
10862 * This is the main place to eliminate sorting for
10863 * operations which don't require a sorted node-set.
10864 * E.g. count().
10865 */
10866 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10867 }
10868}
10869
10870/**
10871 * xmlXPathCompPredicate:
10872 * @ctxt: the XPath Parser context
10873 * @filter: act as a filter
10874 *
10875 * [8] Predicate ::= '[' PredicateExpr ']'
10876 * [9] PredicateExpr ::= Expr
10877 *
10878 * Compile a predicate expression
10879 */
10880static void
10881xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10882 int op1 = ctxt->comp->last;
10883
10884 SKIP_BLANKS;
10885 if (CUR != '[') {
10886 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10887 }
10888 NEXT;
10889 SKIP_BLANKS;
10890
10891 ctxt->comp->last = -1;
10892 /*
10893 * This call to xmlXPathCompileExpr() will deactivate sorting
10894 * of the predicate result.
10895 * TODO: Sorting is still activated for filters, since I'm not
10896 * sure if needed. Normally sorting should not be needed, since
10897 * a filter can only diminish the number of items in a sequence,
10898 * but won't change its order; so if the initial sequence is sorted,
10899 * subsequent sorting is not needed.
10900 */
10901 if (! filter)
10902 xmlXPathCompileExpr(ctxt, 0);
10903 else
10904 xmlXPathCompileExpr(ctxt, 1);
10905 CHECK_ERROR;
10906
10907 if (CUR != ']') {
10908 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10909 }
10910
10911 if (filter)
10912 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10913 else
10914 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
10915
10916 NEXT;
10917 SKIP_BLANKS;
10918}
10919
10920/**
10921 * xmlXPathCompNodeTest:
10922 * @ctxt: the XPath Parser context
10923 * @test: pointer to a xmlXPathTestVal
10924 * @type: pointer to a xmlXPathTypeVal
10925 * @prefix: placeholder for a possible name prefix
10926 *
10927 * [7] NodeTest ::= NameTest
10928 * | NodeType '(' ')'
10929 * | 'processing-instruction' '(' Literal ')'
10930 *
10931 * [37] NameTest ::= '*'
10932 * | NCName ':' '*'
10933 * | QName
10934 * [38] NodeType ::= 'comment'
10935 * | 'text'
10936 * | 'processing-instruction'
10937 * | 'node'
10938 *
10939 * Returns the name found and updates @test, @type and @prefix appropriately
10940 */
10941static xmlChar *
10942xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10943 xmlXPathTypeVal *type, const xmlChar **prefix,
10944 xmlChar *name) {
10945 int blanks;
10946
10947 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10948 STRANGE;
10949 return(NULL);
10950 }
10951 *type = (xmlXPathTypeVal) 0;
10952 *test = (xmlXPathTestVal) 0;
10953 *prefix = NULL;
10954 SKIP_BLANKS;
10955
10956 if ((name == NULL) && (CUR == '*')) {
10957 /*
10958 * All elements
10959 */
10960 NEXT;
10961 *test = NODE_TEST_ALL;
10962 return(NULL);
10963 }
10964
10965 if (name == NULL)
10966 name = xmlXPathParseNCName(ctxt);
10967 if (name == NULL) {
10968 XP_ERRORNULL(XPATH_EXPR_ERROR);
10969 }
10970
10971 blanks = IS_BLANK_CH(CUR);
10972 SKIP_BLANKS;
10973 if (CUR == '(') {
10974 NEXT;
10975 /*
10976 * NodeType or PI search
10977 */
10978 if (xmlStrEqual(name, BAD_CAST "comment"))
10979 *type = NODE_TYPE_COMMENT;
10980 else if (xmlStrEqual(name, BAD_CAST "node"))
10981 *type = NODE_TYPE_NODE;
10982 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10983 *type = NODE_TYPE_PI;
10984 else if (xmlStrEqual(name, BAD_CAST "text"))
10985 *type = NODE_TYPE_TEXT;
10986 else {
10987 if (name != NULL)
10988 xmlFree(name);
10989 XP_ERRORNULL(XPATH_EXPR_ERROR);
10990 }
10991
10992 *test = NODE_TEST_TYPE;
10993
10994 SKIP_BLANKS;
10995 if (*type == NODE_TYPE_PI) {
10996 /*
10997 * Specific case: search a PI by name.
10998 */
10999 if (name != NULL)
11000 xmlFree(name);
11001 name = NULL;
11002 if (CUR != ')') {
11003 name = xmlXPathParseLiteral(ctxt);
11004 CHECK_ERROR NULL;
11005 *test = NODE_TEST_PI;
11006 SKIP_BLANKS;
11007 }
11008 }
11009 if (CUR != ')') {
11010 if (name != NULL)
11011 xmlFree(name);
11012 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11013 }
11014 NEXT;
11015 return(name);
11016 }
11017 *test = NODE_TEST_NAME;
11018 if ((!blanks) && (CUR == ':')) {
11019 NEXT;
11020
11021 /*
11022 * Since currently the parser context don't have a
11023 * namespace list associated:
11024 * The namespace name for this prefix can be computed
11025 * only at evaluation time. The compilation is done
11026 * outside of any context.
11027 */
11028#if 0
11029 *prefix = xmlXPathNsLookup(ctxt->context, name);
11030 if (name != NULL)
11031 xmlFree(name);
11032 if (*prefix == NULL) {
11033 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11034 }
11035#else
11036 *prefix = name;
11037#endif
11038
11039 if (CUR == '*') {
11040 /*
11041 * All elements
11042 */
11043 NEXT;
11044 *test = NODE_TEST_ALL;
11045 return(NULL);
11046 }
11047
11048 name = xmlXPathParseNCName(ctxt);
11049 if (name == NULL) {
11050 XP_ERRORNULL(XPATH_EXPR_ERROR);
11051 }
11052 }
11053 return(name);
11054}
11055
11056/**
11057 * xmlXPathIsAxisName:
11058 * @name: a preparsed name token
11059 *
11060 * [6] AxisName ::= 'ancestor'
11061 * | 'ancestor-or-self'
11062 * | 'attribute'
11063 * | 'child'
11064 * | 'descendant'
11065 * | 'descendant-or-self'
11066 * | 'following'
11067 * | 'following-sibling'
11068 * | 'namespace'
11069 * | 'parent'
11070 * | 'preceding'
11071 * | 'preceding-sibling'
11072 * | 'self'
11073 *
11074 * Returns the axis or 0
11075 */
11076static xmlXPathAxisVal
11077xmlXPathIsAxisName(const xmlChar *name) {
11078 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11079 switch (name[0]) {
11080 case 'a':
11081 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11082 ret = AXIS_ANCESTOR;
11083 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11084 ret = AXIS_ANCESTOR_OR_SELF;
11085 if (xmlStrEqual(name, BAD_CAST "attribute"))
11086 ret = AXIS_ATTRIBUTE;
11087 break;
11088 case 'c':
11089 if (xmlStrEqual(name, BAD_CAST "child"))
11090 ret = AXIS_CHILD;
11091 break;
11092 case 'd':
11093 if (xmlStrEqual(name, BAD_CAST "descendant"))
11094 ret = AXIS_DESCENDANT;
11095 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11096 ret = AXIS_DESCENDANT_OR_SELF;
11097 break;
11098 case 'f':
11099 if (xmlStrEqual(name, BAD_CAST "following"))
11100 ret = AXIS_FOLLOWING;
11101 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11102 ret = AXIS_FOLLOWING_SIBLING;
11103 break;
11104 case 'n':
11105 if (xmlStrEqual(name, BAD_CAST "namespace"))
11106 ret = AXIS_NAMESPACE;
11107 break;
11108 case 'p':
11109 if (xmlStrEqual(name, BAD_CAST "parent"))
11110 ret = AXIS_PARENT;
11111 if (xmlStrEqual(name, BAD_CAST "preceding"))
11112 ret = AXIS_PRECEDING;
11113 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11114 ret = AXIS_PRECEDING_SIBLING;
11115 break;
11116 case 's':
11117 if (xmlStrEqual(name, BAD_CAST "self"))
11118 ret = AXIS_SELF;
11119 break;
11120 }
11121 return(ret);
11122}
11123
11124/**
11125 * xmlXPathCompStep:
11126 * @ctxt: the XPath Parser context
11127 *
11128 * [4] Step ::= AxisSpecifier NodeTest Predicate*
11129 * | AbbreviatedStep
11130 *
11131 * [12] AbbreviatedStep ::= '.' | '..'
11132 *
11133 * [5] AxisSpecifier ::= AxisName '::'
11134 * | AbbreviatedAxisSpecifier
11135 *
11136 * [13] AbbreviatedAxisSpecifier ::= '@'?
11137 *
11138 * Modified for XPtr range support as:
11139 *
11140 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11141 * | AbbreviatedStep
11142 * | 'range-to' '(' Expr ')' Predicate*
11143 *
11144 * Compile one step in a Location Path
11145 * A location step of . is short for self::node(). This is
11146 * particularly useful in conjunction with //. For example, the
11147 * location path .//para is short for
11148 * self::node()/descendant-or-self::node()/child::para
11149 * and so will select all para descendant elements of the context
11150 * node.
11151 * Similarly, a location step of .. is short for parent::node().
11152 * For example, ../title is short for parent::node()/child::title
11153 * and so will select the title children of the parent of the context
11154 * node.
11155 */
11156static void
11157xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11158#ifdef LIBXML_XPTR_ENABLED
11159 int rangeto = 0;
11160 int op2 = -1;
11161#endif
11162
11163 SKIP_BLANKS;
11164 if ((CUR == '.') && (NXT(1) == '.')) {
11165 SKIP(2);
11166 SKIP_BLANKS;
11167 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11168 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11169 } else if (CUR == '.') {
11170 NEXT;
11171 SKIP_BLANKS;
11172 } else {
11173 xmlChar *name = NULL;
11174 const xmlChar *prefix = NULL;
11175 xmlXPathTestVal test = (xmlXPathTestVal) 0;
11176 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11177 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11178 int op1;
11179
11180 /*
11181 * The modification needed for XPointer change to the production
11182 */
11183#ifdef LIBXML_XPTR_ENABLED
11184 if (ctxt->xptr) {
11185 name = xmlXPathParseNCName(ctxt);
11186 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11187 op2 = ctxt->comp->last;
11188 xmlFree(name);
11189 SKIP_BLANKS;
11190 if (CUR != '(') {
11191 XP_ERROR(XPATH_EXPR_ERROR);
11192 }
11193 NEXT;
11194 SKIP_BLANKS;
11195
11196 xmlXPathCompileExpr(ctxt, 1);
11197 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11198 CHECK_ERROR;
11199
11200 SKIP_BLANKS;
11201 if (CUR != ')') {
11202 XP_ERROR(XPATH_EXPR_ERROR);
11203 }
11204 NEXT;
11205 rangeto = 1;
11206 goto eval_predicates;
11207 }
11208 }
11209#endif
11210 if (CUR == '*') {
11211 axis = AXIS_CHILD;
11212 } else {
11213 if (name == NULL)
11214 name = xmlXPathParseNCName(ctxt);
11215 if (name != NULL) {
11216 axis = xmlXPathIsAxisName(name);
11217 if (axis != 0) {
11218 SKIP_BLANKS;
11219 if ((CUR == ':') && (NXT(1) == ':')) {
11220 SKIP(2);
11221 xmlFree(name);
11222 name = NULL;
11223 } else {
11224 /* an element name can conflict with an axis one :-\ */
11225 axis = AXIS_CHILD;
11226 }
11227 } else {
11228 axis = AXIS_CHILD;
11229 }
11230 } else if (CUR == '@') {
11231 NEXT;
11232 axis = AXIS_ATTRIBUTE;
11233 } else {
11234 axis = AXIS_CHILD;
11235 }
11236 }
11237
11238 CHECK_ERROR;
11239
11240 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11241 if (test == 0)
11242 return;
11243
11244 if ((prefix != NULL) && (ctxt->context != NULL) &&
11245 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11246 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11247 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11248 }
11249 }
11250#ifdef DEBUG_STEP
11251 xmlGenericError(xmlGenericErrorContext,
11252 "Basis : computing new set\n");
11253#endif
11254
11255#ifdef DEBUG_STEP
11256 xmlGenericError(xmlGenericErrorContext, "Basis : ");
11257 if (ctxt->value == NULL)
11258 xmlGenericError(xmlGenericErrorContext, "no value\n");
11259 else if (ctxt->value->nodesetval == NULL)
11260 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11261 else
11262 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11263#endif
11264
11265#ifdef LIBXML_XPTR_ENABLED
11266eval_predicates:
11267#endif
11268 op1 = ctxt->comp->last;
11269 ctxt->comp->last = -1;
11270
11271 SKIP_BLANKS;
11272 while (CUR == '[') {
11273 xmlXPathCompPredicate(ctxt, 0);
11274 }
11275
11276#ifdef LIBXML_XPTR_ENABLED
11277 if (rangeto) {
11278 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11279 } else
11280#endif
11281 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11282 test, type, (void *)prefix, (void *)name);
11283
11284 }
11285#ifdef DEBUG_STEP
11286 xmlGenericError(xmlGenericErrorContext, "Step : ");
11287 if (ctxt->value == NULL)
11288 xmlGenericError(xmlGenericErrorContext, "no value\n");
11289 else if (ctxt->value->nodesetval == NULL)
11290 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11291 else
11292 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11293 ctxt->value->nodesetval);
11294#endif
11295}
11296
11297/**
11298 * xmlXPathCompRelativeLocationPath:
11299 * @ctxt: the XPath Parser context
11300 *
11301 * [3] RelativeLocationPath ::= Step
11302 * | RelativeLocationPath '/' Step
11303 * | AbbreviatedRelativeLocationPath
11304 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
11305 *
11306 * Compile a relative location path.
11307 */
11308static void
11309xmlXPathCompRelativeLocationPath
11310(xmlXPathParserContextPtr ctxt) {
11311 SKIP_BLANKS;
11312 if ((CUR == '/') && (NXT(1) == '/')) {
11313 SKIP(2);
11314 SKIP_BLANKS;
11315 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11316 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11317 } else if (CUR == '/') {
11318 NEXT;
11319 SKIP_BLANKS;
11320 }
11321 xmlXPathCompStep(ctxt);
11322 SKIP_BLANKS;
11323 while (CUR == '/') {
11324 if ((CUR == '/') && (NXT(1) == '/')) {
11325 SKIP(2);
11326 SKIP_BLANKS;
11327 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11328 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11329 xmlXPathCompStep(ctxt);
11330 } else if (CUR == '/') {
11331 NEXT;
11332 SKIP_BLANKS;
11333 xmlXPathCompStep(ctxt);
11334 }
11335 SKIP_BLANKS;
11336 }
11337}
11338
11339/**
11340 * xmlXPathCompLocationPath:
11341 * @ctxt: the XPath Parser context
11342 *
11343 * [1] LocationPath ::= RelativeLocationPath
11344 * | AbsoluteLocationPath
11345 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
11346 * | AbbreviatedAbsoluteLocationPath
11347 * [10] AbbreviatedAbsoluteLocationPath ::=
11348 * '//' RelativeLocationPath
11349 *
11350 * Compile a location path
11351 *
11352 * // is short for /descendant-or-self::node()/. For example,
11353 * //para is short for /descendant-or-self::node()/child::para and
11354 * so will select any para element in the document (even a para element
11355 * that is a document element will be selected by //para since the
11356 * document element node is a child of the root node); div//para is
11357 * short for div/descendant-or-self::node()/child::para and so will
11358 * select all para descendants of div children.
11359 */
11360static void
11361xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11362 SKIP_BLANKS;
11363 if (CUR != '/') {
11364 xmlXPathCompRelativeLocationPath(ctxt);
11365 } else {
11366 while (CUR == '/') {
11367 if ((CUR == '/') && (NXT(1) == '/')) {
11368 SKIP(2);
11369 SKIP_BLANKS;
11370 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11371 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11372 xmlXPathCompRelativeLocationPath(ctxt);
11373 } else if (CUR == '/') {
11374 NEXT;
11375 SKIP_BLANKS;
11376 if ((CUR != 0 ) &&
11377 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11378 (CUR == '@') || (CUR == '*')))
11379 xmlXPathCompRelativeLocationPath(ctxt);
11380 }
11381 }
11382 }
11383}
11384
11385/************************************************************************
11386 * *
11387 * XPath precompiled expression evaluation *
11388 * *
11389 ************************************************************************/
11390
11391static int
11392xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11393
11394#ifdef DEBUG_STEP
11395static void
11396xmlXPathDebugDumpStepAxis(xmlXPathAxisVal axis,
11397 xmlXPathTestVal test,
11398 int nbNodes)
11399{
11400 xmlGenericError(xmlGenericErrorContext, "new step : ");
11401 switch (axis) {
11402 case AXIS_ANCESTOR:
11403 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11404 break;
11405 case AXIS_ANCESTOR_OR_SELF:
11406 xmlGenericError(xmlGenericErrorContext,
11407 "axis 'ancestors-or-self' ");
11408 break;
11409 case AXIS_ATTRIBUTE:
11410 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11411 break;
11412 case AXIS_CHILD:
11413 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11414 break;
11415 case AXIS_DESCENDANT:
11416 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11417 break;
11418 case AXIS_DESCENDANT_OR_SELF:
11419 xmlGenericError(xmlGenericErrorContext,
11420 "axis 'descendant-or-self' ");
11421 break;
11422 case AXIS_FOLLOWING:
11423 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11424 break;
11425 case AXIS_FOLLOWING_SIBLING:
11426 xmlGenericError(xmlGenericErrorContext,
11427 "axis 'following-siblings' ");
11428 break;
11429 case AXIS_NAMESPACE:
11430 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11431 break;
11432 case AXIS_PARENT:
11433 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11434 break;
11435 case AXIS_PRECEDING:
11436 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11437 break;
11438 case AXIS_PRECEDING_SIBLING:
11439 xmlGenericError(xmlGenericErrorContext,
11440 "axis 'preceding-sibling' ");
11441 break;
11442 case AXIS_SELF:
11443 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11444 break;
11445 }
11446 xmlGenericError(xmlGenericErrorContext,
11447 " context contains %d nodes\n", nbNodes);
11448 switch (test) {
11449 case NODE_TEST_NONE:
11450 xmlGenericError(xmlGenericErrorContext,
11451 " searching for none !!!\n");
11452 break;
11453 case NODE_TEST_TYPE:
11454 xmlGenericError(xmlGenericErrorContext,
11455 " searching for type %d\n", type);
11456 break;
11457 case NODE_TEST_PI:
11458 xmlGenericError(xmlGenericErrorContext,
11459 " searching for PI !!!\n");
11460 break;
11461 case NODE_TEST_ALL:
11462 xmlGenericError(xmlGenericErrorContext,
11463 " searching for *\n");
11464 break;
11465 case NODE_TEST_NS:
11466 xmlGenericError(xmlGenericErrorContext,
11467 " searching for namespace %s\n",
11468 prefix);
11469 break;
11470 case NODE_TEST_NAME:
11471 xmlGenericError(xmlGenericErrorContext,
11472 " searching for name %s\n", name);
11473 if (prefix != NULL)
11474 xmlGenericError(xmlGenericErrorContext,
11475 " with namespace %s\n", prefix);
11476 break;
11477 }
11478 xmlGenericError(xmlGenericErrorContext, "Testing : ");
11479}
11480#endif /* DEBUG_STEP */
11481
11482static int
11483xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11484 xmlXPathStepOpPtr op,
11485 xmlNodeSetPtr set,
11486 int contextSize,
11487 int hasNsNodes)
11488{
11489 if (op->ch1 != -1) {
11490 xmlXPathCompExprPtr comp = ctxt->comp;
11491 /*
11492 * Process inner predicates first.
11493 */
11494 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11495 /*
11496 * TODO: raise an internal error.
11497 */
11498 }
11499 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11500 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11501 CHECK_ERROR0;
11502 if (contextSize <= 0)
11503 return(0);
11504 }
11505 if (op->ch2 != -1) {
11506 xmlXPathContextPtr xpctxt = ctxt->context;
11507 xmlNodePtr contextNode, oldContextNode;
11508 xmlDocPtr oldContextDoc;
11509 int i, res, contextPos = 0, newContextSize;
11510 xmlXPathStepOpPtr exprOp;
11511 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11512
11513#ifdef LIBXML_XPTR_ENABLED
11514 /*
11515 * URGENT TODO: Check the following:
11516 * We don't expect location sets if evaluating prediates, right?
11517 * Only filters should expect location sets, right?
11518 */
11519#endif
11520 /*
11521 * SPEC XPath 1.0:
11522 * "For each node in the node-set to be filtered, the
11523 * PredicateExpr is evaluated with that node as the
11524 * context node, with the number of nodes in the
11525 * node-set as the context size, and with the proximity
11526 * position of the node in the node-set with respect to
11527 * the axis as the context position;"
11528 * @oldset is the node-set" to be filtered.
11529 *
11530 * SPEC XPath 1.0:
11531 * "only predicates change the context position and
11532 * context size (see [2.4 Predicates])."
11533 * Example:
11534 * node-set context pos
11535 * nA 1
11536 * nB 2
11537 * nC 3
11538 * After applying predicate [position() > 1] :
11539 * node-set context pos
11540 * nB 1
11541 * nC 2
11542 */
11543 oldContextNode = xpctxt->node;
11544 oldContextDoc = xpctxt->doc;
11545 /*
11546 * Get the expression of this predicate.
11547 */
11548 exprOp = &ctxt->comp->steps[op->ch2];
11549 newContextSize = 0;
11550 for (i = 0; i < set->nodeNr; i++) {
11551 if (set->nodeTab[i] == NULL)
11552 continue;
11553
11554 contextNode = set->nodeTab[i];
11555 xpctxt->node = contextNode;
11556 xpctxt->contextSize = contextSize;
11557 xpctxt->proximityPosition = ++contextPos;
11558
11559 /*
11560 * Also set the xpath document in case things like
11561 * key() are evaluated in the predicate.
11562 */
11563 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11564 (contextNode->doc != NULL))
11565 xpctxt->doc = contextNode->doc;
11566 /*
11567 * Evaluate the predicate expression with 1 context node
11568 * at a time; this node is packaged into a node set; this
11569 * node set is handed over to the evaluation mechanism.
11570 */
11571 if (contextObj == NULL)
11572 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11573 else
11574 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11575 contextNode);
11576
11577 valuePush(ctxt, contextObj);
11578
11579 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11580
11581 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11582 xmlXPathNodeSetClear(set, hasNsNodes);
11583 newContextSize = 0;
11584 goto evaluation_exit;
11585 }
11586
11587 if (res != 0) {
11588 newContextSize++;
11589 } else {
11590 /*
11591 * Remove the entry from the initial node set.
11592 */
11593 set->nodeTab[i] = NULL;
11594 if (contextNode->type == XML_NAMESPACE_DECL)
11595 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11596 }
11597 if (ctxt->value == contextObj) {
11598 /*
11599 * Don't free the temporary XPath object holding the
11600 * context node, in order to avoid massive recreation
11601 * inside this loop.
11602 */
11603 valuePop(ctxt);
11604 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11605 } else {
11606 /*
11607 * TODO: The object was lost in the evaluation machinery.
11608 * Can this happen? Maybe in internal-error cases.
11609 */
11610 contextObj = NULL;
11611 }
11612 }
11613
11614 if (contextObj != NULL) {
11615 if (ctxt->value == contextObj)
11616 valuePop(ctxt);
11617 xmlXPathReleaseObject(xpctxt, contextObj);
11618 }
11619evaluation_exit:
11620 if (exprRes != NULL)
11621 xmlXPathReleaseObject(ctxt->context, exprRes);
11622 /*
11623 * Reset/invalidate the context.
11624 */
11625 xpctxt->node = oldContextNode;
11626 xpctxt->doc = oldContextDoc;
11627 xpctxt->contextSize = -1;
11628 xpctxt->proximityPosition = -1;
11629 return(newContextSize);
11630 }
11631 return(contextSize);
11632}
11633
11634static int
11635xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11636 xmlXPathStepOpPtr op,
11637 xmlNodeSetPtr set,
11638 int contextSize,
11639 int minPos,
11640 int maxPos,
11641 int hasNsNodes)
11642{
11643 if (op->ch1 != -1) {
11644 xmlXPathCompExprPtr comp = ctxt->comp;
11645 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11646 /*
11647 * TODO: raise an internal error.
11648 */
11649 }
11650 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11651 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11652 CHECK_ERROR0;
11653 if (contextSize <= 0)
11654 return(0);
11655 }
11656 /*
11657 * Check if the node set contains a sufficient number of nodes for
11658 * the requested range.
11659 */
11660 if (contextSize < minPos) {
11661 xmlXPathNodeSetClear(set, hasNsNodes);
11662 return(0);
11663 }
11664 if (op->ch2 == -1) {
11665 /*
11666 * TODO: Can this ever happen?
11667 */
11668 return (contextSize);
11669 } else {
11670 xmlDocPtr oldContextDoc;
11671 int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11672 xmlXPathStepOpPtr exprOp;
11673 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11674 xmlNodePtr oldContextNode, contextNode = NULL;
11675 xmlXPathContextPtr xpctxt = ctxt->context;
11676
11677#ifdef LIBXML_XPTR_ENABLED
11678 /*
11679 * URGENT TODO: Check the following:
11680 * We don't expect location sets if evaluating prediates, right?
11681 * Only filters should expect location sets, right?
11682 */
11683#endif /* LIBXML_XPTR_ENABLED */
11684
11685 /*
11686 * Save old context.
11687 */
11688 oldContextNode = xpctxt->node;
11689 oldContextDoc = xpctxt->doc;
11690 /*
11691 * Get the expression of this predicate.
11692 */
11693 exprOp = &ctxt->comp->steps[op->ch2];
11694 for (i = 0; i < set->nodeNr; i++) {
11695 if (set->nodeTab[i] == NULL)
11696 continue;
11697
11698 contextNode = set->nodeTab[i];
11699 xpctxt->node = contextNode;
11700 xpctxt->contextSize = contextSize;
11701 xpctxt->proximityPosition = ++contextPos;
11702
11703 /*
11704 * Initialize the new set.
11705 * Also set the xpath document in case things like
11706 * key() evaluation are attempted on the predicate
11707 */
11708 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11709 (contextNode->doc != NULL))
11710 xpctxt->doc = contextNode->doc;
11711 /*
11712 * Evaluate the predicate expression with 1 context node
11713 * at a time; this node is packaged into a node set; this
11714 * node set is handed over to the evaluation mechanism.
11715 */
11716 if (contextObj == NULL)
11717 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11718 else
11719 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11720 contextNode);
11721
11722 valuePush(ctxt, contextObj);
11723 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11724
11725 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11726 xmlXPathObjectPtr tmp;
11727 /* pop the result */
11728 tmp = valuePop(ctxt);
11729 xmlXPathReleaseObject(xpctxt, tmp);
11730 /* then pop off contextObj, which will be freed later */
11731 valuePop(ctxt);
11732 goto evaluation_error;
11733 }
11734
11735 if (res)
11736 pos++;
11737
11738 if (res && (pos >= minPos) && (pos <= maxPos)) {
11739 /*
11740 * Fits in the requested range.
11741 */
11742 newContextSize++;
11743 if (minPos == maxPos) {
11744 /*
11745 * Only 1 node was requested.
11746 */
11747 if (contextNode->type == XML_NAMESPACE_DECL) {
11748 /*
11749 * As always: take care of those nasty
11750 * namespace nodes.
11751 */
11752 set->nodeTab[i] = NULL;
11753 }
11754 xmlXPathNodeSetClear(set, hasNsNodes);
11755 set->nodeNr = 1;
11756 set->nodeTab[0] = contextNode;
11757 goto evaluation_exit;
11758 }
11759 if (pos == maxPos) {
11760 /*
11761 * We are done.
11762 */
11763 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11764 goto evaluation_exit;
11765 }
11766 } else {
11767 /*
11768 * Remove the entry from the initial node set.
11769 */
11770 set->nodeTab[i] = NULL;
11771 if (contextNode->type == XML_NAMESPACE_DECL)
11772 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11773 }
11774 if (exprRes != NULL) {
11775 xmlXPathReleaseObject(ctxt->context, exprRes);
11776 exprRes = NULL;
11777 }
11778 if (ctxt->value == contextObj) {
11779 /*
11780 * Don't free the temporary XPath object holding the
11781 * context node, in order to avoid massive recreation
11782 * inside this loop.
11783 */
11784 valuePop(ctxt);
11785 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11786 } else {
11787 /*
11788 * The object was lost in the evaluation machinery.
11789 * Can this happen? Maybe in case of internal-errors.
11790 */
11791 contextObj = NULL;
11792 }
11793 }
11794 goto evaluation_exit;
11795
11796evaluation_error:
11797 xmlXPathNodeSetClear(set, hasNsNodes);
11798 newContextSize = 0;
11799
11800evaluation_exit:
11801 if (contextObj != NULL) {
11802 if (ctxt->value == contextObj)
11803 valuePop(ctxt);
11804 xmlXPathReleaseObject(xpctxt, contextObj);
11805 }
11806 if (exprRes != NULL)
11807 xmlXPathReleaseObject(ctxt->context, exprRes);
11808 /*
11809 * Reset/invalidate the context.
11810 */
11811 xpctxt->node = oldContextNode;
11812 xpctxt->doc = oldContextDoc;
11813 xpctxt->contextSize = -1;
11814 xpctxt->proximityPosition = -1;
11815 return(newContextSize);
11816 }
11817 return(contextSize);
11818}
11819
11820static int
11821xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11822 xmlXPathStepOpPtr op,
11823 int *maxPos)
11824{
11825
11826 xmlXPathStepOpPtr exprOp;
11827
11828 /*
11829 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11830 */
11831
11832 /*
11833 * If not -1, then ch1 will point to:
11834 * 1) For predicates (XPATH_OP_PREDICATE):
11835 * - an inner predicate operator
11836 * 2) For filters (XPATH_OP_FILTER):
11837 * - an inner filter operater OR
11838 * - an expression selecting the node set.
11839 * E.g. "key('a', 'b')" or "(//foo | //bar)".
11840 */
11841 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11842 return(0);
11843
11844 if (op->ch2 != -1) {
11845 exprOp = &ctxt->comp->steps[op->ch2];
11846 } else
11847 return(0);
11848
11849 if ((exprOp != NULL) &&
11850 (exprOp->op == XPATH_OP_VALUE) &&
11851 (exprOp->value4 != NULL) &&
11852 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11853 {
11854 /*
11855 * We have a "[n]" predicate here.
11856 * TODO: Unfortunately this simplistic test here is not
11857 * able to detect a position() predicate in compound
11858 * expressions like "[@attr = 'a" and position() = 1],
11859 * and even not the usage of position() in
11860 * "[position() = 1]"; thus - obviously - a position-range,
11861 * like it "[position() < 5]", is also not detected.
11862 * Maybe we could rewrite the AST to ease the optimization.
11863 */
11864 *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11865
11866 if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
11867 (float) *maxPos)
11868 {
11869 return(1);
11870 }
11871 }
11872 return(0);
11873}
11874
11875static int
11876xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11877 xmlXPathStepOpPtr op,
11878 xmlNodePtr * first, xmlNodePtr * last,
11879 int toBool)
11880{
11881
11882#define XP_TEST_HIT \
11883 if (hasAxisRange != 0) { \
11884 if (++pos == maxPos) { \
11885 addNode(seq, cur); \
11886 goto axis_range_end; } \
11887 } else { \
11888 addNode(seq, cur); \
11889 if (breakOnFirstHit) goto first_hit; }
11890
11891#define XP_TEST_HIT_NS \
11892 if (hasAxisRange != 0) { \
11893 if (++pos == maxPos) { \
11894 hasNsNodes = 1; \
11895 xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
11896 goto axis_range_end; } \
11897 } else { \
11898 hasNsNodes = 1; \
11899 xmlXPathNodeSetAddNs(seq, \
11900 xpctxt->node, (xmlNsPtr) cur); \
11901 if (breakOnFirstHit) goto first_hit; }
11902
11903 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11904 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11905 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11906 const xmlChar *prefix = op->value4;
11907 const xmlChar *name = op->value5;
11908 const xmlChar *URI = NULL;
11909
11910#ifdef DEBUG_STEP
11911 int nbMatches = 0, prevMatches = 0;
11912#endif
11913 int total = 0, hasNsNodes = 0;
11914 /* The popped object holding the context nodes */
11915 xmlXPathObjectPtr obj;
11916 /* The set of context nodes for the node tests */
11917 xmlNodeSetPtr contextSeq;
11918 int contextIdx;
11919 xmlNodePtr contextNode;
11920 /* The context node for a compound traversal */
11921 xmlNodePtr outerContextNode;
11922 /* The final resulting node set wrt to all context nodes */
11923 xmlNodeSetPtr outSeq;
11924 /*
11925 * The temporary resulting node set wrt 1 context node.
11926 * Used to feed predicate evaluation.
11927 */
11928 xmlNodeSetPtr seq;
11929 xmlNodePtr cur;
11930 /* First predicate operator */
11931 xmlXPathStepOpPtr predOp;
11932 int maxPos; /* The requested position() (when a "[n]" predicate) */
11933 int hasPredicateRange, hasAxisRange, pos, size, newSize;
11934 int breakOnFirstHit;
11935
11936 xmlXPathTraversalFunction next = NULL;
11937 /* compound axis traversal */
11938 xmlXPathTraversalFunctionExt outerNext = NULL;
11939 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
11940 xmlXPathNodeSetMergeFunction mergeAndClear;
11941 xmlNodePtr oldContextNode;
11942 xmlXPathContextPtr xpctxt = ctxt->context;
11943
11944
11945 CHECK_TYPE0(XPATH_NODESET);
11946 obj = valuePop(ctxt);
11947 /*
11948 * Setup namespaces.
11949 */
11950 if (prefix != NULL) {
11951 URI = xmlXPathNsLookup(xpctxt, prefix);
11952 if (URI == NULL) {
11953 xmlXPathReleaseObject(xpctxt, obj);
11954 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11955 }
11956 }
11957 /*
11958 * Setup axis.
11959 *
11960 * MAYBE FUTURE TODO: merging optimizations:
11961 * - If the nodes to be traversed wrt to the initial nodes and
11962 * the current axis cannot overlap, then we could avoid searching
11963 * for duplicates during the merge.
11964 * But the question is how/when to evaluate if they cannot overlap.
11965 * Example: if we know that for two initial nodes, the one is
11966 * not in the ancestor-or-self axis of the other, then we could safely
11967 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
11968 * the descendant-or-self axis.
11969 */
11970 addNode = xmlXPathNodeSetAdd;
11971 mergeAndClear = xmlXPathNodeSetMergeAndClear;
11972 switch (axis) {
11973 case AXIS_ANCESTOR:
11974 first = NULL;
11975 next = xmlXPathNextAncestor;
11976 break;
11977 case AXIS_ANCESTOR_OR_SELF:
11978 first = NULL;
11979 next = xmlXPathNextAncestorOrSelf;
11980 break;
11981 case AXIS_ATTRIBUTE:
11982 first = NULL;
11983 last = NULL;
11984 next = xmlXPathNextAttribute;
11985 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11986 break;
11987 case AXIS_CHILD:
11988 last = NULL;
11989 if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
11990 /*
11991 * This iterator will give us only nodes which can
11992 * hold element nodes.
11993 */
11994 outerNext = xmlXPathNextDescendantOrSelfElemParent;
11995 }
11996 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
11997 (type == NODE_TYPE_NODE))
11998 {
11999 /*
12000 * Optimization if an element node type is 'element'.
12001 */
12002 next = xmlXPathNextChildElement;
12003 } else
12004 next = xmlXPathNextChild;
12005 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12006 break;
12007 case AXIS_DESCENDANT:
12008 last = NULL;
12009 next = xmlXPathNextDescendant;
12010 break;
12011 case AXIS_DESCENDANT_OR_SELF:
12012 last = NULL;
12013 next = xmlXPathNextDescendantOrSelf;
12014 break;
12015 case AXIS_FOLLOWING:
12016 last = NULL;
12017 next = xmlXPathNextFollowing;
12018 break;
12019 case AXIS_FOLLOWING_SIBLING:
12020 last = NULL;
12021 next = xmlXPathNextFollowingSibling;
12022 break;
12023 case AXIS_NAMESPACE:
12024 first = NULL;
12025 last = NULL;
12026 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12027 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12028 break;
12029 case AXIS_PARENT:
12030 first = NULL;
12031 next = xmlXPathNextParent;
12032 break;
12033 case AXIS_PRECEDING:
12034 first = NULL;
12035 next = xmlXPathNextPrecedingInternal;
12036 break;
12037 case AXIS_PRECEDING_SIBLING:
12038 first = NULL;
12039 next = xmlXPathNextPrecedingSibling;
12040 break;
12041 case AXIS_SELF:
12042 first = NULL;
12043 last = NULL;
12044 next = xmlXPathNextSelf;
12045 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12046 break;
12047 }
12048
12049#ifdef DEBUG_STEP
12050 xmlXPathDebugDumpStepAxis(axis, test,
12051 (obj->nodesetval != NULL) ? obj->nodsetval->nodeNr : 0);
12052#endif
12053
12054 if (next == NULL) {
12055 xmlXPathReleaseObject(xpctxt, obj);
12056 return(0);
12057 }
12058 contextSeq = obj->nodesetval;
12059 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12060 xmlXPathReleaseObject(xpctxt, obj);
12061 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12062 return(0);
12063 }
12064 /*
12065 * Predicate optimization ---------------------------------------------
12066 * If this step has a last predicate, which contains a position(),
12067 * then we'll optimize (although not exactly "position()", but only
12068 * the short-hand form, i.e., "[n]".
12069 *
12070 * Example - expression "/foo[parent::bar][1]":
12071 *
12072 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12073 * ROOT -- op->ch1
12074 * PREDICATE -- op->ch2 (predOp)
12075 * PREDICATE -- predOp->ch1 = [parent::bar]
12076 * SORT
12077 * COLLECT 'parent' 'name' 'node' bar
12078 * NODE
12079 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12080 *
12081 */
12082 maxPos = 0;
12083 predOp = NULL;
12084 hasPredicateRange = 0;
12085 hasAxisRange = 0;
12086 if (op->ch2 != -1) {
12087 /*
12088 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12089 */
12090 predOp = &ctxt->comp->steps[op->ch2];
12091 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12092 if (predOp->ch1 != -1) {
12093 /*
12094 * Use the next inner predicate operator.
12095 */
12096 predOp = &ctxt->comp->steps[predOp->ch1];
12097 hasPredicateRange = 1;
12098 } else {
12099 /*
12100 * There's no other predicate than the [n] predicate.
12101 */
12102 predOp = NULL;
12103 hasAxisRange = 1;
12104 }
12105 }
12106 }
12107 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12108 /*
12109 * Axis traversal -----------------------------------------------------
12110 */
12111 /*
12112 * 2.3 Node Tests
12113 * - For the attribute axis, the principal node type is attribute.
12114 * - For the namespace axis, the principal node type is namespace.
12115 * - For other axes, the principal node type is element.
12116 *
12117 * A node test * is true for any node of the
12118 * principal node type. For example, child::* will
12119 * select all element children of the context node
12120 */
12121 oldContextNode = xpctxt->node;
12122 addNode = xmlXPathNodeSetAddUnique;
12123 outSeq = NULL;
12124 seq = NULL;
12125 outerContextNode = NULL;
12126 contextNode = NULL;
12127 contextIdx = 0;
12128
12129
12130 while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
12131 if (outerNext != NULL) {
12132 /*
12133 * This is a compound traversal.
12134 */
12135 if (contextNode == NULL) {
12136 /*
12137 * Set the context for the outer traversal.
12138 */
12139 outerContextNode = contextSeq->nodeTab[contextIdx++];
12140 contextNode = outerNext(NULL, outerContextNode);
12141 } else
12142 contextNode = outerNext(contextNode, outerContextNode);
12143 if (contextNode == NULL)
12144 continue;
12145 /*
12146 * Set the context for the main traversal.
12147 */
12148 xpctxt->node = contextNode;
12149 } else
12150 xpctxt->node = contextSeq->nodeTab[contextIdx++];
12151
12152 if (seq == NULL) {
12153 seq = xmlXPathNodeSetCreate(NULL);
12154 if (seq == NULL) {
12155 total = 0;
12156 goto error;
12157 }
12158 }
12159 /*
12160 * Traverse the axis and test the nodes.
12161 */
12162 pos = 0;
12163 cur = NULL;
12164 hasNsNodes = 0;
12165 do {
12166 cur = next(ctxt, cur);
12167 if (cur == NULL)
12168 break;
12169
12170 /*
12171 * QUESTION TODO: What does the "first" and "last" stuff do?
12172 */
12173 if ((first != NULL) && (*first != NULL)) {
12174 if (*first == cur)
12175 break;
12176 if (((total % 256) == 0) &&
12177#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12178 (xmlXPathCmpNodesExt(*first, cur) >= 0))
12179#else
12180 (xmlXPathCmpNodes(*first, cur) >= 0))
12181#endif
12182 {
12183 break;
12184 }
12185 }
12186 if ((last != NULL) && (*last != NULL)) {
12187 if (*last == cur)
12188 break;
12189 if (((total % 256) == 0) &&
12190#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12191 (xmlXPathCmpNodesExt(cur, *last) >= 0))
12192#else
12193 (xmlXPathCmpNodes(cur, *last) >= 0))
12194#endif
12195 {
12196 break;
12197 }
12198 }
12199
12200 total++;
12201
12202#ifdef DEBUG_STEP
12203 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12204#endif
12205
12206 switch (test) {
12207 case NODE_TEST_NONE:
12208 total = 0;
12209 STRANGE
12210 goto error;
12211 case NODE_TEST_TYPE:
12212 /*
12213 * TODO: Don't we need to use
12214 * xmlXPathNodeSetAddNs() for namespace nodes here?
12215 * Surprisingly, some c14n tests fail, if we do this.
12216 */
12217 if (type == NODE_TYPE_NODE) {
12218 switch (cur->type) {
12219 case XML_DOCUMENT_NODE:
12220 case XML_HTML_DOCUMENT_NODE:
12221#ifdef LIBXML_DOCB_ENABLED
12222 case XML_DOCB_DOCUMENT_NODE:
12223#endif
12224 case XML_ELEMENT_NODE:
12225 case XML_ATTRIBUTE_NODE:
12226 case XML_PI_NODE:
12227 case XML_COMMENT_NODE:
12228 case XML_CDATA_SECTION_NODE:
12229 case XML_TEXT_NODE:
12230 case XML_NAMESPACE_DECL:
12231 XP_TEST_HIT
12232 break;
12233 default:
12234 break;
12235 }
12236 } else if (cur->type == type) {
12237 if (type == XML_NAMESPACE_DECL)
12238 XP_TEST_HIT_NS
12239 else
12240 XP_TEST_HIT
12241 } else if ((type == NODE_TYPE_TEXT) &&
12242 (cur->type == XML_CDATA_SECTION_NODE))
12243 {
12244 XP_TEST_HIT
12245 }
12246 break;
12247 case NODE_TEST_PI:
12248 if ((cur->type == XML_PI_NODE) &&
12249 ((name == NULL) || xmlStrEqual(name, cur->name)))
12250 {
12251 XP_TEST_HIT
12252 }
12253 break;
12254 case NODE_TEST_ALL:
12255 if (axis == AXIS_ATTRIBUTE) {
12256 if (cur->type == XML_ATTRIBUTE_NODE)
12257 {
12258 XP_TEST_HIT
12259 }
12260 } else if (axis == AXIS_NAMESPACE) {
12261 if (cur->type == XML_NAMESPACE_DECL)
12262 {
12263 XP_TEST_HIT_NS
12264 }
12265 } else {
12266 if (cur->type == XML_ELEMENT_NODE) {
12267 if (prefix == NULL)
12268 {
12269 XP_TEST_HIT
12270
12271 } else if ((cur->ns != NULL) &&
12272 (xmlStrEqual(URI, cur->ns->href)))
12273 {
12274 XP_TEST_HIT
12275 }
12276 }
12277 }
12278 break;
12279 case NODE_TEST_NS:{
12280 TODO;
12281 break;
12282 }
12283 case NODE_TEST_NAME:
12284 if (axis == AXIS_ATTRIBUTE) {
12285 if (cur->type != XML_ATTRIBUTE_NODE)
12286 break;
12287 } else if (axis == AXIS_NAMESPACE) {
12288 if (cur->type != XML_NAMESPACE_DECL)
12289 break;
12290 } else {
12291 if (cur->type != XML_ELEMENT_NODE)
12292 break;
12293 }
12294 switch (cur->type) {
12295 case XML_ELEMENT_NODE:
12296 if (xmlStrEqual(name, cur->name)) {
12297 if (prefix == NULL) {
12298 if (cur->ns == NULL)
12299 {
12300 XP_TEST_HIT
12301 }
12302 } else {
12303 if ((cur->ns != NULL) &&
12304 (xmlStrEqual(URI, cur->ns->href)))
12305 {
12306 XP_TEST_HIT
12307 }
12308 }
12309 }
12310 break;
12311 case XML_ATTRIBUTE_NODE:{
12312 xmlAttrPtr attr = (xmlAttrPtr) cur;
12313
12314 if (xmlStrEqual(name, attr->name)) {
12315 if (prefix == NULL) {
12316 if ((attr->ns == NULL) ||
12317 (attr->ns->prefix == NULL))
12318 {
12319 XP_TEST_HIT
12320 }
12321 } else {
12322 if ((attr->ns != NULL) &&
12323 (xmlStrEqual(URI,
12324 attr->ns->href)))
12325 {
12326 XP_TEST_HIT
12327 }
12328 }
12329 }
12330 break;
12331 }
12332 case XML_NAMESPACE_DECL:
12333 if (cur->type == XML_NAMESPACE_DECL) {
12334 xmlNsPtr ns = (xmlNsPtr) cur;
12335
12336 if ((ns->prefix != NULL) && (name != NULL)
12337 && (xmlStrEqual(ns->prefix, name)))
12338 {
12339 XP_TEST_HIT_NS
12340 }
12341 }
12342 break;
12343 default:
12344 break;
12345 }
12346 break;
12347 } /* switch(test) */
12348 } while (cur != NULL);
12349
12350 goto apply_predicates;
12351
12352axis_range_end: /* ----------------------------------------------------- */
12353 /*
12354 * We have a "/foo[n]", and position() = n was reached.
12355 * Note that we can have as well "/foo/::parent::foo[1]", so
12356 * a duplicate-aware merge is still needed.
12357 * Merge with the result.
12358 */
12359 if (outSeq == NULL) {
12360 outSeq = seq;
12361 seq = NULL;
12362 } else
12363 outSeq = mergeAndClear(outSeq, seq, 0);
12364 /*
12365 * Break if only a true/false result was requested.
12366 */
12367 if (toBool)
12368 break;
12369 continue;
12370
12371first_hit: /* ---------------------------------------------------------- */
12372 /*
12373 * Break if only a true/false result was requested and
12374 * no predicates existed and a node test succeeded.
12375 */
12376 if (outSeq == NULL) {
12377 outSeq = seq;
12378 seq = NULL;
12379 } else
12380 outSeq = mergeAndClear(outSeq, seq, 0);
12381 break;
12382
12383#ifdef DEBUG_STEP
12384 if (seq != NULL)
12385 nbMatches += seq->nodeNr;
12386#endif
12387
12388apply_predicates: /* --------------------------------------------------- */
12389 /*
12390 * Apply predicates.
12391 */
12392 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12393 /*
12394 * E.g. when we have a "/foo[some expression][n]".
12395 */
12396 /*
12397 * QUESTION TODO: The old predicate evaluation took into
12398 * account location-sets.
12399 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12400 * Do we expect such a set here?
12401 * All what I learned now from the evaluation semantics
12402 * does not indicate that a location-set will be processed
12403 * here, so this looks OK.
12404 */
12405 /*
12406 * Iterate over all predicates, starting with the outermost
12407 * predicate.
12408 * TODO: Problem: we cannot execute the inner predicates first
12409 * since we cannot go back *up* the operator tree!
12410 * Options we have:
12411 * 1) Use of recursive functions (like is it currently done
12412 * via xmlXPathCompOpEval())
12413 * 2) Add a predicate evaluation information stack to the
12414 * context struct
12415 * 3) Change the way the operators are linked; we need a
12416 * "parent" field on xmlXPathStepOp
12417 *
12418 * For the moment, I'll try to solve this with a recursive
12419 * function: xmlXPathCompOpEvalPredicate().
12420 */
12421 size = seq->nodeNr;
12422 if (hasPredicateRange != 0)
12423 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12424 predOp, seq, size, maxPos, maxPos, hasNsNodes);
12425 else
12426 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12427 predOp, seq, size, hasNsNodes);
12428
12429 if (ctxt->error != XPATH_EXPRESSION_OK) {
12430 total = 0;
12431 goto error;
12432 }
12433 /*
12434 * Add the filtered set of nodes to the result node set.
12435 */
12436 if (newSize == 0) {
12437 /*
12438 * The predicates filtered all nodes out.
12439 */
12440 xmlXPathNodeSetClear(seq, hasNsNodes);
12441 } else if (seq->nodeNr > 0) {
12442 /*
12443 * Add to result set.
12444 */
12445 if (outSeq == NULL) {
12446 if (size != newSize) {
12447 /*
12448 * We need to merge and clear here, since
12449 * the sequence will contained NULLed entries.
12450 */
12451 outSeq = mergeAndClear(NULL, seq, 1);
12452 } else {
12453 outSeq = seq;
12454 seq = NULL;
12455 }
12456 } else
12457 outSeq = mergeAndClear(outSeq, seq,
12458 (size != newSize) ? 1: 0);
12459 /*
12460 * Break if only a true/false result was requested.
12461 */
12462 if (toBool)
12463 break;
12464 }
12465 } else if (seq->nodeNr > 0) {
12466 /*
12467 * Add to result set.
12468 */
12469 if (outSeq == NULL) {
12470 outSeq = seq;
12471 seq = NULL;
12472 } else {
12473 outSeq = mergeAndClear(outSeq, seq, 0);
12474 }
12475 }
12476 }
12477
12478error:
12479 if ((obj->boolval) && (obj->user != NULL)) {
12480 /*
12481 * QUESTION TODO: What does this do and why?
12482 * TODO: Do we have to do this also for the "error"
12483 * cleanup further down?
12484 */
12485 ctxt->value->boolval = 1;
12486 ctxt->value->user = obj->user;
12487 obj->user = NULL;
12488 obj->boolval = 0;
12489 }
12490 xmlXPathReleaseObject(xpctxt, obj);
12491
12492 /*
12493 * Ensure we return at least an emtpy set.
12494 */
12495 if (outSeq == NULL) {
12496 if ((seq != NULL) && (seq->nodeNr == 0))
12497 outSeq = seq;
12498 else
12499 outSeq = xmlXPathNodeSetCreate(NULL);
12500 }
12501 if ((seq != NULL) && (seq != outSeq)) {
12502 xmlXPathFreeNodeSet(seq);
12503 }
12504 /*
12505 * Hand over the result. Better to push the set also in
12506 * case of errors.
12507 */
12508 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12509 /*
12510 * Reset the context node.
12511 */
12512 xpctxt->node = oldContextNode;
12513
12514#ifdef DEBUG_STEP
12515 xmlGenericError(xmlGenericErrorContext,
12516 "\nExamined %d nodes, found %d nodes at that step\n",
12517 total, nbMatches);
12518#endif
12519
12520 return(total);
12521}
12522
12523static int
12524xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12525 xmlXPathStepOpPtr op, xmlNodePtr * first);
12526
12527/**
12528 * xmlXPathCompOpEvalFirst:
12529 * @ctxt: the XPath parser context with the compiled expression
12530 * @op: an XPath compiled operation
12531 * @first: the first elem found so far
12532 *
12533 * Evaluate the Precompiled XPath operation searching only the first
12534 * element in document order
12535 *
12536 * Returns the number of examined objects.
12537 */
12538static int
12539xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12540 xmlXPathStepOpPtr op, xmlNodePtr * first)
12541{
12542 int total = 0, cur;
12543 xmlXPathCompExprPtr comp;
12544 xmlXPathObjectPtr arg1, arg2;
12545
12546 CHECK_ERROR0;
12547 comp = ctxt->comp;
12548 switch (op->op) {
12549 case XPATH_OP_END:
12550 return (0);
12551 case XPATH_OP_UNION:
12552 total =
12553 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12554 first);
12555 CHECK_ERROR0;
12556 if ((ctxt->value != NULL)
12557 && (ctxt->value->type == XPATH_NODESET)
12558 && (ctxt->value->nodesetval != NULL)
12559 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12560 /*
12561 * limit tree traversing to first node in the result
12562 */
12563 /*
12564 * OPTIMIZE TODO: This implicitely sorts
12565 * the result, even if not needed. E.g. if the argument
12566 * of the count() function, no sorting is needed.
12567 * OPTIMIZE TODO: How do we know if the node-list wasn't
12568 * aready sorted?
12569 */
12570 if (ctxt->value->nodesetval->nodeNr > 1)
12571 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12572 *first = ctxt->value->nodesetval->nodeTab[0];
12573 }
12574 cur =
12575 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12576 first);
12577 CHECK_ERROR0;
12578 CHECK_TYPE0(XPATH_NODESET);
12579 arg2 = valuePop(ctxt);
12580
12581 CHECK_TYPE0(XPATH_NODESET);
12582 arg1 = valuePop(ctxt);
12583
12584 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12585 arg2->nodesetval);
12586 valuePush(ctxt, arg1);
12587 xmlXPathReleaseObject(ctxt->context, arg2);
12588 /* optimizer */
12589 if (total > cur)
12590 xmlXPathCompSwap(op);
12591 return (total + cur);
12592 case XPATH_OP_ROOT:
12593 xmlXPathRoot(ctxt);
12594 return (0);
12595 case XPATH_OP_NODE:
12596 if (op->ch1 != -1)
12597 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12598 CHECK_ERROR0;
12599 if (op->ch2 != -1)
12600 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12601 CHECK_ERROR0;
12602 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12603 ctxt->context->node));
12604 return (total);
12605 case XPATH_OP_RESET:
12606 if (op->ch1 != -1)
12607 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12608 CHECK_ERROR0;
12609 if (op->ch2 != -1)
12610 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12611 CHECK_ERROR0;
12612 ctxt->context->node = NULL;
12613 return (total);
12614 case XPATH_OP_COLLECT:{
12615 if (op->ch1 == -1)
12616 return (total);
12617
12618 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12619 CHECK_ERROR0;
12620
12621 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12622 return (total);
12623 }
12624 case XPATH_OP_VALUE:
12625 valuePush(ctxt,
12626 xmlXPathCacheObjectCopy(ctxt->context,
12627 (xmlXPathObjectPtr) op->value4));
12628 return (0);
12629 case XPATH_OP_SORT:
12630 if (op->ch1 != -1)
12631 total +=
12632 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12633 first);
12634 CHECK_ERROR0;
12635 if ((ctxt->value != NULL)
12636 && (ctxt->value->type == XPATH_NODESET)
12637 && (ctxt->value->nodesetval != NULL)
12638 && (ctxt->value->nodesetval->nodeNr > 1))
12639 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12640 return (total);
12641#ifdef XP_OPTIMIZED_FILTER_FIRST
12642 case XPATH_OP_FILTER:
12643 total =+ xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12644 return (total);
12645#endif
12646 default:
12647 return (xmlXPathCompOpEval(ctxt, op));
12648 }
12649}
12650
12651/**
12652 * xmlXPathCompOpEvalLast:
12653 * @ctxt: the XPath parser context with the compiled expression
12654 * @op: an XPath compiled operation
12655 * @last: the last elem found so far
12656 *
12657 * Evaluate the Precompiled XPath operation searching only the last
12658 * element in document order
12659 *
12660 * Returns the number of nodes traversed
12661 */
12662static int
12663xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12664 xmlNodePtr * last)
12665{
12666 int total = 0, cur;
12667 xmlXPathCompExprPtr comp;
12668 xmlXPathObjectPtr arg1, arg2;
12669 xmlNodePtr bak;
12670 xmlDocPtr bakd;
12671 int pp;
12672 int cs;
12673
12674 CHECK_ERROR0;
12675 comp = ctxt->comp;
12676 switch (op->op) {
12677 case XPATH_OP_END:
12678 return (0);
12679 case XPATH_OP_UNION:
12680 bakd = ctxt->context->doc;
12681 bak = ctxt->context->node;
12682 pp = ctxt->context->proximityPosition;
12683 cs = ctxt->context->contextSize;
12684 total =
12685 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12686 CHECK_ERROR0;
12687 if ((ctxt->value != NULL)
12688 && (ctxt->value->type == XPATH_NODESET)
12689 && (ctxt->value->nodesetval != NULL)
12690 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12691 /*
12692 * limit tree traversing to first node in the result
12693 */
12694 if (ctxt->value->nodesetval->nodeNr > 1)
12695 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12696 *last =
12697 ctxt->value->nodesetval->nodeTab[ctxt->value->
12698 nodesetval->nodeNr -
12699 1];
12700 }
12701 ctxt->context->doc = bakd;
12702 ctxt->context->node = bak;
12703 ctxt->context->proximityPosition = pp;
12704 ctxt->context->contextSize = cs;
12705 cur =
12706 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12707 CHECK_ERROR0;
12708 if ((ctxt->value != NULL)
12709 && (ctxt->value->type == XPATH_NODESET)
12710 && (ctxt->value->nodesetval != NULL)
12711 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12712 }
12713 CHECK_TYPE0(XPATH_NODESET);
12714 arg2 = valuePop(ctxt);
12715
12716 CHECK_TYPE0(XPATH_NODESET);
12717 arg1 = valuePop(ctxt);
12718
12719 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12720 arg2->nodesetval);
12721 valuePush(ctxt, arg1);
12722 xmlXPathReleaseObject(ctxt->context, arg2);
12723 /* optimizer */
12724 if (total > cur)
12725 xmlXPathCompSwap(op);
12726 return (total + cur);
12727 case XPATH_OP_ROOT:
12728 xmlXPathRoot(ctxt);
12729 return (0);
12730 case XPATH_OP_NODE:
12731 if (op->ch1 != -1)
12732 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12733 CHECK_ERROR0;
12734 if (op->ch2 != -1)
12735 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12736 CHECK_ERROR0;
12737 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12738 ctxt->context->node));
12739 return (total);
12740 case XPATH_OP_RESET:
12741 if (op->ch1 != -1)
12742 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12743 CHECK_ERROR0;
12744 if (op->ch2 != -1)
12745 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12746 CHECK_ERROR0;
12747 ctxt->context->node = NULL;
12748 return (total);
12749 case XPATH_OP_COLLECT:{
12750 if (op->ch1 == -1)
12751 return (0);
12752
12753 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12754 CHECK_ERROR0;
12755
12756 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12757 return (total);
12758 }
12759 case XPATH_OP_VALUE:
12760 valuePush(ctxt,
12761 xmlXPathCacheObjectCopy(ctxt->context,
12762 (xmlXPathObjectPtr) op->value4));
12763 return (0);
12764 case XPATH_OP_SORT:
12765 if (op->ch1 != -1)
12766 total +=
12767 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12768 last);
12769 CHECK_ERROR0;
12770 if ((ctxt->value != NULL)
12771 && (ctxt->value->type == XPATH_NODESET)
12772 && (ctxt->value->nodesetval != NULL)
12773 && (ctxt->value->nodesetval->nodeNr > 1))
12774 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12775 return (total);
12776 default:
12777 return (xmlXPathCompOpEval(ctxt, op));
12778 }
12779}
12780
12781#ifdef XP_OPTIMIZED_FILTER_FIRST
12782static int
12783xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12784 xmlXPathStepOpPtr op, xmlNodePtr * first)
12785{
12786 int total = 0;
12787 xmlXPathCompExprPtr comp;
12788 xmlXPathObjectPtr res;
12789 xmlXPathObjectPtr obj;
12790 xmlNodeSetPtr oldset;
12791 xmlNodePtr oldnode;
12792 xmlDocPtr oldDoc;
12793 int i;
12794
12795 CHECK_ERROR0;
12796 comp = ctxt->comp;
12797 /*
12798 * Optimization for ()[last()] selection i.e. the last elem
12799 */
12800 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12801 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12802 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12803 int f = comp->steps[op->ch2].ch1;
12804
12805 if ((f != -1) &&
12806 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12807 (comp->steps[f].value5 == NULL) &&
12808 (comp->steps[f].value == 0) &&
12809 (comp->steps[f].value4 != NULL) &&
12810 (xmlStrEqual
12811 (comp->steps[f].value4, BAD_CAST "last"))) {
12812 xmlNodePtr last = NULL;
12813
12814 total +=
12815 xmlXPathCompOpEvalLast(ctxt,
12816 &comp->steps[op->ch1],
12817 &last);
12818 CHECK_ERROR0;
12819 /*
12820 * The nodeset should be in document order,
12821 * Keep only the last value
12822 */
12823 if ((ctxt->value != NULL) &&
12824 (ctxt->value->type == XPATH_NODESET) &&
12825 (ctxt->value->nodesetval != NULL) &&
12826 (ctxt->value->nodesetval->nodeTab != NULL) &&
12827 (ctxt->value->nodesetval->nodeNr > 1)) {
12828 ctxt->value->nodesetval->nodeTab[0] =
12829 ctxt->value->nodesetval->nodeTab[ctxt->
12830 value->
12831 nodesetval->
12832 nodeNr -
12833 1];
12834 ctxt->value->nodesetval->nodeNr = 1;
12835 *first = *(ctxt->value->nodesetval->nodeTab);
12836 }
12837 return (total);
12838 }
12839 }
12840
12841 if (op->ch1 != -1)
12842 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12843 CHECK_ERROR0;
12844 if (op->ch2 == -1)
12845 return (total);
12846 if (ctxt->value == NULL)
12847 return (total);
12848
12849#ifdef LIBXML_XPTR_ENABLED
12850 oldnode = ctxt->context->node;
12851 /*
12852 * Hum are we filtering the result of an XPointer expression
12853 */
12854 if (ctxt->value->type == XPATH_LOCATIONSET) {
12855 xmlXPathObjectPtr tmp = NULL;
12856 xmlLocationSetPtr newlocset = NULL;
12857 xmlLocationSetPtr oldlocset;
12858
12859 /*
12860 * Extract the old locset, and then evaluate the result of the
12861 * expression for all the element in the locset. use it to grow
12862 * up a new locset.
12863 */
12864 CHECK_TYPE0(XPATH_LOCATIONSET);
12865 obj = valuePop(ctxt);
12866 oldlocset = obj->user;
12867 ctxt->context->node = NULL;
12868
12869 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12870 ctxt->context->contextSize = 0;
12871 ctxt->context->proximityPosition = 0;
12872 if (op->ch2 != -1)
12873 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12874 res = valuePop(ctxt);
12875 if (res != NULL) {
12876 xmlXPathReleaseObject(ctxt->context, res);
12877 }
12878 valuePush(ctxt, obj);
12879 CHECK_ERROR0;
12880 return (total);
12881 }
12882 newlocset = xmlXPtrLocationSetCreate(NULL);
12883
12884 for (i = 0; i < oldlocset->locNr; i++) {
12885 /*
12886 * Run the evaluation with a node list made of a
12887 * single item in the nodelocset.
12888 */
12889 ctxt->context->node = oldlocset->locTab[i]->user;
12890 ctxt->context->contextSize = oldlocset->locNr;
12891 ctxt->context->proximityPosition = i + 1;
12892 if (tmp == NULL) {
12893 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12894 ctxt->context->node);
12895 } else {
12896 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12897 ctxt->context->node);
12898 }
12899 valuePush(ctxt, tmp);
12900 if (op->ch2 != -1)
12901 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12902 if (ctxt->error != XPATH_EXPRESSION_OK) {
12903 xmlXPathFreeObject(obj);
12904 return(0);
12905 }
12906 /*
12907 * The result of the evaluation need to be tested to
12908 * decided whether the filter succeeded or not
12909 */
12910 res = valuePop(ctxt);
12911 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12912 xmlXPtrLocationSetAdd(newlocset,
12913 xmlXPathCacheObjectCopy(ctxt->context,
12914 oldlocset->locTab[i]));
12915 }
12916 /*
12917 * Cleanup
12918 */
12919 if (res != NULL) {
12920 xmlXPathReleaseObject(ctxt->context, res);
12921 }
12922 if (ctxt->value == tmp) {
12923 valuePop(ctxt);
12924 xmlXPathNodeSetClear(tmp->nodesetval, 1);
12925 /*
12926 * REVISIT TODO: Don't create a temporary nodeset
12927 * for everly iteration.
12928 */
12929 /* OLD: xmlXPathFreeObject(res); */
12930 } else
12931 tmp = NULL;
12932 ctxt->context->node = NULL;
12933 /*
12934 * Only put the first node in the result, then leave.
12935 */
12936 if (newlocset->locNr > 0) {
12937 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
12938 break;
12939 }
12940 }
12941 if (tmp != NULL) {
12942 xmlXPathReleaseObject(ctxt->context, tmp);
12943 }
12944 /*
12945 * The result is used as the new evaluation locset.
12946 */
12947 xmlXPathReleaseObject(ctxt->context, obj);
12948 ctxt->context->node = NULL;
12949 ctxt->context->contextSize = -1;
12950 ctxt->context->proximityPosition = -1;
12951 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12952 ctxt->context->node = oldnode;
12953 return (total);
12954 }
12955#endif /* LIBXML_XPTR_ENABLED */
12956
12957 /*
12958 * Extract the old set, and then evaluate the result of the
12959 * expression for all the element in the set. use it to grow
12960 * up a new set.
12961 */
12962 CHECK_TYPE0(XPATH_NODESET);
12963 obj = valuePop(ctxt);
12964 oldset = obj->nodesetval;
12965
12966 oldnode = ctxt->context->node;
12967 oldDoc = ctxt->context->doc;
12968 ctxt->context->node = NULL;
12969
12970 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
12971 ctxt->context->contextSize = 0;
12972 ctxt->context->proximityPosition = 0;
12973 /* QUESTION TODO: Why was this code commented out?
12974 if (op->ch2 != -1)
12975 total +=
12976 xmlXPathCompOpEval(ctxt,
12977 &comp->steps[op->ch2]);
12978 CHECK_ERROR0;
12979 res = valuePop(ctxt);
12980 if (res != NULL)
12981 xmlXPathFreeObject(res);
12982 */
12983 valuePush(ctxt, obj);
12984 ctxt->context->node = oldnode;
12985 CHECK_ERROR0;
12986 } else {
12987 xmlNodeSetPtr newset;
12988 xmlXPathObjectPtr tmp = NULL;
12989 /*
12990 * Initialize the new set.
12991 * Also set the xpath document in case things like
12992 * key() evaluation are attempted on the predicate
12993 */
12994 newset = xmlXPathNodeSetCreate(NULL);
12995
12996 for (i = 0; i < oldset->nodeNr; i++) {
12997 /*
12998 * Run the evaluation with a node list made of
12999 * a single item in the nodeset.
13000 */
13001 ctxt->context->node = oldset->nodeTab[i];
13002 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13003 (oldset->nodeTab[i]->doc != NULL))
13004 ctxt->context->doc = oldset->nodeTab[i]->doc;
13005 if (tmp == NULL) {
13006 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13007 ctxt->context->node);
13008 } else {
13009 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13010 ctxt->context->node);
13011 }
13012 valuePush(ctxt, tmp);
13013 ctxt->context->contextSize = oldset->nodeNr;
13014 ctxt->context->proximityPosition = i + 1;
13015 if (op->ch2 != -1)
13016 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13017 if (ctxt->error != XPATH_EXPRESSION_OK) {
13018 xmlXPathFreeNodeSet(newset);
13019 xmlXPathFreeObject(obj);
13020 return(0);
13021 }
13022 /*
13023 * The result of the evaluation needs to be tested to
13024 * decide whether the filter succeeded or not
13025 */
13026 res = valuePop(ctxt);
13027 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13028 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13029 }
13030 /*
13031 * Cleanup
13032 */
13033 if (res != NULL) {
13034 xmlXPathReleaseObject(ctxt->context, res);
13035 }
13036 if (ctxt->value == tmp) {
13037 valuePop(ctxt);
13038 /*
13039 * Don't free the temporary nodeset
13040 * in order to avoid massive recreation inside this
13041 * loop.
13042 */
13043 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13044 } else
13045 tmp = NULL;
13046 ctxt->context->node = NULL;
13047 /*
13048 * Only put the first node in the result, then leave.
13049 */
13050 if (newset->nodeNr > 0) {
13051 *first = *(newset->nodeTab);
13052 break;
13053 }
13054 }
13055 if (tmp != NULL) {
13056 xmlXPathReleaseObject(ctxt->context, tmp);
13057 }
13058 /*
13059 * The result is used as the new evaluation set.
13060 */
13061 xmlXPathReleaseObject(ctxt->context, obj);
13062 ctxt->context->node = NULL;
13063 ctxt->context->contextSize = -1;
13064 ctxt->context->proximityPosition = -1;
13065 /* may want to move this past the '}' later */
13066 ctxt->context->doc = oldDoc;
13067 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13068 }
13069 ctxt->context->node = oldnode;
13070 return(total);
13071}
13072#endif /* XP_OPTIMIZED_FILTER_FIRST */
13073
13074/**
13075 * xmlXPathCompOpEval:
13076 * @ctxt: the XPath parser context with the compiled expression
13077 * @op: an XPath compiled operation
13078 *
13079 * Evaluate the Precompiled XPath operation
13080 * Returns the number of nodes traversed
13081 */
13082static int
13083xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13084{
13085 int total = 0;
13086 int equal, ret;
13087 xmlXPathCompExprPtr comp;
13088 xmlXPathObjectPtr arg1, arg2;
13089 xmlNodePtr bak;
13090 xmlDocPtr bakd;
13091 int pp;
13092 int cs;
13093
13094 CHECK_ERROR0;
13095 comp = ctxt->comp;
13096 switch (op->op) {
13097 case XPATH_OP_END:
13098 return (0);
13099 case XPATH_OP_AND:
13100 bakd = ctxt->context->doc;
13101 bak = ctxt->context->node;
13102 pp = ctxt->context->proximityPosition;
13103 cs = ctxt->context->contextSize;
13104 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13105 CHECK_ERROR0;
13106 xmlXPathBooleanFunction(ctxt, 1);
13107 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13108 return (total);
13109 arg2 = valuePop(ctxt);
13110 ctxt->context->doc = bakd;
13111 ctxt->context->node = bak;
13112 ctxt->context->proximityPosition = pp;
13113 ctxt->context->contextSize = cs;
13114 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13115 if (ctxt->error) {
13116 xmlXPathFreeObject(arg2);
13117 return(0);
13118 }
13119 xmlXPathBooleanFunction(ctxt, 1);
13120 arg1 = valuePop(ctxt);
13121 arg1->boolval &= arg2->boolval;
13122 valuePush(ctxt, arg1);
13123 xmlXPathReleaseObject(ctxt->context, arg2);
13124 return (total);
13125 case XPATH_OP_OR:
13126 bakd = ctxt->context->doc;
13127 bak = ctxt->context->node;
13128 pp = ctxt->context->proximityPosition;
13129 cs = ctxt->context->contextSize;
13130 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13131 CHECK_ERROR0;
13132 xmlXPathBooleanFunction(ctxt, 1);
13133 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13134 return (total);
13135 arg2 = valuePop(ctxt);
13136 ctxt->context->doc = bakd;
13137 ctxt->context->node = bak;
13138 ctxt->context->proximityPosition = pp;
13139 ctxt->context->contextSize = cs;
13140 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13141 if (ctxt->error) {
13142 xmlXPathFreeObject(arg2);
13143 return(0);
13144 }
13145 xmlXPathBooleanFunction(ctxt, 1);
13146 arg1 = valuePop(ctxt);
13147 arg1->boolval |= arg2->boolval;
13148 valuePush(ctxt, arg1);
13149 xmlXPathReleaseObject(ctxt->context, arg2);
13150 return (total);
13151 case XPATH_OP_EQUAL:
13152 bakd = ctxt->context->doc;
13153 bak = ctxt->context->node;
13154 pp = ctxt->context->proximityPosition;
13155 cs = ctxt->context->contextSize;
13156 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13157 CHECK_ERROR0;
13158 ctxt->context->doc = bakd;
13159 ctxt->context->node = bak;
13160 ctxt->context->proximityPosition = pp;
13161 ctxt->context->contextSize = cs;
13162 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13163 CHECK_ERROR0;
13164 if (op->value)
13165 equal = xmlXPathEqualValues(ctxt);
13166 else
13167 equal = xmlXPathNotEqualValues(ctxt);
13168 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13169 return (total);
13170 case XPATH_OP_CMP:
13171 bakd = ctxt->context->doc;
13172 bak = ctxt->context->node;
13173 pp = ctxt->context->proximityPosition;
13174 cs = ctxt->context->contextSize;
13175 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13176 CHECK_ERROR0;
13177 ctxt->context->doc = bakd;
13178 ctxt->context->node = bak;
13179 ctxt->context->proximityPosition = pp;
13180 ctxt->context->contextSize = cs;
13181 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13182 CHECK_ERROR0;
13183 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13184 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13185 return (total);
13186 case XPATH_OP_PLUS:
13187 bakd = ctxt->context->doc;
13188 bak = ctxt->context->node;
13189 pp = ctxt->context->proximityPosition;
13190 cs = ctxt->context->contextSize;
13191 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13192 CHECK_ERROR0;
13193 if (op->ch2 != -1) {
13194 ctxt->context->doc = bakd;
13195 ctxt->context->node = bak;
13196 ctxt->context->proximityPosition = pp;
13197 ctxt->context->contextSize = cs;
13198 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13199 }
13200 CHECK_ERROR0;
13201 if (op->value == 0)
13202 xmlXPathSubValues(ctxt);
13203 else if (op->value == 1)
13204 xmlXPathAddValues(ctxt);
13205 else if (op->value == 2)
13206 xmlXPathValueFlipSign(ctxt);
13207 else if (op->value == 3) {
13208 CAST_TO_NUMBER;
13209 CHECK_TYPE0(XPATH_NUMBER);
13210 }
13211 return (total);
13212 case XPATH_OP_MULT:
13213 bakd = ctxt->context->doc;
13214 bak = ctxt->context->node;
13215 pp = ctxt->context->proximityPosition;
13216 cs = ctxt->context->contextSize;
13217 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13218 CHECK_ERROR0;
13219 ctxt->context->doc = bakd;
13220 ctxt->context->node = bak;
13221 ctxt->context->proximityPosition = pp;
13222 ctxt->context->contextSize = cs;
13223 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13224 CHECK_ERROR0;
13225 if (op->value == 0)
13226 xmlXPathMultValues(ctxt);
13227 else if (op->value == 1)
13228 xmlXPathDivValues(ctxt);
13229 else if (op->value == 2)
13230 xmlXPathModValues(ctxt);
13231 return (total);
13232 case XPATH_OP_UNION:
13233 bakd = ctxt->context->doc;
13234 bak = ctxt->context->node;
13235 pp = ctxt->context->proximityPosition;
13236 cs = ctxt->context->contextSize;
13237 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13238 CHECK_ERROR0;
13239 ctxt->context->doc = bakd;
13240 ctxt->context->node = bak;
13241 ctxt->context->proximityPosition = pp;
13242 ctxt->context->contextSize = cs;
13243 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13244 CHECK_ERROR0;
13245 CHECK_TYPE0(XPATH_NODESET);
13246 arg2 = valuePop(ctxt);
13247
13248 CHECK_TYPE0(XPATH_NODESET);
13249 arg1 = valuePop(ctxt);
13250
13251 if ((arg1->nodesetval == NULL) ||
13252 ((arg2->nodesetval != NULL) &&
13253 (arg2->nodesetval->nodeNr != 0)))
13254 {
13255 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13256 arg2->nodesetval);
13257 }
13258
13259 valuePush(ctxt, arg1);
13260 xmlXPathReleaseObject(ctxt->context, arg2);
13261 return (total);
13262 case XPATH_OP_ROOT:
13263 xmlXPathRoot(ctxt);
13264 return (total);
13265 case XPATH_OP_NODE:
13266 if (op->ch1 != -1)
13267 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13268 CHECK_ERROR0;
13269 if (op->ch2 != -1)
13270 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13271 CHECK_ERROR0;
13272 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13273 ctxt->context->node));
13274 return (total);
13275 case XPATH_OP_RESET:
13276 if (op->ch1 != -1)
13277 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13278 CHECK_ERROR0;
13279 if (op->ch2 != -1)
13280 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13281 CHECK_ERROR0;
13282 ctxt->context->node = NULL;
13283 return (total);
13284 case XPATH_OP_COLLECT:{
13285 if (op->ch1 == -1)
13286 return (total);
13287
13288 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13289 CHECK_ERROR0;
13290
13291 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13292 return (total);
13293 }
13294 case XPATH_OP_VALUE:
13295 valuePush(ctxt,
13296 xmlXPathCacheObjectCopy(ctxt->context,
13297 (xmlXPathObjectPtr) op->value4));
13298 return (total);
13299 case XPATH_OP_VARIABLE:{
13300 xmlXPathObjectPtr val;
13301
13302 if (op->ch1 != -1)
13303 total +=
13304 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13305 if (op->value5 == NULL) {
13306 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13307 if (val == NULL) {
13308 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13309 return(0);
13310 }
13311 valuePush(ctxt, val);
13312 } else {
13313 const xmlChar *URI;
13314
13315 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13316 if (URI == NULL) {
13317 xmlGenericError(xmlGenericErrorContext,
13318 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13319 op->value4, op->value5);
13320 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13321 return (total);
13322 }
13323 val = xmlXPathVariableLookupNS(ctxt->context,
13324 op->value4, URI);
13325 if (val == NULL) {
13326 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13327 return(0);
13328 }
13329 valuePush(ctxt, val);
13330 }
13331 return (total);
13332 }
13333 case XPATH_OP_FUNCTION:{
13334 xmlXPathFunction func;
13335 const xmlChar *oldFunc, *oldFuncURI;
13336 int i;
13337
13338 if (op->ch1 != -1)
13339 total +=
13340 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13341 if (ctxt->valueNr < op->value) {
13342 xmlGenericError(xmlGenericErrorContext,
13343 "xmlXPathCompOpEval: parameter error\n");
13344 ctxt->error = XPATH_INVALID_OPERAND;
13345 return (total);
13346 }
13347 for (i = 0; i < op->value; i++)
13348 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13349 xmlGenericError(xmlGenericErrorContext,
13350 "xmlXPathCompOpEval: parameter error\n");
13351 ctxt->error = XPATH_INVALID_OPERAND;
13352 return (total);
13353 }
13354 if (op->cache != NULL)
13355 XML_CAST_FPTR(func) = op->cache;
13356 else {
13357 const xmlChar *URI = NULL;
13358
13359 if (op->value5 == NULL)
13360 func =
13361 xmlXPathFunctionLookup(ctxt->context,
13362 op->value4);
13363 else {
13364 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13365 if (URI == NULL) {
13366 xmlGenericError(xmlGenericErrorContext,
13367 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13368 op->value4, op->value5);
13369 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13370 return (total);
13371 }
13372 func = xmlXPathFunctionLookupNS(ctxt->context,
13373 op->value4, URI);
13374 }
13375 if (func == NULL) {
13376 xmlGenericError(xmlGenericErrorContext,
13377 "xmlXPathCompOpEval: function %s not found\n",
13378 op->value4);
13379 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13380 }
13381 op->cache = XML_CAST_FPTR(func);
13382 op->cacheURI = (void *) URI;
13383 }
13384 oldFunc = ctxt->context->function;
13385 oldFuncURI = ctxt->context->functionURI;
13386 ctxt->context->function = op->value4;
13387 ctxt->context->functionURI = op->cacheURI;
13388 func(ctxt, op->value);
13389 ctxt->context->function = oldFunc;
13390 ctxt->context->functionURI = oldFuncURI;
13391 return (total);
13392 }
13393 case XPATH_OP_ARG:
13394 bakd = ctxt->context->doc;
13395 bak = ctxt->context->node;
13396 pp = ctxt->context->proximityPosition;
13397 cs = ctxt->context->contextSize;
13398 if (op->ch1 != -1)
13399 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13400 ctxt->context->contextSize = cs;
13401 ctxt->context->proximityPosition = pp;
13402 ctxt->context->node = bak;
13403 ctxt->context->doc = bakd;
13404 CHECK_ERROR0;
13405 if (op->ch2 != -1) {
13406 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13407 ctxt->context->doc = bakd;
13408 ctxt->context->node = bak;
13409 CHECK_ERROR0;
13410 }
13411 return (total);
13412 case XPATH_OP_PREDICATE:
13413 case XPATH_OP_FILTER:{
13414 xmlXPathObjectPtr res;
13415 xmlXPathObjectPtr obj, tmp;
13416 xmlNodeSetPtr newset = NULL;
13417 xmlNodeSetPtr oldset;
13418 xmlNodePtr oldnode;
13419 xmlDocPtr oldDoc;
13420 int i;
13421
13422 /*
13423 * Optimization for ()[1] selection i.e. the first elem
13424 */
13425 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13426#ifdef XP_OPTIMIZED_FILTER_FIRST
13427 /*
13428 * FILTER TODO: Can we assume that the inner processing
13429 * will result in an ordered list if we have an
13430 * XPATH_OP_FILTER?
13431 * What about an additional field or flag on
13432 * xmlXPathObject like @sorted ? This way we wouln'd need
13433 * to assume anything, so it would be more robust and
13434 * easier to optimize.
13435 */
13436 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13437 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13438#else
13439 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13440#endif
13441 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13442 xmlXPathObjectPtr val;
13443
13444 val = comp->steps[op->ch2].value4;
13445 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13446 (val->floatval == 1.0)) {
13447 xmlNodePtr first = NULL;
13448
13449 total +=
13450 xmlXPathCompOpEvalFirst(ctxt,
13451 &comp->steps[op->ch1],
13452 &first);
13453 CHECK_ERROR0;
13454 /*
13455 * The nodeset should be in document order,
13456 * Keep only the first value
13457 */
13458 if ((ctxt->value != NULL) &&
13459 (ctxt->value->type == XPATH_NODESET) &&
13460 (ctxt->value->nodesetval != NULL) &&
13461 (ctxt->value->nodesetval->nodeNr > 1))
13462 ctxt->value->nodesetval->nodeNr = 1;
13463 return (total);
13464 }
13465 }
13466 /*
13467 * Optimization for ()[last()] selection i.e. the last elem
13468 */
13469 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13470 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13471 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13472 int f = comp->steps[op->ch2].ch1;
13473
13474 if ((f != -1) &&
13475 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13476 (comp->steps[f].value5 == NULL) &&
13477 (comp->steps[f].value == 0) &&
13478 (comp->steps[f].value4 != NULL) &&
13479 (xmlStrEqual
13480 (comp->steps[f].value4, BAD_CAST "last"))) {
13481 xmlNodePtr last = NULL;
13482
13483 total +=
13484 xmlXPathCompOpEvalLast(ctxt,
13485 &comp->steps[op->ch1],
13486 &last);
13487 CHECK_ERROR0;
13488 /*
13489 * The nodeset should be in document order,
13490 * Keep only the last value
13491 */
13492 if ((ctxt->value != NULL) &&
13493 (ctxt->value->type == XPATH_NODESET) &&
13494 (ctxt->value->nodesetval != NULL) &&
13495 (ctxt->value->nodesetval->nodeTab != NULL) &&
13496 (ctxt->value->nodesetval->nodeNr > 1)) {
13497 ctxt->value->nodesetval->nodeTab[0] =
13498 ctxt->value->nodesetval->nodeTab[ctxt->
13499 value->
13500 nodesetval->
13501 nodeNr -
13502 1];
13503 ctxt->value->nodesetval->nodeNr = 1;
13504 }
13505 return (total);
13506 }
13507 }
13508 /*
13509 * Process inner predicates first.
13510 * Example "index[parent::book][1]":
13511 * ...
13512 * PREDICATE <-- we are here "[1]"
13513 * PREDICATE <-- process "[parent::book]" first
13514 * SORT
13515 * COLLECT 'parent' 'name' 'node' book
13516 * NODE
13517 * ELEM Object is a number : 1
13518 */
13519 if (op->ch1 != -1)
13520 total +=
13521 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13522 CHECK_ERROR0;
13523 if (op->ch2 == -1)
13524 return (total);
13525 if (ctxt->value == NULL)
13526 return (total);
13527
13528 oldnode = ctxt->context->node;
13529
13530#ifdef LIBXML_XPTR_ENABLED
13531 /*
13532 * Hum are we filtering the result of an XPointer expression
13533 */
13534 if (ctxt->value->type == XPATH_LOCATIONSET) {
13535 xmlLocationSetPtr newlocset = NULL;
13536 xmlLocationSetPtr oldlocset;
13537
13538 /*
13539 * Extract the old locset, and then evaluate the result of the
13540 * expression for all the element in the locset. use it to grow
13541 * up a new locset.
13542 */
13543 CHECK_TYPE0(XPATH_LOCATIONSET);
13544 obj = valuePop(ctxt);
13545 oldlocset = obj->user;
13546 ctxt->context->node = NULL;
13547
13548 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13549 ctxt->context->contextSize = 0;
13550 ctxt->context->proximityPosition = 0;
13551 if (op->ch2 != -1)
13552 total +=
13553 xmlXPathCompOpEval(ctxt,
13554 &comp->steps[op->ch2]);
13555 res = valuePop(ctxt);
13556 if (res != NULL) {
13557 xmlXPathReleaseObject(ctxt->context, res);
13558 }
13559 valuePush(ctxt, obj);
13560 CHECK_ERROR0;
13561 return (total);
13562 }
13563 newlocset = xmlXPtrLocationSetCreate(NULL);
13564
13565 for (i = 0; i < oldlocset->locNr; i++) {
13566 /*
13567 * Run the evaluation with a node list made of a
13568 * single item in the nodelocset.
13569 */
13570 ctxt->context->node = oldlocset->locTab[i]->user;
13571 ctxt->context->contextSize = oldlocset->locNr;
13572 ctxt->context->proximityPosition = i + 1;
13573 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13574 ctxt->context->node);
13575 valuePush(ctxt, tmp);
13576
13577 if (op->ch2 != -1)
13578 total +=
13579 xmlXPathCompOpEval(ctxt,
13580 &comp->steps[op->ch2]);
13581 if (ctxt->error != XPATH_EXPRESSION_OK) {
13582 xmlXPathFreeObject(obj);
13583 return(0);
13584 }
13585
13586 /*
13587 * The result of the evaluation need to be tested to
13588 * decided whether the filter succeeded or not
13589 */
13590 res = valuePop(ctxt);
13591 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13592 xmlXPtrLocationSetAdd(newlocset,
13593 xmlXPathObjectCopy
13594 (oldlocset->locTab[i]));
13595 }
13596
13597 /*
13598 * Cleanup
13599 */
13600 if (res != NULL) {
13601 xmlXPathReleaseObject(ctxt->context, res);
13602 }
13603 if (ctxt->value == tmp) {
13604 res = valuePop(ctxt);
13605 xmlXPathReleaseObject(ctxt->context, res);
13606 }
13607
13608 ctxt->context->node = NULL;
13609 }
13610
13611 /*
13612 * The result is used as the new evaluation locset.
13613 */
13614 xmlXPathReleaseObject(ctxt->context, obj);
13615 ctxt->context->node = NULL;
13616 ctxt->context->contextSize = -1;
13617 ctxt->context->proximityPosition = -1;
13618 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13619 ctxt->context->node = oldnode;
13620 return (total);
13621 }
13622#endif /* LIBXML_XPTR_ENABLED */
13623
13624 /*
13625 * Extract the old set, and then evaluate the result of the
13626 * expression for all the element in the set. use it to grow
13627 * up a new set.
13628 */
13629 CHECK_TYPE0(XPATH_NODESET);
13630 obj = valuePop(ctxt);
13631 oldset = obj->nodesetval;
13632
13633 oldnode = ctxt->context->node;
13634 oldDoc = ctxt->context->doc;
13635 ctxt->context->node = NULL;
13636
13637 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13638 ctxt->context->contextSize = 0;
13639 ctxt->context->proximityPosition = 0;
13640/*
13641 if (op->ch2 != -1)
13642 total +=
13643 xmlXPathCompOpEval(ctxt,
13644 &comp->steps[op->ch2]);
13645 CHECK_ERROR0;
13646 res = valuePop(ctxt);
13647 if (res != NULL)
13648 xmlXPathFreeObject(res);
13649*/
13650 valuePush(ctxt, obj);
13651 ctxt->context->node = oldnode;
13652 CHECK_ERROR0;
13653 } else {
13654 tmp = NULL;
13655 /*
13656 * Initialize the new set.
13657 * Also set the xpath document in case things like
13658 * key() evaluation are attempted on the predicate
13659 */
13660 newset = xmlXPathNodeSetCreate(NULL);
13661 /*
13662 * SPEC XPath 1.0:
13663 * "For each node in the node-set to be filtered, the
13664 * PredicateExpr is evaluated with that node as the
13665 * context node, with the number of nodes in the
13666 * node-set as the context size, and with the proximity
13667 * position of the node in the node-set with respect to
13668 * the axis as the context position;"
13669 * @oldset is the node-set" to be filtered.
13670 *
13671 * SPEC XPath 1.0:
13672 * "only predicates change the context position and
13673 * context size (see [2.4 Predicates])."
13674 * Example:
13675 * node-set context pos
13676 * nA 1
13677 * nB 2
13678 * nC 3
13679 * After applying predicate [position() > 1] :
13680 * node-set context pos
13681 * nB 1
13682 * nC 2
13683 *
13684 * removed the first node in the node-set, then
13685 * the context position of the
13686 */
13687 for (i = 0; i < oldset->nodeNr; i++) {
13688 /*
13689 * Run the evaluation with a node list made of
13690 * a single item in the nodeset.
13691 */
13692 ctxt->context->node = oldset->nodeTab[i];
13693 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13694 (oldset->nodeTab[i]->doc != NULL))
13695 ctxt->context->doc = oldset->nodeTab[i]->doc;
13696 if (tmp == NULL) {
13697 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13698 ctxt->context->node);
13699 } else {
13700 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13701 ctxt->context->node);
13702 }
13703 valuePush(ctxt, tmp);
13704 ctxt->context->contextSize = oldset->nodeNr;
13705 ctxt->context->proximityPosition = i + 1;
13706 /*
13707 * Evaluate the predicate against the context node.
13708 * Can/should we optimize position() predicates
13709 * here (e.g. "[1]")?
13710 */
13711 if (op->ch2 != -1)
13712 total +=
13713 xmlXPathCompOpEval(ctxt,
13714 &comp->steps[op->ch2]);
13715 if (ctxt->error != XPATH_EXPRESSION_OK) {
13716 xmlXPathFreeNodeSet(newset);
13717 xmlXPathFreeObject(obj);
13718 return(0);
13719 }
13720
13721 /*
13722 * The result of the evaluation needs to be tested to
13723 * decide whether the filter succeeded or not
13724 */
13725 /*
13726 * OPTIMIZE TODO: Can we use
13727 * xmlXPathNodeSetAdd*Unique()* instead?
13728 */
13729 res = valuePop(ctxt);
13730 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13731 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13732 }
13733
13734 /*
13735 * Cleanup
13736 */
13737 if (res != NULL) {
13738 xmlXPathReleaseObject(ctxt->context, res);
13739 }
13740 if (ctxt->value == tmp) {
13741 valuePop(ctxt);
13742 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13743 /*
13744 * Don't free the temporary nodeset
13745 * in order to avoid massive recreation inside this
13746 * loop.
13747 */
13748 } else
13749 tmp = NULL;
13750 ctxt->context->node = NULL;
13751 }
13752 if (tmp != NULL)
13753 xmlXPathReleaseObject(ctxt->context, tmp);
13754 /*
13755 * The result is used as the new evaluation set.
13756 */
13757 xmlXPathReleaseObject(ctxt->context, obj);
13758 ctxt->context->node = NULL;
13759 ctxt->context->contextSize = -1;
13760 ctxt->context->proximityPosition = -1;
13761 /* may want to move this past the '}' later */
13762 ctxt->context->doc = oldDoc;
13763 valuePush(ctxt,
13764 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13765 }
13766 ctxt->context->node = oldnode;
13767 return (total);
13768 }
13769 case XPATH_OP_SORT:
13770 if (op->ch1 != -1)
13771 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13772 CHECK_ERROR0;
13773 if ((ctxt->value != NULL) &&
13774 (ctxt->value->type == XPATH_NODESET) &&
13775 (ctxt->value->nodesetval != NULL) &&
13776 (ctxt->value->nodesetval->nodeNr > 1))
13777 {
13778 xmlXPathNodeSetSort(ctxt->value->nodesetval);
13779 }
13780 return (total);
13781#ifdef LIBXML_XPTR_ENABLED
13782 case XPATH_OP_RANGETO:{
13783 xmlXPathObjectPtr range;
13784 xmlXPathObjectPtr res, obj;
13785 xmlXPathObjectPtr tmp;
13786 xmlLocationSetPtr newlocset = NULL;
13787 xmlLocationSetPtr oldlocset;
13788 xmlNodeSetPtr oldset;
13789 int i, j;
13790
13791 if (op->ch1 != -1)
13792 total +=
13793 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13794 if (op->ch2 == -1)
13795 return (total);
13796
13797 if (ctxt->value->type == XPATH_LOCATIONSET) {
13798 /*
13799 * Extract the old locset, and then evaluate the result of the
13800 * expression for all the element in the locset. use it to grow
13801 * up a new locset.
13802 */
13803 CHECK_TYPE0(XPATH_LOCATIONSET);
13804 obj = valuePop(ctxt);
13805 oldlocset = obj->user;
13806
13807 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13808 ctxt->context->node = NULL;
13809 ctxt->context->contextSize = 0;
13810 ctxt->context->proximityPosition = 0;
13811 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13812 res = valuePop(ctxt);
13813 if (res != NULL) {
13814 xmlXPathReleaseObject(ctxt->context, res);
13815 }
13816 valuePush(ctxt, obj);
13817 CHECK_ERROR0;
13818 return (total);
13819 }
13820 newlocset = xmlXPtrLocationSetCreate(NULL);
13821
13822 for (i = 0; i < oldlocset->locNr; i++) {
13823 /*
13824 * Run the evaluation with a node list made of a
13825 * single item in the nodelocset.
13826 */
13827 ctxt->context->node = oldlocset->locTab[i]->user;
13828 ctxt->context->contextSize = oldlocset->locNr;
13829 ctxt->context->proximityPosition = i + 1;
13830 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13831 ctxt->context->node);
13832 valuePush(ctxt, tmp);
13833
13834 if (op->ch2 != -1)
13835 total +=
13836 xmlXPathCompOpEval(ctxt,
13837 &comp->steps[op->ch2]);
13838 if (ctxt->error != XPATH_EXPRESSION_OK) {
13839 xmlXPathFreeObject(obj);
13840 return(0);
13841 }
13842
13843 res = valuePop(ctxt);
13844 if (res->type == XPATH_LOCATIONSET) {
13845 xmlLocationSetPtr rloc =
13846 (xmlLocationSetPtr)res->user;
13847 for (j=0; j<rloc->locNr; j++) {
13848 range = xmlXPtrNewRange(
13849 oldlocset->locTab[i]->user,
13850 oldlocset->locTab[i]->index,
13851 rloc->locTab[j]->user2,
13852 rloc->locTab[j]->index2);
13853 if (range != NULL) {
13854 xmlXPtrLocationSetAdd(newlocset, range);
13855 }
13856 }
13857 } else {
13858 range = xmlXPtrNewRangeNodeObject(
13859 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13860 if (range != NULL) {
13861 xmlXPtrLocationSetAdd(newlocset,range);
13862 }
13863 }
13864
13865 /*
13866 * Cleanup
13867 */
13868 if (res != NULL) {
13869 xmlXPathReleaseObject(ctxt->context, res);
13870 }
13871 if (ctxt->value == tmp) {
13872 res = valuePop(ctxt);
13873 xmlXPathReleaseObject(ctxt->context, res);
13874 }
13875
13876 ctxt->context->node = NULL;
13877 }
13878 } else { /* Not a location set */
13879 CHECK_TYPE0(XPATH_NODESET);
13880 obj = valuePop(ctxt);
13881 oldset = obj->nodesetval;
13882 ctxt->context->node = NULL;
13883
13884 newlocset = xmlXPtrLocationSetCreate(NULL);
13885
13886 if (oldset != NULL) {
13887 for (i = 0; i < oldset->nodeNr; i++) {
13888 /*
13889 * Run the evaluation with a node list made of a single item
13890 * in the nodeset.
13891 */
13892 ctxt->context->node = oldset->nodeTab[i];
13893 /*
13894 * OPTIMIZE TODO: Avoid recreation for every iteration.
13895 */
13896 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13897 ctxt->context->node);
13898 valuePush(ctxt, tmp);
13899
13900 if (op->ch2 != -1)
13901 total +=
13902 xmlXPathCompOpEval(ctxt,
13903 &comp->steps[op->ch2]);
13904 if (ctxt->error != XPATH_EXPRESSION_OK) {
13905 xmlXPathFreeObject(obj);
13906 return(0);
13907 }
13908
13909 res = valuePop(ctxt);
13910 range =
13911 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13912 res);
13913 if (range != NULL) {
13914 xmlXPtrLocationSetAdd(newlocset, range);
13915 }
13916
13917 /*
13918 * Cleanup
13919 */
13920 if (res != NULL) {
13921 xmlXPathReleaseObject(ctxt->context, res);
13922 }
13923 if (ctxt->value == tmp) {
13924 res = valuePop(ctxt);
13925 xmlXPathReleaseObject(ctxt->context, res);
13926 }
13927
13928 ctxt->context->node = NULL;
13929 }
13930 }
13931 }
13932
13933 /*
13934 * The result is used as the new evaluation set.
13935 */
13936 xmlXPathReleaseObject(ctxt->context, obj);
13937 ctxt->context->node = NULL;
13938 ctxt->context->contextSize = -1;
13939 ctxt->context->proximityPosition = -1;
13940 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13941 return (total);
13942 }
13943#endif /* LIBXML_XPTR_ENABLED */
13944 }
13945 xmlGenericError(xmlGenericErrorContext,
13946 "XPath: unknown precompiled operation %d\n", op->op);
13947 ctxt->error = XPATH_INVALID_OPERAND;
13948 return (total);
13949}
13950
13951/**
13952 * xmlXPathCompOpEvalToBoolean:
13953 * @ctxt: the XPath parser context
13954 *
13955 * Evaluates if the expression evaluates to true.
13956 *
13957 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13958 */
13959static int
13960xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13961 xmlXPathStepOpPtr op,
13962 int isPredicate)
13963{
13964 xmlXPathObjectPtr resObj = NULL;
13965
13966start:
13967 /* comp = ctxt->comp; */
13968 switch (op->op) {
13969 case XPATH_OP_END:
13970 return (0);
13971 case XPATH_OP_VALUE:
13972 resObj = (xmlXPathObjectPtr) op->value4;
13973 if (isPredicate)
13974 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13975 return(xmlXPathCastToBoolean(resObj));
13976 case XPATH_OP_SORT:
13977 /*
13978 * We don't need sorting for boolean results. Skip this one.
13979 */
13980 if (op->ch1 != -1) {
13981 op = &ctxt->comp->steps[op->ch1];
13982 goto start;
13983 }
13984 return(0);
13985 case XPATH_OP_COLLECT:
13986 if (op->ch1 == -1)
13987 return(0);
13988
13989 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13990 if (ctxt->error != XPATH_EXPRESSION_OK)
13991 return(-1);
13992
13993 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13994 if (ctxt->error != XPATH_EXPRESSION_OK)
13995 return(-1);
13996
13997 resObj = valuePop(ctxt);
13998 if (resObj == NULL)
13999 return(-1);
14000 break;
14001 default:
14002 /*
14003 * Fallback to call xmlXPathCompOpEval().
14004 */
14005 xmlXPathCompOpEval(ctxt, op);
14006 if (ctxt->error != XPATH_EXPRESSION_OK)
14007 return(-1);
14008
14009 resObj = valuePop(ctxt);
14010 if (resObj == NULL)
14011 return(-1);
14012 break;
14013 }
14014
14015 if (resObj) {
14016 int res;
14017
14018 if (resObj->type == XPATH_BOOLEAN) {
14019 res = resObj->boolval;
14020 } else if (isPredicate) {
14021 /*
14022 * For predicates a result of type "number" is handled
14023 * differently:
14024 * SPEC XPath 1.0:
14025 * "If the result is a number, the result will be converted
14026 * to true if the number is equal to the context position
14027 * and will be converted to false otherwise;"
14028 */
14029 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14030 } else {
14031 res = xmlXPathCastToBoolean(resObj);
14032 }
14033 xmlXPathReleaseObject(ctxt->context, resObj);
14034 return(res);
14035 }
14036
14037 return(0);
14038}
14039
14040#ifdef XPATH_STREAMING
14041/**
14042 * xmlXPathRunStreamEval:
14043 * @ctxt: the XPath parser context with the compiled expression
14044 *
14045 * Evaluate the Precompiled Streamable XPath expression in the given context.
14046 */
14047static int
14048xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14049 xmlXPathObjectPtr *resultSeq, int toBool)
14050{
14051 int max_depth, min_depth;
14052 int from_root;
14053 int ret, depth;
14054 int eval_all_nodes;
14055 xmlNodePtr cur = NULL, limit = NULL;
14056 xmlStreamCtxtPtr patstream = NULL;
14057
14058 int nb_nodes = 0;
14059
14060 if ((ctxt == NULL) || (comp == NULL))
14061 return(-1);
14062 max_depth = xmlPatternMaxDepth(comp);
14063 if (max_depth == -1)
14064 return(-1);
14065 if (max_depth == -2)
14066 max_depth = 10000;
14067 min_depth = xmlPatternMinDepth(comp);
14068 if (min_depth == -1)
14069 return(-1);
14070 from_root = xmlPatternFromRoot(comp);
14071 if (from_root < 0)
14072 return(-1);
14073#if 0
14074 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14075#endif
14076
14077 if (! toBool) {
14078 if (resultSeq == NULL)
14079 return(-1);
14080 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14081 if (*resultSeq == NULL)
14082 return(-1);
14083 }
14084
14085 /*
14086 * handle the special cases of "/" amd "." being matched
14087 */
14088 if (min_depth == 0) {
14089 if (from_root) {
14090 /* Select "/" */
14091 if (toBool)
14092 return(1);
14093 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14094 (xmlNodePtr) ctxt->doc);
14095 } else {
14096 /* Select "self::node()" */
14097 if (toBool)
14098 return(1);
14099 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14100 }
14101 }
14102 if (max_depth == 0) {
14103 return(0);
14104 }
14105
14106 if (from_root) {
14107 cur = (xmlNodePtr)ctxt->doc;
14108 } else if (ctxt->node != NULL) {
14109 switch (ctxt->node->type) {
14110 case XML_ELEMENT_NODE:
14111 case XML_DOCUMENT_NODE:
14112 case XML_DOCUMENT_FRAG_NODE:
14113 case XML_HTML_DOCUMENT_NODE:
14114#ifdef LIBXML_DOCB_ENABLED
14115 case XML_DOCB_DOCUMENT_NODE:
14116#endif
14117 cur = ctxt->node;
14118 break;
14119 case XML_ATTRIBUTE_NODE:
14120 case XML_TEXT_NODE:
14121 case XML_CDATA_SECTION_NODE:
14122 case XML_ENTITY_REF_NODE:
14123 case XML_ENTITY_NODE:
14124 case XML_PI_NODE:
14125 case XML_COMMENT_NODE:
14126 case XML_NOTATION_NODE:
14127 case XML_DTD_NODE:
14128 case XML_DOCUMENT_TYPE_NODE:
14129 case XML_ELEMENT_DECL:
14130 case XML_ATTRIBUTE_DECL:
14131 case XML_ENTITY_DECL:
14132 case XML_NAMESPACE_DECL:
14133 case XML_XINCLUDE_START:
14134 case XML_XINCLUDE_END:
14135 break;
14136 }
14137 limit = cur;
14138 }
14139 if (cur == NULL) {
14140 return(0);
14141 }
14142
14143 patstream = xmlPatternGetStreamCtxt(comp);
14144 if (patstream == NULL) {
14145 /*
14146 * QUESTION TODO: Is this an error?
14147 */
14148 return(0);
14149 }
14150
14151 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14152
14153 if (from_root) {
14154 ret = xmlStreamPush(patstream, NULL, NULL);
14155 if (ret < 0) {
14156 } else if (ret == 1) {
14157 if (toBool)
14158 goto return_1;
14159 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14160 }
14161 }
14162 depth = 0;
14163 goto scan_children;
14164next_node:
14165 do {
14166 nb_nodes++;
14167
14168 switch (cur->type) {
14169 case XML_ELEMENT_NODE:
14170 case XML_TEXT_NODE:
14171 case XML_CDATA_SECTION_NODE:
14172 case XML_COMMENT_NODE:
14173 case XML_PI_NODE:
14174 if (cur->type == XML_ELEMENT_NODE) {
14175 ret = xmlStreamPush(patstream, cur->name,
14176 (cur->ns ? cur->ns->href : NULL));
14177 } else if (eval_all_nodes)
14178 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14179 else
14180 break;
14181
14182 if (ret < 0) {
14183 /* NOP. */
14184 } else if (ret == 1) {
14185 if (toBool)
14186 goto return_1;
14187 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14188 }
14189 if ((cur->children == NULL) || (depth >= max_depth)) {
14190 ret = xmlStreamPop(patstream);
14191 while (cur->next != NULL) {
14192 cur = cur->next;
14193 if ((cur->type != XML_ENTITY_DECL) &&
14194 (cur->type != XML_DTD_NODE))
14195 goto next_node;
14196 }
14197 }
14198 default:
14199 break;
14200 }
14201
14202scan_children:
14203 if ((cur->children != NULL) && (depth < max_depth)) {
14204 /*
14205 * Do not descend on entities declarations
14206 */
14207 if (cur->children->type != XML_ENTITY_DECL) {
14208 cur = cur->children;
14209 depth++;
14210 /*
14211 * Skip DTDs
14212 */
14213 if (cur->type != XML_DTD_NODE)
14214 continue;
14215 }
14216 }
14217
14218 if (cur == limit)
14219 break;
14220
14221 while (cur->next != NULL) {
14222 cur = cur->next;
14223 if ((cur->type != XML_ENTITY_DECL) &&
14224 (cur->type != XML_DTD_NODE))
14225 goto next_node;
14226 }
14227
14228 do {
14229 cur = cur->parent;
14230 depth--;
14231 if ((cur == NULL) || (cur == limit))
14232 goto done;
14233 if (cur->type == XML_ELEMENT_NODE) {
14234 ret = xmlStreamPop(patstream);
14235 } else if ((eval_all_nodes) &&
14236 ((cur->type == XML_TEXT_NODE) ||
14237 (cur->type == XML_CDATA_SECTION_NODE) ||
14238 (cur->type == XML_COMMENT_NODE) ||
14239 (cur->type == XML_PI_NODE)))
14240 {
14241 ret = xmlStreamPop(patstream);
14242 }
14243 if (cur->next != NULL) {
14244 cur = cur->next;
14245 break;
14246 }
14247 } while (cur != NULL);
14248
14249 } while ((cur != NULL) && (depth >= 0));
14250
14251done:
14252
14253#if 0
14254 printf("stream eval: checked %d nodes selected %d\n",
14255 nb_nodes, retObj->nodesetval->nodeNr);
14256#endif
14257
14258 if (patstream)
14259 xmlFreeStreamCtxt(patstream);
14260 return(0);
14261
14262return_1:
14263 if (patstream)
14264 xmlFreeStreamCtxt(patstream);
14265 return(1);
14266}
14267#endif /* XPATH_STREAMING */
14268
14269/**
14270 * xmlXPathRunEval:
14271 * @ctxt: the XPath parser context with the compiled expression
14272 * @toBool: evaluate to a boolean result
14273 *
14274 * Evaluate the Precompiled XPath expression in the given context.
14275 */
14276static int
14277xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14278{
14279 xmlXPathCompExprPtr comp;
14280
14281 if ((ctxt == NULL) || (ctxt->comp == NULL))
14282 return(-1);
14283
14284 if (ctxt->valueTab == NULL) {
14285 /* Allocate the value stack */
14286 ctxt->valueTab = (xmlXPathObjectPtr *)
14287 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14288 if (ctxt->valueTab == NULL) {
14289 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14290 xmlFree(ctxt);
14291 }
14292 ctxt->valueNr = 0;
14293 ctxt->valueMax = 10;
14294 ctxt->value = NULL;
14295 }
14296#ifdef XPATH_STREAMING
14297 if (ctxt->comp->stream) {
14298 int res;
14299
14300 if (toBool) {
14301 /*
14302 * Evaluation to boolean result.
14303 */
14304 res = xmlXPathRunStreamEval(ctxt->context,
14305 ctxt->comp->stream, NULL, 1);
14306 if (res != -1)
14307 return(res);
14308 } else {
14309 xmlXPathObjectPtr resObj = NULL;
14310
14311 /*
14312 * Evaluation to a sequence.
14313 */
14314 res = xmlXPathRunStreamEval(ctxt->context,
14315 ctxt->comp->stream, &resObj, 0);
14316
14317 if ((res != -1) && (resObj != NULL)) {
14318 valuePush(ctxt, resObj);
14319 return(0);
14320 }
14321 if (resObj != NULL)
14322 xmlXPathReleaseObject(ctxt->context, resObj);
14323 }
14324 /*
14325 * QUESTION TODO: This falls back to normal XPath evaluation
14326 * if res == -1. Is this intended?
14327 */
14328 }
14329#endif
14330 comp = ctxt->comp;
14331 if (comp->last < 0) {
14332 xmlGenericError(xmlGenericErrorContext,
14333 "xmlXPathRunEval: last is less than zero\n");
14334 return(-1);
14335 }
14336 if (toBool)
14337 return(xmlXPathCompOpEvalToBoolean(ctxt,
14338 &comp->steps[comp->last], 0));
14339 else
14340 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14341
14342 return(0);
14343}
14344
14345/************************************************************************
14346 * *
14347 * Public interfaces *
14348 * *
14349 ************************************************************************/
14350
14351/**
14352 * xmlXPathEvalPredicate:
14353 * @ctxt: the XPath context
14354 * @res: the Predicate Expression evaluation result
14355 *
14356 * Evaluate a predicate result for the current node.
14357 * A PredicateExpr is evaluated by evaluating the Expr and converting
14358 * the result to a boolean. If the result is a number, the result will
14359 * be converted to true if the number is equal to the position of the
14360 * context node in the context node list (as returned by the position
14361 * function) and will be converted to false otherwise; if the result
14362 * is not a number, then the result will be converted as if by a call
14363 * to the boolean function.
14364 *
14365 * Returns 1 if predicate is true, 0 otherwise
14366 */
14367int
14368xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14369 if ((ctxt == NULL) || (res == NULL)) return(0);
14370 switch (res->type) {
14371 case XPATH_BOOLEAN:
14372 return(res->boolval);
14373 case XPATH_NUMBER:
14374 return(res->floatval == ctxt->proximityPosition);
14375 case XPATH_NODESET:
14376 case XPATH_XSLT_TREE:
14377 if (res->nodesetval == NULL)
14378 return(0);
14379 return(res->nodesetval->nodeNr != 0);
14380 case XPATH_STRING:
14381 return((res->stringval != NULL) &&
14382 (xmlStrlen(res->stringval) != 0));
14383 default:
14384 STRANGE
14385 }
14386 return(0);
14387}
14388
14389/**
14390 * xmlXPathEvaluatePredicateResult:
14391 * @ctxt: the XPath Parser context
14392 * @res: the Predicate Expression evaluation result
14393 *
14394 * Evaluate a predicate result for the current node.
14395 * A PredicateExpr is evaluated by evaluating the Expr and converting
14396 * the result to a boolean. If the result is a number, the result will
14397 * be converted to true if the number is equal to the position of the
14398 * context node in the context node list (as returned by the position
14399 * function) and will be converted to false otherwise; if the result
14400 * is not a number, then the result will be converted as if by a call
14401 * to the boolean function.
14402 *
14403 * Returns 1 if predicate is true, 0 otherwise
14404 */
14405int
14406xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14407 xmlXPathObjectPtr res) {
14408 if ((ctxt == NULL) || (res == NULL)) return(0);
14409 switch (res->type) {
14410 case XPATH_BOOLEAN:
14411 return(res->boolval);
14412 case XPATH_NUMBER:
14413#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14414 return((res->floatval == ctxt->context->proximityPosition) &&
14415 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14416#else
14417 return(res->floatval == ctxt->context->proximityPosition);
14418#endif
14419 case XPATH_NODESET:
14420 case XPATH_XSLT_TREE:
14421 if (res->nodesetval == NULL)
14422 return(0);
14423 return(res->nodesetval->nodeNr != 0);
14424 case XPATH_STRING:
14425 return((res->stringval != NULL) && (res->stringval[0] != 0));
14426#ifdef LIBXML_XPTR_ENABLED
14427 case XPATH_LOCATIONSET:{
14428 xmlLocationSetPtr ptr = res->user;
14429 if (ptr == NULL)
14430 return(0);
14431 return (ptr->locNr != 0);
14432 }
14433#endif
14434 default:
14435 STRANGE
14436 }
14437 return(0);
14438}
14439
14440#ifdef XPATH_STREAMING
14441/**
14442 * xmlXPathTryStreamCompile:
14443 * @ctxt: an XPath context
14444 * @str: the XPath expression
14445 *
14446 * Try to compile the XPath expression as a streamable subset.
14447 *
14448 * Returns the compiled expression or NULL if failed to compile.
14449 */
14450static xmlXPathCompExprPtr
14451xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14452 /*
14453 * Optimization: use streaming patterns when the XPath expression can
14454 * be compiled to a stream lookup
14455 */
14456 xmlPatternPtr stream;
14457 xmlXPathCompExprPtr comp;
14458 xmlDictPtr dict = NULL;
14459 const xmlChar **namespaces = NULL;
14460 xmlNsPtr ns;
14461 int i, j;
14462
14463 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14464 (!xmlStrchr(str, '@'))) {
14465 const xmlChar *tmp;
14466
14467 /*
14468 * We don't try to handle expressions using the verbose axis
14469 * specifiers ("::"), just the simplied form at this point.
14470 * Additionally, if there is no list of namespaces available and
14471 * there's a ":" in the expression, indicating a prefixed QName,
14472 * then we won't try to compile either. xmlPatterncompile() needs
14473 * to have a list of namespaces at compilation time in order to
14474 * compile prefixed name tests.
14475 */
14476 tmp = xmlStrchr(str, ':');
14477 if ((tmp != NULL) &&
14478 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14479 return(NULL);
14480
14481 if (ctxt != NULL) {
14482 dict = ctxt->dict;
14483 if (ctxt->nsNr > 0) {
14484 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14485 if (namespaces == NULL) {
14486 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14487 return(NULL);
14488 }
14489 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14490 ns = ctxt->namespaces[j];
14491 namespaces[i++] = ns->href;
14492 namespaces[i++] = ns->prefix;
14493 }
14494 namespaces[i++] = NULL;
14495 namespaces[i++] = NULL;
14496 }
14497 }
14498
14499 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14500 &namespaces[0]);
14501 if (namespaces != NULL) {
14502 xmlFree((xmlChar **)namespaces);
14503 }
14504 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14505 comp = xmlXPathNewCompExpr();
14506 if (comp == NULL) {
14507 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14508 return(NULL);
14509 }
14510 comp->stream = stream;
14511 comp->dict = dict;
14512 if (comp->dict)
14513 xmlDictReference(comp->dict);
14514 return(comp);
14515 }
14516 xmlFreePattern(stream);
14517 }
14518 return(NULL);
14519}
14520#endif /* XPATH_STREAMING */
14521
14522static int
14523xmlXPathCanRewriteDosExpression(xmlChar *expr)
14524{
14525 if (expr == NULL)
14526 return(0);
14527 do {
14528 if ((*expr == '/') && (*(++expr) == '/'))
14529 return(1);
14530 } while (*expr++);
14531 return(0);
14532}
14533static void
14534xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14535{
14536 /*
14537 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14538 * internal representation.
14539 */
14540 if (op->ch1 != -1) {
14541 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14542 ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
14543 ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14544 ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14545 {
14546 /*
14547 * This is a "child::foo"
14548 */
14549 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14550
14551 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14552 (prevop->ch1 != -1) &&
14553 ((xmlXPathAxisVal) prevop->value ==
14554 AXIS_DESCENDANT_OR_SELF) &&
14555 (prevop->ch2 == -1) &&
14556 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14557 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
14558 (comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
14559 {
14560 /*
14561 * This is a "/descendant-or-self::node()" without predicates.
14562 * Eliminate it.
14563 */
14564 op->ch1 = prevop->ch1;
14565 op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
14566 }
14567 }
14568 if (op->ch1 != -1)
14569 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14570 }
14571 if (op->ch2 != -1)
14572 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14573}
14574
14575/**
14576 * xmlXPathCtxtCompile:
14577 * @ctxt: an XPath context
14578 * @str: the XPath expression
14579 *
14580 * Compile an XPath expression
14581 *
14582 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14583 * the caller has to free the object.
14584 */
14585xmlXPathCompExprPtr
14586xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14587 xmlXPathParserContextPtr pctxt;
14588 xmlXPathCompExprPtr comp;
14589
14590#ifdef XPATH_STREAMING
14591 comp = xmlXPathTryStreamCompile(ctxt, str);
14592 if (comp != NULL)
14593 return(comp);
14594#endif
14595
14596 xmlXPathInit();
14597
14598 pctxt = xmlXPathNewParserContext(str, ctxt);
14599 if (pctxt == NULL)
14600 return NULL;
14601 xmlXPathCompileExpr(pctxt, 1);
14602
14603 if( pctxt->error != XPATH_EXPRESSION_OK )
14604 {
14605 xmlXPathFreeParserContext(pctxt);
14606 return(NULL);
14607 }
14608
14609 if (*pctxt->cur != 0) {
14610 /*
14611 * aleksey: in some cases this line prints *second* error message
14612 * (see bug #78858) and probably this should be fixed.
14613 * However, we are not sure that all error messages are printed
14614 * out in other places. It's not critical so we leave it as-is for now
14615 */
14616 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14617 comp = NULL;
14618 } else {
14619 comp = pctxt->comp;
14620 pctxt->comp = NULL;
14621 }
14622 xmlXPathFreeParserContext(pctxt);
14623
14624 if (comp != NULL) {
14625 comp->expr = xmlStrdup(str);
14626#ifdef DEBUG_EVAL_COUNTS
14627 comp->string = xmlStrdup(str);
14628 comp->nb = 0;
14629#endif
14630 if ((comp->expr != NULL) &&
14631 (comp->nbStep > 2) &&
14632 (comp->last >= 0) &&
14633 (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14634 {
14635 xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
14636 }
14637 }
14638 return(comp);
14639}
14640
14641/**
14642 * xmlXPathCompile:
14643 * @str: the XPath expression
14644 *
14645 * Compile an XPath expression
14646 *
14647 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14648 * the caller has to free the object.
14649 */
14650xmlXPathCompExprPtr
14651xmlXPathCompile(const xmlChar *str) {
14652 return(xmlXPathCtxtCompile(NULL, str));
14653}
14654
14655/**
14656 * xmlXPathCompiledEvalInternal:
14657 * @comp: the compiled XPath expression
14658 * @ctxt: the XPath context
14659 * @resObj: the resulting XPath object or NULL
14660 * @toBool: 1 if only a boolean result is requested
14661 *
14662 * Evaluate the Precompiled XPath expression in the given context.
14663 * The caller has to free @resObj.
14664 *
14665 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14666 * the caller has to free the object.
14667 */
14668static int
14669xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14670 xmlXPathContextPtr ctxt,
14671 xmlXPathObjectPtr *resObj,
14672 int toBool)
14673{
14674 xmlXPathParserContextPtr pctxt;
14675#ifndef LIBXML_THREAD_ENABLED
14676 static int reentance = 0;
14677#endif
14678 int res;
14679
14680 CHECK_CTXT_NEG(ctxt)
14681
14682 if (comp == NULL)
14683 return(-1);
14684 xmlXPathInit();
14685
14686#ifndef LIBXML_THREAD_ENABLED
14687 reentance++;
14688 if (reentance > 1)
14689 xmlXPathDisableOptimizer = 1;
14690#endif
14691
14692#ifdef DEBUG_EVAL_COUNTS
14693 comp->nb++;
14694 if ((comp->string != NULL) && (comp->nb > 100)) {
14695 fprintf(stderr, "100 x %s\n", comp->string);
14696 comp->nb = 0;
14697 }
14698#endif
14699 pctxt = xmlXPathCompParserContext(comp, ctxt);
14700 res = xmlXPathRunEval(pctxt, toBool);
14701
14702 if (resObj) {
14703 if (pctxt->value == NULL) {
14704 xmlGenericError(xmlGenericErrorContext,
14705 "xmlXPathCompiledEval: evaluation failed\n");
14706 *resObj = NULL;
14707 } else {
14708 *resObj = valuePop(pctxt);
14709 }
14710 }
14711
14712 /*
14713 * Pop all remaining objects from the stack.
14714 */
14715 if (pctxt->valueNr > 0) {
14716 xmlXPathObjectPtr tmp;
14717 int stack = 0;
14718
14719 do {
14720 tmp = valuePop(pctxt);
14721 if (tmp != NULL) {
14722 stack++;
14723 xmlXPathReleaseObject(ctxt, tmp);
14724 }
14725 } while (tmp != NULL);
14726 if ((stack != 0) &&
14727 ((toBool) || ((resObj) && (*resObj))))
14728 {
14729 xmlGenericError(xmlGenericErrorContext,
14730 "xmlXPathCompiledEval: %d objects left on the stack.\n",
14731 stack);
14732 }
14733 }
14734
14735 if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14736 xmlXPathFreeObject(*resObj);
14737 *resObj = NULL;
14738 }
14739 pctxt->comp = NULL;
14740 xmlXPathFreeParserContext(pctxt);
14741#ifndef LIBXML_THREAD_ENABLED
14742 reentance--;
14743#endif
14744
14745 return(res);
14746}
14747
14748/**
14749 * xmlXPathCompiledEval:
14750 * @comp: the compiled XPath expression
14751 * @ctx: the XPath context
14752 *
14753 * Evaluate the Precompiled XPath expression in the given context.
14754 *
14755 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14756 * the caller has to free the object.
14757 */
14758xmlXPathObjectPtr
14759xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14760{
14761 xmlXPathObjectPtr res = NULL;
14762
14763 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14764 return(res);
14765}
14766
14767/**
14768 * xmlXPathCompiledEvalToBoolean:
14769 * @comp: the compiled XPath expression
14770 * @ctxt: the XPath context
14771 *
14772 * Applies the XPath boolean() function on the result of the given
14773 * compiled expression.
14774 *
14775 * Returns 1 if the expression evaluated to true, 0 if to false and
14776 * -1 in API and internal errors.
14777 */
14778int
14779xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14780 xmlXPathContextPtr ctxt)
14781{
14782 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14783}
14784
14785/**
14786 * xmlXPathEvalExpr:
14787 * @ctxt: the XPath Parser context
14788 *
14789 * Parse and evaluate an XPath expression in the given context,
14790 * then push the result on the context stack
14791 */
14792void
14793xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14794#ifdef XPATH_STREAMING
14795 xmlXPathCompExprPtr comp;
14796#endif
14797
14798 if (ctxt == NULL) return;
14799
14800#ifdef XPATH_STREAMING
14801 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14802 if (comp != NULL) {
14803 if (ctxt->comp != NULL)
14804 xmlXPathFreeCompExpr(ctxt->comp);
14805 ctxt->comp = comp;
14806 if (ctxt->cur != NULL)
14807 while (*ctxt->cur != 0) ctxt->cur++;
14808 } else
14809#endif
14810 {
14811 xmlXPathCompileExpr(ctxt, 1);
14812 /*
14813 * In this scenario the expression string will sit in ctxt->base.
14814 */
14815 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14816 (ctxt->comp != NULL) &&
14817 (ctxt->base != NULL) &&
14818 (ctxt->comp->nbStep > 2) &&
14819 (ctxt->comp->last >= 0) &&
14820 (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
14821 {
14822 xmlXPathRewriteDOSExpression(ctxt->comp,
14823 &ctxt->comp->steps[ctxt->comp->last]);
14824 }
14825 }
14826 CHECK_ERROR;
14827 xmlXPathRunEval(ctxt, 0);
14828}
14829
14830/**
14831 * xmlXPathEval:
14832 * @str: the XPath expression
14833 * @ctx: the XPath context
14834 *
14835 * Evaluate the XPath Location Path in the given context.
14836 *
14837 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14838 * the caller has to free the object.
14839 */
14840xmlXPathObjectPtr
14841xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14842 xmlXPathParserContextPtr ctxt;
14843 xmlXPathObjectPtr res, tmp, init = NULL;
14844 int stack = 0;
14845
14846 CHECK_CTXT(ctx)
14847
14848 xmlXPathInit();
14849
14850 ctxt = xmlXPathNewParserContext(str, ctx);
14851 if (ctxt == NULL)
14852 return NULL;
14853 xmlXPathEvalExpr(ctxt);
14854
14855 if (ctxt->value == NULL) {
14856 xmlGenericError(xmlGenericErrorContext,
14857 "xmlXPathEval: evaluation failed\n");
14858 res = NULL;
14859 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
14860#ifdef XPATH_STREAMING
14861 && (ctxt->comp->stream == NULL)
14862#endif
14863 ) {
14864 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14865 res = NULL;
14866 } else {
14867 res = valuePop(ctxt);
14868 }
14869
14870 do {
14871 tmp = valuePop(ctxt);
14872 if (tmp != NULL) {
14873 if (tmp != init)
14874 stack++;
14875 xmlXPathReleaseObject(ctx, tmp);
14876 }
14877 } while (tmp != NULL);
14878 if ((stack != 0) && (res != NULL)) {
14879 xmlGenericError(xmlGenericErrorContext,
14880 "xmlXPathEval: %d object left on the stack\n",
14881 stack);
14882 }
14883 if (ctxt->error != XPATH_EXPRESSION_OK) {
14884 xmlXPathFreeObject(res);
14885 res = NULL;
14886 }
14887
14888 xmlXPathFreeParserContext(ctxt);
14889 return(res);
14890}
14891
14892/**
14893 * xmlXPathEvalExpression:
14894 * @str: the XPath expression
14895 * @ctxt: the XPath context
14896 *
14897 * Evaluate the XPath expression in the given context.
14898 *
14899 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14900 * the caller has to free the object.
14901 */
14902xmlXPathObjectPtr
14903xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14904 xmlXPathParserContextPtr pctxt;
14905 xmlXPathObjectPtr res, tmp;
14906 int stack = 0;
14907
14908 CHECK_CTXT(ctxt)
14909
14910 xmlXPathInit();
14911
14912 pctxt = xmlXPathNewParserContext(str, ctxt);
14913 if (pctxt == NULL)
14914 return NULL;
14915 xmlXPathEvalExpr(pctxt);
14916
14917 if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
14918 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14919 res = NULL;
14920 } else {
14921 res = valuePop(pctxt);
14922 }
14923 do {
14924 tmp = valuePop(pctxt);
14925 if (tmp != NULL) {
14926 xmlXPathReleaseObject(ctxt, tmp);
14927 stack++;
14928 }
14929 } while (tmp != NULL);
14930 if ((stack != 0) && (res != NULL)) {
14931 xmlGenericError(xmlGenericErrorContext,
14932 "xmlXPathEvalExpression: %d object left on the stack\n",
14933 stack);
14934 }
14935 xmlXPathFreeParserContext(pctxt);
14936 return(res);
14937}
14938
14939/************************************************************************
14940 * *
14941 * Extra functions not pertaining to the XPath spec *
14942 * *
14943 ************************************************************************/
14944/**
14945 * xmlXPathEscapeUriFunction:
14946 * @ctxt: the XPath Parser context
14947 * @nargs: the number of arguments
14948 *
14949 * Implement the escape-uri() XPath function
14950 * string escape-uri(string $str, bool $escape-reserved)
14951 *
14952 * This function applies the URI escaping rules defined in section 2 of [RFC
14953 * 2396] to the string supplied as $uri-part, which typically represents all
14954 * or part of a URI. The effect of the function is to replace any special
14955 * character in the string by an escape sequence of the form %xx%yy...,
14956 * where xxyy... is the hexadecimal representation of the octets used to
14957 * represent the character in UTF-8.
14958 *
14959 * The set of characters that are escaped depends on the setting of the
14960 * boolean argument $escape-reserved.
14961 *
14962 * If $escape-reserved is true, all characters are escaped other than lower
14963 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14964 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14965 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14966 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14967 * A-F).
14968 *
14969 * If $escape-reserved is false, the behavior differs in that characters
14970 * referred to in [RFC 2396] as reserved characters are not escaped. These
14971 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14972 *
14973 * [RFC 2396] does not define whether escaped URIs should use lower case or
14974 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14975 * compared using string comparison functions, this function must always use
14976 * the upper-case letters A-F.
14977 *
14978 * Generally, $escape-reserved should be set to true when escaping a string
14979 * that is to form a single part of a URI, and to false when escaping an
14980 * entire URI or URI reference.
14981 *
14982 * In the case of non-ascii characters, the string is encoded according to
14983 * utf-8 and then converted according to RFC 2396.
14984 *
14985 * Examples
14986 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14987 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14988 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14989 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14990 *
14991 */
14992static void
14993xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14994 xmlXPathObjectPtr str;
14995 int escape_reserved;
14996 xmlBufferPtr target;
14997 xmlChar *cptr;
14998 xmlChar escape[4];
14999
15000 CHECK_ARITY(2);
15001
15002 escape_reserved = xmlXPathPopBoolean(ctxt);
15003
15004 CAST_TO_STRING;
15005 str = valuePop(ctxt);
15006
15007 target = xmlBufferCreate();
15008
15009 escape[0] = '%';
15010 escape[3] = 0;
15011
15012 if (target) {
15013 for (cptr = str->stringval; *cptr; cptr++) {
15014 if ((*cptr >= 'A' && *cptr <= 'Z') ||
15015 (*cptr >= 'a' && *cptr <= 'z') ||
15016 (*cptr >= '0' && *cptr <= '9') ||
15017 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
15018 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
15019 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
15020 (*cptr == '%' &&
15021 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15022 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15023 (cptr[1] >= '0' && cptr[1] <= '9')) &&
15024 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15025 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15026 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15027 (!escape_reserved &&
15028 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15029 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15030 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15031 *cptr == ','))) {
15032 xmlBufferAdd(target, cptr, 1);
15033 } else {
15034 if ((*cptr >> 4) < 10)
15035 escape[1] = '0' + (*cptr >> 4);
15036 else
15037 escape[1] = 'A' - 10 + (*cptr >> 4);
15038 if ((*cptr & 0xF) < 10)
15039 escape[2] = '0' + (*cptr & 0xF);
15040 else
15041 escape[2] = 'A' - 10 + (*cptr & 0xF);
15042
15043 xmlBufferAdd(target, &escape[0], 3);
15044 }
15045 }
15046 }
15047 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15048 xmlBufferContent(target)));
15049 xmlBufferFree(target);
15050 xmlXPathReleaseObject(ctxt->context, str);
15051}
15052
15053/**
15054 * xmlXPathRegisterAllFunctions:
15055 * @ctxt: the XPath context
15056 *
15057 * Registers all default XPath functions in this context
15058 */
15059void
15060xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15061{
15062 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15063 xmlXPathBooleanFunction);
15064 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15065 xmlXPathCeilingFunction);
15066 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15067 xmlXPathCountFunction);
15068 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15069 xmlXPathConcatFunction);
15070 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15071 xmlXPathContainsFunction);
15072 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15073 xmlXPathIdFunction);
15074 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15075 xmlXPathFalseFunction);
15076 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15077 xmlXPathFloorFunction);
15078 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15079 xmlXPathLastFunction);
15080 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15081 xmlXPathLangFunction);
15082 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15083 xmlXPathLocalNameFunction);
15084 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15085 xmlXPathNotFunction);
15086 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15087 xmlXPathNameFunction);
15088 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15089 xmlXPathNamespaceURIFunction);
15090 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15091 xmlXPathNormalizeFunction);
15092 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15093 xmlXPathNumberFunction);
15094 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15095 xmlXPathPositionFunction);
15096 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15097 xmlXPathRoundFunction);
15098 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15099 xmlXPathStringFunction);
15100 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15101 xmlXPathStringLengthFunction);
15102 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15103 xmlXPathStartsWithFunction);
15104 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15105 xmlXPathSubstringFunction);
15106 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15107 xmlXPathSubstringBeforeFunction);
15108 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15109 xmlXPathSubstringAfterFunction);
15110 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15111 xmlXPathSumFunction);
15112 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15113 xmlXPathTrueFunction);
15114 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15115 xmlXPathTranslateFunction);
15116
15117 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15118 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15119 xmlXPathEscapeUriFunction);
15120}
15121
15122#endif /* LIBXML_XPATH_ENABLED */
15123#define bottom_xpath
15124#include "elfgcchack.h"
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette