VirtualBox

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

Last change on this file since 50079 was 42884, checked in by vboxsync, 12 years ago

libxml: patch from upstream

  • Property svn:eol-style set to native
File size: 412.7 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: daniel@veillard.com
14 *
15 */
16
17#define IN_LIBXML
18#include "libxml.h"
19
20#include <string.h>
21
22#ifdef HAVE_SYS_TYPES_H
23#include <sys/types.h>
24#endif
25#ifdef HAVE_MATH_H
26#include <math.h>
27#endif
28#ifdef HAVE_FLOAT_H
29#include <float.h>
30#endif
31#ifdef HAVE_CTYPE_H
32#include <ctype.h>
33#endif
34#ifdef HAVE_SIGNAL_H
35#include <signal.h>
36#endif
37
38#include <libxml/xmlmemory.h>
39#include <libxml/tree.h>
40#include <libxml/valid.h>
41#include <libxml/xpath.h>
42#include <libxml/xpathInternals.h>
43#include <libxml/parserInternals.h>
44#include <libxml/hash.h>
45#ifdef LIBXML_XPTR_ENABLED
46#include <libxml/xpointer.h>
47#endif
48#ifdef LIBXML_DEBUG_ENABLED
49#include <libxml/debugXML.h>
50#endif
51#include <libxml/xmlerror.h>
52#include <libxml/threads.h>
53#include <libxml/globals.h>
54#ifdef LIBXML_PATTERN_ENABLED
55#include <libxml/pattern.h>
56#endif
57
58#ifdef LIBXML_PATTERN_ENABLED
59#define XPATH_STREAMING
60#endif
61
62#define TODO \
63 xmlGenericError(xmlGenericErrorContext, \
64 "Unimplemented block at %s:%d\n", \
65 __FILE__, __LINE__);
66
67/*
68* XP_OPTIMIZED_NON_ELEM_COMPARISON:
69* If defined, this will use xmlXPathCmpNodesExt() instead of
70* xmlXPathCmpNodes(). The new function is optimized comparison of
71* non-element nodes; actually it will speed up comparison only if
72* xmlXPathOrderDocElems() was called in order to index the elements of
73* a tree in document order; Libxslt does such an indexing, thus it will
74* benefit from this optimization.
75*/
76#define XP_OPTIMIZED_NON_ELEM_COMPARISON
77
78/*
79* XP_OPTIMIZED_FILTER_FIRST:
80* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
81* in a way, that it stop evaluation at the first node.
82*/
83#define XP_OPTIMIZED_FILTER_FIRST
84
85/*
86* XP_DEBUG_OBJ_USAGE:
87* Internal flag to enable tracking of how much XPath objects have been
88* created.
89*/
90/* #define XP_DEBUG_OBJ_USAGE */
91
92/*
93 * TODO:
94 * There are a few spots where some tests are done which depend upon ascii
95 * data. These should be enhanced for full UTF8 support (see particularly
96 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
97 */
98
99#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
100
101/************************************************************************
102 * *
103 * Floating point stuff *
104 * *
105 ************************************************************************/
106
107#ifndef TRIO_REPLACE_STDIO
108#define TRIO_PUBLIC static
109#endif
110#include "trionan.c"
111
112/*
113 * The lack of portability of this section of the libc is annoying !
114 */
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 "Stack usage errror\n",
256 "?? Unknown error ??\n" /* Must be last in the list! */
257};
258#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
259 sizeof(xmlXPathErrorMessages[0])) - 1)
260/**
261 * xmlXPathErrMemory:
262 * @ctxt: an XPath context
263 * @extra: extra informations
264 *
265 * Handle a redefinition of attribute error
266 */
267static void
268xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
269{
270 if (ctxt != NULL) {
271 if (extra) {
272 xmlChar buf[200];
273
274 xmlStrPrintf(buf, 200,
275 BAD_CAST "Memory allocation failed : %s\n",
276 extra);
277 ctxt->lastError.message = (char *) xmlStrdup(buf);
278 } else {
279 ctxt->lastError.message = (char *)
280 xmlStrdup(BAD_CAST "Memory allocation failed\n");
281 }
282 ctxt->lastError.domain = XML_FROM_XPATH;
283 ctxt->lastError.code = XML_ERR_NO_MEMORY;
284 if (ctxt->error != NULL)
285 ctxt->error(ctxt->userData, &ctxt->lastError);
286 } else {
287 if (extra)
288 __xmlRaiseError(NULL, NULL, NULL,
289 NULL, NULL, XML_FROM_XPATH,
290 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
291 extra, NULL, NULL, 0, 0,
292 "Memory allocation failed : %s\n", extra);
293 else
294 __xmlRaiseError(NULL, NULL, NULL,
295 NULL, NULL, XML_FROM_XPATH,
296 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
297 NULL, NULL, NULL, 0, 0,
298 "Memory allocation failed\n");
299 }
300}
301
302/**
303 * xmlXPathPErrMemory:
304 * @ctxt: an XPath parser context
305 * @extra: extra informations
306 *
307 * Handle a redefinition of attribute error
308 */
309static void
310xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
311{
312 if (ctxt == NULL)
313 xmlXPathErrMemory(NULL, extra);
314 else {
315 ctxt->error = XPATH_MEMORY_ERROR;
316 xmlXPathErrMemory(ctxt->context, extra);
317 }
318}
319
320/**
321 * xmlXPathErr:
322 * @ctxt: a XPath parser context
323 * @error: the error code
324 *
325 * Handle an XPath error
326 */
327void
328xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
329{
330 if ((error < 0) || (error > MAXERRNO))
331 error = MAXERRNO;
332 if (ctxt == NULL) {
333 __xmlRaiseError(NULL, NULL, NULL,
334 NULL, NULL, XML_FROM_XPATH,
335 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
336 XML_ERR_ERROR, NULL, 0,
337 NULL, NULL, NULL, 0, 0,
338 xmlXPathErrorMessages[error]);
339 return;
340 }
341 ctxt->error = error;
342 if (ctxt->context == NULL) {
343 __xmlRaiseError(NULL, NULL, NULL,
344 NULL, NULL, XML_FROM_XPATH,
345 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
346 XML_ERR_ERROR, NULL, 0,
347 (const char *) ctxt->base, NULL, NULL,
348 ctxt->cur - ctxt->base, 0,
349 xmlXPathErrorMessages[error]);
350 return;
351 }
352
353 /* cleanup current last error */
354 xmlResetError(&ctxt->context->lastError);
355
356 ctxt->context->lastError.domain = XML_FROM_XPATH;
357 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
358 XPATH_EXPRESSION_OK;
359 ctxt->context->lastError.level = XML_ERR_ERROR;
360 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
361 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
362 ctxt->context->lastError.node = ctxt->context->debugNode;
363 if (ctxt->context->error != NULL) {
364 ctxt->context->error(ctxt->context->userData,
365 &ctxt->context->lastError);
366 } else {
367 __xmlRaiseError(NULL, NULL, NULL,
368 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
369 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
370 XML_ERR_ERROR, NULL, 0,
371 (const char *) ctxt->base, NULL, NULL,
372 ctxt->cur - ctxt->base, 0,
373 xmlXPathErrorMessages[error]);
374 }
375
376}
377
378/**
379 * xmlXPatherror:
380 * @ctxt: the XPath Parser context
381 * @file: the file name
382 * @line: the line number
383 * @no: the error number
384 *
385 * Formats an error message.
386 */
387void
388xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
389 int line ATTRIBUTE_UNUSED, int no) {
390 xmlXPathErr(ctxt, no);
391}
392
393/************************************************************************
394 * *
395 * Utilities *
396 * *
397 ************************************************************************/
398
399/**
400 * xsltPointerList:
401 *
402 * Pointer-list for various purposes.
403 */
404typedef struct _xmlPointerList xmlPointerList;
405typedef xmlPointerList *xmlPointerListPtr;
406struct _xmlPointerList {
407 void **items;
408 int number;
409 int size;
410};
411/*
412* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
413* and here, we should make the functions public.
414*/
415static int
416xmlPointerListAddSize(xmlPointerListPtr list,
417 void *item,
418 int initialSize)
419{
420 if (list->items == NULL) {
421 if (initialSize <= 0)
422 initialSize = 1;
423 list->items = (void **) xmlMalloc(
424 initialSize * sizeof(void *));
425 if (list->items == NULL) {
426 xmlXPathErrMemory(NULL,
427 "xmlPointerListCreate: allocating item\n");
428 return(-1);
429 }
430 list->number = 0;
431 list->size = initialSize;
432 } else if (list->size <= list->number) {
433 list->size *= 2;
434 list->items = (void **) xmlRealloc(list->items,
435 list->size * sizeof(void *));
436 if (list->items == NULL) {
437 xmlXPathErrMemory(NULL,
438 "xmlPointerListCreate: re-allocating item\n");
439 list->size = 0;
440 return(-1);
441 }
442 }
443 list->items[list->number++] = item;
444 return(0);
445}
446
447/**
448 * xsltPointerListCreate:
449 *
450 * Creates an xsltPointerList structure.
451 *
452 * Returns a xsltPointerList structure or NULL in case of an error.
453 */
454static xmlPointerListPtr
455xmlPointerListCreate(int initialSize)
456{
457 xmlPointerListPtr ret;
458
459 ret = xmlMalloc(sizeof(xmlPointerList));
460 if (ret == NULL) {
461 xmlXPathErrMemory(NULL,
462 "xmlPointerListCreate: allocating item\n");
463 return (NULL);
464 }
465 memset(ret, 0, sizeof(xmlPointerList));
466 if (initialSize > 0) {
467 xmlPointerListAddSize(ret, NULL, initialSize);
468 ret->number = 0;
469 }
470 return (ret);
471}
472
473/**
474 * xsltPointerListFree:
475 *
476 * Frees the xsltPointerList structure. This does not free
477 * the content of the list.
478 */
479static void
480xmlPointerListFree(xmlPointerListPtr list)
481{
482 if (list == NULL)
483 return;
484 if (list->items != NULL)
485 xmlFree(list->items);
486 xmlFree(list);
487}
488
489/************************************************************************
490 * *
491 * Parser Types *
492 * *
493 ************************************************************************/
494
495/*
496 * Types are private:
497 */
498
499typedef enum {
500 XPATH_OP_END=0,
501 XPATH_OP_AND,
502 XPATH_OP_OR,
503 XPATH_OP_EQUAL,
504 XPATH_OP_CMP,
505 XPATH_OP_PLUS,
506 XPATH_OP_MULT,
507 XPATH_OP_UNION,
508 XPATH_OP_ROOT,
509 XPATH_OP_NODE,
510 XPATH_OP_RESET, /* 10 */
511 XPATH_OP_COLLECT,
512 XPATH_OP_VALUE, /* 12 */
513 XPATH_OP_VARIABLE,
514 XPATH_OP_FUNCTION,
515 XPATH_OP_ARG,
516 XPATH_OP_PREDICATE,
517 XPATH_OP_FILTER, /* 17 */
518 XPATH_OP_SORT /* 18 */
519#ifdef LIBXML_XPTR_ENABLED
520 ,XPATH_OP_RANGETO
521#endif
522} xmlXPathOp;
523
524typedef enum {
525 AXIS_ANCESTOR = 1,
526 AXIS_ANCESTOR_OR_SELF,
527 AXIS_ATTRIBUTE,
528 AXIS_CHILD,
529 AXIS_DESCENDANT,
530 AXIS_DESCENDANT_OR_SELF,
531 AXIS_FOLLOWING,
532 AXIS_FOLLOWING_SIBLING,
533 AXIS_NAMESPACE,
534 AXIS_PARENT,
535 AXIS_PRECEDING,
536 AXIS_PRECEDING_SIBLING,
537 AXIS_SELF
538} xmlXPathAxisVal;
539
540typedef enum {
541 NODE_TEST_NONE = 0,
542 NODE_TEST_TYPE = 1,
543 NODE_TEST_PI = 2,
544 NODE_TEST_ALL = 3,
545 NODE_TEST_NS = 4,
546 NODE_TEST_NAME = 5
547} xmlXPathTestVal;
548
549typedef enum {
550 NODE_TYPE_NODE = 0,
551 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
552 NODE_TYPE_TEXT = XML_TEXT_NODE,
553 NODE_TYPE_PI = XML_PI_NODE
554} xmlXPathTypeVal;
555
556#define XP_REWRITE_DOS_CHILD_ELEM 1
557
558typedef struct _xmlXPathStepOp xmlXPathStepOp;
559typedef xmlXPathStepOp *xmlXPathStepOpPtr;
560struct _xmlXPathStepOp {
561 xmlXPathOp op; /* The identifier of the operation */
562 int ch1; /* First child */
563 int ch2; /* Second child */
564 int value;
565 int value2;
566 int value3;
567 void *value4;
568 void *value5;
569 void *cache;
570 void *cacheURI;
571 int rewriteType;
572};
573
574struct _xmlXPathCompExpr {
575 int nbStep; /* Number of steps in this expression */
576 int maxStep; /* Maximum number of steps allocated */
577 xmlXPathStepOp *steps; /* ops for computation of this expression */
578 int last; /* index of last step in expression */
579 xmlChar *expr; /* the expression being computed */
580 xmlDictPtr dict; /* the dictionnary to use if any */
581#ifdef DEBUG_EVAL_COUNTS
582 int nb;
583 xmlChar *string;
584#endif
585#ifdef XPATH_STREAMING
586 xmlPatternPtr stream;
587#endif
588};
589
590/************************************************************************
591 * *
592 * Forward declarations *
593 * *
594 ************************************************************************/
595static void
596xmlXPathFreeValueTree(xmlNodeSetPtr obj);
597static void
598xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
599static int
600xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
601 xmlXPathStepOpPtr op, xmlNodePtr *first);
602static int
603xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
604 xmlXPathStepOpPtr op,
605 int isPredicate);
606
607/************************************************************************
608 * *
609 * Parser Type functions *
610 * *
611 ************************************************************************/
612
613/**
614 * xmlXPathNewCompExpr:
615 *
616 * Create a new Xpath component
617 *
618 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
619 */
620static xmlXPathCompExprPtr
621xmlXPathNewCompExpr(void) {
622 xmlXPathCompExprPtr cur;
623
624 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
625 if (cur == NULL) {
626 xmlXPathErrMemory(NULL, "allocating component\n");
627 return(NULL);
628 }
629 memset(cur, 0, sizeof(xmlXPathCompExpr));
630 cur->maxStep = 10;
631 cur->nbStep = 0;
632 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
633 sizeof(xmlXPathStepOp));
634 if (cur->steps == NULL) {
635 xmlXPathErrMemory(NULL, "allocating steps\n");
636 xmlFree(cur);
637 return(NULL);
638 }
639 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
640 cur->last = -1;
641#ifdef DEBUG_EVAL_COUNTS
642 cur->nb = 0;
643#endif
644 return(cur);
645}
646
647/**
648 * xmlXPathFreeCompExpr:
649 * @comp: an XPATH comp
650 *
651 * Free up the memory allocated by @comp
652 */
653void
654xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
655{
656 xmlXPathStepOpPtr op;
657 int i;
658
659 if (comp == NULL)
660 return;
661 if (comp->dict == NULL) {
662 for (i = 0; i < comp->nbStep; i++) {
663 op = &comp->steps[i];
664 if (op->value4 != NULL) {
665 if (op->op == XPATH_OP_VALUE)
666 xmlXPathFreeObject(op->value4);
667 else
668 xmlFree(op->value4);
669 }
670 if (op->value5 != NULL)
671 xmlFree(op->value5);
672 }
673 } else {
674 for (i = 0; i < comp->nbStep; i++) {
675 op = &comp->steps[i];
676 if (op->value4 != NULL) {
677 if (op->op == XPATH_OP_VALUE)
678 xmlXPathFreeObject(op->value4);
679 }
680 }
681 xmlDictFree(comp->dict);
682 }
683 if (comp->steps != NULL) {
684 xmlFree(comp->steps);
685 }
686#ifdef DEBUG_EVAL_COUNTS
687 if (comp->string != NULL) {
688 xmlFree(comp->string);
689 }
690#endif
691#ifdef XPATH_STREAMING
692 if (comp->stream != NULL) {
693 xmlFreePatternList(comp->stream);
694 }
695#endif
696 if (comp->expr != NULL) {
697 xmlFree(comp->expr);
698 }
699
700 xmlFree(comp);
701}
702
703/**
704 * xmlXPathCompExprAdd:
705 * @comp: the compiled expression
706 * @ch1: first child index
707 * @ch2: second child index
708 * @op: an op
709 * @value: the first int value
710 * @value2: the second int value
711 * @value3: the third int value
712 * @value4: the first string value
713 * @value5: the second string value
714 *
715 * Add a step to an XPath Compiled Expression
716 *
717 * Returns -1 in case of failure, the index otherwise
718 */
719static int
720xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
721 xmlXPathOp op, int value,
722 int value2, int value3, void *value4, void *value5) {
723 if (comp->nbStep >= comp->maxStep) {
724 xmlXPathStepOp *real;
725
726 comp->maxStep *= 2;
727 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
728 comp->maxStep * sizeof(xmlXPathStepOp));
729 if (real == NULL) {
730 comp->maxStep /= 2;
731 xmlXPathErrMemory(NULL, "adding step\n");
732 return(-1);
733 }
734 comp->steps = real;
735 }
736 comp->last = comp->nbStep;
737 comp->steps[comp->nbStep].rewriteType = 0;
738 comp->steps[comp->nbStep].ch1 = ch1;
739 comp->steps[comp->nbStep].ch2 = ch2;
740 comp->steps[comp->nbStep].op = op;
741 comp->steps[comp->nbStep].value = value;
742 comp->steps[comp->nbStep].value2 = value2;
743 comp->steps[comp->nbStep].value3 = value3;
744 if ((comp->dict != NULL) &&
745 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
746 (op == XPATH_OP_COLLECT))) {
747 if (value4 != NULL) {
748 comp->steps[comp->nbStep].value4 = (xmlChar *)
749 (void *)xmlDictLookup(comp->dict, value4, -1);
750 xmlFree(value4);
751 } else
752 comp->steps[comp->nbStep].value4 = NULL;
753 if (value5 != NULL) {
754 comp->steps[comp->nbStep].value5 = (xmlChar *)
755 (void *)xmlDictLookup(comp->dict, value5, -1);
756 xmlFree(value5);
757 } else
758 comp->steps[comp->nbStep].value5 = NULL;
759 } else {
760 comp->steps[comp->nbStep].value4 = value4;
761 comp->steps[comp->nbStep].value5 = value5;
762 }
763 comp->steps[comp->nbStep].cache = NULL;
764 return(comp->nbStep++);
765}
766
767/**
768 * xmlXPathCompSwap:
769 * @comp: the compiled expression
770 * @op: operation index
771 *
772 * Swaps 2 operations in the compiled expression
773 */
774static void
775xmlXPathCompSwap(xmlXPathStepOpPtr op) {
776 int tmp;
777
778#ifndef LIBXML_THREAD_ENABLED
779 /*
780 * Since this manipulates possibly shared variables, this is
781 * disabled if one detects that the library is used in a multithreaded
782 * application
783 */
784 if (xmlXPathDisableOptimizer)
785 return;
786#endif
787
788 tmp = op->ch1;
789 op->ch1 = op->ch2;
790 op->ch2 = tmp;
791}
792
793#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
794 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
795 (op), (val), (val2), (val3), (val4), (val5))
796#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
797 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
798 (op), (val), (val2), (val3), (val4), (val5))
799
800#define PUSH_LEAVE_EXPR(op, val, val2) \
801xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
802
803#define PUSH_UNARY_EXPR(op, ch, val, val2) \
804xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
805
806#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
807xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
808 (val), (val2), 0 ,NULL ,NULL)
809
810/************************************************************************
811 * *
812 * XPath object cache structures *
813 * *
814 ************************************************************************/
815
816/* #define XP_DEFAULT_CACHE_ON */
817
818#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
819
820typedef struct _xmlXPathContextCache xmlXPathContextCache;
821typedef xmlXPathContextCache *xmlXPathContextCachePtr;
822struct _xmlXPathContextCache {
823 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
824 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
825 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
826 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
827 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
828 int maxNodeset;
829 int maxString;
830 int maxBoolean;
831 int maxNumber;
832 int maxMisc;
833#ifdef XP_DEBUG_OBJ_USAGE
834 int dbgCachedAll;
835 int dbgCachedNodeset;
836 int dbgCachedString;
837 int dbgCachedBool;
838 int dbgCachedNumber;
839 int dbgCachedPoint;
840 int dbgCachedRange;
841 int dbgCachedLocset;
842 int dbgCachedUsers;
843 int dbgCachedXSLTTree;
844 int dbgCachedUndefined;
845
846
847 int dbgReusedAll;
848 int dbgReusedNodeset;
849 int dbgReusedString;
850 int dbgReusedBool;
851 int dbgReusedNumber;
852 int dbgReusedPoint;
853 int dbgReusedRange;
854 int dbgReusedLocset;
855 int dbgReusedUsers;
856 int dbgReusedXSLTTree;
857 int dbgReusedUndefined;
858
859#endif
860};
861
862/************************************************************************
863 * *
864 * Debugging related functions *
865 * *
866 ************************************************************************/
867
868#define STRANGE \
869 xmlGenericError(xmlGenericErrorContext, \
870 "Internal error at %s:%d\n", \
871 __FILE__, __LINE__);
872
873#ifdef LIBXML_DEBUG_ENABLED
874static void
875xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
876 int i;
877 char shift[100];
878
879 for (i = 0;((i < depth) && (i < 25));i++)
880 shift[2 * i] = shift[2 * i + 1] = ' ';
881 shift[2 * i] = shift[2 * i + 1] = 0;
882 if (cur == NULL) {
883 fprintf(output, shift);
884 fprintf(output, "Node is NULL !\n");
885 return;
886
887 }
888
889 if ((cur->type == XML_DOCUMENT_NODE) ||
890 (cur->type == XML_HTML_DOCUMENT_NODE)) {
891 fprintf(output, shift);
892 fprintf(output, " /\n");
893 } else if (cur->type == XML_ATTRIBUTE_NODE)
894 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
895 else
896 xmlDebugDumpOneNode(output, cur, depth);
897}
898static void
899xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
900 xmlNodePtr tmp;
901 int i;
902 char shift[100];
903
904 for (i = 0;((i < depth) && (i < 25));i++)
905 shift[2 * i] = shift[2 * i + 1] = ' ';
906 shift[2 * i] = shift[2 * i + 1] = 0;
907 if (cur == NULL) {
908 fprintf(output, shift);
909 fprintf(output, "Node is NULL !\n");
910 return;
911
912 }
913
914 while (cur != NULL) {
915 tmp = cur;
916 cur = cur->next;
917 xmlDebugDumpOneNode(output, tmp, depth);
918 }
919}
920
921static void
922xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
923 int i;
924 char shift[100];
925
926 for (i = 0;((i < depth) && (i < 25));i++)
927 shift[2 * i] = shift[2 * i + 1] = ' ';
928 shift[2 * i] = shift[2 * i + 1] = 0;
929
930 if (cur == NULL) {
931 fprintf(output, shift);
932 fprintf(output, "NodeSet is NULL !\n");
933 return;
934
935 }
936
937 if (cur != NULL) {
938 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
939 for (i = 0;i < cur->nodeNr;i++) {
940 fprintf(output, shift);
941 fprintf(output, "%d", i + 1);
942 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
943 }
944 }
945}
946
947static void
948xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
949 int i;
950 char shift[100];
951
952 for (i = 0;((i < depth) && (i < 25));i++)
953 shift[2 * i] = shift[2 * i + 1] = ' ';
954 shift[2 * i] = shift[2 * i + 1] = 0;
955
956 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
957 fprintf(output, shift);
958 fprintf(output, "Value Tree is NULL !\n");
959 return;
960
961 }
962
963 fprintf(output, shift);
964 fprintf(output, "%d", i + 1);
965 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
966}
967#if defined(LIBXML_XPTR_ENABLED)
968static void
969xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
970 int i;
971 char shift[100];
972
973 for (i = 0;((i < depth) && (i < 25));i++)
974 shift[2 * i] = shift[2 * i + 1] = ' ';
975 shift[2 * i] = shift[2 * i + 1] = 0;
976
977 if (cur == NULL) {
978 fprintf(output, shift);
979 fprintf(output, "LocationSet is NULL !\n");
980 return;
981
982 }
983
984 for (i = 0;i < cur->locNr;i++) {
985 fprintf(output, shift);
986 fprintf(output, "%d : ", i + 1);
987 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
988 }
989}
990#endif /* LIBXML_XPTR_ENABLED */
991
992/**
993 * xmlXPathDebugDumpObject:
994 * @output: the FILE * to dump the output
995 * @cur: the object to inspect
996 * @depth: indentation level
997 *
998 * Dump the content of the object for debugging purposes
999 */
1000void
1001xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1002 int i;
1003 char shift[100];
1004
1005 if (output == NULL) return;
1006
1007 for (i = 0;((i < depth) && (i < 25));i++)
1008 shift[2 * i] = shift[2 * i + 1] = ' ';
1009 shift[2 * i] = shift[2 * i + 1] = 0;
1010
1011
1012 fprintf(output, shift);
1013
1014 if (cur == NULL) {
1015 fprintf(output, "Object is empty (NULL)\n");
1016 return;
1017 }
1018 switch(cur->type) {
1019 case XPATH_UNDEFINED:
1020 fprintf(output, "Object is uninitialized\n");
1021 break;
1022 case XPATH_NODESET:
1023 fprintf(output, "Object is a Node Set :\n");
1024 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1025 break;
1026 case XPATH_XSLT_TREE:
1027 fprintf(output, "Object is an XSLT value tree :\n");
1028 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1029 break;
1030 case XPATH_BOOLEAN:
1031 fprintf(output, "Object is a Boolean : ");
1032 if (cur->boolval) fprintf(output, "true\n");
1033 else fprintf(output, "false\n");
1034 break;
1035 case XPATH_NUMBER:
1036 switch (xmlXPathIsInf(cur->floatval)) {
1037 case 1:
1038 fprintf(output, "Object is a number : Infinity\n");
1039 break;
1040 case -1:
1041 fprintf(output, "Object is a number : -Infinity\n");
1042 break;
1043 default:
1044 if (xmlXPathIsNaN(cur->floatval)) {
1045 fprintf(output, "Object is a number : NaN\n");
1046 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1047 fprintf(output, "Object is a number : 0\n");
1048 } else {
1049 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1050 }
1051 }
1052 break;
1053 case XPATH_STRING:
1054 fprintf(output, "Object is a string : ");
1055 xmlDebugDumpString(output, cur->stringval);
1056 fprintf(output, "\n");
1057 break;
1058 case XPATH_POINT:
1059 fprintf(output, "Object is a point : index %d in node", cur->index);
1060 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1061 fprintf(output, "\n");
1062 break;
1063 case XPATH_RANGE:
1064 if ((cur->user2 == NULL) ||
1065 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1066 fprintf(output, "Object is a collapsed range :\n");
1067 fprintf(output, shift);
1068 if (cur->index >= 0)
1069 fprintf(output, "index %d in ", cur->index);
1070 fprintf(output, "node\n");
1071 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1072 depth + 1);
1073 } else {
1074 fprintf(output, "Object is a range :\n");
1075 fprintf(output, shift);
1076 fprintf(output, "From ");
1077 if (cur->index >= 0)
1078 fprintf(output, "index %d in ", cur->index);
1079 fprintf(output, "node\n");
1080 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1081 depth + 1);
1082 fprintf(output, shift);
1083 fprintf(output, "To ");
1084 if (cur->index2 >= 0)
1085 fprintf(output, "index %d in ", cur->index2);
1086 fprintf(output, "node\n");
1087 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1088 depth + 1);
1089 fprintf(output, "\n");
1090 }
1091 break;
1092 case XPATH_LOCATIONSET:
1093#if defined(LIBXML_XPTR_ENABLED)
1094 fprintf(output, "Object is a Location Set:\n");
1095 xmlXPathDebugDumpLocationSet(output,
1096 (xmlLocationSetPtr) cur->user, depth);
1097#endif
1098 break;
1099 case XPATH_USERS:
1100 fprintf(output, "Object is user defined\n");
1101 break;
1102 }
1103}
1104
1105static void
1106xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1107 xmlXPathStepOpPtr op, int depth) {
1108 int i;
1109 char shift[100];
1110
1111 for (i = 0;((i < depth) && (i < 25));i++)
1112 shift[2 * i] = shift[2 * i + 1] = ' ';
1113 shift[2 * i] = shift[2 * i + 1] = 0;
1114
1115 fprintf(output, shift);
1116 if (op == NULL) {
1117 fprintf(output, "Step is NULL\n");
1118 return;
1119 }
1120 switch (op->op) {
1121 case XPATH_OP_END:
1122 fprintf(output, "END"); break;
1123 case XPATH_OP_AND:
1124 fprintf(output, "AND"); break;
1125 case XPATH_OP_OR:
1126 fprintf(output, "OR"); break;
1127 case XPATH_OP_EQUAL:
1128 if (op->value)
1129 fprintf(output, "EQUAL =");
1130 else
1131 fprintf(output, "EQUAL !=");
1132 break;
1133 case XPATH_OP_CMP:
1134 if (op->value)
1135 fprintf(output, "CMP <");
1136 else
1137 fprintf(output, "CMP >");
1138 if (!op->value2)
1139 fprintf(output, "=");
1140 break;
1141 case XPATH_OP_PLUS:
1142 if (op->value == 0)
1143 fprintf(output, "PLUS -");
1144 else if (op->value == 1)
1145 fprintf(output, "PLUS +");
1146 else if (op->value == 2)
1147 fprintf(output, "PLUS unary -");
1148 else if (op->value == 3)
1149 fprintf(output, "PLUS unary - -");
1150 break;
1151 case XPATH_OP_MULT:
1152 if (op->value == 0)
1153 fprintf(output, "MULT *");
1154 else if (op->value == 1)
1155 fprintf(output, "MULT div");
1156 else
1157 fprintf(output, "MULT mod");
1158 break;
1159 case XPATH_OP_UNION:
1160 fprintf(output, "UNION"); break;
1161 case XPATH_OP_ROOT:
1162 fprintf(output, "ROOT"); break;
1163 case XPATH_OP_NODE:
1164 fprintf(output, "NODE"); break;
1165 case XPATH_OP_RESET:
1166 fprintf(output, "RESET"); break;
1167 case XPATH_OP_SORT:
1168 fprintf(output, "SORT"); break;
1169 case XPATH_OP_COLLECT: {
1170 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1171 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1172 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1173 const xmlChar *prefix = op->value4;
1174 const xmlChar *name = op->value5;
1175
1176 fprintf(output, "COLLECT ");
1177 switch (axis) {
1178 case AXIS_ANCESTOR:
1179 fprintf(output, " 'ancestors' "); break;
1180 case AXIS_ANCESTOR_OR_SELF:
1181 fprintf(output, " 'ancestors-or-self' "); break;
1182 case AXIS_ATTRIBUTE:
1183 fprintf(output, " 'attributes' "); break;
1184 case AXIS_CHILD:
1185 fprintf(output, " 'child' "); break;
1186 case AXIS_DESCENDANT:
1187 fprintf(output, " 'descendant' "); break;
1188 case AXIS_DESCENDANT_OR_SELF:
1189 fprintf(output, " 'descendant-or-self' "); break;
1190 case AXIS_FOLLOWING:
1191 fprintf(output, " 'following' "); break;
1192 case AXIS_FOLLOWING_SIBLING:
1193 fprintf(output, " 'following-siblings' "); break;
1194 case AXIS_NAMESPACE:
1195 fprintf(output, " 'namespace' "); break;
1196 case AXIS_PARENT:
1197 fprintf(output, " 'parent' "); break;
1198 case AXIS_PRECEDING:
1199 fprintf(output, " 'preceding' "); break;
1200 case AXIS_PRECEDING_SIBLING:
1201 fprintf(output, " 'preceding-sibling' "); break;
1202 case AXIS_SELF:
1203 fprintf(output, " 'self' "); break;
1204 }
1205 switch (test) {
1206 case NODE_TEST_NONE:
1207 fprintf(output, "'none' "); break;
1208 case NODE_TEST_TYPE:
1209 fprintf(output, "'type' "); break;
1210 case NODE_TEST_PI:
1211 fprintf(output, "'PI' "); break;
1212 case NODE_TEST_ALL:
1213 fprintf(output, "'all' "); break;
1214 case NODE_TEST_NS:
1215 fprintf(output, "'namespace' "); break;
1216 case NODE_TEST_NAME:
1217 fprintf(output, "'name' "); break;
1218 }
1219 switch (type) {
1220 case NODE_TYPE_NODE:
1221 fprintf(output, "'node' "); break;
1222 case NODE_TYPE_COMMENT:
1223 fprintf(output, "'comment' "); break;
1224 case NODE_TYPE_TEXT:
1225 fprintf(output, "'text' "); break;
1226 case NODE_TYPE_PI:
1227 fprintf(output, "'PI' "); break;
1228 }
1229 if (prefix != NULL)
1230 fprintf(output, "%s:", prefix);
1231 if (name != NULL)
1232 fprintf(output, "%s", (const char *) name);
1233 break;
1234
1235 }
1236 case XPATH_OP_VALUE: {
1237 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1238
1239 fprintf(output, "ELEM ");
1240 xmlXPathDebugDumpObject(output, object, 0);
1241 goto finish;
1242 }
1243 case XPATH_OP_VARIABLE: {
1244 const xmlChar *prefix = op->value5;
1245 const xmlChar *name = op->value4;
1246
1247 if (prefix != NULL)
1248 fprintf(output, "VARIABLE %s:%s", prefix, name);
1249 else
1250 fprintf(output, "VARIABLE %s", name);
1251 break;
1252 }
1253 case XPATH_OP_FUNCTION: {
1254 int nbargs = op->value;
1255 const xmlChar *prefix = op->value5;
1256 const xmlChar *name = op->value4;
1257
1258 if (prefix != NULL)
1259 fprintf(output, "FUNCTION %s:%s(%d args)",
1260 prefix, name, nbargs);
1261 else
1262 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1263 break;
1264 }
1265 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1266 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1267 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1268#ifdef LIBXML_XPTR_ENABLED
1269 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1270#endif
1271 default:
1272 fprintf(output, "UNKNOWN %d\n", op->op); return;
1273 }
1274 fprintf(output, "\n");
1275finish:
1276 if (op->ch1 >= 0)
1277 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1278 if (op->ch2 >= 0)
1279 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1280}
1281
1282/**
1283 * xmlXPathDebugDumpCompExpr:
1284 * @output: the FILE * for the output
1285 * @comp: the precompiled XPath expression
1286 * @depth: the indentation level.
1287 *
1288 * Dumps the tree of the compiled XPath expression.
1289 */
1290void
1291xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1292 int depth) {
1293 int i;
1294 char shift[100];
1295
1296 if ((output == NULL) || (comp == NULL)) return;
1297
1298 for (i = 0;((i < depth) && (i < 25));i++)
1299 shift[2 * i] = shift[2 * i + 1] = ' ';
1300 shift[2 * i] = shift[2 * i + 1] = 0;
1301
1302 fprintf(output, shift);
1303
1304 fprintf(output, "Compiled Expression : %d elements\n",
1305 comp->nbStep);
1306 i = comp->last;
1307 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1308}
1309
1310#ifdef XP_DEBUG_OBJ_USAGE
1311
1312/*
1313* XPath object usage related debugging variables.
1314*/
1315static int xmlXPathDebugObjCounterUndefined = 0;
1316static int xmlXPathDebugObjCounterNodeset = 0;
1317static int xmlXPathDebugObjCounterBool = 0;
1318static int xmlXPathDebugObjCounterNumber = 0;
1319static int xmlXPathDebugObjCounterString = 0;
1320static int xmlXPathDebugObjCounterPoint = 0;
1321static int xmlXPathDebugObjCounterRange = 0;
1322static int xmlXPathDebugObjCounterLocset = 0;
1323static int xmlXPathDebugObjCounterUsers = 0;
1324static int xmlXPathDebugObjCounterXSLTTree = 0;
1325static int xmlXPathDebugObjCounterAll = 0;
1326
1327static int xmlXPathDebugObjTotalUndefined = 0;
1328static int xmlXPathDebugObjTotalNodeset = 0;
1329static int xmlXPathDebugObjTotalBool = 0;
1330static int xmlXPathDebugObjTotalNumber = 0;
1331static int xmlXPathDebugObjTotalString = 0;
1332static int xmlXPathDebugObjTotalPoint = 0;
1333static int xmlXPathDebugObjTotalRange = 0;
1334static int xmlXPathDebugObjTotalLocset = 0;
1335static int xmlXPathDebugObjTotalUsers = 0;
1336static int xmlXPathDebugObjTotalXSLTTree = 0;
1337static int xmlXPathDebugObjTotalAll = 0;
1338
1339static int xmlXPathDebugObjMaxUndefined = 0;
1340static int xmlXPathDebugObjMaxNodeset = 0;
1341static int xmlXPathDebugObjMaxBool = 0;
1342static int xmlXPathDebugObjMaxNumber = 0;
1343static int xmlXPathDebugObjMaxString = 0;
1344static int xmlXPathDebugObjMaxPoint = 0;
1345static int xmlXPathDebugObjMaxRange = 0;
1346static int xmlXPathDebugObjMaxLocset = 0;
1347static int xmlXPathDebugObjMaxUsers = 0;
1348static int xmlXPathDebugObjMaxXSLTTree = 0;
1349static int xmlXPathDebugObjMaxAll = 0;
1350
1351/* REVISIT TODO: Make this static when committing */
1352static void
1353xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1354{
1355 if (ctxt != NULL) {
1356 if (ctxt->cache != NULL) {
1357 xmlXPathContextCachePtr cache =
1358 (xmlXPathContextCachePtr) ctxt->cache;
1359
1360 cache->dbgCachedAll = 0;
1361 cache->dbgCachedNodeset = 0;
1362 cache->dbgCachedString = 0;
1363 cache->dbgCachedBool = 0;
1364 cache->dbgCachedNumber = 0;
1365 cache->dbgCachedPoint = 0;
1366 cache->dbgCachedRange = 0;
1367 cache->dbgCachedLocset = 0;
1368 cache->dbgCachedUsers = 0;
1369 cache->dbgCachedXSLTTree = 0;
1370 cache->dbgCachedUndefined = 0;
1371
1372 cache->dbgReusedAll = 0;
1373 cache->dbgReusedNodeset = 0;
1374 cache->dbgReusedString = 0;
1375 cache->dbgReusedBool = 0;
1376 cache->dbgReusedNumber = 0;
1377 cache->dbgReusedPoint = 0;
1378 cache->dbgReusedRange = 0;
1379 cache->dbgReusedLocset = 0;
1380 cache->dbgReusedUsers = 0;
1381 cache->dbgReusedXSLTTree = 0;
1382 cache->dbgReusedUndefined = 0;
1383 }
1384 }
1385
1386 xmlXPathDebugObjCounterUndefined = 0;
1387 xmlXPathDebugObjCounterNodeset = 0;
1388 xmlXPathDebugObjCounterBool = 0;
1389 xmlXPathDebugObjCounterNumber = 0;
1390 xmlXPathDebugObjCounterString = 0;
1391 xmlXPathDebugObjCounterPoint = 0;
1392 xmlXPathDebugObjCounterRange = 0;
1393 xmlXPathDebugObjCounterLocset = 0;
1394 xmlXPathDebugObjCounterUsers = 0;
1395 xmlXPathDebugObjCounterXSLTTree = 0;
1396 xmlXPathDebugObjCounterAll = 0;
1397
1398 xmlXPathDebugObjTotalUndefined = 0;
1399 xmlXPathDebugObjTotalNodeset = 0;
1400 xmlXPathDebugObjTotalBool = 0;
1401 xmlXPathDebugObjTotalNumber = 0;
1402 xmlXPathDebugObjTotalString = 0;
1403 xmlXPathDebugObjTotalPoint = 0;
1404 xmlXPathDebugObjTotalRange = 0;
1405 xmlXPathDebugObjTotalLocset = 0;
1406 xmlXPathDebugObjTotalUsers = 0;
1407 xmlXPathDebugObjTotalXSLTTree = 0;
1408 xmlXPathDebugObjTotalAll = 0;
1409
1410 xmlXPathDebugObjMaxUndefined = 0;
1411 xmlXPathDebugObjMaxNodeset = 0;
1412 xmlXPathDebugObjMaxBool = 0;
1413 xmlXPathDebugObjMaxNumber = 0;
1414 xmlXPathDebugObjMaxString = 0;
1415 xmlXPathDebugObjMaxPoint = 0;
1416 xmlXPathDebugObjMaxRange = 0;
1417 xmlXPathDebugObjMaxLocset = 0;
1418 xmlXPathDebugObjMaxUsers = 0;
1419 xmlXPathDebugObjMaxXSLTTree = 0;
1420 xmlXPathDebugObjMaxAll = 0;
1421
1422}
1423
1424static void
1425xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1426 xmlXPathObjectType objType)
1427{
1428 int isCached = 0;
1429
1430 if (ctxt != NULL) {
1431 if (ctxt->cache != NULL) {
1432 xmlXPathContextCachePtr cache =
1433 (xmlXPathContextCachePtr) ctxt->cache;
1434
1435 isCached = 1;
1436
1437 cache->dbgReusedAll++;
1438 switch (objType) {
1439 case XPATH_UNDEFINED:
1440 cache->dbgReusedUndefined++;
1441 break;
1442 case XPATH_NODESET:
1443 cache->dbgReusedNodeset++;
1444 break;
1445 case XPATH_BOOLEAN:
1446 cache->dbgReusedBool++;
1447 break;
1448 case XPATH_NUMBER:
1449 cache->dbgReusedNumber++;
1450 break;
1451 case XPATH_STRING:
1452 cache->dbgReusedString++;
1453 break;
1454 case XPATH_POINT:
1455 cache->dbgReusedPoint++;
1456 break;
1457 case XPATH_RANGE:
1458 cache->dbgReusedRange++;
1459 break;
1460 case XPATH_LOCATIONSET:
1461 cache->dbgReusedLocset++;
1462 break;
1463 case XPATH_USERS:
1464 cache->dbgReusedUsers++;
1465 break;
1466 case XPATH_XSLT_TREE:
1467 cache->dbgReusedXSLTTree++;
1468 break;
1469 default:
1470 break;
1471 }
1472 }
1473 }
1474
1475 switch (objType) {
1476 case XPATH_UNDEFINED:
1477 if (! isCached)
1478 xmlXPathDebugObjTotalUndefined++;
1479 xmlXPathDebugObjCounterUndefined++;
1480 if (xmlXPathDebugObjCounterUndefined >
1481 xmlXPathDebugObjMaxUndefined)
1482 xmlXPathDebugObjMaxUndefined =
1483 xmlXPathDebugObjCounterUndefined;
1484 break;
1485 case XPATH_NODESET:
1486 if (! isCached)
1487 xmlXPathDebugObjTotalNodeset++;
1488 xmlXPathDebugObjCounterNodeset++;
1489 if (xmlXPathDebugObjCounterNodeset >
1490 xmlXPathDebugObjMaxNodeset)
1491 xmlXPathDebugObjMaxNodeset =
1492 xmlXPathDebugObjCounterNodeset;
1493 break;
1494 case XPATH_BOOLEAN:
1495 if (! isCached)
1496 xmlXPathDebugObjTotalBool++;
1497 xmlXPathDebugObjCounterBool++;
1498 if (xmlXPathDebugObjCounterBool >
1499 xmlXPathDebugObjMaxBool)
1500 xmlXPathDebugObjMaxBool =
1501 xmlXPathDebugObjCounterBool;
1502 break;
1503 case XPATH_NUMBER:
1504 if (! isCached)
1505 xmlXPathDebugObjTotalNumber++;
1506 xmlXPathDebugObjCounterNumber++;
1507 if (xmlXPathDebugObjCounterNumber >
1508 xmlXPathDebugObjMaxNumber)
1509 xmlXPathDebugObjMaxNumber =
1510 xmlXPathDebugObjCounterNumber;
1511 break;
1512 case XPATH_STRING:
1513 if (! isCached)
1514 xmlXPathDebugObjTotalString++;
1515 xmlXPathDebugObjCounterString++;
1516 if (xmlXPathDebugObjCounterString >
1517 xmlXPathDebugObjMaxString)
1518 xmlXPathDebugObjMaxString =
1519 xmlXPathDebugObjCounterString;
1520 break;
1521 case XPATH_POINT:
1522 if (! isCached)
1523 xmlXPathDebugObjTotalPoint++;
1524 xmlXPathDebugObjCounterPoint++;
1525 if (xmlXPathDebugObjCounterPoint >
1526 xmlXPathDebugObjMaxPoint)
1527 xmlXPathDebugObjMaxPoint =
1528 xmlXPathDebugObjCounterPoint;
1529 break;
1530 case XPATH_RANGE:
1531 if (! isCached)
1532 xmlXPathDebugObjTotalRange++;
1533 xmlXPathDebugObjCounterRange++;
1534 if (xmlXPathDebugObjCounterRange >
1535 xmlXPathDebugObjMaxRange)
1536 xmlXPathDebugObjMaxRange =
1537 xmlXPathDebugObjCounterRange;
1538 break;
1539 case XPATH_LOCATIONSET:
1540 if (! isCached)
1541 xmlXPathDebugObjTotalLocset++;
1542 xmlXPathDebugObjCounterLocset++;
1543 if (xmlXPathDebugObjCounterLocset >
1544 xmlXPathDebugObjMaxLocset)
1545 xmlXPathDebugObjMaxLocset =
1546 xmlXPathDebugObjCounterLocset;
1547 break;
1548 case XPATH_USERS:
1549 if (! isCached)
1550 xmlXPathDebugObjTotalUsers++;
1551 xmlXPathDebugObjCounterUsers++;
1552 if (xmlXPathDebugObjCounterUsers >
1553 xmlXPathDebugObjMaxUsers)
1554 xmlXPathDebugObjMaxUsers =
1555 xmlXPathDebugObjCounterUsers;
1556 break;
1557 case XPATH_XSLT_TREE:
1558 if (! isCached)
1559 xmlXPathDebugObjTotalXSLTTree++;
1560 xmlXPathDebugObjCounterXSLTTree++;
1561 if (xmlXPathDebugObjCounterXSLTTree >
1562 xmlXPathDebugObjMaxXSLTTree)
1563 xmlXPathDebugObjMaxXSLTTree =
1564 xmlXPathDebugObjCounterXSLTTree;
1565 break;
1566 default:
1567 break;
1568 }
1569 if (! isCached)
1570 xmlXPathDebugObjTotalAll++;
1571 xmlXPathDebugObjCounterAll++;
1572 if (xmlXPathDebugObjCounterAll >
1573 xmlXPathDebugObjMaxAll)
1574 xmlXPathDebugObjMaxAll =
1575 xmlXPathDebugObjCounterAll;
1576}
1577
1578static void
1579xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1580 xmlXPathObjectType objType)
1581{
1582 int isCached = 0;
1583
1584 if (ctxt != NULL) {
1585 if (ctxt->cache != NULL) {
1586 xmlXPathContextCachePtr cache =
1587 (xmlXPathContextCachePtr) ctxt->cache;
1588
1589 isCached = 1;
1590
1591 cache->dbgCachedAll++;
1592 switch (objType) {
1593 case XPATH_UNDEFINED:
1594 cache->dbgCachedUndefined++;
1595 break;
1596 case XPATH_NODESET:
1597 cache->dbgCachedNodeset++;
1598 break;
1599 case XPATH_BOOLEAN:
1600 cache->dbgCachedBool++;
1601 break;
1602 case XPATH_NUMBER:
1603 cache->dbgCachedNumber++;
1604 break;
1605 case XPATH_STRING:
1606 cache->dbgCachedString++;
1607 break;
1608 case XPATH_POINT:
1609 cache->dbgCachedPoint++;
1610 break;
1611 case XPATH_RANGE:
1612 cache->dbgCachedRange++;
1613 break;
1614 case XPATH_LOCATIONSET:
1615 cache->dbgCachedLocset++;
1616 break;
1617 case XPATH_USERS:
1618 cache->dbgCachedUsers++;
1619 break;
1620 case XPATH_XSLT_TREE:
1621 cache->dbgCachedXSLTTree++;
1622 break;
1623 default:
1624 break;
1625 }
1626
1627 }
1628 }
1629 switch (objType) {
1630 case XPATH_UNDEFINED:
1631 xmlXPathDebugObjCounterUndefined--;
1632 break;
1633 case XPATH_NODESET:
1634 xmlXPathDebugObjCounterNodeset--;
1635 break;
1636 case XPATH_BOOLEAN:
1637 xmlXPathDebugObjCounterBool--;
1638 break;
1639 case XPATH_NUMBER:
1640 xmlXPathDebugObjCounterNumber--;
1641 break;
1642 case XPATH_STRING:
1643 xmlXPathDebugObjCounterString--;
1644 break;
1645 case XPATH_POINT:
1646 xmlXPathDebugObjCounterPoint--;
1647 break;
1648 case XPATH_RANGE:
1649 xmlXPathDebugObjCounterRange--;
1650 break;
1651 case XPATH_LOCATIONSET:
1652 xmlXPathDebugObjCounterLocset--;
1653 break;
1654 case XPATH_USERS:
1655 xmlXPathDebugObjCounterUsers--;
1656 break;
1657 case XPATH_XSLT_TREE:
1658 xmlXPathDebugObjCounterXSLTTree--;
1659 break;
1660 default:
1661 break;
1662 }
1663 xmlXPathDebugObjCounterAll--;
1664}
1665
1666/* REVISIT TODO: Make this static when committing */
1667static void
1668xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
1669{
1670 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
1671 reqXSLTTree, reqUndefined;
1672 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
1673 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
1674 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
1675 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
1676 int leftObjs = xmlXPathDebugObjCounterAll;
1677
1678 reqAll = xmlXPathDebugObjTotalAll;
1679 reqNodeset = xmlXPathDebugObjTotalNodeset;
1680 reqString = xmlXPathDebugObjTotalString;
1681 reqBool = xmlXPathDebugObjTotalBool;
1682 reqNumber = xmlXPathDebugObjTotalNumber;
1683 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
1684 reqUndefined = xmlXPathDebugObjTotalUndefined;
1685
1686 printf("# XPath object usage:\n");
1687
1688 if (ctxt != NULL) {
1689 if (ctxt->cache != NULL) {
1690 xmlXPathContextCachePtr cache =
1691 (xmlXPathContextCachePtr) ctxt->cache;
1692
1693 reAll = cache->dbgReusedAll;
1694 reqAll += reAll;
1695 reNodeset = cache->dbgReusedNodeset;
1696 reqNodeset += reNodeset;
1697 reString = cache->dbgReusedString;
1698 reqString += reString;
1699 reBool = cache->dbgReusedBool;
1700 reqBool += reBool;
1701 reNumber = cache->dbgReusedNumber;
1702 reqNumber += reNumber;
1703 reXSLTTree = cache->dbgReusedXSLTTree;
1704 reqXSLTTree += reXSLTTree;
1705 reUndefined = cache->dbgReusedUndefined;
1706 reqUndefined += reUndefined;
1707
1708 caAll = cache->dbgCachedAll;
1709 caBool = cache->dbgCachedBool;
1710 caNodeset = cache->dbgCachedNodeset;
1711 caString = cache->dbgCachedString;
1712 caNumber = cache->dbgCachedNumber;
1713 caXSLTTree = cache->dbgCachedXSLTTree;
1714 caUndefined = cache->dbgCachedUndefined;
1715
1716 if (cache->nodesetObjs)
1717 leftObjs -= cache->nodesetObjs->number;
1718 if (cache->stringObjs)
1719 leftObjs -= cache->stringObjs->number;
1720 if (cache->booleanObjs)
1721 leftObjs -= cache->booleanObjs->number;
1722 if (cache->numberObjs)
1723 leftObjs -= cache->numberObjs->number;
1724 if (cache->miscObjs)
1725 leftObjs -= cache->miscObjs->number;
1726 }
1727 }
1728
1729 printf("# all\n");
1730 printf("# total : %d\n", reqAll);
1731 printf("# left : %d\n", leftObjs);
1732 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
1733 printf("# reused : %d\n", reAll);
1734 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
1735
1736 printf("# node-sets\n");
1737 printf("# total : %d\n", reqNodeset);
1738 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
1739 printf("# reused : %d\n", reNodeset);
1740 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
1741
1742 printf("# strings\n");
1743 printf("# total : %d\n", reqString);
1744 printf("# created: %d\n", xmlXPathDebugObjTotalString);
1745 printf("# reused : %d\n", reString);
1746 printf("# max : %d\n", xmlXPathDebugObjMaxString);
1747
1748 printf("# booleans\n");
1749 printf("# total : %d\n", reqBool);
1750 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
1751 printf("# reused : %d\n", reBool);
1752 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
1753
1754 printf("# numbers\n");
1755 printf("# total : %d\n", reqNumber);
1756 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
1757 printf("# reused : %d\n", reNumber);
1758 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
1759
1760 printf("# XSLT result tree fragments\n");
1761 printf("# total : %d\n", reqXSLTTree);
1762 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
1763 printf("# reused : %d\n", reXSLTTree);
1764 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
1765
1766 printf("# undefined\n");
1767 printf("# total : %d\n", reqUndefined);
1768 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
1769 printf("# reused : %d\n", reUndefined);
1770 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
1771
1772}
1773
1774#endif /* XP_DEBUG_OBJ_USAGE */
1775
1776#endif /* LIBXML_DEBUG_ENABLED */
1777
1778/************************************************************************
1779 * *
1780 * XPath object caching *
1781 * *
1782 ************************************************************************/
1783
1784/**
1785 * xmlXPathNewCache:
1786 *
1787 * Create a new object cache
1788 *
1789 * Returns the xmlXPathCache just allocated.
1790 */
1791static xmlXPathContextCachePtr
1792xmlXPathNewCache(void)
1793{
1794 xmlXPathContextCachePtr ret;
1795
1796 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1797 if (ret == NULL) {
1798 xmlXPathErrMemory(NULL, "creating object cache\n");
1799 return(NULL);
1800 }
1801 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
1802 ret->maxNodeset = 100;
1803 ret->maxString = 100;
1804 ret->maxBoolean = 100;
1805 ret->maxNumber = 100;
1806 ret->maxMisc = 100;
1807 return(ret);
1808}
1809
1810static void
1811xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
1812{
1813 int i;
1814 xmlXPathObjectPtr obj;
1815
1816 if (list == NULL)
1817 return;
1818
1819 for (i = 0; i < list->number; i++) {
1820 obj = list->items[i];
1821 /*
1822 * Note that it is already assured that we don't need to
1823 * look out for namespace nodes in the node-set.
1824 */
1825 if (obj->nodesetval != NULL) {
1826 if (obj->nodesetval->nodeTab != NULL)
1827 xmlFree(obj->nodesetval->nodeTab);
1828 xmlFree(obj->nodesetval);
1829 }
1830 xmlFree(obj);
1831#ifdef XP_DEBUG_OBJ_USAGE
1832 xmlXPathDebugObjCounterAll--;
1833#endif
1834 }
1835 xmlPointerListFree(list);
1836}
1837
1838static void
1839xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1840{
1841 if (cache == NULL)
1842 return;
1843 if (cache->nodesetObjs)
1844 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1845 if (cache->stringObjs)
1846 xmlXPathCacheFreeObjectList(cache->stringObjs);
1847 if (cache->booleanObjs)
1848 xmlXPathCacheFreeObjectList(cache->booleanObjs);
1849 if (cache->numberObjs)
1850 xmlXPathCacheFreeObjectList(cache->numberObjs);
1851 if (cache->miscObjs)
1852 xmlXPathCacheFreeObjectList(cache->miscObjs);
1853 xmlFree(cache);
1854}
1855
1856/**
1857 * xmlXPathContextSetCache:
1858 *
1859 * @ctxt: the XPath context
1860 * @active: enables/disables (creates/frees) the cache
1861 * @value: a value with semantics dependant on @options
1862 * @options: options (currently only the value 0 is used)
1863 *
1864 * Creates/frees an object cache on the XPath context.
1865 * If activates XPath objects (xmlXPathObject) will be cached internally
1866 * to be reused.
1867 * @options:
1868 * 0: This will set the XPath object caching:
1869 * @value:
1870 * This will set the maximum number of XPath objects
1871 * to be cached per slot
1872 * There are 5 slots for: node-set, string, number, boolean, and
1873 * misc objects. Use <0 for the default number (100).
1874 * Other values for @options have currently no effect.
1875 *
1876 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1877 */
1878int
1879xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1880 int active,
1881 int value,
1882 int options)
1883{
1884 if (ctxt == NULL)
1885 return(-1);
1886 if (active) {
1887 xmlXPathContextCachePtr cache;
1888
1889 if (ctxt->cache == NULL) {
1890 ctxt->cache = xmlXPathNewCache();
1891 if (ctxt->cache == NULL)
1892 return(-1);
1893 }
1894 cache = (xmlXPathContextCachePtr) ctxt->cache;
1895 if (options == 0) {
1896 if (value < 0)
1897 value = 100;
1898 cache->maxNodeset = value;
1899 cache->maxString = value;
1900 cache->maxNumber = value;
1901 cache->maxBoolean = value;
1902 cache->maxMisc = value;
1903 }
1904 } else if (ctxt->cache != NULL) {
1905 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1906 ctxt->cache = NULL;
1907 }
1908 return(0);
1909}
1910
1911/**
1912 * xmlXPathCacheWrapNodeSet:
1913 * @ctxt: the XPath context
1914 * @val: the NodePtr value
1915 *
1916 * This is the cached version of xmlXPathWrapNodeSet().
1917 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1918 *
1919 * Returns the created or reused object.
1920 */
1921static xmlXPathObjectPtr
1922xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
1923{
1924 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1925 xmlXPathContextCachePtr cache =
1926 (xmlXPathContextCachePtr) ctxt->cache;
1927
1928 if ((cache->miscObjs != NULL) &&
1929 (cache->miscObjs->number != 0))
1930 {
1931 xmlXPathObjectPtr ret;
1932
1933 ret = (xmlXPathObjectPtr)
1934 cache->miscObjs->items[--cache->miscObjs->number];
1935 ret->type = XPATH_NODESET;
1936 ret->nodesetval = val;
1937#ifdef XP_DEBUG_OBJ_USAGE
1938 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
1939#endif
1940 return(ret);
1941 }
1942 }
1943
1944 return(xmlXPathWrapNodeSet(val));
1945
1946}
1947
1948/**
1949 * xmlXPathCacheWrapString:
1950 * @ctxt: the XPath context
1951 * @val: the xmlChar * value
1952 *
1953 * This is the cached version of xmlXPathWrapString().
1954 * Wraps the @val string into an XPath object.
1955 *
1956 * Returns the created or reused object.
1957 */
1958static xmlXPathObjectPtr
1959xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
1960{
1961 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1962 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1963
1964 if ((cache->stringObjs != NULL) &&
1965 (cache->stringObjs->number != 0))
1966 {
1967
1968 xmlXPathObjectPtr ret;
1969
1970 ret = (xmlXPathObjectPtr)
1971 cache->stringObjs->items[--cache->stringObjs->number];
1972 ret->type = XPATH_STRING;
1973 ret->stringval = val;
1974#ifdef XP_DEBUG_OBJ_USAGE
1975 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1976#endif
1977 return(ret);
1978 } else if ((cache->miscObjs != NULL) &&
1979 (cache->miscObjs->number != 0))
1980 {
1981 xmlXPathObjectPtr ret;
1982 /*
1983 * Fallback to misc-cache.
1984 */
1985 ret = (xmlXPathObjectPtr)
1986 cache->miscObjs->items[--cache->miscObjs->number];
1987
1988 ret->type = XPATH_STRING;
1989 ret->stringval = val;
1990#ifdef XP_DEBUG_OBJ_USAGE
1991 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1992#endif
1993 return(ret);
1994 }
1995 }
1996 return(xmlXPathWrapString(val));
1997}
1998
1999/**
2000 * xmlXPathCacheNewNodeSet:
2001 * @ctxt: the XPath context
2002 * @val: the NodePtr value
2003 *
2004 * This is the cached version of xmlXPathNewNodeSet().
2005 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2006 * it with the single Node @val
2007 *
2008 * Returns the created or reused object.
2009 */
2010static xmlXPathObjectPtr
2011xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2012{
2013 if ((ctxt != NULL) && (ctxt->cache)) {
2014 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2015
2016 if ((cache->nodesetObjs != NULL) &&
2017 (cache->nodesetObjs->number != 0))
2018 {
2019 xmlXPathObjectPtr ret;
2020 /*
2021 * Use the nodset-cache.
2022 */
2023 ret = (xmlXPathObjectPtr)
2024 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2025 ret->type = XPATH_NODESET;
2026 ret->boolval = 0;
2027 if (val) {
2028 if ((ret->nodesetval->nodeMax == 0) ||
2029 (val->type == XML_NAMESPACE_DECL))
2030 {
2031 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2032 } else {
2033 ret->nodesetval->nodeTab[0] = val;
2034 ret->nodesetval->nodeNr = 1;
2035 }
2036 }
2037#ifdef XP_DEBUG_OBJ_USAGE
2038 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2039#endif
2040 return(ret);
2041 } else if ((cache->miscObjs != NULL) &&
2042 (cache->miscObjs->number != 0))
2043 {
2044 xmlXPathObjectPtr ret;
2045 /*
2046 * Fallback to misc-cache.
2047 */
2048
2049 ret = (xmlXPathObjectPtr)
2050 cache->miscObjs->items[--cache->miscObjs->number];
2051
2052 ret->type = XPATH_NODESET;
2053 ret->boolval = 0;
2054 ret->nodesetval = xmlXPathNodeSetCreate(val);
2055#ifdef XP_DEBUG_OBJ_USAGE
2056 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2057#endif
2058 return(ret);
2059 }
2060 }
2061 return(xmlXPathNewNodeSet(val));
2062}
2063
2064/**
2065 * xmlXPathCacheNewCString:
2066 * @ctxt: the XPath context
2067 * @val: the char * value
2068 *
2069 * This is the cached version of xmlXPathNewCString().
2070 * Acquire an xmlXPathObjectPtr of type string and of value @val
2071 *
2072 * Returns the created or reused object.
2073 */
2074static xmlXPathObjectPtr
2075xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2076{
2077 if ((ctxt != NULL) && (ctxt->cache)) {
2078 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2079
2080 if ((cache->stringObjs != NULL) &&
2081 (cache->stringObjs->number != 0))
2082 {
2083 xmlXPathObjectPtr ret;
2084
2085 ret = (xmlXPathObjectPtr)
2086 cache->stringObjs->items[--cache->stringObjs->number];
2087
2088 ret->type = XPATH_STRING;
2089 ret->stringval = xmlStrdup(BAD_CAST val);
2090#ifdef XP_DEBUG_OBJ_USAGE
2091 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2092#endif
2093 return(ret);
2094 } else if ((cache->miscObjs != NULL) &&
2095 (cache->miscObjs->number != 0))
2096 {
2097 xmlXPathObjectPtr ret;
2098
2099 ret = (xmlXPathObjectPtr)
2100 cache->miscObjs->items[--cache->miscObjs->number];
2101
2102 ret->type = XPATH_STRING;
2103 ret->stringval = xmlStrdup(BAD_CAST val);
2104#ifdef XP_DEBUG_OBJ_USAGE
2105 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2106#endif
2107 return(ret);
2108 }
2109 }
2110 return(xmlXPathNewCString(val));
2111}
2112
2113/**
2114 * xmlXPathCacheNewString:
2115 * @ctxt: the XPath context
2116 * @val: the xmlChar * value
2117 *
2118 * This is the cached version of xmlXPathNewString().
2119 * Acquire an xmlXPathObjectPtr of type string and of value @val
2120 *
2121 * Returns the created or reused object.
2122 */
2123static xmlXPathObjectPtr
2124xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2125{
2126 if ((ctxt != NULL) && (ctxt->cache)) {
2127 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2128
2129 if ((cache->stringObjs != NULL) &&
2130 (cache->stringObjs->number != 0))
2131 {
2132 xmlXPathObjectPtr ret;
2133
2134 ret = (xmlXPathObjectPtr)
2135 cache->stringObjs->items[--cache->stringObjs->number];
2136 ret->type = XPATH_STRING;
2137 if (val != NULL)
2138 ret->stringval = xmlStrdup(val);
2139 else
2140 ret->stringval = xmlStrdup((const xmlChar *)"");
2141#ifdef XP_DEBUG_OBJ_USAGE
2142 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2143#endif
2144 return(ret);
2145 } else if ((cache->miscObjs != NULL) &&
2146 (cache->miscObjs->number != 0))
2147 {
2148 xmlXPathObjectPtr ret;
2149
2150 ret = (xmlXPathObjectPtr)
2151 cache->miscObjs->items[--cache->miscObjs->number];
2152
2153 ret->type = XPATH_STRING;
2154 if (val != NULL)
2155 ret->stringval = xmlStrdup(val);
2156 else
2157 ret->stringval = xmlStrdup((const xmlChar *)"");
2158#ifdef XP_DEBUG_OBJ_USAGE
2159 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2160#endif
2161 return(ret);
2162 }
2163 }
2164 return(xmlXPathNewString(val));
2165}
2166
2167/**
2168 * xmlXPathCacheNewBoolean:
2169 * @ctxt: the XPath context
2170 * @val: the boolean value
2171 *
2172 * This is the cached version of xmlXPathNewBoolean().
2173 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2174 *
2175 * Returns the created or reused object.
2176 */
2177static xmlXPathObjectPtr
2178xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2179{
2180 if ((ctxt != NULL) && (ctxt->cache)) {
2181 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2182
2183 if ((cache->booleanObjs != NULL) &&
2184 (cache->booleanObjs->number != 0))
2185 {
2186 xmlXPathObjectPtr ret;
2187
2188 ret = (xmlXPathObjectPtr)
2189 cache->booleanObjs->items[--cache->booleanObjs->number];
2190 ret->type = XPATH_BOOLEAN;
2191 ret->boolval = (val != 0);
2192#ifdef XP_DEBUG_OBJ_USAGE
2193 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2194#endif
2195 return(ret);
2196 } else if ((cache->miscObjs != NULL) &&
2197 (cache->miscObjs->number != 0))
2198 {
2199 xmlXPathObjectPtr ret;
2200
2201 ret = (xmlXPathObjectPtr)
2202 cache->miscObjs->items[--cache->miscObjs->number];
2203
2204 ret->type = XPATH_BOOLEAN;
2205 ret->boolval = (val != 0);
2206#ifdef XP_DEBUG_OBJ_USAGE
2207 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2208#endif
2209 return(ret);
2210 }
2211 }
2212 return(xmlXPathNewBoolean(val));
2213}
2214
2215/**
2216 * xmlXPathCacheNewFloat:
2217 * @ctxt: the XPath context
2218 * @val: the double value
2219 *
2220 * This is the cached version of xmlXPathNewFloat().
2221 * Acquires an xmlXPathObjectPtr of type double and of value @val
2222 *
2223 * Returns the created or reused object.
2224 */
2225static xmlXPathObjectPtr
2226xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2227{
2228 if ((ctxt != NULL) && (ctxt->cache)) {
2229 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2230
2231 if ((cache->numberObjs != NULL) &&
2232 (cache->numberObjs->number != 0))
2233 {
2234 xmlXPathObjectPtr ret;
2235
2236 ret = (xmlXPathObjectPtr)
2237 cache->numberObjs->items[--cache->numberObjs->number];
2238 ret->type = XPATH_NUMBER;
2239 ret->floatval = val;
2240#ifdef XP_DEBUG_OBJ_USAGE
2241 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2242#endif
2243 return(ret);
2244 } else if ((cache->miscObjs != NULL) &&
2245 (cache->miscObjs->number != 0))
2246 {
2247 xmlXPathObjectPtr ret;
2248
2249 ret = (xmlXPathObjectPtr)
2250 cache->miscObjs->items[--cache->miscObjs->number];
2251
2252 ret->type = XPATH_NUMBER;
2253 ret->floatval = val;
2254#ifdef XP_DEBUG_OBJ_USAGE
2255 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2256#endif
2257 return(ret);
2258 }
2259 }
2260 return(xmlXPathNewFloat(val));
2261}
2262
2263/**
2264 * xmlXPathCacheConvertString:
2265 * @ctxt: the XPath context
2266 * @val: an XPath object
2267 *
2268 * This is the cached version of xmlXPathConvertString().
2269 * Converts an existing object to its string() equivalent
2270 *
2271 * Returns a created or reused object, the old one is freed (cached)
2272 * (or the operation is done directly on @val)
2273 */
2274
2275static xmlXPathObjectPtr
2276xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2277 xmlChar *res = NULL;
2278
2279 if (val == NULL)
2280 return(xmlXPathCacheNewCString(ctxt, ""));
2281
2282 switch (val->type) {
2283 case XPATH_UNDEFINED:
2284#ifdef DEBUG_EXPR
2285 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2286#endif
2287 break;
2288 case XPATH_NODESET:
2289 case XPATH_XSLT_TREE:
2290 res = xmlXPathCastNodeSetToString(val->nodesetval);
2291 break;
2292 case XPATH_STRING:
2293 return(val);
2294 case XPATH_BOOLEAN:
2295 res = xmlXPathCastBooleanToString(val->boolval);
2296 break;
2297 case XPATH_NUMBER:
2298 res = xmlXPathCastNumberToString(val->floatval);
2299 break;
2300 case XPATH_USERS:
2301 case XPATH_POINT:
2302 case XPATH_RANGE:
2303 case XPATH_LOCATIONSET:
2304 TODO;
2305 break;
2306 }
2307 xmlXPathReleaseObject(ctxt, val);
2308 if (res == NULL)
2309 return(xmlXPathCacheNewCString(ctxt, ""));
2310 return(xmlXPathCacheWrapString(ctxt, res));
2311}
2312
2313/**
2314 * xmlXPathCacheObjectCopy:
2315 * @ctxt: the XPath context
2316 * @val: the original object
2317 *
2318 * This is the cached version of xmlXPathObjectCopy().
2319 * Acquire a copy of a given object
2320 *
2321 * Returns a created or reused created object.
2322 */
2323static xmlXPathObjectPtr
2324xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2325{
2326 if (val == NULL)
2327 return(NULL);
2328
2329 if (XP_HAS_CACHE(ctxt)) {
2330 switch (val->type) {
2331 case XPATH_NODESET:
2332 return(xmlXPathCacheWrapNodeSet(ctxt,
2333 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2334 case XPATH_STRING:
2335 return(xmlXPathCacheNewString(ctxt, val->stringval));
2336 case XPATH_BOOLEAN:
2337 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2338 case XPATH_NUMBER:
2339 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2340 default:
2341 break;
2342 }
2343 }
2344 return(xmlXPathObjectCopy(val));
2345}
2346
2347/**
2348 * xmlXPathCacheConvertBoolean:
2349 * @ctxt: the XPath context
2350 * @val: an XPath object
2351 *
2352 * This is the cached version of xmlXPathConvertBoolean().
2353 * Converts an existing object to its boolean() equivalent
2354 *
2355 * Returns a created or reused object, the old one is freed (or the operation
2356 * is done directly on @val)
2357 */
2358static xmlXPathObjectPtr
2359xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2360 xmlXPathObjectPtr ret;
2361
2362 if (val == NULL)
2363 return(xmlXPathCacheNewBoolean(ctxt, 0));
2364 if (val->type == XPATH_BOOLEAN)
2365 return(val);
2366 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2367 xmlXPathReleaseObject(ctxt, val);
2368 return(ret);
2369}
2370
2371/**
2372 * xmlXPathCacheConvertNumber:
2373 * @ctxt: the XPath context
2374 * @val: an XPath object
2375 *
2376 * This is the cached version of xmlXPathConvertNumber().
2377 * Converts an existing object to its number() equivalent
2378 *
2379 * Returns a created or reused object, the old one is freed (or the operation
2380 * is done directly on @val)
2381 */
2382static xmlXPathObjectPtr
2383xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2384 xmlXPathObjectPtr ret;
2385
2386 if (val == NULL)
2387 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2388 if (val->type == XPATH_NUMBER)
2389 return(val);
2390 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2391 xmlXPathReleaseObject(ctxt, val);
2392 return(ret);
2393}
2394
2395/************************************************************************
2396 * *
2397 * Parser stacks related functions and macros *
2398 * *
2399 ************************************************************************/
2400
2401/**
2402 * xmlXPathSetFrame:
2403 * @ctxt: an XPath parser context
2404 *
2405 * Set the callee evaluation frame
2406 *
2407 * Returns the previous frame value to be restored once done
2408 */
2409static int
2410xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2411 int ret;
2412
2413 if (ctxt == NULL)
2414 return(0);
2415 ret = ctxt->valueFrame;
2416 ctxt->valueFrame = ctxt->valueNr;
2417 return(ret);
2418}
2419
2420/**
2421 * xmlXPathPopFrame:
2422 * @ctxt: an XPath parser context
2423 * @frame: the previous frame value
2424 *
2425 * Remove the callee evaluation frame
2426 */
2427static void
2428xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2429 if (ctxt == NULL)
2430 return;
2431 if (ctxt->valueNr < ctxt->valueFrame) {
2432 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2433 }
2434 ctxt->valueFrame = frame;
2435}
2436
2437/**
2438 * valuePop:
2439 * @ctxt: an XPath evaluation context
2440 *
2441 * Pops the top XPath object from the value stack
2442 *
2443 * Returns the XPath object just removed
2444 */
2445xmlXPathObjectPtr
2446valuePop(xmlXPathParserContextPtr ctxt)
2447{
2448 xmlXPathObjectPtr ret;
2449
2450 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2451 return (NULL);
2452
2453 if (ctxt->valueNr <= ctxt->valueFrame) {
2454 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2455 return (NULL);
2456 }
2457
2458 ctxt->valueNr--;
2459 if (ctxt->valueNr > 0)
2460 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2461 else
2462 ctxt->value = NULL;
2463 ret = ctxt->valueTab[ctxt->valueNr];
2464 ctxt->valueTab[ctxt->valueNr] = NULL;
2465 return (ret);
2466}
2467/**
2468 * valuePush:
2469 * @ctxt: an XPath evaluation context
2470 * @value: the XPath object
2471 *
2472 * Pushes a new XPath object on top of the value stack
2473 *
2474 * returns the number of items on the value stack
2475 */
2476int
2477valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2478{
2479 if ((ctxt == NULL) || (value == NULL)) return(-1);
2480 if (ctxt->valueNr >= ctxt->valueMax) {
2481 xmlXPathObjectPtr *tmp;
2482
2483 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2484 2 * ctxt->valueMax *
2485 sizeof(ctxt->valueTab[0]));
2486 if (tmp == NULL) {
2487 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
2488 ctxt->error = XPATH_MEMORY_ERROR;
2489 return (0);
2490 }
2491 ctxt->valueMax *= 2;
2492 ctxt->valueTab = tmp;
2493 }
2494 ctxt->valueTab[ctxt->valueNr] = value;
2495 ctxt->value = value;
2496 return (ctxt->valueNr++);
2497}
2498
2499/**
2500 * xmlXPathPopBoolean:
2501 * @ctxt: an XPath parser context
2502 *
2503 * Pops a boolean from the stack, handling conversion if needed.
2504 * Check error with #xmlXPathCheckError.
2505 *
2506 * Returns the boolean
2507 */
2508int
2509xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2510 xmlXPathObjectPtr obj;
2511 int ret;
2512
2513 obj = valuePop(ctxt);
2514 if (obj == NULL) {
2515 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2516 return(0);
2517 }
2518 if (obj->type != XPATH_BOOLEAN)
2519 ret = xmlXPathCastToBoolean(obj);
2520 else
2521 ret = obj->boolval;
2522 xmlXPathReleaseObject(ctxt->context, obj);
2523 return(ret);
2524}
2525
2526/**
2527 * xmlXPathPopNumber:
2528 * @ctxt: an XPath parser context
2529 *
2530 * Pops a number from the stack, handling conversion if needed.
2531 * Check error with #xmlXPathCheckError.
2532 *
2533 * Returns the number
2534 */
2535double
2536xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2537 xmlXPathObjectPtr obj;
2538 double ret;
2539
2540 obj = valuePop(ctxt);
2541 if (obj == NULL) {
2542 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2543 return(0);
2544 }
2545 if (obj->type != XPATH_NUMBER)
2546 ret = xmlXPathCastToNumber(obj);
2547 else
2548 ret = obj->floatval;
2549 xmlXPathReleaseObject(ctxt->context, obj);
2550 return(ret);
2551}
2552
2553/**
2554 * xmlXPathPopString:
2555 * @ctxt: an XPath parser context
2556 *
2557 * Pops a string from the stack, handling conversion if needed.
2558 * Check error with #xmlXPathCheckError.
2559 *
2560 * Returns the string
2561 */
2562xmlChar *
2563xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2564 xmlXPathObjectPtr obj;
2565 xmlChar * ret;
2566
2567 obj = valuePop(ctxt);
2568 if (obj == NULL) {
2569 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2570 return(NULL);
2571 }
2572 ret = xmlXPathCastToString(obj); /* this does required strdup */
2573 /* TODO: needs refactoring somewhere else */
2574 if (obj->stringval == ret)
2575 obj->stringval = NULL;
2576 xmlXPathReleaseObject(ctxt->context, obj);
2577 return(ret);
2578}
2579
2580/**
2581 * xmlXPathPopNodeSet:
2582 * @ctxt: an XPath parser context
2583 *
2584 * Pops a node-set from the stack, handling conversion if needed.
2585 * Check error with #xmlXPathCheckError.
2586 *
2587 * Returns the node-set
2588 */
2589xmlNodeSetPtr
2590xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2591 xmlXPathObjectPtr obj;
2592 xmlNodeSetPtr ret;
2593
2594 if (ctxt == NULL) return(NULL);
2595 if (ctxt->value == NULL) {
2596 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2597 return(NULL);
2598 }
2599 if (!xmlXPathStackIsNodeSet(ctxt)) {
2600 xmlXPathSetTypeError(ctxt);
2601 return(NULL);
2602 }
2603 obj = valuePop(ctxt);
2604 ret = obj->nodesetval;
2605#if 0
2606 /* to fix memory leak of not clearing obj->user */
2607 if (obj->boolval && obj->user != NULL)
2608 xmlFreeNodeList((xmlNodePtr) obj->user);
2609#endif
2610 obj->nodesetval = NULL;
2611 xmlXPathReleaseObject(ctxt->context, obj);
2612 return(ret);
2613}
2614
2615/**
2616 * xmlXPathPopExternal:
2617 * @ctxt: an XPath parser context
2618 *
2619 * Pops an external object from the stack, handling conversion if needed.
2620 * Check error with #xmlXPathCheckError.
2621 *
2622 * Returns the object
2623 */
2624void *
2625xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2626 xmlXPathObjectPtr obj;
2627 void * ret;
2628
2629 if ((ctxt == NULL) || (ctxt->value == NULL)) {
2630 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2631 return(NULL);
2632 }
2633 if (ctxt->value->type != XPATH_USERS) {
2634 xmlXPathSetTypeError(ctxt);
2635 return(NULL);
2636 }
2637 obj = valuePop(ctxt);
2638 ret = obj->user;
2639 obj->user = NULL;
2640 xmlXPathReleaseObject(ctxt->context, obj);
2641 return(ret);
2642}
2643
2644/*
2645 * Macros for accessing the content. Those should be used only by the parser,
2646 * and not exported.
2647 *
2648 * Dirty macros, i.e. one need to make assumption on the context to use them
2649 *
2650 * CUR_PTR return the current pointer to the xmlChar to be parsed.
2651 * CUR returns the current xmlChar value, i.e. a 8 bit value
2652 * in ISO-Latin or UTF-8.
2653 * This should be used internally by the parser
2654 * only to compare to ASCII values otherwise it would break when
2655 * running with UTF-8 encoding.
2656 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
2657 * to compare on ASCII based substring.
2658 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2659 * strings within the parser.
2660 * CURRENT Returns the current char value, with the full decoding of
2661 * UTF-8 if we are using this mode. It returns an int.
2662 * NEXT Skip to the next character, this does the proper decoding
2663 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
2664 * It returns the pointer to the current xmlChar.
2665 */
2666
2667#define CUR (*ctxt->cur)
2668#define SKIP(val) ctxt->cur += (val)
2669#define NXT(val) ctxt->cur[(val)]
2670#define CUR_PTR ctxt->cur
2671#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2672
2673#define COPY_BUF(l,b,i,v) \
2674 if (l == 1) b[i++] = (xmlChar) v; \
2675 else i += xmlCopyChar(l,&b[i],v)
2676
2677#define NEXTL(l) ctxt->cur += l
2678
2679#define SKIP_BLANKS \
2680 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2681
2682#define CURRENT (*ctxt->cur)
2683#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
2684
2685
2686#ifndef DBL_DIG
2687#define DBL_DIG 16
2688#endif
2689#ifndef DBL_EPSILON
2690#define DBL_EPSILON 1E-9
2691#endif
2692
2693#define UPPER_DOUBLE 1E9
2694#define LOWER_DOUBLE 1E-5
2695#define LOWER_DOUBLE_EXP 5
2696
2697#define INTEGER_DIGITS DBL_DIG
2698#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
2699#define EXPONENT_DIGITS (3 + 2)
2700
2701/**
2702 * xmlXPathFormatNumber:
2703 * @number: number to format
2704 * @buffer: output buffer
2705 * @buffersize: size of output buffer
2706 *
2707 * Convert the number into a string representation.
2708 */
2709static void
2710xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2711{
2712 switch (xmlXPathIsInf(number)) {
2713 case 1:
2714 if (buffersize > (int)sizeof("Infinity"))
2715 snprintf(buffer, buffersize, "Infinity");
2716 break;
2717 case -1:
2718 if (buffersize > (int)sizeof("-Infinity"))
2719 snprintf(buffer, buffersize, "-Infinity");
2720 break;
2721 default:
2722 if (xmlXPathIsNaN(number)) {
2723 if (buffersize > (int)sizeof("NaN"))
2724 snprintf(buffer, buffersize, "NaN");
2725 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
2726 snprintf(buffer, buffersize, "0");
2727 } else if (number == ((int) number)) {
2728 char work[30];
2729 char *ptr, *cur;
2730 int value = (int) number;
2731
2732 ptr = &buffer[0];
2733 if (value == 0) {
2734 *ptr++ = '0';
2735 } else {
2736 snprintf(work, 29, "%d", value);
2737 cur = &work[0];
2738 while ((*cur) && (ptr - buffer < buffersize)) {
2739 *ptr++ = *cur++;
2740 }
2741 }
2742 if (ptr - buffer < buffersize) {
2743 *ptr = 0;
2744 } else if (buffersize > 0) {
2745 ptr--;
2746 *ptr = 0;
2747 }
2748 } else {
2749 /*
2750 For the dimension of work,
2751 DBL_DIG is number of significant digits
2752 EXPONENT is only needed for "scientific notation"
2753 3 is sign, decimal point, and terminating zero
2754 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2755 Note that this dimension is slightly (a few characters)
2756 larger than actually necessary.
2757 */
2758 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2759 int integer_place, fraction_place;
2760 char *ptr;
2761 char *after_fraction;
2762 double absolute_value;
2763 int size;
2764
2765 absolute_value = fabs(number);
2766
2767 /*
2768 * First choose format - scientific or regular floating point.
2769 * In either case, result is in work, and after_fraction points
2770 * just past the fractional part.
2771 */
2772 if ( ((absolute_value > UPPER_DOUBLE) ||
2773 (absolute_value < LOWER_DOUBLE)) &&
2774 (absolute_value != 0.0) ) {
2775 /* Use scientific notation */
2776 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2777 fraction_place = DBL_DIG - 1;
2778 size = snprintf(work, sizeof(work),"%*.*e",
2779 integer_place, fraction_place, number);
2780 while ((size > 0) && (work[size] != 'e')) size--;
2781
2782 }
2783 else {
2784 /* Use regular notation */
2785 if (absolute_value > 0.0) {
2786 integer_place = (int)log10(absolute_value);
2787 if (integer_place > 0)
2788 fraction_place = DBL_DIG - integer_place - 1;
2789 else
2790 fraction_place = DBL_DIG - integer_place;
2791 } else {
2792 fraction_place = 1;
2793 }
2794 size = snprintf(work, sizeof(work), "%0.*f",
2795 fraction_place, number);
2796 }
2797
2798 /* Remove fractional trailing zeroes */
2799 after_fraction = work + size;
2800 ptr = after_fraction;
2801 while (*(--ptr) == '0')
2802 ;
2803 if (*ptr != '.')
2804 ptr++;
2805 while ((*ptr++ = *after_fraction++) != 0);
2806
2807 /* Finally copy result back to caller */
2808 size = strlen(work) + 1;
2809 if (size > buffersize) {
2810 work[buffersize - 1] = 0;
2811 size = buffersize;
2812 }
2813 memmove(buffer, work, size);
2814 }
2815 break;
2816 }
2817}
2818
2819
2820/************************************************************************
2821 * *
2822 * Routines to handle NodeSets *
2823 * *
2824 ************************************************************************/
2825
2826/**
2827 * xmlXPathOrderDocElems:
2828 * @doc: an input document
2829 *
2830 * Call this routine to speed up XPath computation on static documents.
2831 * This stamps all the element nodes with the document order
2832 * Like for line information, the order is kept in the element->content
2833 * field, the value stored is actually - the node number (starting at -1)
2834 * to be able to differentiate from line numbers.
2835 *
2836 * Returns the number of elements found in the document or -1 in case
2837 * of error.
2838 */
2839long
2840xmlXPathOrderDocElems(xmlDocPtr doc) {
2841 long count = 0;
2842 xmlNodePtr cur;
2843
2844 if (doc == NULL)
2845 return(-1);
2846 cur = doc->children;
2847 while (cur != NULL) {
2848 if (cur->type == XML_ELEMENT_NODE) {
2849 cur->content = (void *) (-(++count));
2850 if (cur->children != NULL) {
2851 cur = cur->children;
2852 continue;
2853 }
2854 }
2855 if (cur->next != NULL) {
2856 cur = cur->next;
2857 continue;
2858 }
2859 do {
2860 cur = cur->parent;
2861 if (cur == NULL)
2862 break;
2863 if (cur == (xmlNodePtr) doc) {
2864 cur = NULL;
2865 break;
2866 }
2867 if (cur->next != NULL) {
2868 cur = cur->next;
2869 break;
2870 }
2871 } while (cur != NULL);
2872 }
2873 return(count);
2874}
2875
2876/**
2877 * xmlXPathCmpNodes:
2878 * @node1: the first node
2879 * @node2: the second node
2880 *
2881 * Compare two nodes w.r.t document order
2882 *
2883 * Returns -2 in case of error 1 if first point < second point, 0 if
2884 * it's the same node, -1 otherwise
2885 */
2886int
2887xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2888 int depth1, depth2;
2889 int attr1 = 0, attr2 = 0;
2890 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
2891 xmlNodePtr cur, root;
2892
2893 if ((node1 == NULL) || (node2 == NULL))
2894 return(-2);
2895 /*
2896 * a couple of optimizations which will avoid computations in most cases
2897 */
2898 if (node1 == node2) /* trivial case */
2899 return(0);
2900 if (node1->type == XML_ATTRIBUTE_NODE) {
2901 attr1 = 1;
2902 attrNode1 = node1;
2903 node1 = node1->parent;
2904 }
2905 if (node2->type == XML_ATTRIBUTE_NODE) {
2906 attr2 = 1;
2907 attrNode2 = node2;
2908 node2 = node2->parent;
2909 }
2910 if (node1 == node2) {
2911 if (attr1 == attr2) {
2912 /* not required, but we keep attributes in order */
2913 if (attr1 != 0) {
2914 cur = attrNode2->prev;
2915 while (cur != NULL) {
2916 if (cur == attrNode1)
2917 return (1);
2918 cur = cur->prev;
2919 }
2920 return (-1);
2921 }
2922 return(0);
2923 }
2924 if (attr2 == 1)
2925 return(1);
2926 return(-1);
2927 }
2928 if ((node1->type == XML_NAMESPACE_DECL) ||
2929 (node2->type == XML_NAMESPACE_DECL))
2930 return(1);
2931 if (node1 == node2->prev)
2932 return(1);
2933 if (node1 == node2->next)
2934 return(-1);
2935
2936 /*
2937 * Speedup using document order if availble.
2938 */
2939 if ((node1->type == XML_ELEMENT_NODE) &&
2940 (node2->type == XML_ELEMENT_NODE) &&
2941 (0 > (long) node1->content) &&
2942 (0 > (long) node2->content) &&
2943 (node1->doc == node2->doc)) {
2944 long l1, l2;
2945
2946 l1 = -((long) node1->content);
2947 l2 = -((long) node2->content);
2948 if (l1 < l2)
2949 return(1);
2950 if (l1 > l2)
2951 return(-1);
2952 }
2953
2954 /*
2955 * compute depth to root
2956 */
2957 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2958 if (cur == node1)
2959 return(1);
2960 depth2++;
2961 }
2962 root = cur;
2963 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2964 if (cur == node2)
2965 return(-1);
2966 depth1++;
2967 }
2968 /*
2969 * Distinct document (or distinct entities :-( ) case.
2970 */
2971 if (root != cur) {
2972 return(-2);
2973 }
2974 /*
2975 * get the nearest common ancestor.
2976 */
2977 while (depth1 > depth2) {
2978 depth1--;
2979 node1 = node1->parent;
2980 }
2981 while (depth2 > depth1) {
2982 depth2--;
2983 node2 = node2->parent;
2984 }
2985 while (node1->parent != node2->parent) {
2986 node1 = node1->parent;
2987 node2 = node2->parent;
2988 /* should not happen but just in case ... */
2989 if ((node1 == NULL) || (node2 == NULL))
2990 return(-2);
2991 }
2992 /*
2993 * Find who's first.
2994 */
2995 if (node1 == node2->prev)
2996 return(1);
2997 if (node1 == node2->next)
2998 return(-1);
2999 /*
3000 * Speedup using document order if availble.
3001 */
3002 if ((node1->type == XML_ELEMENT_NODE) &&
3003 (node2->type == XML_ELEMENT_NODE) &&
3004 (0 > (long) node1->content) &&
3005 (0 > (long) node2->content) &&
3006 (node1->doc == node2->doc)) {
3007 long l1, l2;
3008
3009 l1 = -((long) node1->content);
3010 l2 = -((long) node2->content);
3011 if (l1 < l2)
3012 return(1);
3013 if (l1 > l2)
3014 return(-1);
3015 }
3016
3017 for (cur = node1->next;cur != NULL;cur = cur->next)
3018 if (cur == node2)
3019 return(1);
3020 return(-1); /* assume there is no sibling list corruption */
3021}
3022
3023#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3024/**
3025 * xmlXPathCmpNodesExt:
3026 * @node1: the first node
3027 * @node2: the second node
3028 *
3029 * Compare two nodes w.r.t document order.
3030 * This one is optimized for handling of non-element nodes.
3031 *
3032 * Returns -2 in case of error 1 if first point < second point, 0 if
3033 * it's the same node, -1 otherwise
3034 */
3035static int
3036xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
3037 int depth1, depth2;
3038 int misc = 0, precedence1 = 0, precedence2 = 0;
3039 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
3040 xmlNodePtr cur, root;
3041 long l1, l2;
3042
3043 if ((node1 == NULL) || (node2 == NULL))
3044 return(-2);
3045
3046 if (node1 == node2)
3047 return(0);
3048
3049 /*
3050 * a couple of optimizations which will avoid computations in most cases
3051 */
3052 switch (node1->type) {
3053 case XML_ELEMENT_NODE:
3054 if (node2->type == XML_ELEMENT_NODE) {
3055 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
3056 (0 > (long) node2->content) &&
3057 (node1->doc == node2->doc))
3058 {
3059 l1 = -((long) node1->content);
3060 l2 = -((long) node2->content);
3061 if (l1 < l2)
3062 return(1);
3063 if (l1 > l2)
3064 return(-1);
3065 } else
3066 goto turtle_comparison;
3067 }
3068 break;
3069 case XML_ATTRIBUTE_NODE:
3070 precedence1 = 1; /* element is owner */
3071 miscNode1 = node1;
3072 node1 = node1->parent;
3073 misc = 1;
3074 break;
3075 case XML_TEXT_NODE:
3076 case XML_CDATA_SECTION_NODE:
3077 case XML_COMMENT_NODE:
3078 case XML_PI_NODE: {
3079 miscNode1 = node1;
3080 /*
3081 * Find nearest element node.
3082 */
3083 if (node1->prev != NULL) {
3084 do {
3085 node1 = node1->prev;
3086 if (node1->type == XML_ELEMENT_NODE) {
3087 precedence1 = 3; /* element in prev-sibl axis */
3088 break;
3089 }
3090 if (node1->prev == NULL) {
3091 precedence1 = 2; /* element is parent */
3092 /*
3093 * URGENT TODO: Are there any cases, where the
3094 * parent of such a node is not an element node?
3095 */
3096 node1 = node1->parent;
3097 break;
3098 }
3099 } while (1);
3100 } else {
3101 precedence1 = 2; /* element is parent */
3102 node1 = node1->parent;
3103 }
3104 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
3105 (0 <= (long) node1->content)) {
3106 /*
3107 * Fallback for whatever case.
3108 */
3109 node1 = miscNode1;
3110 precedence1 = 0;
3111 } else
3112 misc = 1;
3113 }
3114 break;
3115 case XML_NAMESPACE_DECL:
3116 /*
3117 * TODO: why do we return 1 for namespace nodes?
3118 */
3119 return(1);
3120 default:
3121 break;
3122 }
3123 switch (node2->type) {
3124 case XML_ELEMENT_NODE:
3125 break;
3126 case XML_ATTRIBUTE_NODE:
3127 precedence2 = 1; /* element is owner */
3128 miscNode2 = node2;
3129 node2 = node2->parent;
3130 misc = 1;
3131 break;
3132 case XML_TEXT_NODE:
3133 case XML_CDATA_SECTION_NODE:
3134 case XML_COMMENT_NODE:
3135 case XML_PI_NODE: {
3136 miscNode2 = node2;
3137 if (node2->prev != NULL) {
3138 do {
3139 node2 = node2->prev;
3140 if (node2->type == XML_ELEMENT_NODE) {
3141 precedence2 = 3; /* element in prev-sibl axis */
3142 break;
3143 }
3144 if (node2->prev == NULL) {
3145 precedence2 = 2; /* element is parent */
3146 node2 = node2->parent;
3147 break;
3148 }
3149 } while (1);
3150 } else {
3151 precedence2 = 2; /* element is parent */
3152 node2 = node2->parent;
3153 }
3154 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3155 (0 <= (long) node1->content))
3156 {
3157 node2 = miscNode2;
3158 precedence2 = 0;
3159 } else
3160 misc = 1;
3161 }
3162 break;
3163 case XML_NAMESPACE_DECL:
3164 return(1);
3165 default:
3166 break;
3167 }
3168 if (misc) {
3169 if (node1 == node2) {
3170 if (precedence1 == precedence2) {
3171 /*
3172 * The ugly case; but normally there aren't many
3173 * adjacent non-element nodes around.
3174 */
3175 cur = miscNode2->prev;
3176 while (cur != NULL) {
3177 if (cur == miscNode1)
3178 return(1);
3179 if (cur->type == XML_ELEMENT_NODE)
3180 return(-1);
3181 cur = cur->prev;
3182 }
3183 return (-1);
3184 } else {
3185 /*
3186 * Evaluate based on higher precedence wrt to the element.
3187 * TODO: This assumes attributes are sorted before content.
3188 * Is this 100% correct?
3189 */
3190 if (precedence1 < precedence2)
3191 return(1);
3192 else
3193 return(-1);
3194 }
3195 }
3196 /*
3197 * Special case: One of the helper-elements is contained by the other.
3198 * <foo>
3199 * <node2>
3200 * <node1>Text-1(precedence1 == 2)</node1>
3201 * </node2>
3202 * Text-6(precedence2 == 3)
3203 * </foo>
3204 */
3205 if ((precedence2 == 3) && (precedence1 > 1)) {
3206 cur = node1->parent;
3207 while (cur) {
3208 if (cur == node2)
3209 return(1);
3210 cur = cur->parent;
3211 }
3212 }
3213 if ((precedence1 == 3) && (precedence2 > 1)) {
3214 cur = node2->parent;
3215 while (cur) {
3216 if (cur == node1)
3217 return(-1);
3218 cur = cur->parent;
3219 }
3220 }
3221 }
3222
3223 /*
3224 * Speedup using document order if availble.
3225 */
3226 if ((node1->type == XML_ELEMENT_NODE) &&
3227 (node2->type == XML_ELEMENT_NODE) &&
3228 (0 > (long) node1->content) &&
3229 (0 > (long) node2->content) &&
3230 (node1->doc == node2->doc)) {
3231
3232 l1 = -((long) node1->content);
3233 l2 = -((long) node2->content);
3234 if (l1 < l2)
3235 return(1);
3236 if (l1 > l2)
3237 return(-1);
3238 }
3239
3240turtle_comparison:
3241
3242 if (node1 == node2->prev)
3243 return(1);
3244 if (node1 == node2->next)
3245 return(-1);
3246 /*
3247 * compute depth to root
3248 */
3249 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3250 if (cur == node1)
3251 return(1);
3252 depth2++;
3253 }
3254 root = cur;
3255 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3256 if (cur == node2)
3257 return(-1);
3258 depth1++;
3259 }
3260 /*
3261 * Distinct document (or distinct entities :-( ) case.
3262 */
3263 if (root != cur) {
3264 return(-2);
3265 }
3266 /*
3267 * get the nearest common ancestor.
3268 */
3269 while (depth1 > depth2) {
3270 depth1--;
3271 node1 = node1->parent;
3272 }
3273 while (depth2 > depth1) {
3274 depth2--;
3275 node2 = node2->parent;
3276 }
3277 while (node1->parent != node2->parent) {
3278 node1 = node1->parent;
3279 node2 = node2->parent;
3280 /* should not happen but just in case ... */
3281 if ((node1 == NULL) || (node2 == NULL))
3282 return(-2);
3283 }
3284 /*
3285 * Find who's first.
3286 */
3287 if (node1 == node2->prev)
3288 return(1);
3289 if (node1 == node2->next)
3290 return(-1);
3291 /*
3292 * Speedup using document order if availble.
3293 */
3294 if ((node1->type == XML_ELEMENT_NODE) &&
3295 (node2->type == XML_ELEMENT_NODE) &&
3296 (0 > (long) node1->content) &&
3297 (0 > (long) node2->content) &&
3298 (node1->doc == node2->doc)) {
3299
3300 l1 = -((long) node1->content);
3301 l2 = -((long) node2->content);
3302 if (l1 < l2)
3303 return(1);
3304 if (l1 > l2)
3305 return(-1);
3306 }
3307
3308 for (cur = node1->next;cur != NULL;cur = cur->next)
3309 if (cur == node2)
3310 return(1);
3311 return(-1); /* assume there is no sibling list corruption */
3312}
3313#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
3314
3315/**
3316 * xmlXPathNodeSetSort:
3317 * @set: the node set
3318 *
3319 * Sort the node set in document order
3320 */
3321void
3322xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3323 int i, j, incr, len;
3324 xmlNodePtr tmp;
3325
3326 if (set == NULL)
3327 return;
3328
3329 /* Use Shell's sort to sort the node-set */
3330 len = set->nodeNr;
3331 for (incr = len / 2; incr > 0; incr /= 2) {
3332 for (i = incr; i < len; i++) {
3333 j = i - incr;
3334 while (j >= 0) {
3335#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3336 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3337 set->nodeTab[j + incr]) == -1)
3338#else
3339 if (xmlXPathCmpNodes(set->nodeTab[j],
3340 set->nodeTab[j + incr]) == -1)
3341#endif
3342 {
3343 tmp = set->nodeTab[j];
3344 set->nodeTab[j] = set->nodeTab[j + incr];
3345 set->nodeTab[j + incr] = tmp;
3346 j -= incr;
3347 } else
3348 break;
3349 }
3350 }
3351 }
3352}
3353
3354#define XML_NODESET_DEFAULT 10
3355/**
3356 * xmlXPathNodeSetDupNs:
3357 * @node: the parent node of the namespace XPath node
3358 * @ns: the libxml namespace declaration node.
3359 *
3360 * Namespace node in libxml don't match the XPath semantic. In a node set
3361 * the namespace nodes are duplicated and the next pointer is set to the
3362 * parent node in the XPath semantic.
3363 *
3364 * Returns the newly created object.
3365 */
3366static xmlNodePtr
3367xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3368 xmlNsPtr cur;
3369
3370 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3371 return(NULL);
3372 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3373 return((xmlNodePtr) ns);
3374
3375 /*
3376 * Allocate a new Namespace and fill the fields.
3377 */
3378 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3379 if (cur == NULL) {
3380 xmlXPathErrMemory(NULL, "duplicating namespace\n");
3381 return(NULL);
3382 }
3383 memset(cur, 0, sizeof(xmlNs));
3384 cur->type = XML_NAMESPACE_DECL;
3385 if (ns->href != NULL)
3386 cur->href = xmlStrdup(ns->href);
3387 if (ns->prefix != NULL)
3388 cur->prefix = xmlStrdup(ns->prefix);
3389 cur->next = (xmlNsPtr) node;
3390 return((xmlNodePtr) cur);
3391}
3392
3393/**
3394 * xmlXPathNodeSetFreeNs:
3395 * @ns: the XPath namespace node found in a nodeset.
3396 *
3397 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3398 * the namespace nodes are duplicated and the next pointer is set to the
3399 * parent node in the XPath semantic. Check if such a node needs to be freed
3400 */
3401void
3402xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3403 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3404 return;
3405
3406 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3407 if (ns->href != NULL)
3408 xmlFree((xmlChar *)ns->href);
3409 if (ns->prefix != NULL)
3410 xmlFree((xmlChar *)ns->prefix);
3411 xmlFree(ns);
3412 }
3413}
3414
3415/**
3416 * xmlXPathNodeSetCreate:
3417 * @val: an initial xmlNodePtr, or NULL
3418 *
3419 * Create a new xmlNodeSetPtr of type double and of value @val
3420 *
3421 * Returns the newly created object.
3422 */
3423xmlNodeSetPtr
3424xmlXPathNodeSetCreate(xmlNodePtr val) {
3425 xmlNodeSetPtr ret;
3426
3427 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3428 if (ret == NULL) {
3429 xmlXPathErrMemory(NULL, "creating nodeset\n");
3430 return(NULL);
3431 }
3432 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3433 if (val != NULL) {
3434 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3435 sizeof(xmlNodePtr));
3436 if (ret->nodeTab == NULL) {
3437 xmlXPathErrMemory(NULL, "creating nodeset\n");
3438 xmlFree(ret);
3439 return(NULL);
3440 }
3441 memset(ret->nodeTab, 0 ,
3442 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3443 ret->nodeMax = XML_NODESET_DEFAULT;
3444 if (val->type == XML_NAMESPACE_DECL) {
3445 xmlNsPtr ns = (xmlNsPtr) val;
3446
3447 ret->nodeTab[ret->nodeNr++] =
3448 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3449 } else
3450 ret->nodeTab[ret->nodeNr++] = val;
3451 }
3452 return(ret);
3453}
3454
3455/**
3456 * xmlXPathNodeSetCreateSize:
3457 * @size: the initial size of the set
3458 *
3459 * Create a new xmlNodeSetPtr of type double and of value @val
3460 *
3461 * Returns the newly created object.
3462 */
3463static xmlNodeSetPtr
3464xmlXPathNodeSetCreateSize(int size) {
3465 xmlNodeSetPtr ret;
3466
3467 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3468 if (ret == NULL) {
3469 xmlXPathErrMemory(NULL, "creating nodeset\n");
3470 return(NULL);
3471 }
3472 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3473 if (size < XML_NODESET_DEFAULT)
3474 size = XML_NODESET_DEFAULT;
3475 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3476 if (ret->nodeTab == NULL) {
3477 xmlXPathErrMemory(NULL, "creating nodeset\n");
3478 xmlFree(ret);
3479 return(NULL);
3480 }
3481 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3482 ret->nodeMax = size;
3483 return(ret);
3484}
3485
3486/**
3487 * xmlXPathNodeSetContains:
3488 * @cur: the node-set
3489 * @val: the node
3490 *
3491 * checks whether @cur contains @val
3492 *
3493 * Returns true (1) if @cur contains @val, false (0) otherwise
3494 */
3495int
3496xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3497 int i;
3498
3499 if ((cur == NULL) || (val == NULL)) return(0);
3500 if (val->type == XML_NAMESPACE_DECL) {
3501 for (i = 0; i < cur->nodeNr; i++) {
3502 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3503 xmlNsPtr ns1, ns2;
3504
3505 ns1 = (xmlNsPtr) val;
3506 ns2 = (xmlNsPtr) cur->nodeTab[i];
3507 if (ns1 == ns2)
3508 return(1);
3509 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3510 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3511 return(1);
3512 }
3513 }
3514 } else {
3515 for (i = 0; i < cur->nodeNr; i++) {
3516 if (cur->nodeTab[i] == val)
3517 return(1);
3518 }
3519 }
3520 return(0);
3521}
3522
3523/**
3524 * xmlXPathNodeSetAddNs:
3525 * @cur: the initial node set
3526 * @node: the hosting node
3527 * @ns: a the namespace node
3528 *
3529 * add a new namespace node to an existing NodeSet
3530 */
3531void
3532xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3533 int i;
3534
3535
3536 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3537 (ns->type != XML_NAMESPACE_DECL) ||
3538 (node->type != XML_ELEMENT_NODE))
3539 return;
3540
3541 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3542 /*
3543 * prevent duplicates
3544 */
3545 for (i = 0;i < cur->nodeNr;i++) {
3546 if ((cur->nodeTab[i] != NULL) &&
3547 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3548 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3549 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3550 return;
3551 }
3552
3553 /*
3554 * grow the nodeTab if needed
3555 */
3556 if (cur->nodeMax == 0) {
3557 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3558 sizeof(xmlNodePtr));
3559 if (cur->nodeTab == NULL) {
3560 xmlXPathErrMemory(NULL, "growing nodeset\n");
3561 return;
3562 }
3563 memset(cur->nodeTab, 0 ,
3564 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3565 cur->nodeMax = XML_NODESET_DEFAULT;
3566 } else if (cur->nodeNr == cur->nodeMax) {
3567 xmlNodePtr *temp;
3568
3569 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3570 sizeof(xmlNodePtr));
3571 if (temp == NULL) {
3572 xmlXPathErrMemory(NULL, "growing nodeset\n");
3573 return;
3574 }
3575 cur->nodeMax *= 2;
3576 cur->nodeTab = temp;
3577 }
3578 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3579}
3580
3581/**
3582 * xmlXPathNodeSetAdd:
3583 * @cur: the initial node set
3584 * @val: a new xmlNodePtr
3585 *
3586 * add a new xmlNodePtr to an existing NodeSet
3587 */
3588void
3589xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3590 int i;
3591
3592 if ((cur == NULL) || (val == NULL)) return;
3593
3594#if 0
3595 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3596 return; /* an XSLT fake node */
3597#endif
3598
3599 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3600 /*
3601 * prevent duplcates
3602 */
3603 for (i = 0;i < cur->nodeNr;i++)
3604 if (cur->nodeTab[i] == val) return;
3605
3606 /*
3607 * grow the nodeTab if needed
3608 */
3609 if (cur->nodeMax == 0) {
3610 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3611 sizeof(xmlNodePtr));
3612 if (cur->nodeTab == NULL) {
3613 xmlXPathErrMemory(NULL, "growing nodeset\n");
3614 return;
3615 }
3616 memset(cur->nodeTab, 0 ,
3617 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3618 cur->nodeMax = XML_NODESET_DEFAULT;
3619 } else if (cur->nodeNr == cur->nodeMax) {
3620 xmlNodePtr *temp;
3621
3622 cur->nodeMax *= 2;
3623 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3624 sizeof(xmlNodePtr));
3625 if (temp == NULL) {
3626 xmlXPathErrMemory(NULL, "growing nodeset\n");
3627 return;
3628 }
3629 cur->nodeTab = temp;
3630 }
3631 if (val->type == XML_NAMESPACE_DECL) {
3632 xmlNsPtr ns = (xmlNsPtr) val;
3633
3634 cur->nodeTab[cur->nodeNr++] =
3635 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3636 } else
3637 cur->nodeTab[cur->nodeNr++] = val;
3638}
3639
3640/**
3641 * xmlXPathNodeSetAddUnique:
3642 * @cur: the initial node set
3643 * @val: a new xmlNodePtr
3644 *
3645 * add a new xmlNodePtr to an existing NodeSet, optimized version
3646 * when we are sure the node is not already in the set.
3647 */
3648void
3649xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3650 if ((cur == NULL) || (val == NULL)) return;
3651
3652#if 0
3653 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3654 return; /* an XSLT fake node */
3655#endif
3656
3657 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3658 /*
3659 * grow the nodeTab if needed
3660 */
3661 if (cur->nodeMax == 0) {
3662 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3663 sizeof(xmlNodePtr));
3664 if (cur->nodeTab == NULL) {
3665 xmlXPathErrMemory(NULL, "growing nodeset\n");
3666 return;
3667 }
3668 memset(cur->nodeTab, 0 ,
3669 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3670 cur->nodeMax = XML_NODESET_DEFAULT;
3671 } else if (cur->nodeNr == cur->nodeMax) {
3672 xmlNodePtr *temp;
3673
3674 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3675 sizeof(xmlNodePtr));
3676 if (temp == NULL) {
3677 xmlXPathErrMemory(NULL, "growing nodeset\n");
3678 return;
3679 }
3680 cur->nodeTab = temp;
3681 cur->nodeMax *= 2;
3682 }
3683 if (val->type == XML_NAMESPACE_DECL) {
3684 xmlNsPtr ns = (xmlNsPtr) val;
3685
3686 cur->nodeTab[cur->nodeNr++] =
3687 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3688 } else
3689 cur->nodeTab[cur->nodeNr++] = val;
3690}
3691
3692/**
3693 * xmlXPathNodeSetMerge:
3694 * @val1: the first NodeSet or NULL
3695 * @val2: the second NodeSet
3696 *
3697 * Merges two nodesets, all nodes from @val2 are added to @val1
3698 * if @val1 is NULL, a new set is created and copied from @val2
3699 *
3700 * Returns @val1 once extended or NULL in case of error.
3701 */
3702xmlNodeSetPtr
3703xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3704 int i, j, initNr, skip;
3705 xmlNodePtr n1, n2;
3706
3707 if (val2 == NULL) return(val1);
3708 if (val1 == NULL) {
3709 val1 = xmlXPathNodeSetCreate(NULL);
3710#if 0
3711 /*
3712 * TODO: The optimization won't work in every case, since
3713 * those nasty namespace nodes need to be added with
3714 * xmlXPathNodeSetDupNs() to the set; thus a pure
3715 * memcpy is not possible.
3716 * If there was a flag on the nodesetval, indicating that
3717 * some temporary nodes are in, that would be helpfull.
3718 */
3719 /*
3720 * Optimization: Create an equally sized node-set
3721 * and memcpy the content.
3722 */
3723 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3724 if (val1 == NULL)
3725 return(NULL);
3726 if (val2->nodeNr != 0) {
3727 if (val2->nodeNr == 1)
3728 *(val1->nodeTab) = *(val2->nodeTab);
3729 else {
3730 memcpy(val1->nodeTab, val2->nodeTab,
3731 val2->nodeNr * sizeof(xmlNodePtr));
3732 }
3733 val1->nodeNr = val2->nodeNr;
3734 }
3735 return(val1);
3736#endif
3737 }
3738
3739 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3740 initNr = val1->nodeNr;
3741
3742 for (i = 0;i < val2->nodeNr;i++) {
3743 n2 = val2->nodeTab[i];
3744 /*
3745 * check against duplicates
3746 */
3747 skip = 0;
3748 for (j = 0; j < initNr; j++) {
3749 n1 = val1->nodeTab[j];
3750 if (n1 == n2) {
3751 skip = 1;
3752 break;
3753 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3754 (n2->type == XML_NAMESPACE_DECL)) {
3755 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3756 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3757 ((xmlNsPtr) n2)->prefix)))
3758 {
3759 skip = 1;
3760 break;
3761 }
3762 }
3763 }
3764 if (skip)
3765 continue;
3766
3767 /*
3768 * grow the nodeTab if needed
3769 */
3770 if (val1->nodeMax == 0) {
3771 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3772 sizeof(xmlNodePtr));
3773 if (val1->nodeTab == NULL) {
3774 xmlXPathErrMemory(NULL, "merging nodeset\n");
3775 return(NULL);
3776 }
3777 memset(val1->nodeTab, 0 ,
3778 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3779 val1->nodeMax = XML_NODESET_DEFAULT;
3780 } else if (val1->nodeNr == val1->nodeMax) {
3781 xmlNodePtr *temp;
3782
3783 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3784 sizeof(xmlNodePtr));
3785 if (temp == NULL) {
3786 xmlXPathErrMemory(NULL, "merging nodeset\n");
3787 return(NULL);
3788 }
3789 val1->nodeTab = temp;
3790 val1->nodeMax *= 2;
3791 }
3792 if (n2->type == XML_NAMESPACE_DECL) {
3793 xmlNsPtr ns = (xmlNsPtr) n2;
3794
3795 val1->nodeTab[val1->nodeNr++] =
3796 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3797 } else
3798 val1->nodeTab[val1->nodeNr++] = n2;
3799 }
3800
3801 return(val1);
3802}
3803
3804#if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3805/**
3806 * xmlXPathNodeSetMergeUnique:
3807 * @val1: the first NodeSet or NULL
3808 * @val2: the second NodeSet
3809 *
3810 * Merges two nodesets, all nodes from @val2 are added to @val1
3811 * if @val1 is NULL, a new set is created and copied from @val2
3812 *
3813 * Returns @val1 once extended or NULL in case of error.
3814 */
3815static xmlNodeSetPtr
3816xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3817 int i;
3818
3819 if (val2 == NULL) return(val1);
3820 if (val1 == NULL) {
3821 val1 = xmlXPathNodeSetCreate(NULL);
3822 }
3823
3824 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3825
3826 for (i = 0;i < val2->nodeNr;i++) {
3827 /*
3828 * grow the nodeTab if needed
3829 */
3830 if (val1->nodeMax == 0) {
3831 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3832 sizeof(xmlNodePtr));
3833 if (val1->nodeTab == NULL) {
3834 xmlXPathErrMemory(NULL, "merging nodeset\n");
3835 return(NULL);
3836 }
3837 memset(val1->nodeTab, 0 ,
3838 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3839 val1->nodeMax = XML_NODESET_DEFAULT;
3840 } else if (val1->nodeNr == val1->nodeMax) {
3841 xmlNodePtr *temp;
3842
3843 val1->nodeMax *= 2;
3844 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3845 sizeof(xmlNodePtr));
3846 if (temp == NULL) {
3847 xmlXPathErrMemory(NULL, "merging nodeset\n");
3848 return(NULL);
3849 }
3850 val1->nodeTab = temp;
3851 }
3852 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3853 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
3854
3855 val1->nodeTab[val1->nodeNr++] =
3856 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3857 } else
3858 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
3859 }
3860
3861 return(val1);
3862}
3863#endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3864
3865/**
3866 * xmlXPathNodeSetMergeAndClear:
3867 * @set1: the first NodeSet or NULL
3868 * @set2: the second NodeSet
3869 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3870 *
3871 * Merges two nodesets, all nodes from @set2 are added to @set1
3872 * if @set1 is NULL, a new set is created and copied from @set2.
3873 * Checks for duplicate nodes. Clears set2.
3874 *
3875 * Returns @set1 once extended or NULL in case of error.
3876 */
3877static xmlNodeSetPtr
3878xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3879 int hasNullEntries)
3880{
3881 if ((set1 == NULL) && (hasNullEntries == 0)) {
3882 /*
3883 * Note that doing a memcpy of the list, namespace nodes are
3884 * just assigned to set1, since set2 is cleared anyway.
3885 */
3886 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3887 if (set1 == NULL)
3888 return(NULL);
3889 if (set2->nodeNr != 0) {
3890 memcpy(set1->nodeTab, set2->nodeTab,
3891 set2->nodeNr * sizeof(xmlNodePtr));
3892 set1->nodeNr = set2->nodeNr;
3893 }
3894 } else {
3895 int i, j, initNbSet1;
3896 xmlNodePtr n1, n2;
3897
3898 if (set1 == NULL)
3899 set1 = xmlXPathNodeSetCreate(NULL);
3900
3901 initNbSet1 = set1->nodeNr;
3902 for (i = 0;i < set2->nodeNr;i++) {
3903 n2 = set2->nodeTab[i];
3904 /*
3905 * Skip NULLed entries.
3906 */
3907 if (n2 == NULL)
3908 continue;
3909 /*
3910 * Skip duplicates.
3911 */
3912 for (j = 0; j < initNbSet1; j++) {
3913 n1 = set1->nodeTab[j];
3914 if (n1 == n2) {
3915 goto skip_node;
3916 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3917 (n2->type == XML_NAMESPACE_DECL))
3918 {
3919 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3920 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3921 ((xmlNsPtr) n2)->prefix)))
3922 {
3923 /*
3924 * Free the namespace node.
3925 */
3926 set2->nodeTab[i] = NULL;
3927 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3928 goto skip_node;
3929 }
3930 }
3931 }
3932 /*
3933 * grow the nodeTab if needed
3934 */
3935 if (set1->nodeMax == 0) {
3936 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3937 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3938 if (set1->nodeTab == NULL) {
3939 xmlXPathErrMemory(NULL, "merging nodeset\n");
3940 return(NULL);
3941 }
3942 memset(set1->nodeTab, 0,
3943 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3944 set1->nodeMax = XML_NODESET_DEFAULT;
3945 } else if (set1->nodeNr >= set1->nodeMax) {
3946 xmlNodePtr *temp;
3947
3948 temp = (xmlNodePtr *) xmlRealloc(
3949 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3950 if (temp == NULL) {
3951 xmlXPathErrMemory(NULL, "merging nodeset\n");
3952 return(NULL);
3953 }
3954 set1->nodeTab = temp;
3955 set1->nodeMax *= 2;
3956 }
3957 if (n2->type == XML_NAMESPACE_DECL) {
3958 xmlNsPtr ns = (xmlNsPtr) n2;
3959
3960 set1->nodeTab[set1->nodeNr++] =
3961 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3962 } else
3963 set1->nodeTab[set1->nodeNr++] = n2;
3964skip_node:
3965 {}
3966 }
3967 }
3968 set2->nodeNr = 0;
3969 return(set1);
3970}
3971
3972/**
3973 * xmlXPathNodeSetMergeAndClearNoDupls:
3974 * @set1: the first NodeSet or NULL
3975 * @set2: the second NodeSet
3976 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3977 *
3978 * Merges two nodesets, all nodes from @set2 are added to @set1
3979 * if @set1 is NULL, a new set is created and copied from @set2.
3980 * Doesn't chack for duplicate nodes. Clears set2.
3981 *
3982 * Returns @set1 once extended or NULL in case of error.
3983 */
3984static xmlNodeSetPtr
3985xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3986 int hasNullEntries)
3987{
3988 if (set2 == NULL)
3989 return(set1);
3990 if ((set1 == NULL) && (hasNullEntries == 0)) {
3991 /*
3992 * Note that doing a memcpy of the list, namespace nodes are
3993 * just assigned to set1, since set2 is cleared anyway.
3994 */
3995 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3996 if (set1 == NULL)
3997 return(NULL);
3998 if (set2->nodeNr != 0) {
3999 memcpy(set1->nodeTab, set2->nodeTab,
4000 set2->nodeNr * sizeof(xmlNodePtr));
4001 set1->nodeNr = set2->nodeNr;
4002 }
4003 } else {
4004 int i;
4005 xmlNodePtr n2;
4006
4007 if (set1 == NULL)
4008 set1 = xmlXPathNodeSetCreate(NULL);
4009
4010 for (i = 0;i < set2->nodeNr;i++) {
4011 n2 = set2->nodeTab[i];
4012 /*
4013 * Skip NULLed entries.
4014 */
4015 if (n2 == NULL)
4016 continue;
4017 if (set1->nodeMax == 0) {
4018 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4019 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4020 if (set1->nodeTab == NULL) {
4021 xmlXPathErrMemory(NULL, "merging nodeset\n");
4022 return(NULL);
4023 }
4024 memset(set1->nodeTab, 0,
4025 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4026 set1->nodeMax = XML_NODESET_DEFAULT;
4027 } else if (set1->nodeNr >= set1->nodeMax) {
4028 xmlNodePtr *temp;
4029
4030 temp = (xmlNodePtr *) xmlRealloc(
4031 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4032 if (temp == NULL) {
4033 xmlXPathErrMemory(NULL, "merging nodeset\n");
4034 return(NULL);
4035 }
4036 set1->nodeTab = temp;
4037 set1->nodeMax *= 2;
4038 }
4039 set1->nodeTab[set1->nodeNr++] = n2;
4040 }
4041 }
4042 set2->nodeNr = 0;
4043 return(set1);
4044}
4045
4046/**
4047 * xmlXPathNodeSetDel:
4048 * @cur: the initial node set
4049 * @val: an xmlNodePtr
4050 *
4051 * Removes an xmlNodePtr from an existing NodeSet
4052 */
4053void
4054xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4055 int i;
4056
4057 if (cur == NULL) return;
4058 if (val == NULL) return;
4059
4060 /*
4061 * find node in nodeTab
4062 */
4063 for (i = 0;i < cur->nodeNr;i++)
4064 if (cur->nodeTab[i] == val) break;
4065
4066 if (i >= cur->nodeNr) { /* not found */
4067#ifdef DEBUG
4068 xmlGenericError(xmlGenericErrorContext,
4069 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4070 val->name);
4071#endif
4072 return;
4073 }
4074 if ((cur->nodeTab[i] != NULL) &&
4075 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4076 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4077 cur->nodeNr--;
4078 for (;i < cur->nodeNr;i++)
4079 cur->nodeTab[i] = cur->nodeTab[i + 1];
4080 cur->nodeTab[cur->nodeNr] = NULL;
4081}
4082
4083/**
4084 * xmlXPathNodeSetRemove:
4085 * @cur: the initial node set
4086 * @val: the index to remove
4087 *
4088 * Removes an entry from an existing NodeSet list.
4089 */
4090void
4091xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4092 if (cur == NULL) return;
4093 if (val >= cur->nodeNr) return;
4094 if ((cur->nodeTab[val] != NULL) &&
4095 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4096 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4097 cur->nodeNr--;
4098 for (;val < cur->nodeNr;val++)
4099 cur->nodeTab[val] = cur->nodeTab[val + 1];
4100 cur->nodeTab[cur->nodeNr] = NULL;
4101}
4102
4103/**
4104 * xmlXPathFreeNodeSet:
4105 * @obj: the xmlNodeSetPtr to free
4106 *
4107 * Free the NodeSet compound (not the actual nodes !).
4108 */
4109void
4110xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4111 if (obj == NULL) return;
4112 if (obj->nodeTab != NULL) {
4113 int i;
4114
4115 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4116 for (i = 0;i < obj->nodeNr;i++)
4117 if ((obj->nodeTab[i] != NULL) &&
4118 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4119 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4120 xmlFree(obj->nodeTab);
4121 }
4122 xmlFree(obj);
4123}
4124
4125/**
4126 * xmlXPathNodeSetClear:
4127 * @set: the node set to clear
4128 *
4129 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4130 * are feed), but does *not* free the list itself. Sets the length of the
4131 * list to 0.
4132 */
4133static void
4134xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4135{
4136 if ((set == NULL) || (set->nodeNr <= 0))
4137 return;
4138 else if (hasNsNodes) {
4139 int i;
4140 xmlNodePtr node;
4141
4142 for (i = 0; i < set->nodeNr; i++) {
4143 node = set->nodeTab[i];
4144 if ((node != NULL) &&
4145 (node->type == XML_NAMESPACE_DECL))
4146 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4147 }
4148 }
4149 set->nodeNr = 0;
4150}
4151
4152/**
4153 * xmlXPathNodeSetClearFromPos:
4154 * @set: the node set to be cleared
4155 * @pos: the start position to clear from
4156 *
4157 * Clears the list from temporary XPath objects (e.g. namespace nodes
4158 * are feed) starting with the entry at @pos, but does *not* free the list
4159 * itself. Sets the length of the list to @pos.
4160 */
4161static void
4162xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4163{
4164 if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4165 return;
4166 else if ((hasNsNodes)) {
4167 int i;
4168 xmlNodePtr node;
4169
4170 for (i = pos; i < set->nodeNr; i++) {
4171 node = set->nodeTab[i];
4172 if ((node != NULL) &&
4173 (node->type == XML_NAMESPACE_DECL))
4174 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4175 }
4176 }
4177 set->nodeNr = pos;
4178}
4179
4180/**
4181 * xmlXPathFreeValueTree:
4182 * @obj: the xmlNodeSetPtr to free
4183 *
4184 * Free the NodeSet compound and the actual tree, this is different
4185 * from xmlXPathFreeNodeSet()
4186 */
4187static void
4188xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4189 int i;
4190
4191 if (obj == NULL) return;
4192
4193 if (obj->nodeTab != NULL) {
4194 for (i = 0;i < obj->nodeNr;i++) {
4195 if (obj->nodeTab[i] != NULL) {
4196 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4197 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4198 } else {
4199 xmlFreeNodeList(obj->nodeTab[i]);
4200 }
4201 }
4202 }
4203 xmlFree(obj->nodeTab);
4204 }
4205 xmlFree(obj);
4206}
4207
4208#if defined(DEBUG) || defined(DEBUG_STEP)
4209/**
4210 * xmlGenericErrorContextNodeSet:
4211 * @output: a FILE * for the output
4212 * @obj: the xmlNodeSetPtr to display
4213 *
4214 * Quick display of a NodeSet
4215 */
4216void
4217xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4218 int i;
4219
4220 if (output == NULL) output = xmlGenericErrorContext;
4221 if (obj == NULL) {
4222 fprintf(output, "NodeSet == NULL !\n");
4223 return;
4224 }
4225 if (obj->nodeNr == 0) {
4226 fprintf(output, "NodeSet is empty\n");
4227 return;
4228 }
4229 if (obj->nodeTab == NULL) {
4230 fprintf(output, " nodeTab == NULL !\n");
4231 return;
4232 }
4233 for (i = 0; i < obj->nodeNr; i++) {
4234 if (obj->nodeTab[i] == NULL) {
4235 fprintf(output, " NULL !\n");
4236 return;
4237 }
4238 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4239 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4240 fprintf(output, " /");
4241 else if (obj->nodeTab[i]->name == NULL)
4242 fprintf(output, " noname!");
4243 else fprintf(output, " %s", obj->nodeTab[i]->name);
4244 }
4245 fprintf(output, "\n");
4246}
4247#endif
4248
4249/**
4250 * xmlXPathNewNodeSet:
4251 * @val: the NodePtr value
4252 *
4253 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4254 * it with the single Node @val
4255 *
4256 * Returns the newly created object.
4257 */
4258xmlXPathObjectPtr
4259xmlXPathNewNodeSet(xmlNodePtr val) {
4260 xmlXPathObjectPtr ret;
4261
4262 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4263 if (ret == NULL) {
4264 xmlXPathErrMemory(NULL, "creating nodeset\n");
4265 return(NULL);
4266 }
4267 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4268 ret->type = XPATH_NODESET;
4269 ret->boolval = 0;
4270 ret->nodesetval = xmlXPathNodeSetCreate(val);
4271 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4272#ifdef XP_DEBUG_OBJ_USAGE
4273 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4274#endif
4275 return(ret);
4276}
4277
4278/**
4279 * xmlXPathNewValueTree:
4280 * @val: the NodePtr value
4281 *
4282 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4283 * it with the tree root @val
4284 *
4285 * Returns the newly created object.
4286 */
4287xmlXPathObjectPtr
4288xmlXPathNewValueTree(xmlNodePtr val) {
4289 xmlXPathObjectPtr ret;
4290
4291 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4292 if (ret == NULL) {
4293 xmlXPathErrMemory(NULL, "creating result value tree\n");
4294 return(NULL);
4295 }
4296 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4297 ret->type = XPATH_XSLT_TREE;
4298 ret->boolval = 1;
4299 ret->user = (void *) val;
4300 ret->nodesetval = xmlXPathNodeSetCreate(val);
4301#ifdef XP_DEBUG_OBJ_USAGE
4302 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4303#endif
4304 return(ret);
4305}
4306
4307/**
4308 * xmlXPathNewNodeSetList:
4309 * @val: an existing NodeSet
4310 *
4311 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4312 * it with the Nodeset @val
4313 *
4314 * Returns the newly created object.
4315 */
4316xmlXPathObjectPtr
4317xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4318{
4319 xmlXPathObjectPtr ret;
4320 int i;
4321
4322 if (val == NULL)
4323 ret = NULL;
4324 else if (val->nodeTab == NULL)
4325 ret = xmlXPathNewNodeSet(NULL);
4326 else {
4327 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4328 for (i = 1; i < val->nodeNr; ++i)
4329 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
4330 }
4331
4332 return (ret);
4333}
4334
4335/**
4336 * xmlXPathWrapNodeSet:
4337 * @val: the NodePtr value
4338 *
4339 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4340 *
4341 * Returns the newly created object.
4342 */
4343xmlXPathObjectPtr
4344xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4345 xmlXPathObjectPtr ret;
4346
4347 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4348 if (ret == NULL) {
4349 xmlXPathErrMemory(NULL, "creating node set object\n");
4350 return(NULL);
4351 }
4352 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4353 ret->type = XPATH_NODESET;
4354 ret->nodesetval = val;
4355#ifdef XP_DEBUG_OBJ_USAGE
4356 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4357#endif
4358 return(ret);
4359}
4360
4361/**
4362 * xmlXPathFreeNodeSetList:
4363 * @obj: an existing NodeSetList object
4364 *
4365 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4366 * the list contrary to xmlXPathFreeObject().
4367 */
4368void
4369xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4370 if (obj == NULL) return;
4371#ifdef XP_DEBUG_OBJ_USAGE
4372 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4373#endif
4374 xmlFree(obj);
4375}
4376
4377/**
4378 * xmlXPathDifference:
4379 * @nodes1: a node-set
4380 * @nodes2: a node-set
4381 *
4382 * Implements the EXSLT - Sets difference() function:
4383 * node-set set:difference (node-set, node-set)
4384 *
4385 * Returns the difference between the two node sets, or nodes1 if
4386 * nodes2 is empty
4387 */
4388xmlNodeSetPtr
4389xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4390 xmlNodeSetPtr ret;
4391 int i, l1;
4392 xmlNodePtr cur;
4393
4394 if (xmlXPathNodeSetIsEmpty(nodes2))
4395 return(nodes1);
4396
4397 ret = xmlXPathNodeSetCreate(NULL);
4398 if (xmlXPathNodeSetIsEmpty(nodes1))
4399 return(ret);
4400
4401 l1 = xmlXPathNodeSetGetLength(nodes1);
4402
4403 for (i = 0; i < l1; i++) {
4404 cur = xmlXPathNodeSetItem(nodes1, i);
4405 if (!xmlXPathNodeSetContains(nodes2, cur))
4406 xmlXPathNodeSetAddUnique(ret, cur);
4407 }
4408 return(ret);
4409}
4410
4411/**
4412 * xmlXPathIntersection:
4413 * @nodes1: a node-set
4414 * @nodes2: a node-set
4415 *
4416 * Implements the EXSLT - Sets intersection() function:
4417 * node-set set:intersection (node-set, node-set)
4418 *
4419 * Returns a node set comprising the nodes that are within both the
4420 * node sets passed as arguments
4421 */
4422xmlNodeSetPtr
4423xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4424 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4425 int i, l1;
4426 xmlNodePtr cur;
4427
4428 if (xmlXPathNodeSetIsEmpty(nodes1))
4429 return(ret);
4430 if (xmlXPathNodeSetIsEmpty(nodes2))
4431 return(ret);
4432
4433 l1 = xmlXPathNodeSetGetLength(nodes1);
4434
4435 for (i = 0; i < l1; i++) {
4436 cur = xmlXPathNodeSetItem(nodes1, i);
4437 if (xmlXPathNodeSetContains(nodes2, cur))
4438 xmlXPathNodeSetAddUnique(ret, cur);
4439 }
4440 return(ret);
4441}
4442
4443/**
4444 * xmlXPathDistinctSorted:
4445 * @nodes: a node-set, sorted by document order
4446 *
4447 * Implements the EXSLT - Sets distinct() function:
4448 * node-set set:distinct (node-set)
4449 *
4450 * Returns a subset of the nodes contained in @nodes, or @nodes if
4451 * it is empty
4452 */
4453xmlNodeSetPtr
4454xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4455 xmlNodeSetPtr ret;
4456 xmlHashTablePtr hash;
4457 int i, l;
4458 xmlChar * strval;
4459 xmlNodePtr cur;
4460
4461 if (xmlXPathNodeSetIsEmpty(nodes))
4462 return(nodes);
4463
4464 ret = xmlXPathNodeSetCreate(NULL);
4465 l = xmlXPathNodeSetGetLength(nodes);
4466 hash = xmlHashCreate (l);
4467 for (i = 0; i < l; i++) {
4468 cur = xmlXPathNodeSetItem(nodes, i);
4469 strval = xmlXPathCastNodeToString(cur);
4470 if (xmlHashLookup(hash, strval) == NULL) {
4471 xmlHashAddEntry(hash, strval, strval);
4472 xmlXPathNodeSetAddUnique(ret, cur);
4473 } else {
4474 xmlFree(strval);
4475 }
4476 }
4477 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4478 return(ret);
4479}
4480
4481/**
4482 * xmlXPathDistinct:
4483 * @nodes: a node-set
4484 *
4485 * Implements the EXSLT - Sets distinct() function:
4486 * node-set set:distinct (node-set)
4487 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4488 * is called with the sorted node-set
4489 *
4490 * Returns a subset of the nodes contained in @nodes, or @nodes if
4491 * it is empty
4492 */
4493xmlNodeSetPtr
4494xmlXPathDistinct (xmlNodeSetPtr nodes) {
4495 if (xmlXPathNodeSetIsEmpty(nodes))
4496 return(nodes);
4497
4498 xmlXPathNodeSetSort(nodes);
4499 return(xmlXPathDistinctSorted(nodes));
4500}
4501
4502/**
4503 * xmlXPathHasSameNodes:
4504 * @nodes1: a node-set
4505 * @nodes2: a node-set
4506 *
4507 * Implements the EXSLT - Sets has-same-nodes function:
4508 * boolean set:has-same-node(node-set, node-set)
4509 *
4510 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4511 * otherwise
4512 */
4513int
4514xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4515 int i, l;
4516 xmlNodePtr cur;
4517
4518 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4519 xmlXPathNodeSetIsEmpty(nodes2))
4520 return(0);
4521
4522 l = xmlXPathNodeSetGetLength(nodes1);
4523 for (i = 0; i < l; i++) {
4524 cur = xmlXPathNodeSetItem(nodes1, i);
4525 if (xmlXPathNodeSetContains(nodes2, cur))
4526 return(1);
4527 }
4528 return(0);
4529}
4530
4531/**
4532 * xmlXPathNodeLeadingSorted:
4533 * @nodes: a node-set, sorted by document order
4534 * @node: a node
4535 *
4536 * Implements the EXSLT - Sets leading() function:
4537 * node-set set:leading (node-set, node-set)
4538 *
4539 * Returns the nodes in @nodes that precede @node in document order,
4540 * @nodes if @node is NULL or an empty node-set if @nodes
4541 * doesn't contain @node
4542 */
4543xmlNodeSetPtr
4544xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4545 int i, l;
4546 xmlNodePtr cur;
4547 xmlNodeSetPtr ret;
4548
4549 if (node == NULL)
4550 return(nodes);
4551
4552 ret = xmlXPathNodeSetCreate(NULL);
4553 if (xmlXPathNodeSetIsEmpty(nodes) ||
4554 (!xmlXPathNodeSetContains(nodes, node)))
4555 return(ret);
4556
4557 l = xmlXPathNodeSetGetLength(nodes);
4558 for (i = 0; i < l; i++) {
4559 cur = xmlXPathNodeSetItem(nodes, i);
4560 if (cur == node)
4561 break;
4562 xmlXPathNodeSetAddUnique(ret, cur);
4563 }
4564 return(ret);
4565}
4566
4567/**
4568 * xmlXPathNodeLeading:
4569 * @nodes: a node-set
4570 * @node: a node
4571 *
4572 * Implements the EXSLT - Sets leading() function:
4573 * node-set set:leading (node-set, node-set)
4574 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4575 * is called.
4576 *
4577 * Returns the nodes in @nodes that precede @node in document order,
4578 * @nodes if @node is NULL or an empty node-set if @nodes
4579 * doesn't contain @node
4580 */
4581xmlNodeSetPtr
4582xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4583 xmlXPathNodeSetSort(nodes);
4584 return(xmlXPathNodeLeadingSorted(nodes, node));
4585}
4586
4587/**
4588 * xmlXPathLeadingSorted:
4589 * @nodes1: a node-set, sorted by document order
4590 * @nodes2: a node-set, sorted by document order
4591 *
4592 * Implements the EXSLT - Sets leading() function:
4593 * node-set set:leading (node-set, node-set)
4594 *
4595 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4596 * in document order, @nodes1 if @nodes2 is NULL or empty or
4597 * an empty node-set if @nodes1 doesn't contain @nodes2
4598 */
4599xmlNodeSetPtr
4600xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4601 if (xmlXPathNodeSetIsEmpty(nodes2))
4602 return(nodes1);
4603 return(xmlXPathNodeLeadingSorted(nodes1,
4604 xmlXPathNodeSetItem(nodes2, 1)));
4605}
4606
4607/**
4608 * xmlXPathLeading:
4609 * @nodes1: a node-set
4610 * @nodes2: a node-set
4611 *
4612 * Implements the EXSLT - Sets leading() function:
4613 * node-set set:leading (node-set, node-set)
4614 * @nodes1 and @nodes2 are sorted by document order, then
4615 * #exslSetsLeadingSorted is called.
4616 *
4617 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4618 * in document order, @nodes1 if @nodes2 is NULL or empty or
4619 * an empty node-set if @nodes1 doesn't contain @nodes2
4620 */
4621xmlNodeSetPtr
4622xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4623 if (xmlXPathNodeSetIsEmpty(nodes2))
4624 return(nodes1);
4625 if (xmlXPathNodeSetIsEmpty(nodes1))
4626 return(xmlXPathNodeSetCreate(NULL));
4627 xmlXPathNodeSetSort(nodes1);
4628 xmlXPathNodeSetSort(nodes2);
4629 return(xmlXPathNodeLeadingSorted(nodes1,
4630 xmlXPathNodeSetItem(nodes2, 1)));
4631}
4632
4633/**
4634 * xmlXPathNodeTrailingSorted:
4635 * @nodes: a node-set, sorted by document order
4636 * @node: a node
4637 *
4638 * Implements the EXSLT - Sets trailing() function:
4639 * node-set set:trailing (node-set, node-set)
4640 *
4641 * Returns the nodes in @nodes that follow @node in document order,
4642 * @nodes if @node is NULL or an empty node-set if @nodes
4643 * doesn't contain @node
4644 */
4645xmlNodeSetPtr
4646xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4647 int i, l;
4648 xmlNodePtr cur;
4649 xmlNodeSetPtr ret;
4650
4651 if (node == NULL)
4652 return(nodes);
4653
4654 ret = xmlXPathNodeSetCreate(NULL);
4655 if (xmlXPathNodeSetIsEmpty(nodes) ||
4656 (!xmlXPathNodeSetContains(nodes, node)))
4657 return(ret);
4658
4659 l = xmlXPathNodeSetGetLength(nodes);
4660 for (i = l - 1; i >= 0; i--) {
4661 cur = xmlXPathNodeSetItem(nodes, i);
4662 if (cur == node)
4663 break;
4664 xmlXPathNodeSetAddUnique(ret, cur);
4665 }
4666 xmlXPathNodeSetSort(ret); /* bug 413451 */
4667 return(ret);
4668}
4669
4670/**
4671 * xmlXPathNodeTrailing:
4672 * @nodes: a node-set
4673 * @node: a node
4674 *
4675 * Implements the EXSLT - Sets trailing() function:
4676 * node-set set:trailing (node-set, node-set)
4677 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4678 * is called.
4679 *
4680 * Returns the nodes in @nodes that follow @node in document order,
4681 * @nodes if @node is NULL or an empty node-set if @nodes
4682 * doesn't contain @node
4683 */
4684xmlNodeSetPtr
4685xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4686 xmlXPathNodeSetSort(nodes);
4687 return(xmlXPathNodeTrailingSorted(nodes, node));
4688}
4689
4690/**
4691 * xmlXPathTrailingSorted:
4692 * @nodes1: a node-set, sorted by document order
4693 * @nodes2: a node-set, sorted by document order
4694 *
4695 * Implements the EXSLT - Sets trailing() function:
4696 * node-set set:trailing (node-set, node-set)
4697 *
4698 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4699 * in document order, @nodes1 if @nodes2 is NULL or empty or
4700 * an empty node-set if @nodes1 doesn't contain @nodes2
4701 */
4702xmlNodeSetPtr
4703xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4704 if (xmlXPathNodeSetIsEmpty(nodes2))
4705 return(nodes1);
4706 return(xmlXPathNodeTrailingSorted(nodes1,
4707 xmlXPathNodeSetItem(nodes2, 0)));
4708}
4709
4710/**
4711 * xmlXPathTrailing:
4712 * @nodes1: a node-set
4713 * @nodes2: a node-set
4714 *
4715 * Implements the EXSLT - Sets trailing() function:
4716 * node-set set:trailing (node-set, node-set)
4717 * @nodes1 and @nodes2 are sorted by document order, then
4718 * #xmlXPathTrailingSorted is called.
4719 *
4720 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4721 * in document order, @nodes1 if @nodes2 is NULL or empty or
4722 * an empty node-set if @nodes1 doesn't contain @nodes2
4723 */
4724xmlNodeSetPtr
4725xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4726 if (xmlXPathNodeSetIsEmpty(nodes2))
4727 return(nodes1);
4728 if (xmlXPathNodeSetIsEmpty(nodes1))
4729 return(xmlXPathNodeSetCreate(NULL));
4730 xmlXPathNodeSetSort(nodes1);
4731 xmlXPathNodeSetSort(nodes2);
4732 return(xmlXPathNodeTrailingSorted(nodes1,
4733 xmlXPathNodeSetItem(nodes2, 0)));
4734}
4735
4736/************************************************************************
4737 * *
4738 * Routines to handle extra functions *
4739 * *
4740 ************************************************************************/
4741
4742/**
4743 * xmlXPathRegisterFunc:
4744 * @ctxt: the XPath context
4745 * @name: the function name
4746 * @f: the function implementation or NULL
4747 *
4748 * Register a new function. If @f is NULL it unregisters the function
4749 *
4750 * Returns 0 in case of success, -1 in case of error
4751 */
4752int
4753xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4754 xmlXPathFunction f) {
4755 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4756}
4757
4758/**
4759 * xmlXPathRegisterFuncNS:
4760 * @ctxt: the XPath context
4761 * @name: the function name
4762 * @ns_uri: the function namespace URI
4763 * @f: the function implementation or NULL
4764 *
4765 * Register a new function. If @f is NULL it unregisters the function
4766 *
4767 * Returns 0 in case of success, -1 in case of error
4768 */
4769int
4770xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4771 const xmlChar *ns_uri, xmlXPathFunction f) {
4772 if (ctxt == NULL)
4773 return(-1);
4774 if (name == NULL)
4775 return(-1);
4776
4777 if (ctxt->funcHash == NULL)
4778 ctxt->funcHash = xmlHashCreate(0);
4779 if (ctxt->funcHash == NULL)
4780 return(-1);
4781 if (f == NULL)
4782 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4783 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
4784}
4785
4786/**
4787 * xmlXPathRegisterFuncLookup:
4788 * @ctxt: the XPath context
4789 * @f: the lookup function
4790 * @funcCtxt: the lookup data
4791 *
4792 * Registers an external mechanism to do function lookup.
4793 */
4794void
4795xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4796 xmlXPathFuncLookupFunc f,
4797 void *funcCtxt) {
4798 if (ctxt == NULL)
4799 return;
4800 ctxt->funcLookupFunc = f;
4801 ctxt->funcLookupData = funcCtxt;
4802}
4803
4804/**
4805 * xmlXPathFunctionLookup:
4806 * @ctxt: the XPath context
4807 * @name: the function name
4808 *
4809 * Search in the Function array of the context for the given
4810 * function.
4811 *
4812 * Returns the xmlXPathFunction or NULL if not found
4813 */
4814xmlXPathFunction
4815xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4816 if (ctxt == NULL)
4817 return (NULL);
4818
4819 if (ctxt->funcLookupFunc != NULL) {
4820 xmlXPathFunction ret;
4821 xmlXPathFuncLookupFunc f;
4822
4823 f = ctxt->funcLookupFunc;
4824 ret = f(ctxt->funcLookupData, name, NULL);
4825 if (ret != NULL)
4826 return(ret);
4827 }
4828 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4829}
4830
4831/**
4832 * xmlXPathFunctionLookupNS:
4833 * @ctxt: the XPath context
4834 * @name: the function name
4835 * @ns_uri: the function namespace URI
4836 *
4837 * Search in the Function array of the context for the given
4838 * function.
4839 *
4840 * Returns the xmlXPathFunction or NULL if not found
4841 */
4842xmlXPathFunction
4843xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4844 const xmlChar *ns_uri) {
4845 xmlXPathFunction ret;
4846
4847 if (ctxt == NULL)
4848 return(NULL);
4849 if (name == NULL)
4850 return(NULL);
4851
4852 if (ctxt->funcLookupFunc != NULL) {
4853 xmlXPathFuncLookupFunc f;
4854
4855 f = ctxt->funcLookupFunc;
4856 ret = f(ctxt->funcLookupData, name, ns_uri);
4857 if (ret != NULL)
4858 return(ret);
4859 }
4860
4861 if (ctxt->funcHash == NULL)
4862 return(NULL);
4863
4864 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4865 return(ret);
4866}
4867
4868/**
4869 * xmlXPathRegisteredFuncsCleanup:
4870 * @ctxt: the XPath context
4871 *
4872 * Cleanup the XPath context data associated to registered functions
4873 */
4874void
4875xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4876 if (ctxt == NULL)
4877 return;
4878
4879 xmlHashFree(ctxt->funcHash, NULL);
4880 ctxt->funcHash = NULL;
4881}
4882
4883/************************************************************************
4884 * *
4885 * Routines to handle Variables *
4886 * *
4887 ************************************************************************/
4888
4889/**
4890 * xmlXPathRegisterVariable:
4891 * @ctxt: the XPath context
4892 * @name: the variable name
4893 * @value: the variable value or NULL
4894 *
4895 * Register a new variable value. If @value is NULL it unregisters
4896 * the variable
4897 *
4898 * Returns 0 in case of success, -1 in case of error
4899 */
4900int
4901xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4902 xmlXPathObjectPtr value) {
4903 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4904}
4905
4906/**
4907 * xmlXPathRegisterVariableNS:
4908 * @ctxt: the XPath context
4909 * @name: the variable name
4910 * @ns_uri: the variable namespace URI
4911 * @value: the variable value or NULL
4912 *
4913 * Register a new variable value. If @value is NULL it unregisters
4914 * the variable
4915 *
4916 * Returns 0 in case of success, -1 in case of error
4917 */
4918int
4919xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4920 const xmlChar *ns_uri,
4921 xmlXPathObjectPtr value) {
4922 if (ctxt == NULL)
4923 return(-1);
4924 if (name == NULL)
4925 return(-1);
4926
4927 if (ctxt->varHash == NULL)
4928 ctxt->varHash = xmlHashCreate(0);
4929 if (ctxt->varHash == NULL)
4930 return(-1);
4931 if (value == NULL)
4932 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4933 (xmlHashDeallocator)xmlXPathFreeObject));
4934 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4935 (void *) value,
4936 (xmlHashDeallocator)xmlXPathFreeObject));
4937}
4938
4939/**
4940 * xmlXPathRegisterVariableLookup:
4941 * @ctxt: the XPath context
4942 * @f: the lookup function
4943 * @data: the lookup data
4944 *
4945 * register an external mechanism to do variable lookup
4946 */
4947void
4948xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4949 xmlXPathVariableLookupFunc f, void *data) {
4950 if (ctxt == NULL)
4951 return;
4952 ctxt->varLookupFunc = f;
4953 ctxt->varLookupData = data;
4954}
4955
4956/**
4957 * xmlXPathVariableLookup:
4958 * @ctxt: the XPath context
4959 * @name: the variable name
4960 *
4961 * Search in the Variable array of the context for the given
4962 * variable value.
4963 *
4964 * Returns a copy of the value or NULL if not found
4965 */
4966xmlXPathObjectPtr
4967xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4968 if (ctxt == NULL)
4969 return(NULL);
4970
4971 if (ctxt->varLookupFunc != NULL) {
4972 xmlXPathObjectPtr ret;
4973
4974 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4975 (ctxt->varLookupData, name, NULL);
4976 return(ret);
4977 }
4978 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4979}
4980
4981/**
4982 * xmlXPathVariableLookupNS:
4983 * @ctxt: the XPath context
4984 * @name: the variable name
4985 * @ns_uri: the variable namespace URI
4986 *
4987 * Search in the Variable array of the context for the given
4988 * variable value.
4989 *
4990 * Returns the a copy of the value or NULL if not found
4991 */
4992xmlXPathObjectPtr
4993xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4994 const xmlChar *ns_uri) {
4995 if (ctxt == NULL)
4996 return(NULL);
4997
4998 if (ctxt->varLookupFunc != NULL) {
4999 xmlXPathObjectPtr ret;
5000
5001 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5002 (ctxt->varLookupData, name, ns_uri);
5003 if (ret != NULL) return(ret);
5004 }
5005
5006 if (ctxt->varHash == NULL)
5007 return(NULL);
5008 if (name == NULL)
5009 return(NULL);
5010
5011 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5012 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5013}
5014
5015/**
5016 * xmlXPathRegisteredVariablesCleanup:
5017 * @ctxt: the XPath context
5018 *
5019 * Cleanup the XPath context data associated to registered variables
5020 */
5021void
5022xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5023 if (ctxt == NULL)
5024 return;
5025
5026 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
5027 ctxt->varHash = NULL;
5028}
5029
5030/**
5031 * xmlXPathRegisterNs:
5032 * @ctxt: the XPath context
5033 * @prefix: the namespace prefix
5034 * @ns_uri: the namespace name
5035 *
5036 * Register a new namespace. If @ns_uri is NULL it unregisters
5037 * the namespace
5038 *
5039 * Returns 0 in case of success, -1 in case of error
5040 */
5041int
5042xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5043 const xmlChar *ns_uri) {
5044 if (ctxt == NULL)
5045 return(-1);
5046 if (prefix == NULL)
5047 return(-1);
5048
5049 if (ctxt->nsHash == NULL)
5050 ctxt->nsHash = xmlHashCreate(10);
5051 if (ctxt->nsHash == NULL)
5052 return(-1);
5053 if (ns_uri == NULL)
5054 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5055 (xmlHashDeallocator)xmlFree));
5056 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5057 (xmlHashDeallocator)xmlFree));
5058}
5059
5060/**
5061 * xmlXPathNsLookup:
5062 * @ctxt: the XPath context
5063 * @prefix: the namespace prefix value
5064 *
5065 * Search in the namespace declaration array of the context for the given
5066 * namespace name associated to the given prefix
5067 *
5068 * Returns the value or NULL if not found
5069 */
5070const xmlChar *
5071xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5072 if (ctxt == NULL)
5073 return(NULL);
5074 if (prefix == NULL)
5075 return(NULL);
5076
5077#ifdef XML_XML_NAMESPACE
5078 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5079 return(XML_XML_NAMESPACE);
5080#endif
5081
5082 if (ctxt->namespaces != NULL) {
5083 int i;
5084
5085 for (i = 0;i < ctxt->nsNr;i++) {
5086 if ((ctxt->namespaces[i] != NULL) &&
5087 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5088 return(ctxt->namespaces[i]->href);
5089 }
5090 }
5091
5092 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5093}
5094
5095/**
5096 * xmlXPathRegisteredNsCleanup:
5097 * @ctxt: the XPath context
5098 *
5099 * Cleanup the XPath context data associated to registered variables
5100 */
5101void
5102xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5103 if (ctxt == NULL)
5104 return;
5105
5106 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
5107 ctxt->nsHash = NULL;
5108}
5109
5110/************************************************************************
5111 * *
5112 * Routines to handle Values *
5113 * *
5114 ************************************************************************/
5115
5116/* Allocations are terrible, one needs to optimize all this !!! */
5117
5118/**
5119 * xmlXPathNewFloat:
5120 * @val: the double value
5121 *
5122 * Create a new xmlXPathObjectPtr of type double and of value @val
5123 *
5124 * Returns the newly created object.
5125 */
5126xmlXPathObjectPtr
5127xmlXPathNewFloat(double val) {
5128 xmlXPathObjectPtr ret;
5129
5130 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5131 if (ret == NULL) {
5132 xmlXPathErrMemory(NULL, "creating float object\n");
5133 return(NULL);
5134 }
5135 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5136 ret->type = XPATH_NUMBER;
5137 ret->floatval = val;
5138#ifdef XP_DEBUG_OBJ_USAGE
5139 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5140#endif
5141 return(ret);
5142}
5143
5144/**
5145 * xmlXPathNewBoolean:
5146 * @val: the boolean value
5147 *
5148 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5149 *
5150 * Returns the newly created object.
5151 */
5152xmlXPathObjectPtr
5153xmlXPathNewBoolean(int val) {
5154 xmlXPathObjectPtr ret;
5155
5156 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5157 if (ret == NULL) {
5158 xmlXPathErrMemory(NULL, "creating boolean object\n");
5159 return(NULL);
5160 }
5161 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5162 ret->type = XPATH_BOOLEAN;
5163 ret->boolval = (val != 0);
5164#ifdef XP_DEBUG_OBJ_USAGE
5165 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5166#endif
5167 return(ret);
5168}
5169
5170/**
5171 * xmlXPathNewString:
5172 * @val: the xmlChar * value
5173 *
5174 * Create a new xmlXPathObjectPtr of type string and of value @val
5175 *
5176 * Returns the newly created object.
5177 */
5178xmlXPathObjectPtr
5179xmlXPathNewString(const xmlChar *val) {
5180 xmlXPathObjectPtr ret;
5181
5182 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5183 if (ret == NULL) {
5184 xmlXPathErrMemory(NULL, "creating string object\n");
5185 return(NULL);
5186 }
5187 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5188 ret->type = XPATH_STRING;
5189 if (val != NULL)
5190 ret->stringval = xmlStrdup(val);
5191 else
5192 ret->stringval = xmlStrdup((const xmlChar *)"");
5193#ifdef XP_DEBUG_OBJ_USAGE
5194 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5195#endif
5196 return(ret);
5197}
5198
5199/**
5200 * xmlXPathWrapString:
5201 * @val: the xmlChar * value
5202 *
5203 * Wraps the @val string into an XPath object.
5204 *
5205 * Returns the newly created object.
5206 */
5207xmlXPathObjectPtr
5208xmlXPathWrapString (xmlChar *val) {
5209 xmlXPathObjectPtr ret;
5210
5211 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5212 if (ret == NULL) {
5213 xmlXPathErrMemory(NULL, "creating string object\n");
5214 return(NULL);
5215 }
5216 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5217 ret->type = XPATH_STRING;
5218 ret->stringval = val;
5219#ifdef XP_DEBUG_OBJ_USAGE
5220 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5221#endif
5222 return(ret);
5223}
5224
5225/**
5226 * xmlXPathNewCString:
5227 * @val: the char * value
5228 *
5229 * Create a new xmlXPathObjectPtr of type string and of value @val
5230 *
5231 * Returns the newly created object.
5232 */
5233xmlXPathObjectPtr
5234xmlXPathNewCString(const char *val) {
5235 xmlXPathObjectPtr ret;
5236
5237 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5238 if (ret == NULL) {
5239 xmlXPathErrMemory(NULL, "creating string object\n");
5240 return(NULL);
5241 }
5242 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5243 ret->type = XPATH_STRING;
5244 ret->stringval = xmlStrdup(BAD_CAST val);
5245#ifdef XP_DEBUG_OBJ_USAGE
5246 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5247#endif
5248 return(ret);
5249}
5250
5251/**
5252 * xmlXPathWrapCString:
5253 * @val: the char * value
5254 *
5255 * Wraps a string into an XPath object.
5256 *
5257 * Returns the newly created object.
5258 */
5259xmlXPathObjectPtr
5260xmlXPathWrapCString (char * val) {
5261 return(xmlXPathWrapString((xmlChar *)(val)));
5262}
5263
5264/**
5265 * xmlXPathWrapExternal:
5266 * @val: the user data
5267 *
5268 * Wraps the @val data into an XPath object.
5269 *
5270 * Returns the newly created object.
5271 */
5272xmlXPathObjectPtr
5273xmlXPathWrapExternal (void *val) {
5274 xmlXPathObjectPtr ret;
5275
5276 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5277 if (ret == NULL) {
5278 xmlXPathErrMemory(NULL, "creating user object\n");
5279 return(NULL);
5280 }
5281 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5282 ret->type = XPATH_USERS;
5283 ret->user = val;
5284#ifdef XP_DEBUG_OBJ_USAGE
5285 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5286#endif
5287 return(ret);
5288}
5289
5290/**
5291 * xmlXPathObjectCopy:
5292 * @val: the original object
5293 *
5294 * allocate a new copy of a given object
5295 *
5296 * Returns the newly created object.
5297 */
5298xmlXPathObjectPtr
5299xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5300 xmlXPathObjectPtr ret;
5301
5302 if (val == NULL)
5303 return(NULL);
5304
5305 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5306 if (ret == NULL) {
5307 xmlXPathErrMemory(NULL, "copying object\n");
5308 return(NULL);
5309 }
5310 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5311#ifdef XP_DEBUG_OBJ_USAGE
5312 xmlXPathDebugObjUsageRequested(NULL, val->type);
5313#endif
5314 switch (val->type) {
5315 case XPATH_BOOLEAN:
5316 case XPATH_NUMBER:
5317 case XPATH_POINT:
5318 case XPATH_RANGE:
5319 break;
5320 case XPATH_STRING:
5321 ret->stringval = xmlStrdup(val->stringval);
5322 break;
5323 case XPATH_XSLT_TREE:
5324#if 0
5325/*
5326 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5327 this previous handling is no longer correct, and can cause some serious
5328 problems (ref. bug 145547)
5329*/
5330 if ((val->nodesetval != NULL) &&
5331 (val->nodesetval->nodeTab != NULL)) {
5332 xmlNodePtr cur, tmp;
5333 xmlDocPtr top;
5334
5335 ret->boolval = 1;
5336 top = xmlNewDoc(NULL);
5337 top->name = (char *)
5338 xmlStrdup(val->nodesetval->nodeTab[0]->name);
5339 ret->user = top;
5340 if (top != NULL) {
5341 top->doc = top;
5342 cur = val->nodesetval->nodeTab[0]->children;
5343 while (cur != NULL) {
5344 tmp = xmlDocCopyNode(cur, top, 1);
5345 xmlAddChild((xmlNodePtr) top, tmp);
5346 cur = cur->next;
5347 }
5348 }
5349
5350 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5351 } else
5352 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5353 /* Deallocate the copied tree value */
5354 break;
5355#endif
5356 case XPATH_NODESET:
5357 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5358 /* Do not deallocate the copied tree value */
5359 ret->boolval = 0;
5360 break;
5361 case XPATH_LOCATIONSET:
5362#ifdef LIBXML_XPTR_ENABLED
5363 {
5364 xmlLocationSetPtr loc = val->user;
5365 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5366 break;
5367 }
5368#endif
5369 case XPATH_USERS:
5370 ret->user = val->user;
5371 break;
5372 case XPATH_UNDEFINED:
5373 xmlGenericError(xmlGenericErrorContext,
5374 "xmlXPathObjectCopy: unsupported type %d\n",
5375 val->type);
5376 break;
5377 }
5378 return(ret);
5379}
5380
5381/**
5382 * xmlXPathFreeObject:
5383 * @obj: the object to free
5384 *
5385 * Free up an xmlXPathObjectPtr object.
5386 */
5387void
5388xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5389 if (obj == NULL) return;
5390 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5391 if (obj->boolval) {
5392#if 0
5393 if (obj->user != NULL) {
5394 xmlXPathFreeNodeSet(obj->nodesetval);
5395 xmlFreeNodeList((xmlNodePtr) obj->user);
5396 } else
5397#endif
5398 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5399 if (obj->nodesetval != NULL)
5400 xmlXPathFreeValueTree(obj->nodesetval);
5401 } else {
5402 if (obj->nodesetval != NULL)
5403 xmlXPathFreeNodeSet(obj->nodesetval);
5404 }
5405#ifdef LIBXML_XPTR_ENABLED
5406 } else if (obj->type == XPATH_LOCATIONSET) {
5407 if (obj->user != NULL)
5408 xmlXPtrFreeLocationSet(obj->user);
5409#endif
5410 } else if (obj->type == XPATH_STRING) {
5411 if (obj->stringval != NULL)
5412 xmlFree(obj->stringval);
5413 }
5414#ifdef XP_DEBUG_OBJ_USAGE
5415 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5416#endif
5417 xmlFree(obj);
5418}
5419
5420/**
5421 * xmlXPathReleaseObject:
5422 * @obj: the xmlXPathObjectPtr to free or to cache
5423 *
5424 * Depending on the state of the cache this frees the given
5425 * XPath object or stores it in the cache.
5426 */
5427static void
5428xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5429{
5430#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5431 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5432 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5433
5434#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5435
5436 if (obj == NULL)
5437 return;
5438 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5439 xmlXPathFreeObject(obj);
5440 } else {
5441 xmlXPathContextCachePtr cache =
5442 (xmlXPathContextCachePtr) ctxt->cache;
5443
5444 switch (obj->type) {
5445 case XPATH_NODESET:
5446 case XPATH_XSLT_TREE:
5447 if (obj->nodesetval != NULL) {
5448 if (obj->boolval) {
5449 /*
5450 * It looks like the @boolval is used for
5451 * evaluation if this an XSLT Result Tree Fragment.
5452 * TODO: Check if this assumption is correct.
5453 */
5454 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5455 xmlXPathFreeValueTree(obj->nodesetval);
5456 obj->nodesetval = NULL;
5457 } else if ((obj->nodesetval->nodeMax <= 40) &&
5458 (XP_CACHE_WANTS(cache->nodesetObjs,
5459 cache->maxNodeset)))
5460 {
5461 XP_CACHE_ADD(cache->nodesetObjs, obj);
5462 goto obj_cached;
5463 } else {
5464 xmlXPathFreeNodeSet(obj->nodesetval);
5465 obj->nodesetval = NULL;
5466 }
5467 }
5468 break;
5469 case XPATH_STRING:
5470 if (obj->stringval != NULL)
5471 xmlFree(obj->stringval);
5472
5473 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5474 XP_CACHE_ADD(cache->stringObjs, obj);
5475 goto obj_cached;
5476 }
5477 break;
5478 case XPATH_BOOLEAN:
5479 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5480 XP_CACHE_ADD(cache->booleanObjs, obj);
5481 goto obj_cached;
5482 }
5483 break;
5484 case XPATH_NUMBER:
5485 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5486 XP_CACHE_ADD(cache->numberObjs, obj);
5487 goto obj_cached;
5488 }
5489 break;
5490#ifdef LIBXML_XPTR_ENABLED
5491 case XPATH_LOCATIONSET:
5492 if (obj->user != NULL) {
5493 xmlXPtrFreeLocationSet(obj->user);
5494 }
5495 goto free_obj;
5496#endif
5497 default:
5498 goto free_obj;
5499 }
5500
5501 /*
5502 * Fallback to adding to the misc-objects slot.
5503 */
5504 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5505 XP_CACHE_ADD(cache->miscObjs, obj);
5506 } else
5507 goto free_obj;
5508
5509obj_cached:
5510
5511#ifdef XP_DEBUG_OBJ_USAGE
5512 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5513#endif
5514
5515 if (obj->nodesetval != NULL) {
5516 xmlNodeSetPtr tmpset = obj->nodesetval;
5517
5518 /*
5519 * TODO: Due to those nasty ns-nodes, we need to traverse
5520 * the list and free the ns-nodes.
5521 * URGENT TODO: Check if it's actually slowing things down.
5522 * Maybe we shouldn't try to preserve the list.
5523 */
5524 if (tmpset->nodeNr > 1) {
5525 int i;
5526 xmlNodePtr node;
5527
5528 for (i = 0; i < tmpset->nodeNr; i++) {
5529 node = tmpset->nodeTab[i];
5530 if ((node != NULL) &&
5531 (node->type == XML_NAMESPACE_DECL))
5532 {
5533 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5534 }
5535 }
5536 } else if (tmpset->nodeNr == 1) {
5537 if ((tmpset->nodeTab[0] != NULL) &&
5538 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5539 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5540 }
5541 tmpset->nodeNr = 0;
5542 memset(obj, 0, sizeof(xmlXPathObject));
5543 obj->nodesetval = tmpset;
5544 } else
5545 memset(obj, 0, sizeof(xmlXPathObject));
5546
5547 return;
5548
5549free_obj:
5550 /*
5551 * Cache is full; free the object.
5552 */
5553 if (obj->nodesetval != NULL)
5554 xmlXPathFreeNodeSet(obj->nodesetval);
5555#ifdef XP_DEBUG_OBJ_USAGE
5556 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5557#endif
5558 xmlFree(obj);
5559 }
5560 return;
5561}
5562
5563
5564/************************************************************************
5565 * *
5566 * Type Casting Routines *
5567 * *
5568 ************************************************************************/
5569
5570/**
5571 * xmlXPathCastBooleanToString:
5572 * @val: a boolean
5573 *
5574 * Converts a boolean to its string value.
5575 *
5576 * Returns a newly allocated string.
5577 */
5578xmlChar *
5579xmlXPathCastBooleanToString (int val) {
5580 xmlChar *ret;
5581 if (val)
5582 ret = xmlStrdup((const xmlChar *) "true");
5583 else
5584 ret = xmlStrdup((const xmlChar *) "false");
5585 return(ret);
5586}
5587
5588/**
5589 * xmlXPathCastNumberToString:
5590 * @val: a number
5591 *
5592 * Converts a number to its string value.
5593 *
5594 * Returns a newly allocated string.
5595 */
5596xmlChar *
5597xmlXPathCastNumberToString (double val) {
5598 xmlChar *ret;
5599 switch (xmlXPathIsInf(val)) {
5600 case 1:
5601 ret = xmlStrdup((const xmlChar *) "Infinity");
5602 break;
5603 case -1:
5604 ret = xmlStrdup((const xmlChar *) "-Infinity");
5605 break;
5606 default:
5607 if (xmlXPathIsNaN(val)) {
5608 ret = xmlStrdup((const xmlChar *) "NaN");
5609 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5610 ret = xmlStrdup((const xmlChar *) "0");
5611 } else {
5612 /* could be improved */
5613 char buf[100];
5614 xmlXPathFormatNumber(val, buf, 99);
5615 buf[99] = 0;
5616 ret = xmlStrdup((const xmlChar *) buf);
5617 }
5618 }
5619 return(ret);
5620}
5621
5622/**
5623 * xmlXPathCastNodeToString:
5624 * @node: a node
5625 *
5626 * Converts a node to its string value.
5627 *
5628 * Returns a newly allocated string.
5629 */
5630xmlChar *
5631xmlXPathCastNodeToString (xmlNodePtr node) {
5632xmlChar *ret;
5633 if ((ret = xmlNodeGetContent(node)) == NULL)
5634 ret = xmlStrdup((const xmlChar *) "");
5635 return(ret);
5636}
5637
5638/**
5639 * xmlXPathCastNodeSetToString:
5640 * @ns: a node-set
5641 *
5642 * Converts a node-set to its string value.
5643 *
5644 * Returns a newly allocated string.
5645 */
5646xmlChar *
5647xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5648 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5649 return(xmlStrdup((const xmlChar *) ""));
5650
5651 if (ns->nodeNr > 1)
5652 xmlXPathNodeSetSort(ns);
5653 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5654}
5655
5656/**
5657 * xmlXPathCastToString:
5658 * @val: an XPath object
5659 *
5660 * Converts an existing object to its string() equivalent
5661 *
5662 * Returns the allocated string value of the object, NULL in case of error.
5663 * It's up to the caller to free the string memory with xmlFree().
5664 */
5665xmlChar *
5666xmlXPathCastToString(xmlXPathObjectPtr val) {
5667 xmlChar *ret = NULL;
5668
5669 if (val == NULL)
5670 return(xmlStrdup((const xmlChar *) ""));
5671 switch (val->type) {
5672 case XPATH_UNDEFINED:
5673#ifdef DEBUG_EXPR
5674 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5675#endif
5676 ret = xmlStrdup((const xmlChar *) "");
5677 break;
5678 case XPATH_NODESET:
5679 case XPATH_XSLT_TREE:
5680 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5681 break;
5682 case XPATH_STRING:
5683 return(xmlStrdup(val->stringval));
5684 case XPATH_BOOLEAN:
5685 ret = xmlXPathCastBooleanToString(val->boolval);
5686 break;
5687 case XPATH_NUMBER: {
5688 ret = xmlXPathCastNumberToString(val->floatval);
5689 break;
5690 }
5691 case XPATH_USERS:
5692 case XPATH_POINT:
5693 case XPATH_RANGE:
5694 case XPATH_LOCATIONSET:
5695 TODO
5696 ret = xmlStrdup((const xmlChar *) "");
5697 break;
5698 }
5699 return(ret);
5700}
5701
5702/**
5703 * xmlXPathConvertString:
5704 * @val: an XPath object
5705 *
5706 * Converts an existing object to its string() equivalent
5707 *
5708 * Returns the new object, the old one is freed (or the operation
5709 * is done directly on @val)
5710 */
5711xmlXPathObjectPtr
5712xmlXPathConvertString(xmlXPathObjectPtr val) {
5713 xmlChar *res = NULL;
5714
5715 if (val == NULL)
5716 return(xmlXPathNewCString(""));
5717
5718 switch (val->type) {
5719 case XPATH_UNDEFINED:
5720#ifdef DEBUG_EXPR
5721 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5722#endif
5723 break;
5724 case XPATH_NODESET:
5725 case XPATH_XSLT_TREE:
5726 res = xmlXPathCastNodeSetToString(val->nodesetval);
5727 break;
5728 case XPATH_STRING:
5729 return(val);
5730 case XPATH_BOOLEAN:
5731 res = xmlXPathCastBooleanToString(val->boolval);
5732 break;
5733 case XPATH_NUMBER:
5734 res = xmlXPathCastNumberToString(val->floatval);
5735 break;
5736 case XPATH_USERS:
5737 case XPATH_POINT:
5738 case XPATH_RANGE:
5739 case XPATH_LOCATIONSET:
5740 TODO;
5741 break;
5742 }
5743 xmlXPathFreeObject(val);
5744 if (res == NULL)
5745 return(xmlXPathNewCString(""));
5746 return(xmlXPathWrapString(res));
5747}
5748
5749/**
5750 * xmlXPathCastBooleanToNumber:
5751 * @val: a boolean
5752 *
5753 * Converts a boolean to its number value
5754 *
5755 * Returns the number value
5756 */
5757double
5758xmlXPathCastBooleanToNumber(int val) {
5759 if (val)
5760 return(1.0);
5761 return(0.0);
5762}
5763
5764/**
5765 * xmlXPathCastStringToNumber:
5766 * @val: a string
5767 *
5768 * Converts a string to its number value
5769 *
5770 * Returns the number value
5771 */
5772double
5773xmlXPathCastStringToNumber(const xmlChar * val) {
5774 return(xmlXPathStringEvalNumber(val));
5775}
5776
5777/**
5778 * xmlXPathCastNodeToNumber:
5779 * @node: a node
5780 *
5781 * Converts a node to its number value
5782 *
5783 * Returns the number value
5784 */
5785double
5786xmlXPathCastNodeToNumber (xmlNodePtr node) {
5787 xmlChar *strval;
5788 double ret;
5789
5790 if (node == NULL)
5791 return(xmlXPathNAN);
5792 strval = xmlXPathCastNodeToString(node);
5793 if (strval == NULL)
5794 return(xmlXPathNAN);
5795 ret = xmlXPathCastStringToNumber(strval);
5796 xmlFree(strval);
5797
5798 return(ret);
5799}
5800
5801/**
5802 * xmlXPathCastNodeSetToNumber:
5803 * @ns: a node-set
5804 *
5805 * Converts a node-set to its number value
5806 *
5807 * Returns the number value
5808 */
5809double
5810xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5811 xmlChar *str;
5812 double ret;
5813
5814 if (ns == NULL)
5815 return(xmlXPathNAN);
5816 str = xmlXPathCastNodeSetToString(ns);
5817 ret = xmlXPathCastStringToNumber(str);
5818 xmlFree(str);
5819 return(ret);
5820}
5821
5822/**
5823 * xmlXPathCastToNumber:
5824 * @val: an XPath object
5825 *
5826 * Converts an XPath object to its number value
5827 *
5828 * Returns the number value
5829 */
5830double
5831xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5832 double ret = 0.0;
5833
5834 if (val == NULL)
5835 return(xmlXPathNAN);
5836 switch (val->type) {
5837 case XPATH_UNDEFINED:
5838#ifdef DEGUB_EXPR
5839 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5840#endif
5841 ret = xmlXPathNAN;
5842 break;
5843 case XPATH_NODESET:
5844 case XPATH_XSLT_TREE:
5845 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5846 break;
5847 case XPATH_STRING:
5848 ret = xmlXPathCastStringToNumber(val->stringval);
5849 break;
5850 case XPATH_NUMBER:
5851 ret = val->floatval;
5852 break;
5853 case XPATH_BOOLEAN:
5854 ret = xmlXPathCastBooleanToNumber(val->boolval);
5855 break;
5856 case XPATH_USERS:
5857 case XPATH_POINT:
5858 case XPATH_RANGE:
5859 case XPATH_LOCATIONSET:
5860 TODO;
5861 ret = xmlXPathNAN;
5862 break;
5863 }
5864 return(ret);
5865}
5866
5867/**
5868 * xmlXPathConvertNumber:
5869 * @val: an XPath object
5870 *
5871 * Converts an existing object to its number() equivalent
5872 *
5873 * Returns the new object, the old one is freed (or the operation
5874 * is done directly on @val)
5875 */
5876xmlXPathObjectPtr
5877xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5878 xmlXPathObjectPtr ret;
5879
5880 if (val == NULL)
5881 return(xmlXPathNewFloat(0.0));
5882 if (val->type == XPATH_NUMBER)
5883 return(val);
5884 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5885 xmlXPathFreeObject(val);
5886 return(ret);
5887}
5888
5889/**
5890 * xmlXPathCastNumberToBoolean:
5891 * @val: a number
5892 *
5893 * Converts a number to its boolean value
5894 *
5895 * Returns the boolean value
5896 */
5897int
5898xmlXPathCastNumberToBoolean (double val) {
5899 if (xmlXPathIsNaN(val) || (val == 0.0))
5900 return(0);
5901 return(1);
5902}
5903
5904/**
5905 * xmlXPathCastStringToBoolean:
5906 * @val: a string
5907 *
5908 * Converts a string to its boolean value
5909 *
5910 * Returns the boolean value
5911 */
5912int
5913xmlXPathCastStringToBoolean (const xmlChar *val) {
5914 if ((val == NULL) || (xmlStrlen(val) == 0))
5915 return(0);
5916 return(1);
5917}
5918
5919/**
5920 * xmlXPathCastNodeSetToBoolean:
5921 * @ns: a node-set
5922 *
5923 * Converts a node-set to its boolean value
5924 *
5925 * Returns the boolean value
5926 */
5927int
5928xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5929 if ((ns == NULL) || (ns->nodeNr == 0))
5930 return(0);
5931 return(1);
5932}
5933
5934/**
5935 * xmlXPathCastToBoolean:
5936 * @val: an XPath object
5937 *
5938 * Converts an XPath object to its boolean value
5939 *
5940 * Returns the boolean value
5941 */
5942int
5943xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5944 int ret = 0;
5945
5946 if (val == NULL)
5947 return(0);
5948 switch (val->type) {
5949 case XPATH_UNDEFINED:
5950#ifdef DEBUG_EXPR
5951 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
5952#endif
5953 ret = 0;
5954 break;
5955 case XPATH_NODESET:
5956 case XPATH_XSLT_TREE:
5957 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5958 break;
5959 case XPATH_STRING:
5960 ret = xmlXPathCastStringToBoolean(val->stringval);
5961 break;
5962 case XPATH_NUMBER:
5963 ret = xmlXPathCastNumberToBoolean(val->floatval);
5964 break;
5965 case XPATH_BOOLEAN:
5966 ret = val->boolval;
5967 break;
5968 case XPATH_USERS:
5969 case XPATH_POINT:
5970 case XPATH_RANGE:
5971 case XPATH_LOCATIONSET:
5972 TODO;
5973 ret = 0;
5974 break;
5975 }
5976 return(ret);
5977}
5978
5979
5980/**
5981 * xmlXPathConvertBoolean:
5982 * @val: an XPath object
5983 *
5984 * Converts an existing object to its boolean() equivalent
5985 *
5986 * Returns the new object, the old one is freed (or the operation
5987 * is done directly on @val)
5988 */
5989xmlXPathObjectPtr
5990xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
5991 xmlXPathObjectPtr ret;
5992
5993 if (val == NULL)
5994 return(xmlXPathNewBoolean(0));
5995 if (val->type == XPATH_BOOLEAN)
5996 return(val);
5997 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
5998 xmlXPathFreeObject(val);
5999 return(ret);
6000}
6001
6002/************************************************************************
6003 * *
6004 * Routines to handle XPath contexts *
6005 * *
6006 ************************************************************************/
6007
6008/**
6009 * xmlXPathNewContext:
6010 * @doc: the XML document
6011 *
6012 * Create a new xmlXPathContext
6013 *
6014 * Returns the xmlXPathContext just allocated. The caller will need to free it.
6015 */
6016xmlXPathContextPtr
6017xmlXPathNewContext(xmlDocPtr doc) {
6018 xmlXPathContextPtr ret;
6019
6020 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6021 if (ret == NULL) {
6022 xmlXPathErrMemory(NULL, "creating context\n");
6023 return(NULL);
6024 }
6025 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6026 ret->doc = doc;
6027 ret->node = NULL;
6028
6029 ret->varHash = NULL;
6030
6031 ret->nb_types = 0;
6032 ret->max_types = 0;
6033 ret->types = NULL;
6034
6035 ret->funcHash = xmlHashCreate(0);
6036
6037 ret->nb_axis = 0;
6038 ret->max_axis = 0;
6039 ret->axis = NULL;
6040
6041 ret->nsHash = NULL;
6042 ret->user = NULL;
6043
6044 ret->contextSize = -1;
6045 ret->proximityPosition = -1;
6046
6047#ifdef XP_DEFAULT_CACHE_ON
6048 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6049 xmlXPathFreeContext(ret);
6050 return(NULL);
6051 }
6052#endif
6053
6054 xmlXPathRegisterAllFunctions(ret);
6055
6056 return(ret);
6057}
6058
6059/**
6060 * xmlXPathFreeContext:
6061 * @ctxt: the context to free
6062 *
6063 * Free up an xmlXPathContext
6064 */
6065void
6066xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6067 if (ctxt == NULL) return;
6068
6069 if (ctxt->cache != NULL)
6070 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6071 xmlXPathRegisteredNsCleanup(ctxt);
6072 xmlXPathRegisteredFuncsCleanup(ctxt);
6073 xmlXPathRegisteredVariablesCleanup(ctxt);
6074 xmlResetError(&ctxt->lastError);
6075 xmlFree(ctxt);
6076}
6077
6078/************************************************************************
6079 * *
6080 * Routines to handle XPath parser contexts *
6081 * *
6082 ************************************************************************/
6083
6084#define CHECK_CTXT(ctxt) \
6085 if (ctxt == NULL) { \
6086 __xmlRaiseError(NULL, NULL, NULL, \
6087 NULL, NULL, XML_FROM_XPATH, \
6088 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6089 __FILE__, __LINE__, \
6090 NULL, NULL, NULL, 0, 0, \
6091 "NULL context pointer\n"); \
6092 return(NULL); \
6093 } \
6094
6095#define CHECK_CTXT_NEG(ctxt) \
6096 if (ctxt == NULL) { \
6097 __xmlRaiseError(NULL, NULL, NULL, \
6098 NULL, NULL, XML_FROM_XPATH, \
6099 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6100 __FILE__, __LINE__, \
6101 NULL, NULL, NULL, 0, 0, \
6102 "NULL context pointer\n"); \
6103 return(-1); \
6104 } \
6105
6106
6107#define CHECK_CONTEXT(ctxt) \
6108 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
6109 (ctxt->doc->children == NULL)) { \
6110 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
6111 return(NULL); \
6112 }
6113
6114
6115/**
6116 * xmlXPathNewParserContext:
6117 * @str: the XPath expression
6118 * @ctxt: the XPath context
6119 *
6120 * Create a new xmlXPathParserContext
6121 *
6122 * Returns the xmlXPathParserContext just allocated.
6123 */
6124xmlXPathParserContextPtr
6125xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6126 xmlXPathParserContextPtr ret;
6127
6128 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6129 if (ret == NULL) {
6130 xmlXPathErrMemory(ctxt, "creating parser context\n");
6131 return(NULL);
6132 }
6133 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6134 ret->cur = ret->base = str;
6135 ret->context = ctxt;
6136
6137 ret->comp = xmlXPathNewCompExpr();
6138 if (ret->comp == NULL) {
6139 xmlFree(ret->valueTab);
6140 xmlFree(ret);
6141 return(NULL);
6142 }
6143 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6144 ret->comp->dict = ctxt->dict;
6145 xmlDictReference(ret->comp->dict);
6146 }
6147
6148 return(ret);
6149}
6150
6151/**
6152 * xmlXPathCompParserContext:
6153 * @comp: the XPath compiled expression
6154 * @ctxt: the XPath context
6155 *
6156 * Create a new xmlXPathParserContext when processing a compiled expression
6157 *
6158 * Returns the xmlXPathParserContext just allocated.
6159 */
6160static xmlXPathParserContextPtr
6161xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6162 xmlXPathParserContextPtr ret;
6163
6164 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6165 if (ret == NULL) {
6166 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6167 return(NULL);
6168 }
6169 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6170
6171 /* Allocate the value stack */
6172 ret->valueTab = (xmlXPathObjectPtr *)
6173 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6174 if (ret->valueTab == NULL) {
6175 xmlFree(ret);
6176 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6177 return(NULL);
6178 }
6179 ret->valueNr = 0;
6180 ret->valueMax = 10;
6181 ret->value = NULL;
6182 ret->valueFrame = 0;
6183
6184 ret->context = ctxt;
6185 ret->comp = comp;
6186
6187 return(ret);
6188}
6189
6190/**
6191 * xmlXPathFreeParserContext:
6192 * @ctxt: the context to free
6193 *
6194 * Free up an xmlXPathParserContext
6195 */
6196void
6197xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6198 if (ctxt->valueTab != NULL) {
6199 xmlFree(ctxt->valueTab);
6200 }
6201 if (ctxt->comp != NULL) {
6202#ifdef XPATH_STREAMING
6203 if (ctxt->comp->stream != NULL) {
6204 xmlFreePatternList(ctxt->comp->stream);
6205 ctxt->comp->stream = NULL;
6206 }
6207#endif
6208 xmlXPathFreeCompExpr(ctxt->comp);
6209 }
6210 xmlFree(ctxt);
6211}
6212
6213/************************************************************************
6214 * *
6215 * The implicit core function library *
6216 * *
6217 ************************************************************************/
6218
6219/**
6220 * xmlXPathNodeValHash:
6221 * @node: a node pointer
6222 *
6223 * Function computing the beginning of the string value of the node,
6224 * used to speed up comparisons
6225 *
6226 * Returns an int usable as a hash
6227 */
6228static unsigned int
6229xmlXPathNodeValHash(xmlNodePtr node) {
6230 int len = 2;
6231 const xmlChar * string = NULL;
6232 xmlNodePtr tmp = NULL;
6233 unsigned int ret = 0;
6234
6235 if (node == NULL)
6236 return(0);
6237
6238 if (node->type == XML_DOCUMENT_NODE) {
6239 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6240 if (tmp == NULL)
6241 node = node->children;
6242 else
6243 node = tmp;
6244
6245 if (node == NULL)
6246 return(0);
6247 }
6248
6249 switch (node->type) {
6250 case XML_COMMENT_NODE:
6251 case XML_PI_NODE:
6252 case XML_CDATA_SECTION_NODE:
6253 case XML_TEXT_NODE:
6254 string = node->content;
6255 if (string == NULL)
6256 return(0);
6257 if (string[0] == 0)
6258 return(0);
6259 return(((unsigned int) string[0]) +
6260 (((unsigned int) string[1]) << 8));
6261 case XML_NAMESPACE_DECL:
6262 string = ((xmlNsPtr)node)->href;
6263 if (string == NULL)
6264 return(0);
6265 if (string[0] == 0)
6266 return(0);
6267 return(((unsigned int) string[0]) +
6268 (((unsigned int) string[1]) << 8));
6269 case XML_ATTRIBUTE_NODE:
6270 tmp = ((xmlAttrPtr) node)->children;
6271 break;
6272 case XML_ELEMENT_NODE:
6273 tmp = node->children;
6274 break;
6275 default:
6276 return(0);
6277 }
6278 while (tmp != NULL) {
6279 switch (tmp->type) {
6280 case XML_COMMENT_NODE:
6281 case XML_PI_NODE:
6282 case XML_CDATA_SECTION_NODE:
6283 case XML_TEXT_NODE:
6284 string = tmp->content;
6285 break;
6286 case XML_NAMESPACE_DECL:
6287 string = ((xmlNsPtr)tmp)->href;
6288 break;
6289 default:
6290 break;
6291 }
6292 if ((string != NULL) && (string[0] != 0)) {
6293 if (len == 1) {
6294 return(ret + (((unsigned int) string[0]) << 8));
6295 }
6296 if (string[1] == 0) {
6297 len = 1;
6298 ret = (unsigned int) string[0];
6299 } else {
6300 return(((unsigned int) string[0]) +
6301 (((unsigned int) string[1]) << 8));
6302 }
6303 }
6304 /*
6305 * Skip to next node
6306 */
6307 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6308 if (tmp->children->type != XML_ENTITY_DECL) {
6309 tmp = tmp->children;
6310 continue;
6311 }
6312 }
6313 if (tmp == node)
6314 break;
6315
6316 if (tmp->next != NULL) {
6317 tmp = tmp->next;
6318 continue;
6319 }
6320
6321 do {
6322 tmp = tmp->parent;
6323 if (tmp == NULL)
6324 break;
6325 if (tmp == node) {
6326 tmp = NULL;
6327 break;
6328 }
6329 if (tmp->next != NULL) {
6330 tmp = tmp->next;
6331 break;
6332 }
6333 } while (tmp != NULL);
6334 }
6335 return(ret);
6336}
6337
6338/**
6339 * xmlXPathStringHash:
6340 * @string: a string
6341 *
6342 * Function computing the beginning of the string value of the node,
6343 * used to speed up comparisons
6344 *
6345 * Returns an int usable as a hash
6346 */
6347static unsigned int
6348xmlXPathStringHash(const xmlChar * string) {
6349 if (string == NULL)
6350 return((unsigned int) 0);
6351 if (string[0] == 0)
6352 return(0);
6353 return(((unsigned int) string[0]) +
6354 (((unsigned int) string[1]) << 8));
6355}
6356
6357/**
6358 * xmlXPathCompareNodeSetFloat:
6359 * @ctxt: the XPath Parser context
6360 * @inf: less than (1) or greater than (0)
6361 * @strict: is the comparison strict
6362 * @arg: the node set
6363 * @f: the value
6364 *
6365 * Implement the compare operation between a nodeset and a number
6366 * @ns < @val (1, 1, ...
6367 * @ns <= @val (1, 0, ...
6368 * @ns > @val (0, 1, ...
6369 * @ns >= @val (0, 0, ...
6370 *
6371 * If one object to be compared is a node-set and the other is a number,
6372 * then the comparison will be true if and only if there is a node in the
6373 * node-set such that the result of performing the comparison on the number
6374 * to be compared and on the result of converting the string-value of that
6375 * node to a number using the number function is true.
6376 *
6377 * Returns 0 or 1 depending on the results of the test.
6378 */
6379static int
6380xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6381 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6382 int i, ret = 0;
6383 xmlNodeSetPtr ns;
6384 xmlChar *str2;
6385
6386 if ((f == NULL) || (arg == NULL) ||
6387 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6388 xmlXPathReleaseObject(ctxt->context, arg);
6389 xmlXPathReleaseObject(ctxt->context, f);
6390 return(0);
6391 }
6392 ns = arg->nodesetval;
6393 if (ns != NULL) {
6394 for (i = 0;i < ns->nodeNr;i++) {
6395 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6396 if (str2 != NULL) {
6397 valuePush(ctxt,
6398 xmlXPathCacheNewString(ctxt->context, str2));
6399 xmlFree(str2);
6400 xmlXPathNumberFunction(ctxt, 1);
6401 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6402 ret = xmlXPathCompareValues(ctxt, inf, strict);
6403 if (ret)
6404 break;
6405 }
6406 }
6407 }
6408 xmlXPathReleaseObject(ctxt->context, arg);
6409 xmlXPathReleaseObject(ctxt->context, f);
6410 return(ret);
6411}
6412
6413/**
6414 * xmlXPathCompareNodeSetString:
6415 * @ctxt: the XPath Parser context
6416 * @inf: less than (1) or greater than (0)
6417 * @strict: is the comparison strict
6418 * @arg: the node set
6419 * @s: the value
6420 *
6421 * Implement the compare operation between a nodeset and a string
6422 * @ns < @val (1, 1, ...
6423 * @ns <= @val (1, 0, ...
6424 * @ns > @val (0, 1, ...
6425 * @ns >= @val (0, 0, ...
6426 *
6427 * If one object to be compared is a node-set and the other is a string,
6428 * then the comparison will be true if and only if there is a node in
6429 * the node-set such that the result of performing the comparison on the
6430 * string-value of the node and the other string is true.
6431 *
6432 * Returns 0 or 1 depending on the results of the test.
6433 */
6434static int
6435xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6436 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6437 int i, ret = 0;
6438 xmlNodeSetPtr ns;
6439 xmlChar *str2;
6440
6441 if ((s == NULL) || (arg == NULL) ||
6442 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6443 xmlXPathReleaseObject(ctxt->context, arg);
6444 xmlXPathReleaseObject(ctxt->context, s);
6445 return(0);
6446 }
6447 ns = arg->nodesetval;
6448 if (ns != NULL) {
6449 for (i = 0;i < ns->nodeNr;i++) {
6450 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6451 if (str2 != NULL) {
6452 valuePush(ctxt,
6453 xmlXPathCacheNewString(ctxt->context, str2));
6454 xmlFree(str2);
6455 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6456 ret = xmlXPathCompareValues(ctxt, inf, strict);
6457 if (ret)
6458 break;
6459 }
6460 }
6461 }
6462 xmlXPathReleaseObject(ctxt->context, arg);
6463 xmlXPathReleaseObject(ctxt->context, s);
6464 return(ret);
6465}
6466
6467/**
6468 * xmlXPathCompareNodeSets:
6469 * @inf: less than (1) or greater than (0)
6470 * @strict: is the comparison strict
6471 * @arg1: the first node set object
6472 * @arg2: the second node set object
6473 *
6474 * Implement the compare operation on nodesets:
6475 *
6476 * If both objects to be compared are node-sets, then the comparison
6477 * will be true if and only if there is a node in the first node-set
6478 * and a node in the second node-set such that the result of performing
6479 * the comparison on the string-values of the two nodes is true.
6480 * ....
6481 * When neither object to be compared is a node-set and the operator
6482 * is <=, <, >= or >, then the objects are compared by converting both
6483 * objects to numbers and comparing the numbers according to IEEE 754.
6484 * ....
6485 * The number function converts its argument to a number as follows:
6486 * - a string that consists of optional whitespace followed by an
6487 * optional minus sign followed by a Number followed by whitespace
6488 * is converted to the IEEE 754 number that is nearest (according
6489 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6490 * represented by the string; any other string is converted to NaN
6491 *
6492 * Conclusion all nodes need to be converted first to their string value
6493 * and then the comparison must be done when possible
6494 */
6495static int
6496xmlXPathCompareNodeSets(int inf, int strict,
6497 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6498 int i, j, init = 0;
6499 double val1;
6500 double *values2;
6501 int ret = 0;
6502 xmlNodeSetPtr ns1;
6503 xmlNodeSetPtr ns2;
6504
6505 if ((arg1 == NULL) ||
6506 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6507 xmlXPathFreeObject(arg2);
6508 return(0);
6509 }
6510 if ((arg2 == NULL) ||
6511 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6512 xmlXPathFreeObject(arg1);
6513 xmlXPathFreeObject(arg2);
6514 return(0);
6515 }
6516
6517 ns1 = arg1->nodesetval;
6518 ns2 = arg2->nodesetval;
6519
6520 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6521 xmlXPathFreeObject(arg1);
6522 xmlXPathFreeObject(arg2);
6523 return(0);
6524 }
6525 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6526 xmlXPathFreeObject(arg1);
6527 xmlXPathFreeObject(arg2);
6528 return(0);
6529 }
6530
6531 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6532 if (values2 == NULL) {
6533 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6534 xmlXPathFreeObject(arg1);
6535 xmlXPathFreeObject(arg2);
6536 return(0);
6537 }
6538 for (i = 0;i < ns1->nodeNr;i++) {
6539 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6540 if (xmlXPathIsNaN(val1))
6541 continue;
6542 for (j = 0;j < ns2->nodeNr;j++) {
6543 if (init == 0) {
6544 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6545 }
6546 if (xmlXPathIsNaN(values2[j]))
6547 continue;
6548 if (inf && strict)
6549 ret = (val1 < values2[j]);
6550 else if (inf && !strict)
6551 ret = (val1 <= values2[j]);
6552 else if (!inf && strict)
6553 ret = (val1 > values2[j]);
6554 else if (!inf && !strict)
6555 ret = (val1 >= values2[j]);
6556 if (ret)
6557 break;
6558 }
6559 if (ret)
6560 break;
6561 init = 1;
6562 }
6563 xmlFree(values2);
6564 xmlXPathFreeObject(arg1);
6565 xmlXPathFreeObject(arg2);
6566 return(ret);
6567}
6568
6569/**
6570 * xmlXPathCompareNodeSetValue:
6571 * @ctxt: the XPath Parser context
6572 * @inf: less than (1) or greater than (0)
6573 * @strict: is the comparison strict
6574 * @arg: the node set
6575 * @val: the value
6576 *
6577 * Implement the compare operation between a nodeset and a value
6578 * @ns < @val (1, 1, ...
6579 * @ns <= @val (1, 0, ...
6580 * @ns > @val (0, 1, ...
6581 * @ns >= @val (0, 0, ...
6582 *
6583 * If one object to be compared is a node-set and the other is a boolean,
6584 * then the comparison will be true if and only if the result of performing
6585 * the comparison on the boolean and on the result of converting
6586 * the node-set to a boolean using the boolean function is true.
6587 *
6588 * Returns 0 or 1 depending on the results of the test.
6589 */
6590static int
6591xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6592 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6593 if ((val == NULL) || (arg == NULL) ||
6594 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6595 return(0);
6596
6597 switch(val->type) {
6598 case XPATH_NUMBER:
6599 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6600 case XPATH_NODESET:
6601 case XPATH_XSLT_TREE:
6602 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6603 case XPATH_STRING:
6604 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6605 case XPATH_BOOLEAN:
6606 valuePush(ctxt, arg);
6607 xmlXPathBooleanFunction(ctxt, 1);
6608 valuePush(ctxt, val);
6609 return(xmlXPathCompareValues(ctxt, inf, strict));
6610 default:
6611 TODO
6612 }
6613 return(0);
6614}
6615
6616/**
6617 * xmlXPathEqualNodeSetString:
6618 * @arg: the nodeset object argument
6619 * @str: the string to compare to.
6620 * @neq: flag to show whether for '=' (0) or '!=' (1)
6621 *
6622 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6623 * If one object to be compared is a node-set and the other is a string,
6624 * then the comparison will be true if and only if there is a node in
6625 * the node-set such that the result of performing the comparison on the
6626 * string-value of the node and the other string is true.
6627 *
6628 * Returns 0 or 1 depending on the results of the test.
6629 */
6630static int
6631xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6632{
6633 int i;
6634 xmlNodeSetPtr ns;
6635 xmlChar *str2;
6636 unsigned int hash;
6637
6638 if ((str == NULL) || (arg == NULL) ||
6639 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6640 return (0);
6641 ns = arg->nodesetval;
6642 /*
6643 * A NULL nodeset compared with a string is always false
6644 * (since there is no node equal, and no node not equal)
6645 */
6646 if ((ns == NULL) || (ns->nodeNr <= 0) )
6647 return (0);
6648 hash = xmlXPathStringHash(str);
6649 for (i = 0; i < ns->nodeNr; i++) {
6650 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6651 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6652 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6653 xmlFree(str2);
6654 if (neq)
6655 continue;
6656 return (1);
6657 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6658 if (neq)
6659 continue;
6660 return (1);
6661 } else if (neq) {
6662 if (str2 != NULL)
6663 xmlFree(str2);
6664 return (1);
6665 }
6666 if (str2 != NULL)
6667 xmlFree(str2);
6668 } else if (neq)
6669 return (1);
6670 }
6671 return (0);
6672}
6673
6674/**
6675 * xmlXPathEqualNodeSetFloat:
6676 * @arg: the nodeset object argument
6677 * @f: the float to compare to
6678 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
6679 *
6680 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6681 * If one object to be compared is a node-set and the other is a number,
6682 * then the comparison will be true if and only if there is a node in
6683 * the node-set such that the result of performing the comparison on the
6684 * number to be compared and on the result of converting the string-value
6685 * of that node to a number using the number function is true.
6686 *
6687 * Returns 0 or 1 depending on the results of the test.
6688 */
6689static int
6690xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6691 xmlXPathObjectPtr arg, double f, int neq) {
6692 int i, ret=0;
6693 xmlNodeSetPtr ns;
6694 xmlChar *str2;
6695 xmlXPathObjectPtr val;
6696 double v;
6697
6698 if ((arg == NULL) ||
6699 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6700 return(0);
6701
6702 ns = arg->nodesetval;
6703 if (ns != NULL) {
6704 for (i=0;i<ns->nodeNr;i++) {
6705 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6706 if (str2 != NULL) {
6707 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6708 xmlFree(str2);
6709 xmlXPathNumberFunction(ctxt, 1);
6710 val = valuePop(ctxt);
6711 v = val->floatval;
6712 xmlXPathReleaseObject(ctxt->context, val);
6713 if (!xmlXPathIsNaN(v)) {
6714 if ((!neq) && (v==f)) {
6715 ret = 1;
6716 break;
6717 } else if ((neq) && (v!=f)) {
6718 ret = 1;
6719 break;
6720 }
6721 } else { /* NaN is unequal to any value */
6722 if (neq)
6723 ret = 1;
6724 }
6725 }
6726 }
6727 }
6728
6729 return(ret);
6730}
6731
6732
6733/**
6734 * xmlXPathEqualNodeSets:
6735 * @arg1: first nodeset object argument
6736 * @arg2: second nodeset object argument
6737 * @neq: flag to show whether to test '=' (0) or '!=' (1)
6738 *
6739 * Implement the equal / not equal operation on XPath nodesets:
6740 * @arg1 == @arg2 or @arg1 != @arg2
6741 * If both objects to be compared are node-sets, then the comparison
6742 * will be true if and only if there is a node in the first node-set and
6743 * a node in the second node-set such that the result of performing the
6744 * comparison on the string-values of the two nodes is true.
6745 *
6746 * (needless to say, this is a costly operation)
6747 *
6748 * Returns 0 or 1 depending on the results of the test.
6749 */
6750static int
6751xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6752 int i, j;
6753 unsigned int *hashs1;
6754 unsigned int *hashs2;
6755 xmlChar **values1;
6756 xmlChar **values2;
6757 int ret = 0;
6758 xmlNodeSetPtr ns1;
6759 xmlNodeSetPtr ns2;
6760
6761 if ((arg1 == NULL) ||
6762 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6763 return(0);
6764 if ((arg2 == NULL) ||
6765 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6766 return(0);
6767
6768 ns1 = arg1->nodesetval;
6769 ns2 = arg2->nodesetval;
6770
6771 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6772 return(0);
6773 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6774 return(0);
6775
6776 /*
6777 * for equal, check if there is a node pertaining to both sets
6778 */
6779 if (neq == 0)
6780 for (i = 0;i < ns1->nodeNr;i++)
6781 for (j = 0;j < ns2->nodeNr;j++)
6782 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6783 return(1);
6784
6785 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6786 if (values1 == NULL) {
6787 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6788 return(0);
6789 }
6790 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6791 if (hashs1 == NULL) {
6792 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6793 xmlFree(values1);
6794 return(0);
6795 }
6796 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6797 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6798 if (values2 == NULL) {
6799 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6800 xmlFree(hashs1);
6801 xmlFree(values1);
6802 return(0);
6803 }
6804 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6805 if (hashs2 == NULL) {
6806 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6807 xmlFree(hashs1);
6808 xmlFree(values1);
6809 xmlFree(values2);
6810 return(0);
6811 }
6812 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6813 for (i = 0;i < ns1->nodeNr;i++) {
6814 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6815 for (j = 0;j < ns2->nodeNr;j++) {
6816 if (i == 0)
6817 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6818 if (hashs1[i] != hashs2[j]) {
6819 if (neq) {
6820 ret = 1;
6821 break;
6822 }
6823 }
6824 else {
6825 if (values1[i] == NULL)
6826 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6827 if (values2[j] == NULL)
6828 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6829 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6830 if (ret)
6831 break;
6832 }
6833 }
6834 if (ret)
6835 break;
6836 }
6837 for (i = 0;i < ns1->nodeNr;i++)
6838 if (values1[i] != NULL)
6839 xmlFree(values1[i]);
6840 for (j = 0;j < ns2->nodeNr;j++)
6841 if (values2[j] != NULL)
6842 xmlFree(values2[j]);
6843 xmlFree(values1);
6844 xmlFree(values2);
6845 xmlFree(hashs1);
6846 xmlFree(hashs2);
6847 return(ret);
6848}
6849
6850static int
6851xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6852 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6853 int ret = 0;
6854 /*
6855 *At this point we are assured neither arg1 nor arg2
6856 *is a nodeset, so we can just pick the appropriate routine.
6857 */
6858 switch (arg1->type) {
6859 case XPATH_UNDEFINED:
6860#ifdef DEBUG_EXPR
6861 xmlGenericError(xmlGenericErrorContext,
6862 "Equal: undefined\n");
6863#endif
6864 break;
6865 case XPATH_BOOLEAN:
6866 switch (arg2->type) {
6867 case XPATH_UNDEFINED:
6868#ifdef DEBUG_EXPR
6869 xmlGenericError(xmlGenericErrorContext,
6870 "Equal: undefined\n");
6871#endif
6872 break;
6873 case XPATH_BOOLEAN:
6874#ifdef DEBUG_EXPR
6875 xmlGenericError(xmlGenericErrorContext,
6876 "Equal: %d boolean %d \n",
6877 arg1->boolval, arg2->boolval);
6878#endif
6879 ret = (arg1->boolval == arg2->boolval);
6880 break;
6881 case XPATH_NUMBER:
6882 ret = (arg1->boolval ==
6883 xmlXPathCastNumberToBoolean(arg2->floatval));
6884 break;
6885 case XPATH_STRING:
6886 if ((arg2->stringval == NULL) ||
6887 (arg2->stringval[0] == 0)) ret = 0;
6888 else
6889 ret = 1;
6890 ret = (arg1->boolval == ret);
6891 break;
6892 case XPATH_USERS:
6893 case XPATH_POINT:
6894 case XPATH_RANGE:
6895 case XPATH_LOCATIONSET:
6896 TODO
6897 break;
6898 case XPATH_NODESET:
6899 case XPATH_XSLT_TREE:
6900 break;
6901 }
6902 break;
6903 case XPATH_NUMBER:
6904 switch (arg2->type) {
6905 case XPATH_UNDEFINED:
6906#ifdef DEBUG_EXPR
6907 xmlGenericError(xmlGenericErrorContext,
6908 "Equal: undefined\n");
6909#endif
6910 break;
6911 case XPATH_BOOLEAN:
6912 ret = (arg2->boolval==
6913 xmlXPathCastNumberToBoolean(arg1->floatval));
6914 break;
6915 case XPATH_STRING:
6916 valuePush(ctxt, arg2);
6917 xmlXPathNumberFunction(ctxt, 1);
6918 arg2 = valuePop(ctxt);
6919 /* no break on purpose */
6920 case XPATH_NUMBER:
6921 /* Hand check NaN and Infinity equalities */
6922 if (xmlXPathIsNaN(arg1->floatval) ||
6923 xmlXPathIsNaN(arg2->floatval)) {
6924 ret = 0;
6925 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6926 if (xmlXPathIsInf(arg2->floatval) == 1)
6927 ret = 1;
6928 else
6929 ret = 0;
6930 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6931 if (xmlXPathIsInf(arg2->floatval) == -1)
6932 ret = 1;
6933 else
6934 ret = 0;
6935 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6936 if (xmlXPathIsInf(arg1->floatval) == 1)
6937 ret = 1;
6938 else
6939 ret = 0;
6940 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6941 if (xmlXPathIsInf(arg1->floatval) == -1)
6942 ret = 1;
6943 else
6944 ret = 0;
6945 } else {
6946 ret = (arg1->floatval == arg2->floatval);
6947 }
6948 break;
6949 case XPATH_USERS:
6950 case XPATH_POINT:
6951 case XPATH_RANGE:
6952 case XPATH_LOCATIONSET:
6953 TODO
6954 break;
6955 case XPATH_NODESET:
6956 case XPATH_XSLT_TREE:
6957 break;
6958 }
6959 break;
6960 case XPATH_STRING:
6961 switch (arg2->type) {
6962 case XPATH_UNDEFINED:
6963#ifdef DEBUG_EXPR
6964 xmlGenericError(xmlGenericErrorContext,
6965 "Equal: undefined\n");
6966#endif
6967 break;
6968 case XPATH_BOOLEAN:
6969 if ((arg1->stringval == NULL) ||
6970 (arg1->stringval[0] == 0)) ret = 0;
6971 else
6972 ret = 1;
6973 ret = (arg2->boolval == ret);
6974 break;
6975 case XPATH_STRING:
6976 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6977 break;
6978 case XPATH_NUMBER:
6979 valuePush(ctxt, arg1);
6980 xmlXPathNumberFunction(ctxt, 1);
6981 arg1 = valuePop(ctxt);
6982 /* Hand check NaN and Infinity equalities */
6983 if (xmlXPathIsNaN(arg1->floatval) ||
6984 xmlXPathIsNaN(arg2->floatval)) {
6985 ret = 0;
6986 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6987 if (xmlXPathIsInf(arg2->floatval) == 1)
6988 ret = 1;
6989 else
6990 ret = 0;
6991 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6992 if (xmlXPathIsInf(arg2->floatval) == -1)
6993 ret = 1;
6994 else
6995 ret = 0;
6996 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6997 if (xmlXPathIsInf(arg1->floatval) == 1)
6998 ret = 1;
6999 else
7000 ret = 0;
7001 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7002 if (xmlXPathIsInf(arg1->floatval) == -1)
7003 ret = 1;
7004 else
7005 ret = 0;
7006 } else {
7007 ret = (arg1->floatval == arg2->floatval);
7008 }
7009 break;
7010 case XPATH_USERS:
7011 case XPATH_POINT:
7012 case XPATH_RANGE:
7013 case XPATH_LOCATIONSET:
7014 TODO
7015 break;
7016 case XPATH_NODESET:
7017 case XPATH_XSLT_TREE:
7018 break;
7019 }
7020 break;
7021 case XPATH_USERS:
7022 case XPATH_POINT:
7023 case XPATH_RANGE:
7024 case XPATH_LOCATIONSET:
7025 TODO
7026 break;
7027 case XPATH_NODESET:
7028 case XPATH_XSLT_TREE:
7029 break;
7030 }
7031 xmlXPathReleaseObject(ctxt->context, arg1);
7032 xmlXPathReleaseObject(ctxt->context, arg2);
7033 return(ret);
7034}
7035
7036/**
7037 * xmlXPathEqualValues:
7038 * @ctxt: the XPath Parser context
7039 *
7040 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7041 *
7042 * Returns 0 or 1 depending on the results of the test.
7043 */
7044int
7045xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7046 xmlXPathObjectPtr arg1, arg2, argtmp;
7047 int ret = 0;
7048
7049 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7050 arg2 = valuePop(ctxt);
7051 arg1 = valuePop(ctxt);
7052 if ((arg1 == NULL) || (arg2 == NULL)) {
7053 if (arg1 != NULL)
7054 xmlXPathReleaseObject(ctxt->context, arg1);
7055 else
7056 xmlXPathReleaseObject(ctxt->context, arg2);
7057 XP_ERROR0(XPATH_INVALID_OPERAND);
7058 }
7059
7060 if (arg1 == arg2) {
7061#ifdef DEBUG_EXPR
7062 xmlGenericError(xmlGenericErrorContext,
7063 "Equal: by pointer\n");
7064#endif
7065 xmlXPathFreeObject(arg1);
7066 return(1);
7067 }
7068
7069 /*
7070 *If either argument is a nodeset, it's a 'special case'
7071 */
7072 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7073 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7074 /*
7075 *Hack it to assure arg1 is the nodeset
7076 */
7077 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7078 argtmp = arg2;
7079 arg2 = arg1;
7080 arg1 = argtmp;
7081 }
7082 switch (arg2->type) {
7083 case XPATH_UNDEFINED:
7084#ifdef DEBUG_EXPR
7085 xmlGenericError(xmlGenericErrorContext,
7086 "Equal: undefined\n");
7087#endif
7088 break;
7089 case XPATH_NODESET:
7090 case XPATH_XSLT_TREE:
7091 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7092 break;
7093 case XPATH_BOOLEAN:
7094 if ((arg1->nodesetval == NULL) ||
7095 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7096 else
7097 ret = 1;
7098 ret = (ret == arg2->boolval);
7099 break;
7100 case XPATH_NUMBER:
7101 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7102 break;
7103 case XPATH_STRING:
7104 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7105 break;
7106 case XPATH_USERS:
7107 case XPATH_POINT:
7108 case XPATH_RANGE:
7109 case XPATH_LOCATIONSET:
7110 TODO
7111 break;
7112 }
7113 xmlXPathReleaseObject(ctxt->context, arg1);
7114 xmlXPathReleaseObject(ctxt->context, arg2);
7115 return(ret);
7116 }
7117
7118 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7119}
7120
7121/**
7122 * xmlXPathNotEqualValues:
7123 * @ctxt: the XPath Parser context
7124 *
7125 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7126 *
7127 * Returns 0 or 1 depending on the results of the test.
7128 */
7129int
7130xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7131 xmlXPathObjectPtr arg1, arg2, argtmp;
7132 int ret = 0;
7133
7134 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7135 arg2 = valuePop(ctxt);
7136 arg1 = valuePop(ctxt);
7137 if ((arg1 == NULL) || (arg2 == NULL)) {
7138 if (arg1 != NULL)
7139 xmlXPathReleaseObject(ctxt->context, arg1);
7140 else
7141 xmlXPathReleaseObject(ctxt->context, arg2);
7142 XP_ERROR0(XPATH_INVALID_OPERAND);
7143 }
7144
7145 if (arg1 == arg2) {
7146#ifdef DEBUG_EXPR
7147 xmlGenericError(xmlGenericErrorContext,
7148 "NotEqual: by pointer\n");
7149#endif
7150 xmlXPathReleaseObject(ctxt->context, arg1);
7151 return(0);
7152 }
7153
7154 /*
7155 *If either argument is a nodeset, it's a 'special case'
7156 */
7157 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7158 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7159 /*
7160 *Hack it to assure arg1 is the nodeset
7161 */
7162 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7163 argtmp = arg2;
7164 arg2 = arg1;
7165 arg1 = argtmp;
7166 }
7167 switch (arg2->type) {
7168 case XPATH_UNDEFINED:
7169#ifdef DEBUG_EXPR
7170 xmlGenericError(xmlGenericErrorContext,
7171 "NotEqual: undefined\n");
7172#endif
7173 break;
7174 case XPATH_NODESET:
7175 case XPATH_XSLT_TREE:
7176 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7177 break;
7178 case XPATH_BOOLEAN:
7179 if ((arg1->nodesetval == NULL) ||
7180 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7181 else
7182 ret = 1;
7183 ret = (ret != arg2->boolval);
7184 break;
7185 case XPATH_NUMBER:
7186 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7187 break;
7188 case XPATH_STRING:
7189 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7190 break;
7191 case XPATH_USERS:
7192 case XPATH_POINT:
7193 case XPATH_RANGE:
7194 case XPATH_LOCATIONSET:
7195 TODO
7196 break;
7197 }
7198 xmlXPathReleaseObject(ctxt->context, arg1);
7199 xmlXPathReleaseObject(ctxt->context, arg2);
7200 return(ret);
7201 }
7202
7203 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7204}
7205
7206/**
7207 * xmlXPathCompareValues:
7208 * @ctxt: the XPath Parser context
7209 * @inf: less than (1) or greater than (0)
7210 * @strict: is the comparison strict
7211 *
7212 * Implement the compare operation on XPath objects:
7213 * @arg1 < @arg2 (1, 1, ...
7214 * @arg1 <= @arg2 (1, 0, ...
7215 * @arg1 > @arg2 (0, 1, ...
7216 * @arg1 >= @arg2 (0, 0, ...
7217 *
7218 * When neither object to be compared is a node-set and the operator is
7219 * <=, <, >=, >, then the objects are compared by converted both objects
7220 * to numbers and comparing the numbers according to IEEE 754. The <
7221 * comparison will be true if and only if the first number is less than the
7222 * second number. The <= comparison will be true if and only if the first
7223 * number is less than or equal to the second number. The > comparison
7224 * will be true if and only if the first number is greater than the second
7225 * number. The >= comparison will be true if and only if the first number
7226 * is greater than or equal to the second number.
7227 *
7228 * Returns 1 if the comparison succeeded, 0 if it failed
7229 */
7230int
7231xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7232 int ret = 0, arg1i = 0, arg2i = 0;
7233 xmlXPathObjectPtr arg1, arg2;
7234
7235 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7236 arg2 = valuePop(ctxt);
7237 arg1 = valuePop(ctxt);
7238 if ((arg1 == NULL) || (arg2 == NULL)) {
7239 if (arg1 != NULL)
7240 xmlXPathReleaseObject(ctxt->context, arg1);
7241 else
7242 xmlXPathReleaseObject(ctxt->context, arg2);
7243 XP_ERROR0(XPATH_INVALID_OPERAND);
7244 }
7245
7246 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7247 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7248 /*
7249 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7250 * are not freed from within this routine; they will be freed from the
7251 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7252 */
7253 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7254 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7255 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7256 } else {
7257 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7258 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7259 arg1, arg2);
7260 } else {
7261 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7262 arg2, arg1);
7263 }
7264 }
7265 return(ret);
7266 }
7267
7268 if (arg1->type != XPATH_NUMBER) {
7269 valuePush(ctxt, arg1);
7270 xmlXPathNumberFunction(ctxt, 1);
7271 arg1 = valuePop(ctxt);
7272 }
7273 if (arg1->type != XPATH_NUMBER) {
7274 xmlXPathFreeObject(arg1);
7275 xmlXPathFreeObject(arg2);
7276 XP_ERROR0(XPATH_INVALID_OPERAND);
7277 }
7278 if (arg2->type != XPATH_NUMBER) {
7279 valuePush(ctxt, arg2);
7280 xmlXPathNumberFunction(ctxt, 1);
7281 arg2 = valuePop(ctxt);
7282 }
7283 if (arg2->type != XPATH_NUMBER) {
7284 xmlXPathReleaseObject(ctxt->context, arg1);
7285 xmlXPathReleaseObject(ctxt->context, arg2);
7286 XP_ERROR0(XPATH_INVALID_OPERAND);
7287 }
7288 /*
7289 * Add tests for infinity and nan
7290 * => feedback on 3.4 for Inf and NaN
7291 */
7292 /* Hand check NaN and Infinity comparisons */
7293 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7294 ret=0;
7295 } else {
7296 arg1i=xmlXPathIsInf(arg1->floatval);
7297 arg2i=xmlXPathIsInf(arg2->floatval);
7298 if (inf && strict) {
7299 if ((arg1i == -1 && arg2i != -1) ||
7300 (arg2i == 1 && arg1i != 1)) {
7301 ret = 1;
7302 } else if (arg1i == 0 && arg2i == 0) {
7303 ret = (arg1->floatval < arg2->floatval);
7304 } else {
7305 ret = 0;
7306 }
7307 }
7308 else if (inf && !strict) {
7309 if (arg1i == -1 || arg2i == 1) {
7310 ret = 1;
7311 } else if (arg1i == 0 && arg2i == 0) {
7312 ret = (arg1->floatval <= arg2->floatval);
7313 } else {
7314 ret = 0;
7315 }
7316 }
7317 else if (!inf && strict) {
7318 if ((arg1i == 1 && arg2i != 1) ||
7319 (arg2i == -1 && arg1i != -1)) {
7320 ret = 1;
7321 } else if (arg1i == 0 && arg2i == 0) {
7322 ret = (arg1->floatval > arg2->floatval);
7323 } else {
7324 ret = 0;
7325 }
7326 }
7327 else if (!inf && !strict) {
7328 if (arg1i == 1 || arg2i == -1) {
7329 ret = 1;
7330 } else if (arg1i == 0 && arg2i == 0) {
7331 ret = (arg1->floatval >= arg2->floatval);
7332 } else {
7333 ret = 0;
7334 }
7335 }
7336 }
7337 xmlXPathReleaseObject(ctxt->context, arg1);
7338 xmlXPathReleaseObject(ctxt->context, arg2);
7339 return(ret);
7340}
7341
7342/**
7343 * xmlXPathValueFlipSign:
7344 * @ctxt: the XPath Parser context
7345 *
7346 * Implement the unary - operation on an XPath object
7347 * The numeric operators convert their operands to numbers as if
7348 * by calling the number function.
7349 */
7350void
7351xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7352 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7353 CAST_TO_NUMBER;
7354 CHECK_TYPE(XPATH_NUMBER);
7355 if (xmlXPathIsNaN(ctxt->value->floatval))
7356 ctxt->value->floatval=xmlXPathNAN;
7357 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7358 ctxt->value->floatval=xmlXPathNINF;
7359 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7360 ctxt->value->floatval=xmlXPathPINF;
7361 else if (ctxt->value->floatval == 0) {
7362 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7363 ctxt->value->floatval = xmlXPathNZERO;
7364 else
7365 ctxt->value->floatval = 0;
7366 }
7367 else
7368 ctxt->value->floatval = - ctxt->value->floatval;
7369}
7370
7371/**
7372 * xmlXPathAddValues:
7373 * @ctxt: the XPath Parser context
7374 *
7375 * Implement the add operation on XPath objects:
7376 * The numeric operators convert their operands to numbers as if
7377 * by calling the number function.
7378 */
7379void
7380xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7381 xmlXPathObjectPtr arg;
7382 double val;
7383
7384 arg = valuePop(ctxt);
7385 if (arg == NULL)
7386 XP_ERROR(XPATH_INVALID_OPERAND);
7387 val = xmlXPathCastToNumber(arg);
7388 xmlXPathReleaseObject(ctxt->context, arg);
7389 CAST_TO_NUMBER;
7390 CHECK_TYPE(XPATH_NUMBER);
7391 ctxt->value->floatval += val;
7392}
7393
7394/**
7395 * xmlXPathSubValues:
7396 * @ctxt: the XPath Parser context
7397 *
7398 * Implement the subtraction operation on XPath objects:
7399 * The numeric operators convert their operands to numbers as if
7400 * by calling the number function.
7401 */
7402void
7403xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7404 xmlXPathObjectPtr arg;
7405 double val;
7406
7407 arg = valuePop(ctxt);
7408 if (arg == NULL)
7409 XP_ERROR(XPATH_INVALID_OPERAND);
7410 val = xmlXPathCastToNumber(arg);
7411 xmlXPathReleaseObject(ctxt->context, arg);
7412 CAST_TO_NUMBER;
7413 CHECK_TYPE(XPATH_NUMBER);
7414 ctxt->value->floatval -= val;
7415}
7416
7417/**
7418 * xmlXPathMultValues:
7419 * @ctxt: the XPath Parser context
7420 *
7421 * Implement the multiply operation on XPath objects:
7422 * The numeric operators convert their operands to numbers as if
7423 * by calling the number function.
7424 */
7425void
7426xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7427 xmlXPathObjectPtr arg;
7428 double val;
7429
7430 arg = valuePop(ctxt);
7431 if (arg == NULL)
7432 XP_ERROR(XPATH_INVALID_OPERAND);
7433 val = xmlXPathCastToNumber(arg);
7434 xmlXPathReleaseObject(ctxt->context, arg);
7435 CAST_TO_NUMBER;
7436 CHECK_TYPE(XPATH_NUMBER);
7437 ctxt->value->floatval *= val;
7438}
7439
7440/**
7441 * xmlXPathDivValues:
7442 * @ctxt: the XPath Parser context
7443 *
7444 * Implement the div operation on XPath objects @arg1 / @arg2:
7445 * The numeric operators convert their operands to numbers as if
7446 * by calling the number function.
7447 */
7448void
7449xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7450 xmlXPathObjectPtr arg;
7451 double val;
7452
7453 arg = valuePop(ctxt);
7454 if (arg == NULL)
7455 XP_ERROR(XPATH_INVALID_OPERAND);
7456 val = xmlXPathCastToNumber(arg);
7457 xmlXPathReleaseObject(ctxt->context, arg);
7458 CAST_TO_NUMBER;
7459 CHECK_TYPE(XPATH_NUMBER);
7460 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7461 ctxt->value->floatval = xmlXPathNAN;
7462 else if (val == 0 && xmlXPathGetSign(val) != 0) {
7463 if (ctxt->value->floatval == 0)
7464 ctxt->value->floatval = xmlXPathNAN;
7465 else if (ctxt->value->floatval > 0)
7466 ctxt->value->floatval = xmlXPathNINF;
7467 else if (ctxt->value->floatval < 0)
7468 ctxt->value->floatval = xmlXPathPINF;
7469 }
7470 else if (val == 0) {
7471 if (ctxt->value->floatval == 0)
7472 ctxt->value->floatval = xmlXPathNAN;
7473 else if (ctxt->value->floatval > 0)
7474 ctxt->value->floatval = xmlXPathPINF;
7475 else if (ctxt->value->floatval < 0)
7476 ctxt->value->floatval = xmlXPathNINF;
7477 } else
7478 ctxt->value->floatval /= val;
7479}
7480
7481/**
7482 * xmlXPathModValues:
7483 * @ctxt: the XPath Parser context
7484 *
7485 * Implement the mod operation on XPath objects: @arg1 / @arg2
7486 * The numeric operators convert their operands to numbers as if
7487 * by calling the number function.
7488 */
7489void
7490xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7491 xmlXPathObjectPtr arg;
7492 double arg1, arg2;
7493
7494 arg = valuePop(ctxt);
7495 if (arg == NULL)
7496 XP_ERROR(XPATH_INVALID_OPERAND);
7497 arg2 = xmlXPathCastToNumber(arg);
7498 xmlXPathReleaseObject(ctxt->context, arg);
7499 CAST_TO_NUMBER;
7500 CHECK_TYPE(XPATH_NUMBER);
7501 arg1 = ctxt->value->floatval;
7502 if (arg2 == 0)
7503 ctxt->value->floatval = xmlXPathNAN;
7504 else {
7505 ctxt->value->floatval = fmod(arg1, arg2);
7506 }
7507}
7508
7509/************************************************************************
7510 * *
7511 * The traversal functions *
7512 * *
7513 ************************************************************************/
7514
7515/*
7516 * A traversal function enumerates nodes along an axis.
7517 * Initially it must be called with NULL, and it indicates
7518 * termination on the axis by returning NULL.
7519 */
7520typedef xmlNodePtr (*xmlXPathTraversalFunction)
7521 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7522
7523/*
7524 * xmlXPathTraversalFunctionExt:
7525 * A traversal function enumerates nodes along an axis.
7526 * Initially it must be called with NULL, and it indicates
7527 * termination on the axis by returning NULL.
7528 * The context node of the traversal is specified via @contextNode.
7529 */
7530typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7531 (xmlNodePtr cur, xmlNodePtr contextNode);
7532
7533/*
7534 * xmlXPathNodeSetMergeFunction:
7535 * Used for merging node sets in xmlXPathCollectAndTest().
7536 */
7537typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7538 (xmlNodeSetPtr, xmlNodeSetPtr, int);
7539
7540
7541/**
7542 * xmlXPathNextSelf:
7543 * @ctxt: the XPath Parser context
7544 * @cur: the current node in the traversal
7545 *
7546 * Traversal function for the "self" direction
7547 * The self axis contains just the context node itself
7548 *
7549 * Returns the next element following that axis
7550 */
7551xmlNodePtr
7552xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7553 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7554 if (cur == NULL)
7555 return(ctxt->context->node);
7556 return(NULL);
7557}
7558
7559/**
7560 * xmlXPathNextChild:
7561 * @ctxt: the XPath Parser context
7562 * @cur: the current node in the traversal
7563 *
7564 * Traversal function for the "child" direction
7565 * The child axis contains the children of the context node in document order.
7566 *
7567 * Returns the next element following that axis
7568 */
7569xmlNodePtr
7570xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7571 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7572 if (cur == NULL) {
7573 if (ctxt->context->node == NULL) return(NULL);
7574 switch (ctxt->context->node->type) {
7575 case XML_ELEMENT_NODE:
7576 case XML_TEXT_NODE:
7577 case XML_CDATA_SECTION_NODE:
7578 case XML_ENTITY_REF_NODE:
7579 case XML_ENTITY_NODE:
7580 case XML_PI_NODE:
7581 case XML_COMMENT_NODE:
7582 case XML_NOTATION_NODE:
7583 case XML_DTD_NODE:
7584 return(ctxt->context->node->children);
7585 case XML_DOCUMENT_NODE:
7586 case XML_DOCUMENT_TYPE_NODE:
7587 case XML_DOCUMENT_FRAG_NODE:
7588 case XML_HTML_DOCUMENT_NODE:
7589#ifdef LIBXML_DOCB_ENABLED
7590 case XML_DOCB_DOCUMENT_NODE:
7591#endif
7592 return(((xmlDocPtr) ctxt->context->node)->children);
7593 case XML_ELEMENT_DECL:
7594 case XML_ATTRIBUTE_DECL:
7595 case XML_ENTITY_DECL:
7596 case XML_ATTRIBUTE_NODE:
7597 case XML_NAMESPACE_DECL:
7598 case XML_XINCLUDE_START:
7599 case XML_XINCLUDE_END:
7600 return(NULL);
7601 }
7602 return(NULL);
7603 }
7604 if ((cur->type == XML_DOCUMENT_NODE) ||
7605 (cur->type == XML_HTML_DOCUMENT_NODE))
7606 return(NULL);
7607 return(cur->next);
7608}
7609
7610/**
7611 * xmlXPathNextChildElement:
7612 * @ctxt: the XPath Parser context
7613 * @cur: the current node in the traversal
7614 *
7615 * Traversal function for the "child" direction and nodes of type element.
7616 * The child axis contains the children of the context node in document order.
7617 *
7618 * Returns the next element following that axis
7619 */
7620static xmlNodePtr
7621xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7622 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7623 if (cur == NULL) {
7624 cur = ctxt->context->node;
7625 if (cur == NULL) return(NULL);
7626 /*
7627 * Get the first element child.
7628 */
7629 switch (cur->type) {
7630 case XML_ELEMENT_NODE:
7631 case XML_DOCUMENT_FRAG_NODE:
7632 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7633 case XML_ENTITY_NODE:
7634 cur = cur->children;
7635 if (cur != NULL) {
7636 if (cur->type == XML_ELEMENT_NODE)
7637 return(cur);
7638 do {
7639 cur = cur->next;
7640 } while ((cur != NULL) &&
7641 (cur->type != XML_ELEMENT_NODE));
7642 return(cur);
7643 }
7644 return(NULL);
7645 case XML_DOCUMENT_NODE:
7646 case XML_HTML_DOCUMENT_NODE:
7647#ifdef LIBXML_DOCB_ENABLED
7648 case XML_DOCB_DOCUMENT_NODE:
7649#endif
7650 return(xmlDocGetRootElement((xmlDocPtr) cur));
7651 default:
7652 return(NULL);
7653 }
7654 return(NULL);
7655 }
7656 /*
7657 * Get the next sibling element node.
7658 */
7659 switch (cur->type) {
7660 case XML_ELEMENT_NODE:
7661 case XML_TEXT_NODE:
7662 case XML_ENTITY_REF_NODE:
7663 case XML_ENTITY_NODE:
7664 case XML_CDATA_SECTION_NODE:
7665 case XML_PI_NODE:
7666 case XML_COMMENT_NODE:
7667 case XML_XINCLUDE_END:
7668 break;
7669 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7670 default:
7671 return(NULL);
7672 }
7673 if (cur->next != NULL) {
7674 if (cur->next->type == XML_ELEMENT_NODE)
7675 return(cur->next);
7676 cur = cur->next;
7677 do {
7678 cur = cur->next;
7679 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7680 return(cur);
7681 }
7682 return(NULL);
7683}
7684
7685/**
7686 * xmlXPathNextDescendantOrSelfElemParent:
7687 * @ctxt: the XPath Parser context
7688 * @cur: the current node in the traversal
7689 *
7690 * Traversal function for the "descendant-or-self" axis.
7691 * Additionally it returns only nodes which can be parents of
7692 * element nodes.
7693 *
7694 *
7695 * Returns the next element following that axis
7696 */
7697static xmlNodePtr
7698xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7699 xmlNodePtr contextNode)
7700{
7701 if (cur == NULL) {
7702 if (contextNode == NULL)
7703 return(NULL);
7704 switch (contextNode->type) {
7705 case XML_ELEMENT_NODE:
7706 case XML_XINCLUDE_START:
7707 case XML_DOCUMENT_FRAG_NODE:
7708 case XML_DOCUMENT_NODE:
7709#ifdef LIBXML_DOCB_ENABLED
7710 case XML_DOCB_DOCUMENT_NODE:
7711#endif
7712 case XML_HTML_DOCUMENT_NODE:
7713 return(contextNode);
7714 default:
7715 return(NULL);
7716 }
7717 return(NULL);
7718 } else {
7719 xmlNodePtr start = cur;
7720
7721 while (cur != NULL) {
7722 switch (cur->type) {
7723 case XML_ELEMENT_NODE:
7724 /* TODO: OK to have XInclude here? */
7725 case XML_XINCLUDE_START:
7726 case XML_DOCUMENT_FRAG_NODE:
7727 if (cur != start)
7728 return(cur);
7729 if (cur->children != NULL) {
7730 cur = cur->children;
7731 continue;
7732 }
7733 break;
7734 /* Not sure if we need those here. */
7735 case XML_DOCUMENT_NODE:
7736#ifdef LIBXML_DOCB_ENABLED
7737 case XML_DOCB_DOCUMENT_NODE:
7738#endif
7739 case XML_HTML_DOCUMENT_NODE:
7740 if (cur != start)
7741 return(cur);
7742 return(xmlDocGetRootElement((xmlDocPtr) cur));
7743 default:
7744 break;
7745 }
7746
7747next_sibling:
7748 if ((cur == NULL) || (cur == contextNode))
7749 return(NULL);
7750 if (cur->next != NULL) {
7751 cur = cur->next;
7752 } else {
7753 cur = cur->parent;
7754 goto next_sibling;
7755 }
7756 }
7757 }
7758 return(NULL);
7759}
7760
7761/**
7762 * xmlXPathNextDescendant:
7763 * @ctxt: the XPath Parser context
7764 * @cur: the current node in the traversal
7765 *
7766 * Traversal function for the "descendant" direction
7767 * the descendant axis contains the descendants of the context node in document
7768 * order; a descendant is a child or a child of a child and so on.
7769 *
7770 * Returns the next element following that axis
7771 */
7772xmlNodePtr
7773xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7774 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7775 if (cur == NULL) {
7776 if (ctxt->context->node == NULL)
7777 return(NULL);
7778 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7779 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7780 return(NULL);
7781
7782 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7783 return(ctxt->context->doc->children);
7784 return(ctxt->context->node->children);
7785 }
7786
7787 if (cur->children != NULL) {
7788 /*
7789 * Do not descend on entities declarations
7790 */
7791 if (cur->children->type != XML_ENTITY_DECL) {
7792 cur = cur->children;
7793 /*
7794 * Skip DTDs
7795 */
7796 if (cur->type != XML_DTD_NODE)
7797 return(cur);
7798 }
7799 }
7800
7801 if (cur == ctxt->context->node) return(NULL);
7802
7803 while (cur->next != NULL) {
7804 cur = cur->next;
7805 if ((cur->type != XML_ENTITY_DECL) &&
7806 (cur->type != XML_DTD_NODE))
7807 return(cur);
7808 }
7809
7810 do {
7811 cur = cur->parent;
7812 if (cur == NULL) break;
7813 if (cur == ctxt->context->node) return(NULL);
7814 if (cur->next != NULL) {
7815 cur = cur->next;
7816 return(cur);
7817 }
7818 } while (cur != NULL);
7819 return(cur);
7820}
7821
7822/**
7823 * xmlXPathNextDescendantOrSelf:
7824 * @ctxt: the XPath Parser context
7825 * @cur: the current node in the traversal
7826 *
7827 * Traversal function for the "descendant-or-self" direction
7828 * the descendant-or-self axis contains the context node and the descendants
7829 * of the context node in document order; thus the context node is the first
7830 * node on the axis, and the first child of the context node is the second node
7831 * on the axis
7832 *
7833 * Returns the next element following that axis
7834 */
7835xmlNodePtr
7836xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7837 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7838 if (cur == NULL) {
7839 if (ctxt->context->node == NULL)
7840 return(NULL);
7841 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7842 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7843 return(NULL);
7844 return(ctxt->context->node);
7845 }
7846
7847 return(xmlXPathNextDescendant(ctxt, cur));
7848}
7849
7850/**
7851 * xmlXPathNextParent:
7852 * @ctxt: the XPath Parser context
7853 * @cur: the current node in the traversal
7854 *
7855 * Traversal function for the "parent" direction
7856 * The parent axis contains the parent of the context node, if there is one.
7857 *
7858 * Returns the next element following that axis
7859 */
7860xmlNodePtr
7861xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7862 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7863 /*
7864 * the parent of an attribute or namespace node is the element
7865 * to which the attribute or namespace node is attached
7866 * Namespace handling !!!
7867 */
7868 if (cur == NULL) {
7869 if (ctxt->context->node == NULL) return(NULL);
7870 switch (ctxt->context->node->type) {
7871 case XML_ELEMENT_NODE:
7872 case XML_TEXT_NODE:
7873 case XML_CDATA_SECTION_NODE:
7874 case XML_ENTITY_REF_NODE:
7875 case XML_ENTITY_NODE:
7876 case XML_PI_NODE:
7877 case XML_COMMENT_NODE:
7878 case XML_NOTATION_NODE:
7879 case XML_DTD_NODE:
7880 case XML_ELEMENT_DECL:
7881 case XML_ATTRIBUTE_DECL:
7882 case XML_XINCLUDE_START:
7883 case XML_XINCLUDE_END:
7884 case XML_ENTITY_DECL:
7885 if (ctxt->context->node->parent == NULL)
7886 return((xmlNodePtr) ctxt->context->doc);
7887 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7888 ((ctxt->context->node->parent->name[0] == ' ') ||
7889 (xmlStrEqual(ctxt->context->node->parent->name,
7890 BAD_CAST "fake node libxslt"))))
7891 return(NULL);
7892 return(ctxt->context->node->parent);
7893 case XML_ATTRIBUTE_NODE: {
7894 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7895
7896 return(att->parent);
7897 }
7898 case XML_DOCUMENT_NODE:
7899 case XML_DOCUMENT_TYPE_NODE:
7900 case XML_DOCUMENT_FRAG_NODE:
7901 case XML_HTML_DOCUMENT_NODE:
7902#ifdef LIBXML_DOCB_ENABLED
7903 case XML_DOCB_DOCUMENT_NODE:
7904#endif
7905 return(NULL);
7906 case XML_NAMESPACE_DECL: {
7907 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7908
7909 if ((ns->next != NULL) &&
7910 (ns->next->type != XML_NAMESPACE_DECL))
7911 return((xmlNodePtr) ns->next);
7912 return(NULL);
7913 }
7914 }
7915 }
7916 return(NULL);
7917}
7918
7919/**
7920 * xmlXPathNextAncestor:
7921 * @ctxt: the XPath Parser context
7922 * @cur: the current node in the traversal
7923 *
7924 * Traversal function for the "ancestor" direction
7925 * the ancestor axis contains the ancestors of the context node; the ancestors
7926 * of the context node consist of the parent of context node and the parent's
7927 * parent and so on; the nodes are ordered in reverse document order; thus the
7928 * parent is the first node on the axis, and the parent's parent is the second
7929 * node on the axis
7930 *
7931 * Returns the next element following that axis
7932 */
7933xmlNodePtr
7934xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7935 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7936 /*
7937 * the parent of an attribute or namespace node is the element
7938 * to which the attribute or namespace node is attached
7939 * !!!!!!!!!!!!!
7940 */
7941 if (cur == NULL) {
7942 if (ctxt->context->node == NULL) return(NULL);
7943 switch (ctxt->context->node->type) {
7944 case XML_ELEMENT_NODE:
7945 case XML_TEXT_NODE:
7946 case XML_CDATA_SECTION_NODE:
7947 case XML_ENTITY_REF_NODE:
7948 case XML_ENTITY_NODE:
7949 case XML_PI_NODE:
7950 case XML_COMMENT_NODE:
7951 case XML_DTD_NODE:
7952 case XML_ELEMENT_DECL:
7953 case XML_ATTRIBUTE_DECL:
7954 case XML_ENTITY_DECL:
7955 case XML_NOTATION_NODE:
7956 case XML_XINCLUDE_START:
7957 case XML_XINCLUDE_END:
7958 if (ctxt->context->node->parent == NULL)
7959 return((xmlNodePtr) ctxt->context->doc);
7960 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7961 ((ctxt->context->node->parent->name[0] == ' ') ||
7962 (xmlStrEqual(ctxt->context->node->parent->name,
7963 BAD_CAST "fake node libxslt"))))
7964 return(NULL);
7965 return(ctxt->context->node->parent);
7966 case XML_ATTRIBUTE_NODE: {
7967 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
7968
7969 return(tmp->parent);
7970 }
7971 case XML_DOCUMENT_NODE:
7972 case XML_DOCUMENT_TYPE_NODE:
7973 case XML_DOCUMENT_FRAG_NODE:
7974 case XML_HTML_DOCUMENT_NODE:
7975#ifdef LIBXML_DOCB_ENABLED
7976 case XML_DOCB_DOCUMENT_NODE:
7977#endif
7978 return(NULL);
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 }
7989 return(NULL);
7990 }
7991 if (cur == ctxt->context->doc->children)
7992 return((xmlNodePtr) ctxt->context->doc);
7993 if (cur == (xmlNodePtr) ctxt->context->doc)
7994 return(NULL);
7995 switch (cur->type) {
7996 case XML_ELEMENT_NODE:
7997 case XML_TEXT_NODE:
7998 case XML_CDATA_SECTION_NODE:
7999 case XML_ENTITY_REF_NODE:
8000 case XML_ENTITY_NODE:
8001 case XML_PI_NODE:
8002 case XML_COMMENT_NODE:
8003 case XML_NOTATION_NODE:
8004 case XML_DTD_NODE:
8005 case XML_ELEMENT_DECL:
8006 case XML_ATTRIBUTE_DECL:
8007 case XML_ENTITY_DECL:
8008 case XML_XINCLUDE_START:
8009 case XML_XINCLUDE_END:
8010 if (cur->parent == NULL)
8011 return(NULL);
8012 if ((cur->parent->type == XML_ELEMENT_NODE) &&
8013 ((cur->parent->name[0] == ' ') ||
8014 (xmlStrEqual(cur->parent->name,
8015 BAD_CAST "fake node libxslt"))))
8016 return(NULL);
8017 return(cur->parent);
8018 case XML_ATTRIBUTE_NODE: {
8019 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
8020
8021 return(att->parent);
8022 }
8023 case XML_NAMESPACE_DECL: {
8024 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8025
8026 if ((ns->next != NULL) &&
8027 (ns->next->type != XML_NAMESPACE_DECL))
8028 return((xmlNodePtr) ns->next);
8029 /* Bad, how did that namespace end up here ? */
8030 return(NULL);
8031 }
8032 case XML_DOCUMENT_NODE:
8033 case XML_DOCUMENT_TYPE_NODE:
8034 case XML_DOCUMENT_FRAG_NODE:
8035 case XML_HTML_DOCUMENT_NODE:
8036#ifdef LIBXML_DOCB_ENABLED
8037 case XML_DOCB_DOCUMENT_NODE:
8038#endif
8039 return(NULL);
8040 }
8041 return(NULL);
8042}
8043
8044/**
8045 * xmlXPathNextAncestorOrSelf:
8046 * @ctxt: the XPath Parser context
8047 * @cur: the current node in the traversal
8048 *
8049 * Traversal function for the "ancestor-or-self" direction
8050 * he ancestor-or-self axis contains the context node and ancestors of
8051 * the context node in reverse document order; thus the context node is
8052 * the first node on the axis, and the context node's parent the second;
8053 * parent here is defined the same as with the parent axis.
8054 *
8055 * Returns the next element following that axis
8056 */
8057xmlNodePtr
8058xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8059 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8060 if (cur == NULL)
8061 return(ctxt->context->node);
8062 return(xmlXPathNextAncestor(ctxt, cur));
8063}
8064
8065/**
8066 * xmlXPathNextFollowingSibling:
8067 * @ctxt: the XPath Parser context
8068 * @cur: the current node in the traversal
8069 *
8070 * Traversal function for the "following-sibling" direction
8071 * The following-sibling axis contains the following siblings of the context
8072 * node in document order.
8073 *
8074 * Returns the next element following that axis
8075 */
8076xmlNodePtr
8077xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8078 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8079 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8080 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8081 return(NULL);
8082 if (cur == (xmlNodePtr) ctxt->context->doc)
8083 return(NULL);
8084 if (cur == NULL)
8085 return(ctxt->context->node->next);
8086 return(cur->next);
8087}
8088
8089/**
8090 * xmlXPathNextPrecedingSibling:
8091 * @ctxt: the XPath Parser context
8092 * @cur: the current node in the traversal
8093 *
8094 * Traversal function for the "preceding-sibling" direction
8095 * The preceding-sibling axis contains the preceding siblings of the context
8096 * node in reverse document order; the first preceding sibling is first on the
8097 * axis; the sibling preceding that node is the second on the axis and so on.
8098 *
8099 * Returns the next element following that axis
8100 */
8101xmlNodePtr
8102xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8103 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8104 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8105 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8106 return(NULL);
8107 if (cur == (xmlNodePtr) ctxt->context->doc)
8108 return(NULL);
8109 if (cur == NULL)
8110 return(ctxt->context->node->prev);
8111 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8112 cur = cur->prev;
8113 if (cur == NULL)
8114 return(ctxt->context->node->prev);
8115 }
8116 return(cur->prev);
8117}
8118
8119/**
8120 * xmlXPathNextFollowing:
8121 * @ctxt: the XPath Parser context
8122 * @cur: the current node in the traversal
8123 *
8124 * Traversal function for the "following" direction
8125 * The following axis contains all nodes in the same document as the context
8126 * node that are after the context node in document order, excluding any
8127 * descendants and excluding attribute nodes and namespace nodes; the nodes
8128 * are ordered in document order
8129 *
8130 * Returns the next element following that axis
8131 */
8132xmlNodePtr
8133xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8134 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8135 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
8136 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8137 return(cur->children);
8138
8139 if (cur == NULL) {
8140 cur = ctxt->context->node;
8141 if (cur->type == XML_NAMESPACE_DECL)
8142 return(NULL);
8143 if (cur->type == XML_ATTRIBUTE_NODE)
8144 cur = cur->parent;
8145 }
8146 if (cur == NULL) return(NULL) ; /* ERROR */
8147 if (cur->next != NULL) return(cur->next) ;
8148 do {
8149 cur = cur->parent;
8150 if (cur == NULL) break;
8151 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8152 if (cur->next != NULL) return(cur->next);
8153 } while (cur != NULL);
8154 return(cur);
8155}
8156
8157/*
8158 * xmlXPathIsAncestor:
8159 * @ancestor: the ancestor node
8160 * @node: the current node
8161 *
8162 * Check that @ancestor is a @node's ancestor
8163 *
8164 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8165 */
8166static int
8167xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8168 if ((ancestor == NULL) || (node == NULL)) return(0);
8169 /* nodes need to be in the same document */
8170 if (ancestor->doc != node->doc) return(0);
8171 /* avoid searching if ancestor or node is the root node */
8172 if (ancestor == (xmlNodePtr) node->doc) return(1);
8173 if (node == (xmlNodePtr) ancestor->doc) return(0);
8174 while (node->parent != NULL) {
8175 if (node->parent == ancestor)
8176 return(1);
8177 node = node->parent;
8178 }
8179 return(0);
8180}
8181
8182/**
8183 * xmlXPathNextPreceding:
8184 * @ctxt: the XPath Parser context
8185 * @cur: the current node in the traversal
8186 *
8187 * Traversal function for the "preceding" direction
8188 * the preceding axis contains all nodes in the same document as the context
8189 * node that are before the context node in document order, excluding any
8190 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8191 * ordered in reverse document order
8192 *
8193 * Returns the next element following that axis
8194 */
8195xmlNodePtr
8196xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8197{
8198 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8199 if (cur == NULL) {
8200 cur = ctxt->context->node;
8201 if (cur->type == XML_NAMESPACE_DECL)
8202 return(NULL);
8203 if (cur->type == XML_ATTRIBUTE_NODE)
8204 return(cur->parent);
8205 }
8206 if (cur == NULL)
8207 return (NULL);
8208 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8209 cur = cur->prev;
8210 do {
8211 if (cur->prev != NULL) {
8212 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8213 return (cur);
8214 }
8215
8216 cur = cur->parent;
8217 if (cur == NULL)
8218 return (NULL);
8219 if (cur == ctxt->context->doc->children)
8220 return (NULL);
8221 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8222 return (cur);
8223}
8224
8225/**
8226 * xmlXPathNextPrecedingInternal:
8227 * @ctxt: the XPath Parser context
8228 * @cur: the current node in the traversal
8229 *
8230 * Traversal function for the "preceding" direction
8231 * the preceding axis contains all nodes in the same document as the context
8232 * node that are before the context node in document order, excluding any
8233 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8234 * ordered in reverse document order
8235 * This is a faster implementation but internal only since it requires a
8236 * state kept in the parser context: ctxt->ancestor.
8237 *
8238 * Returns the next element following that axis
8239 */
8240static xmlNodePtr
8241xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8242 xmlNodePtr cur)
8243{
8244 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8245 if (cur == NULL) {
8246 cur = ctxt->context->node;
8247 if (cur == NULL)
8248 return (NULL);
8249 if (cur->type == XML_NAMESPACE_DECL)
8250 return (NULL);
8251 ctxt->ancestor = cur->parent;
8252 }
8253 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8254 cur = cur->prev;
8255 while (cur->prev == NULL) {
8256 cur = cur->parent;
8257 if (cur == NULL)
8258 return (NULL);
8259 if (cur == ctxt->context->doc->children)
8260 return (NULL);
8261 if (cur != ctxt->ancestor)
8262 return (cur);
8263 ctxt->ancestor = cur->parent;
8264 }
8265 cur = cur->prev;
8266 while (cur->last != NULL)
8267 cur = cur->last;
8268 return (cur);
8269}
8270
8271/**
8272 * xmlXPathNextNamespace:
8273 * @ctxt: the XPath Parser context
8274 * @cur: the current attribute in the traversal
8275 *
8276 * Traversal function for the "namespace" direction
8277 * the namespace axis contains the namespace nodes of the context node;
8278 * the order of nodes on this axis is implementation-defined; the axis will
8279 * be empty unless the context node is an element
8280 *
8281 * We keep the XML namespace node at the end of the list.
8282 *
8283 * Returns the next element following that axis
8284 */
8285xmlNodePtr
8286xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8287 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8288 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8289 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
8290 if (ctxt->context->tmpNsList != NULL)
8291 xmlFree(ctxt->context->tmpNsList);
8292 ctxt->context->tmpNsList =
8293 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8294 ctxt->context->tmpNsNr = 0;
8295 if (ctxt->context->tmpNsList != NULL) {
8296 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8297 ctxt->context->tmpNsNr++;
8298 }
8299 }
8300 return((xmlNodePtr) xmlXPathXMLNamespace);
8301 }
8302 if (ctxt->context->tmpNsNr > 0) {
8303 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8304 } else {
8305 if (ctxt->context->tmpNsList != NULL)
8306 xmlFree(ctxt->context->tmpNsList);
8307 ctxt->context->tmpNsList = NULL;
8308 return(NULL);
8309 }
8310}
8311
8312/**
8313 * xmlXPathNextAttribute:
8314 * @ctxt: the XPath Parser context
8315 * @cur: the current attribute in the traversal
8316 *
8317 * Traversal function for the "attribute" direction
8318 * TODO: support DTD inherited default attributes
8319 *
8320 * Returns the next element following that axis
8321 */
8322xmlNodePtr
8323xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8324 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8325 if (ctxt->context->node == NULL)
8326 return(NULL);
8327 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8328 return(NULL);
8329 if (cur == NULL) {
8330 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8331 return(NULL);
8332 return((xmlNodePtr)ctxt->context->node->properties);
8333 }
8334 return((xmlNodePtr)cur->next);
8335}
8336
8337/************************************************************************
8338 * *
8339 * NodeTest Functions *
8340 * *
8341 ************************************************************************/
8342
8343#define IS_FUNCTION 200
8344
8345
8346/************************************************************************
8347 * *
8348 * Implicit tree core function library *
8349 * *
8350 ************************************************************************/
8351
8352/**
8353 * xmlXPathRoot:
8354 * @ctxt: the XPath Parser context
8355 *
8356 * Initialize the context to the root of the document
8357 */
8358void
8359xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8360 if ((ctxt == NULL) || (ctxt->context == NULL))
8361 return;
8362 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
8363 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8364 ctxt->context->node));
8365}
8366
8367/************************************************************************
8368 * *
8369 * The explicit core function library *
8370 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8371 * *
8372 ************************************************************************/
8373
8374
8375/**
8376 * xmlXPathLastFunction:
8377 * @ctxt: the XPath Parser context
8378 * @nargs: the number of arguments
8379 *
8380 * Implement the last() XPath function
8381 * number last()
8382 * The last function returns the number of nodes in the context node list.
8383 */
8384void
8385xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8386 CHECK_ARITY(0);
8387 if (ctxt->context->contextSize >= 0) {
8388 valuePush(ctxt,
8389 xmlXPathCacheNewFloat(ctxt->context,
8390 (double) ctxt->context->contextSize));
8391#ifdef DEBUG_EXPR
8392 xmlGenericError(xmlGenericErrorContext,
8393 "last() : %d\n", ctxt->context->contextSize);
8394#endif
8395 } else {
8396 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8397 }
8398}
8399
8400/**
8401 * xmlXPathPositionFunction:
8402 * @ctxt: the XPath Parser context
8403 * @nargs: the number of arguments
8404 *
8405 * Implement the position() XPath function
8406 * number position()
8407 * The position function returns the position of the context node in the
8408 * context node list. The first position is 1, and so the last position
8409 * will be equal to last().
8410 */
8411void
8412xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8413 CHECK_ARITY(0);
8414 if (ctxt->context->proximityPosition >= 0) {
8415 valuePush(ctxt,
8416 xmlXPathCacheNewFloat(ctxt->context,
8417 (double) ctxt->context->proximityPosition));
8418#ifdef DEBUG_EXPR
8419 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8420 ctxt->context->proximityPosition);
8421#endif
8422 } else {
8423 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8424 }
8425}
8426
8427/**
8428 * xmlXPathCountFunction:
8429 * @ctxt: the XPath Parser context
8430 * @nargs: the number of arguments
8431 *
8432 * Implement the count() XPath function
8433 * number count(node-set)
8434 */
8435void
8436xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8437 xmlXPathObjectPtr cur;
8438
8439 CHECK_ARITY(1);
8440 if ((ctxt->value == NULL) ||
8441 ((ctxt->value->type != XPATH_NODESET) &&
8442 (ctxt->value->type != XPATH_XSLT_TREE)))
8443 XP_ERROR(XPATH_INVALID_TYPE);
8444 cur = valuePop(ctxt);
8445
8446 if ((cur == NULL) || (cur->nodesetval == NULL))
8447 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8448 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8449 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8450 (double) cur->nodesetval->nodeNr));
8451 } else {
8452 if ((cur->nodesetval->nodeNr != 1) ||
8453 (cur->nodesetval->nodeTab == NULL)) {
8454 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8455 } else {
8456 xmlNodePtr tmp;
8457 int i = 0;
8458
8459 tmp = cur->nodesetval->nodeTab[0];
8460 if (tmp != NULL) {
8461 tmp = tmp->children;
8462 while (tmp != NULL) {
8463 tmp = tmp->next;
8464 i++;
8465 }
8466 }
8467 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8468 }
8469 }
8470 xmlXPathReleaseObject(ctxt->context, cur);
8471}
8472
8473/**
8474 * xmlXPathGetElementsByIds:
8475 * @doc: the document
8476 * @ids: a whitespace separated list of IDs
8477 *
8478 * Selects elements by their unique ID.
8479 *
8480 * Returns a node-set of selected elements.
8481 */
8482static xmlNodeSetPtr
8483xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8484 xmlNodeSetPtr ret;
8485 const xmlChar *cur = ids;
8486 xmlChar *ID;
8487 xmlAttrPtr attr;
8488 xmlNodePtr elem = NULL;
8489
8490 if (ids == NULL) return(NULL);
8491
8492 ret = xmlXPathNodeSetCreate(NULL);
8493
8494 while (IS_BLANK_CH(*cur)) cur++;
8495 while (*cur != 0) {
8496 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8497 cur++;
8498
8499 ID = xmlStrndup(ids, cur - ids);
8500 if (ID != NULL) {
8501 /*
8502 * We used to check the fact that the value passed
8503 * was an NCName, but this generated much troubles for
8504 * me and Aleksey Sanin, people blatantly violated that
8505 * constaint, like Visa3D spec.
8506 * if (xmlValidateNCName(ID, 1) == 0)
8507 */
8508 attr = xmlGetID(doc, ID);
8509 if (attr != NULL) {
8510 if (attr->type == XML_ATTRIBUTE_NODE)
8511 elem = attr->parent;
8512 else if (attr->type == XML_ELEMENT_NODE)
8513 elem = (xmlNodePtr) attr;
8514 else
8515 elem = NULL;
8516 if (elem != NULL)
8517 xmlXPathNodeSetAdd(ret, elem);
8518 }
8519 xmlFree(ID);
8520 }
8521
8522 while (IS_BLANK_CH(*cur)) cur++;
8523 ids = cur;
8524 }
8525 return(ret);
8526}
8527
8528/**
8529 * xmlXPathIdFunction:
8530 * @ctxt: the XPath Parser context
8531 * @nargs: the number of arguments
8532 *
8533 * Implement the id() XPath function
8534 * node-set id(object)
8535 * The id function selects elements by their unique ID
8536 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8537 * then the result is the union of the result of applying id to the
8538 * string value of each of the nodes in the argument node-set. When the
8539 * argument to id is of any other type, the argument is converted to a
8540 * string as if by a call to the string function; the string is split
8541 * into a whitespace-separated list of tokens (whitespace is any sequence
8542 * of characters matching the production S); the result is a node-set
8543 * containing the elements in the same document as the context node that
8544 * have a unique ID equal to any of the tokens in the list.
8545 */
8546void
8547xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8548 xmlChar *tokens;
8549 xmlNodeSetPtr ret;
8550 xmlXPathObjectPtr obj;
8551
8552 CHECK_ARITY(1);
8553 obj = valuePop(ctxt);
8554 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8555 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8556 xmlNodeSetPtr ns;
8557 int i;
8558
8559 ret = xmlXPathNodeSetCreate(NULL);
8560
8561 if (obj->nodesetval != NULL) {
8562 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8563 tokens =
8564 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8565 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8566 ret = xmlXPathNodeSetMerge(ret, ns);
8567 xmlXPathFreeNodeSet(ns);
8568 if (tokens != NULL)
8569 xmlFree(tokens);
8570 }
8571 }
8572 xmlXPathReleaseObject(ctxt->context, obj);
8573 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8574 return;
8575 }
8576 obj = xmlXPathCacheConvertString(ctxt->context, obj);
8577 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8578 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8579 xmlXPathReleaseObject(ctxt->context, obj);
8580 return;
8581}
8582
8583/**
8584 * xmlXPathLocalNameFunction:
8585 * @ctxt: the XPath Parser context
8586 * @nargs: the number of arguments
8587 *
8588 * Implement the local-name() XPath function
8589 * string local-name(node-set?)
8590 * The local-name function returns a string containing the local part
8591 * of the name of the node in the argument node-set that is first in
8592 * document order. If the node-set is empty or the first node has no
8593 * name, an empty string is returned. If the argument is omitted it
8594 * defaults to the context node.
8595 */
8596void
8597xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8598 xmlXPathObjectPtr cur;
8599
8600 if (ctxt == NULL) return;
8601
8602 if (nargs == 0) {
8603 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8604 ctxt->context->node));
8605 nargs = 1;
8606 }
8607
8608 CHECK_ARITY(1);
8609 if ((ctxt->value == NULL) ||
8610 ((ctxt->value->type != XPATH_NODESET) &&
8611 (ctxt->value->type != XPATH_XSLT_TREE)))
8612 XP_ERROR(XPATH_INVALID_TYPE);
8613 cur = valuePop(ctxt);
8614
8615 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8616 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8617 } else {
8618 int i = 0; /* Should be first in document order !!!!! */
8619 switch (cur->nodesetval->nodeTab[i]->type) {
8620 case XML_ELEMENT_NODE:
8621 case XML_ATTRIBUTE_NODE:
8622 case XML_PI_NODE:
8623 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8624 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8625 else
8626 valuePush(ctxt,
8627 xmlXPathCacheNewString(ctxt->context,
8628 cur->nodesetval->nodeTab[i]->name));
8629 break;
8630 case XML_NAMESPACE_DECL:
8631 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8632 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8633 break;
8634 default:
8635 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8636 }
8637 }
8638 xmlXPathReleaseObject(ctxt->context, cur);
8639}
8640
8641/**
8642 * xmlXPathNamespaceURIFunction:
8643 * @ctxt: the XPath Parser context
8644 * @nargs: the number of arguments
8645 *
8646 * Implement the namespace-uri() XPath function
8647 * string namespace-uri(node-set?)
8648 * The namespace-uri function returns a string containing the
8649 * namespace URI of the expanded name of the node in the argument
8650 * node-set that is first in document order. If the node-set is empty,
8651 * the first node has no name, or the expanded name has no namespace
8652 * URI, an empty string is returned. If the argument is omitted it
8653 * defaults to the context node.
8654 */
8655void
8656xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8657 xmlXPathObjectPtr cur;
8658
8659 if (ctxt == NULL) return;
8660
8661 if (nargs == 0) {
8662 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8663 ctxt->context->node));
8664 nargs = 1;
8665 }
8666 CHECK_ARITY(1);
8667 if ((ctxt->value == NULL) ||
8668 ((ctxt->value->type != XPATH_NODESET) &&
8669 (ctxt->value->type != XPATH_XSLT_TREE)))
8670 XP_ERROR(XPATH_INVALID_TYPE);
8671 cur = valuePop(ctxt);
8672
8673 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8674 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8675 } else {
8676 int i = 0; /* Should be first in document order !!!!! */
8677 switch (cur->nodesetval->nodeTab[i]->type) {
8678 case XML_ELEMENT_NODE:
8679 case XML_ATTRIBUTE_NODE:
8680 if (cur->nodesetval->nodeTab[i]->ns == NULL)
8681 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8682 else
8683 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8684 cur->nodesetval->nodeTab[i]->ns->href));
8685 break;
8686 default:
8687 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8688 }
8689 }
8690 xmlXPathReleaseObject(ctxt->context, cur);
8691}
8692
8693/**
8694 * xmlXPathNameFunction:
8695 * @ctxt: the XPath Parser context
8696 * @nargs: the number of arguments
8697 *
8698 * Implement the name() XPath function
8699 * string name(node-set?)
8700 * The name function returns a string containing a QName representing
8701 * the name of the node in the argument node-set that is first in document
8702 * order. The QName must represent the name with respect to the namespace
8703 * declarations in effect on the node whose name is being represented.
8704 * Typically, this will be the form in which the name occurred in the XML
8705 * source. This need not be the case if there are namespace declarations
8706 * in effect on the node that associate multiple prefixes with the same
8707 * namespace. However, an implementation may include information about
8708 * the original prefix in its representation of nodes; in this case, an
8709 * implementation can ensure that the returned string is always the same
8710 * as the QName used in the XML source. If the argument it omitted it
8711 * defaults to the context node.
8712 * Libxml keep the original prefix so the "real qualified name" used is
8713 * returned.
8714 */
8715static void
8716xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8717{
8718 xmlXPathObjectPtr cur;
8719
8720 if (nargs == 0) {
8721 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8722 ctxt->context->node));
8723 nargs = 1;
8724 }
8725
8726 CHECK_ARITY(1);
8727 if ((ctxt->value == NULL) ||
8728 ((ctxt->value->type != XPATH_NODESET) &&
8729 (ctxt->value->type != XPATH_XSLT_TREE)))
8730 XP_ERROR(XPATH_INVALID_TYPE);
8731 cur = valuePop(ctxt);
8732
8733 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8734 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8735 } else {
8736 int i = 0; /* Should be first in document order !!!!! */
8737
8738 switch (cur->nodesetval->nodeTab[i]->type) {
8739 case XML_ELEMENT_NODE:
8740 case XML_ATTRIBUTE_NODE:
8741 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8742 valuePush(ctxt,
8743 xmlXPathCacheNewCString(ctxt->context, ""));
8744 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8745 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8746 valuePush(ctxt,
8747 xmlXPathCacheNewString(ctxt->context,
8748 cur->nodesetval->nodeTab[i]->name));
8749 } else {
8750 xmlChar *fullname;
8751
8752 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8753 cur->nodesetval->nodeTab[i]->ns->prefix,
8754 NULL, 0);
8755 if (fullname == cur->nodesetval->nodeTab[i]->name)
8756 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8757 if (fullname == NULL) {
8758 XP_ERROR(XPATH_MEMORY_ERROR);
8759 }
8760 valuePush(ctxt, xmlXPathCacheWrapString(
8761 ctxt->context, fullname));
8762 }
8763 break;
8764 default:
8765 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8766 cur->nodesetval->nodeTab[i]));
8767 xmlXPathLocalNameFunction(ctxt, 1);
8768 }
8769 }
8770 xmlXPathReleaseObject(ctxt->context, cur);
8771}
8772
8773
8774/**
8775 * xmlXPathStringFunction:
8776 * @ctxt: the XPath Parser context
8777 * @nargs: the number of arguments
8778 *
8779 * Implement the string() XPath function
8780 * string string(object?)
8781 * The string function converts an object to a string as follows:
8782 * - A node-set is converted to a string by returning the value of
8783 * the node in the node-set that is first in document order.
8784 * If the node-set is empty, an empty string is returned.
8785 * - A number is converted to a string as follows
8786 * + NaN is converted to the string NaN
8787 * + positive zero is converted to the string 0
8788 * + negative zero is converted to the string 0
8789 * + positive infinity is converted to the string Infinity
8790 * + negative infinity is converted to the string -Infinity
8791 * + if the number is an integer, the number is represented in
8792 * decimal form as a Number with no decimal point and no leading
8793 * zeros, preceded by a minus sign (-) if the number is negative
8794 * + otherwise, the number is represented in decimal form as a
8795 * Number including a decimal point with at least one digit
8796 * before the decimal point and at least one digit after the
8797 * decimal point, preceded by a minus sign (-) if the number
8798 * is negative; there must be no leading zeros before the decimal
8799 * point apart possibly from the one required digit immediately
8800 * before the decimal point; beyond the one required digit
8801 * after the decimal point there must be as many, but only as
8802 * many, more digits as are needed to uniquely distinguish the
8803 * number from all other IEEE 754 numeric values.
8804 * - The boolean false value is converted to the string false.
8805 * The boolean true value is converted to the string true.
8806 *
8807 * If the argument is omitted, it defaults to a node-set with the
8808 * context node as its only member.
8809 */
8810void
8811xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8812 xmlXPathObjectPtr cur;
8813
8814 if (ctxt == NULL) return;
8815 if (nargs == 0) {
8816 valuePush(ctxt,
8817 xmlXPathCacheWrapString(ctxt->context,
8818 xmlXPathCastNodeToString(ctxt->context->node)));
8819 return;
8820 }
8821
8822 CHECK_ARITY(1);
8823 cur = valuePop(ctxt);
8824 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8825 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8826}
8827
8828/**
8829 * xmlXPathStringLengthFunction:
8830 * @ctxt: the XPath Parser context
8831 * @nargs: the number of arguments
8832 *
8833 * Implement the string-length() XPath function
8834 * number string-length(string?)
8835 * The string-length returns the number of characters in the string
8836 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8837 * the context node converted to a string, in other words the value
8838 * of the context node.
8839 */
8840void
8841xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8842 xmlXPathObjectPtr cur;
8843
8844 if (nargs == 0) {
8845 if ((ctxt == NULL) || (ctxt->context == NULL))
8846 return;
8847 if (ctxt->context->node == NULL) {
8848 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8849 } else {
8850 xmlChar *content;
8851
8852 content = xmlXPathCastNodeToString(ctxt->context->node);
8853 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8854 xmlUTF8Strlen(content)));
8855 xmlFree(content);
8856 }
8857 return;
8858 }
8859 CHECK_ARITY(1);
8860 CAST_TO_STRING;
8861 CHECK_TYPE(XPATH_STRING);
8862 cur = valuePop(ctxt);
8863 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8864 xmlUTF8Strlen(cur->stringval)));
8865 xmlXPathReleaseObject(ctxt->context, cur);
8866}
8867
8868/**
8869 * xmlXPathConcatFunction:
8870 * @ctxt: the XPath Parser context
8871 * @nargs: the number of arguments
8872 *
8873 * Implement the concat() XPath function
8874 * string concat(string, string, string*)
8875 * The concat function returns the concatenation of its arguments.
8876 */
8877void
8878xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8879 xmlXPathObjectPtr cur, newobj;
8880 xmlChar *tmp;
8881
8882 if (ctxt == NULL) return;
8883 if (nargs < 2) {
8884 CHECK_ARITY(2);
8885 }
8886
8887 CAST_TO_STRING;
8888 cur = valuePop(ctxt);
8889 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8890 xmlXPathReleaseObject(ctxt->context, cur);
8891 return;
8892 }
8893 nargs--;
8894
8895 while (nargs > 0) {
8896 CAST_TO_STRING;
8897 newobj = valuePop(ctxt);
8898 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8899 xmlXPathReleaseObject(ctxt->context, newobj);
8900 xmlXPathReleaseObject(ctxt->context, cur);
8901 XP_ERROR(XPATH_INVALID_TYPE);
8902 }
8903 tmp = xmlStrcat(newobj->stringval, cur->stringval);
8904 newobj->stringval = cur->stringval;
8905 cur->stringval = tmp;
8906 xmlXPathReleaseObject(ctxt->context, newobj);
8907 nargs--;
8908 }
8909 valuePush(ctxt, cur);
8910}
8911
8912/**
8913 * xmlXPathContainsFunction:
8914 * @ctxt: the XPath Parser context
8915 * @nargs: the number of arguments
8916 *
8917 * Implement the contains() XPath function
8918 * boolean contains(string, string)
8919 * The contains function returns true if the first argument string
8920 * contains the second argument string, and otherwise returns false.
8921 */
8922void
8923xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8924 xmlXPathObjectPtr hay, needle;
8925
8926 CHECK_ARITY(2);
8927 CAST_TO_STRING;
8928 CHECK_TYPE(XPATH_STRING);
8929 needle = valuePop(ctxt);
8930 CAST_TO_STRING;
8931 hay = valuePop(ctxt);
8932
8933 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8934 xmlXPathReleaseObject(ctxt->context, hay);
8935 xmlXPathReleaseObject(ctxt->context, needle);
8936 XP_ERROR(XPATH_INVALID_TYPE);
8937 }
8938 if (xmlStrstr(hay->stringval, needle->stringval))
8939 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8940 else
8941 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8942 xmlXPathReleaseObject(ctxt->context, hay);
8943 xmlXPathReleaseObject(ctxt->context, needle);
8944}
8945
8946/**
8947 * xmlXPathStartsWithFunction:
8948 * @ctxt: the XPath Parser context
8949 * @nargs: the number of arguments
8950 *
8951 * Implement the starts-with() XPath function
8952 * boolean starts-with(string, string)
8953 * The starts-with function returns true if the first argument string
8954 * starts with the second argument string, and otherwise returns false.
8955 */
8956void
8957xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8958 xmlXPathObjectPtr hay, needle;
8959 int n;
8960
8961 CHECK_ARITY(2);
8962 CAST_TO_STRING;
8963 CHECK_TYPE(XPATH_STRING);
8964 needle = valuePop(ctxt);
8965 CAST_TO_STRING;
8966 hay = valuePop(ctxt);
8967
8968 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8969 xmlXPathReleaseObject(ctxt->context, hay);
8970 xmlXPathReleaseObject(ctxt->context, needle);
8971 XP_ERROR(XPATH_INVALID_TYPE);
8972 }
8973 n = xmlStrlen(needle->stringval);
8974 if (xmlStrncmp(hay->stringval, needle->stringval, n))
8975 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8976 else
8977 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8978 xmlXPathReleaseObject(ctxt->context, hay);
8979 xmlXPathReleaseObject(ctxt->context, needle);
8980}
8981
8982/**
8983 * xmlXPathSubstringFunction:
8984 * @ctxt: the XPath Parser context
8985 * @nargs: the number of arguments
8986 *
8987 * Implement the substring() XPath function
8988 * string substring(string, number, number?)
8989 * The substring function returns the substring of the first argument
8990 * starting at the position specified in the second argument with
8991 * length specified in the third argument. For example,
8992 * substring("12345",2,3) returns "234". If the third argument is not
8993 * specified, it returns the substring starting at the position specified
8994 * in the second argument and continuing to the end of the string. For
8995 * example, substring("12345",2) returns "2345". More precisely, each
8996 * character in the string (see [3.6 Strings]) is considered to have a
8997 * numeric position: the position of the first character is 1, the position
8998 * of the second character is 2 and so on. The returned substring contains
8999 * those characters for which the position of the character is greater than
9000 * or equal to the second argument and, if the third argument is specified,
9001 * less than the sum of the second and third arguments; the comparisons
9002 * and addition used for the above follow the standard IEEE 754 rules. Thus:
9003 * - substring("12345", 1.5, 2.6) returns "234"
9004 * - substring("12345", 0, 3) returns "12"
9005 * - substring("12345", 0 div 0, 3) returns ""
9006 * - substring("12345", 1, 0 div 0) returns ""
9007 * - substring("12345", -42, 1 div 0) returns "12345"
9008 * - substring("12345", -1 div 0, 1 div 0) returns ""
9009 */
9010void
9011xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9012 xmlXPathObjectPtr str, start, len;
9013 double le=0, in;
9014 int i, l, m;
9015 xmlChar *ret;
9016
9017 if (nargs < 2) {
9018 CHECK_ARITY(2);
9019 }
9020 if (nargs > 3) {
9021 CHECK_ARITY(3);
9022 }
9023 /*
9024 * take care of possible last (position) argument
9025 */
9026 if (nargs == 3) {
9027 CAST_TO_NUMBER;
9028 CHECK_TYPE(XPATH_NUMBER);
9029 len = valuePop(ctxt);
9030 le = len->floatval;
9031 xmlXPathReleaseObject(ctxt->context, len);
9032 }
9033
9034 CAST_TO_NUMBER;
9035 CHECK_TYPE(XPATH_NUMBER);
9036 start = valuePop(ctxt);
9037 in = start->floatval;
9038 xmlXPathReleaseObject(ctxt->context, start);
9039 CAST_TO_STRING;
9040 CHECK_TYPE(XPATH_STRING);
9041 str = valuePop(ctxt);
9042 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
9043
9044 /*
9045 * If last pos not present, calculate last position
9046 */
9047 if (nargs != 3) {
9048 le = (double)m;
9049 if (in < 1.0)
9050 in = 1.0;
9051 }
9052
9053 /* Need to check for the special cases where either
9054 * the index is NaN, the length is NaN, or both
9055 * arguments are infinity (relying on Inf + -Inf = NaN)
9056 */
9057 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
9058 /*
9059 * To meet the requirements of the spec, the arguments
9060 * must be converted to integer format before
9061 * initial index calculations are done
9062 *
9063 * First we go to integer form, rounding up
9064 * and checking for special cases
9065 */
9066 i = (int) in;
9067 if (((double)i)+0.5 <= in) i++;
9068
9069 if (xmlXPathIsInf(le) == 1) {
9070 l = m;
9071 if (i < 1)
9072 i = 1;
9073 }
9074 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9075 l = 0;
9076 else {
9077 l = (int) le;
9078 if (((double)l)+0.5 <= le) l++;
9079 }
9080
9081 /* Now we normalize inidices */
9082 i -= 1;
9083 l += i;
9084 if (i < 0)
9085 i = 0;
9086 if (l > m)
9087 l = m;
9088
9089 /* number of chars to copy */
9090 l -= i;
9091
9092 ret = xmlUTF8Strsub(str->stringval, i, l);
9093 }
9094 else {
9095 ret = NULL;
9096 }
9097 if (ret == NULL)
9098 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9099 else {
9100 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9101 xmlFree(ret);
9102 }
9103 xmlXPathReleaseObject(ctxt->context, str);
9104}
9105
9106/**
9107 * xmlXPathSubstringBeforeFunction:
9108 * @ctxt: the XPath Parser context
9109 * @nargs: the number of arguments
9110 *
9111 * Implement the substring-before() XPath function
9112 * string substring-before(string, string)
9113 * The substring-before function returns the substring of the first
9114 * argument string that precedes the first occurrence of the second
9115 * argument string in the first argument string, or the empty string
9116 * if the first argument string does not contain the second argument
9117 * string. For example, substring-before("1999/04/01","/") returns 1999.
9118 */
9119void
9120xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9121 xmlXPathObjectPtr str;
9122 xmlXPathObjectPtr find;
9123 xmlBufferPtr target;
9124 const xmlChar *point;
9125 int offset;
9126
9127 CHECK_ARITY(2);
9128 CAST_TO_STRING;
9129 find = valuePop(ctxt);
9130 CAST_TO_STRING;
9131 str = valuePop(ctxt);
9132
9133 target = xmlBufferCreate();
9134 if (target) {
9135 point = xmlStrstr(str->stringval, find->stringval);
9136 if (point) {
9137 offset = (int)(point - str->stringval);
9138 xmlBufferAdd(target, 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 * xmlXPathSubstringAfterFunction:
9150 * @ctxt: the XPath Parser context
9151 * @nargs: the number of arguments
9152 *
9153 * Implement the substring-after() XPath function
9154 * string substring-after(string, string)
9155 * The substring-after function returns the substring of the first
9156 * argument string that follows the first occurrence of the second
9157 * argument string in the first argument string, or the empty stringi
9158 * if the first argument string does not contain the second argument
9159 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9160 * and substring-after("1999/04/01","19") returns 99/04/01.
9161 */
9162void
9163xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9164 xmlXPathObjectPtr str;
9165 xmlXPathObjectPtr find;
9166 xmlBufferPtr target;
9167 const xmlChar *point;
9168 int offset;
9169
9170 CHECK_ARITY(2);
9171 CAST_TO_STRING;
9172 find = valuePop(ctxt);
9173 CAST_TO_STRING;
9174 str = valuePop(ctxt);
9175
9176 target = xmlBufferCreate();
9177 if (target) {
9178 point = xmlStrstr(str->stringval, find->stringval);
9179 if (point) {
9180 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9181 xmlBufferAdd(target, &str->stringval[offset],
9182 xmlStrlen(str->stringval) - offset);
9183 }
9184 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9185 xmlBufferContent(target)));
9186 xmlBufferFree(target);
9187 }
9188 xmlXPathReleaseObject(ctxt->context, str);
9189 xmlXPathReleaseObject(ctxt->context, find);
9190}
9191
9192/**
9193 * xmlXPathNormalizeFunction:
9194 * @ctxt: the XPath Parser context
9195 * @nargs: the number of arguments
9196 *
9197 * Implement the normalize-space() XPath function
9198 * string normalize-space(string?)
9199 * The normalize-space function returns the argument string with white
9200 * space normalized by stripping leading and trailing whitespace
9201 * and replacing sequences of whitespace characters by a single
9202 * space. Whitespace characters are the same allowed by the S production
9203 * in XML. If the argument is omitted, it defaults to the context
9204 * node converted to a string, in other words the value of the context node.
9205 */
9206void
9207xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9208 xmlXPathObjectPtr obj = NULL;
9209 xmlChar *source = NULL;
9210 xmlBufferPtr target;
9211 xmlChar blank;
9212
9213 if (ctxt == NULL) return;
9214 if (nargs == 0) {
9215 /* Use current context node */
9216 valuePush(ctxt,
9217 xmlXPathCacheWrapString(ctxt->context,
9218 xmlXPathCastNodeToString(ctxt->context->node)));
9219 nargs = 1;
9220 }
9221
9222 CHECK_ARITY(1);
9223 CAST_TO_STRING;
9224 CHECK_TYPE(XPATH_STRING);
9225 obj = valuePop(ctxt);
9226 source = obj->stringval;
9227
9228 target = xmlBufferCreate();
9229 if (target && source) {
9230
9231 /* Skip leading whitespaces */
9232 while (IS_BLANK_CH(*source))
9233 source++;
9234
9235 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9236 blank = 0;
9237 while (*source) {
9238 if (IS_BLANK_CH(*source)) {
9239 blank = 0x20;
9240 } else {
9241 if (blank) {
9242 xmlBufferAdd(target, &blank, 1);
9243 blank = 0;
9244 }
9245 xmlBufferAdd(target, source, 1);
9246 }
9247 source++;
9248 }
9249 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9250 xmlBufferContent(target)));
9251 xmlBufferFree(target);
9252 }
9253 xmlXPathReleaseObject(ctxt->context, obj);
9254}
9255
9256/**
9257 * xmlXPathTranslateFunction:
9258 * @ctxt: the XPath Parser context
9259 * @nargs: the number of arguments
9260 *
9261 * Implement the translate() XPath function
9262 * string translate(string, string, string)
9263 * The translate function returns the first argument string with
9264 * occurrences of characters in the second argument string replaced
9265 * by the character at the corresponding position in the third argument
9266 * string. For example, translate("bar","abc","ABC") returns the string
9267 * BAr. If there is a character in the second argument string with no
9268 * character at a corresponding position in the third argument string
9269 * (because the second argument string is longer than the third argument
9270 * string), then occurrences of that character in the first argument
9271 * string are removed. For example, translate("--aaa--","abc-","ABC")
9272 * returns "AAA". If a character occurs more than once in second
9273 * argument string, then the first occurrence determines the replacement
9274 * character. If the third argument string is longer than the second
9275 * argument string, then excess characters are ignored.
9276 */
9277void
9278xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9279 xmlXPathObjectPtr str;
9280 xmlXPathObjectPtr from;
9281 xmlXPathObjectPtr to;
9282 xmlBufferPtr target;
9283 int offset, max;
9284 xmlChar ch;
9285 const xmlChar *point;
9286 xmlChar *cptr;
9287
9288 CHECK_ARITY(3);
9289
9290 CAST_TO_STRING;
9291 to = valuePop(ctxt);
9292 CAST_TO_STRING;
9293 from = valuePop(ctxt);
9294 CAST_TO_STRING;
9295 str = valuePop(ctxt);
9296
9297 target = xmlBufferCreate();
9298 if (target) {
9299 max = xmlUTF8Strlen(to->stringval);
9300 for (cptr = str->stringval; (ch=*cptr); ) {
9301 offset = xmlUTF8Strloc(from->stringval, cptr);
9302 if (offset >= 0) {
9303 if (offset < max) {
9304 point = xmlUTF8Strpos(to->stringval, offset);
9305 if (point)
9306 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
9307 }
9308 } else
9309 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9310
9311 /* Step to next character in input */
9312 cptr++;
9313 if ( ch & 0x80 ) {
9314 /* if not simple ascii, verify proper format */
9315 if ( (ch & 0xc0) != 0xc0 ) {
9316 xmlGenericError(xmlGenericErrorContext,
9317 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9318 /* not asserting an XPath error is probably better */
9319 break;
9320 }
9321 /* then skip over remaining bytes for this char */
9322 while ( (ch <<= 1) & 0x80 )
9323 if ( (*cptr++ & 0xc0) != 0x80 ) {
9324 xmlGenericError(xmlGenericErrorContext,
9325 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9326 /* not asserting an XPath error is probably better */
9327 break;
9328 }
9329 if (ch & 0x80) /* must have had error encountered */
9330 break;
9331 }
9332 }
9333 }
9334 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9335 xmlBufferContent(target)));
9336 xmlBufferFree(target);
9337 xmlXPathReleaseObject(ctxt->context, str);
9338 xmlXPathReleaseObject(ctxt->context, from);
9339 xmlXPathReleaseObject(ctxt->context, to);
9340}
9341
9342/**
9343 * xmlXPathBooleanFunction:
9344 * @ctxt: the XPath Parser context
9345 * @nargs: the number of arguments
9346 *
9347 * Implement the boolean() XPath function
9348 * boolean boolean(object)
9349 * The boolean function converts its argument to a boolean as follows:
9350 * - a number is true if and only if it is neither positive or
9351 * negative zero nor NaN
9352 * - a node-set is true if and only if it is non-empty
9353 * - a string is true if and only if its length is non-zero
9354 */
9355void
9356xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9357 xmlXPathObjectPtr cur;
9358
9359 CHECK_ARITY(1);
9360 cur = valuePop(ctxt);
9361 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9362 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9363 valuePush(ctxt, cur);
9364}
9365
9366/**
9367 * xmlXPathNotFunction:
9368 * @ctxt: the XPath Parser context
9369 * @nargs: the number of arguments
9370 *
9371 * Implement the not() XPath function
9372 * boolean not(boolean)
9373 * The not function returns true if its argument is false,
9374 * and false otherwise.
9375 */
9376void
9377xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9378 CHECK_ARITY(1);
9379 CAST_TO_BOOLEAN;
9380 CHECK_TYPE(XPATH_BOOLEAN);
9381 ctxt->value->boolval = ! ctxt->value->boolval;
9382}
9383
9384/**
9385 * xmlXPathTrueFunction:
9386 * @ctxt: the XPath Parser context
9387 * @nargs: the number of arguments
9388 *
9389 * Implement the true() XPath function
9390 * boolean true()
9391 */
9392void
9393xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9394 CHECK_ARITY(0);
9395 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9396}
9397
9398/**
9399 * xmlXPathFalseFunction:
9400 * @ctxt: the XPath Parser context
9401 * @nargs: the number of arguments
9402 *
9403 * Implement the false() XPath function
9404 * boolean false()
9405 */
9406void
9407xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9408 CHECK_ARITY(0);
9409 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9410}
9411
9412/**
9413 * xmlXPathLangFunction:
9414 * @ctxt: the XPath Parser context
9415 * @nargs: the number of arguments
9416 *
9417 * Implement the lang() XPath function
9418 * boolean lang(string)
9419 * The lang function returns true or false depending on whether the
9420 * language of the context node as specified by xml:lang attributes
9421 * is the same as or is a sublanguage of the language specified by
9422 * the argument string. The language of the context node is determined
9423 * by the value of the xml:lang attribute on the context node, or, if
9424 * the context node has no xml:lang attribute, by the value of the
9425 * xml:lang attribute on the nearest ancestor of the context node that
9426 * has an xml:lang attribute. If there is no such attribute, then lang
9427 * returns false. If there is such an attribute, then lang returns
9428 * true if the attribute value is equal to the argument ignoring case,
9429 * or if there is some suffix starting with - such that the attribute
9430 * value is equal to the argument ignoring that suffix of the attribute
9431 * value and ignoring case.
9432 */
9433void
9434xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9435 xmlXPathObjectPtr val = NULL;
9436 const xmlChar *theLang = NULL;
9437 const xmlChar *lang;
9438 int ret = 0;
9439 int i;
9440
9441 CHECK_ARITY(1);
9442 CAST_TO_STRING;
9443 CHECK_TYPE(XPATH_STRING);
9444 val = valuePop(ctxt);
9445 lang = val->stringval;
9446 theLang = xmlNodeGetLang(ctxt->context->node);
9447 if ((theLang != NULL) && (lang != NULL)) {
9448 for (i = 0;lang[i] != 0;i++)
9449 if (toupper(lang[i]) != toupper(theLang[i]))
9450 goto not_equal;
9451 if ((theLang[i] == 0) || (theLang[i] == '-'))
9452 ret = 1;
9453 }
9454not_equal:
9455 if (theLang != NULL)
9456 xmlFree((void *)theLang);
9457
9458 xmlXPathReleaseObject(ctxt->context, val);
9459 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9460}
9461
9462/**
9463 * xmlXPathNumberFunction:
9464 * @ctxt: the XPath Parser context
9465 * @nargs: the number of arguments
9466 *
9467 * Implement the number() XPath function
9468 * number number(object?)
9469 */
9470void
9471xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9472 xmlXPathObjectPtr cur;
9473 double res;
9474
9475 if (ctxt == NULL) return;
9476 if (nargs == 0) {
9477 if (ctxt->context->node == NULL) {
9478 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9479 } else {
9480 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9481
9482 res = xmlXPathStringEvalNumber(content);
9483 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9484 xmlFree(content);
9485 }
9486 return;
9487 }
9488
9489 CHECK_ARITY(1);
9490 cur = valuePop(ctxt);
9491 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9492}
9493
9494/**
9495 * xmlXPathSumFunction:
9496 * @ctxt: the XPath Parser context
9497 * @nargs: the number of arguments
9498 *
9499 * Implement the sum() XPath function
9500 * number sum(node-set)
9501 * The sum function returns the sum of the values of the nodes in
9502 * the argument node-set.
9503 */
9504void
9505xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9506 xmlXPathObjectPtr cur;
9507 int i;
9508 double res = 0.0;
9509
9510 CHECK_ARITY(1);
9511 if ((ctxt->value == NULL) ||
9512 ((ctxt->value->type != XPATH_NODESET) &&
9513 (ctxt->value->type != XPATH_XSLT_TREE)))
9514 XP_ERROR(XPATH_INVALID_TYPE);
9515 cur = valuePop(ctxt);
9516
9517 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9518 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9519 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9520 }
9521 }
9522 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9523 xmlXPathReleaseObject(ctxt->context, cur);
9524}
9525
9526/*
9527 * To assure working code on multiple platforms, we want to only depend
9528 * upon the characteristic truncation of converting a floating point value
9529 * to an integer. Unfortunately, because of the different storage sizes
9530 * of our internal floating point value (double) and integer (int), we
9531 * can't directly convert (see bug 301162). This macro is a messy
9532 * 'workaround'
9533 */
9534#define XTRUNC(f, v) \
9535 f = fmod((v), INT_MAX); \
9536 f = (v) - (f) + (double)((int)(f));
9537
9538/**
9539 * xmlXPathFloorFunction:
9540 * @ctxt: the XPath Parser context
9541 * @nargs: the number of arguments
9542 *
9543 * Implement the floor() XPath function
9544 * number floor(number)
9545 * The floor function returns the largest (closest to positive infinity)
9546 * number that is not greater than the argument and that is an integer.
9547 */
9548void
9549xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9550 double f;
9551
9552 CHECK_ARITY(1);
9553 CAST_TO_NUMBER;
9554 CHECK_TYPE(XPATH_NUMBER);
9555
9556 XTRUNC(f, ctxt->value->floatval);
9557 if (f != ctxt->value->floatval) {
9558 if (ctxt->value->floatval > 0)
9559 ctxt->value->floatval = f;
9560 else
9561 ctxt->value->floatval = f - 1;
9562 }
9563}
9564
9565/**
9566 * xmlXPathCeilingFunction:
9567 * @ctxt: the XPath Parser context
9568 * @nargs: the number of arguments
9569 *
9570 * Implement the ceiling() XPath function
9571 * number ceiling(number)
9572 * The ceiling function returns the smallest (closest to negative infinity)
9573 * number that is not less than the argument and that is an integer.
9574 */
9575void
9576xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9577 double f;
9578
9579 CHECK_ARITY(1);
9580 CAST_TO_NUMBER;
9581 CHECK_TYPE(XPATH_NUMBER);
9582
9583#if 0
9584 ctxt->value->floatval = ceil(ctxt->value->floatval);
9585#else
9586 XTRUNC(f, ctxt->value->floatval);
9587 if (f != ctxt->value->floatval) {
9588 if (ctxt->value->floatval > 0)
9589 ctxt->value->floatval = f + 1;
9590 else {
9591 if (ctxt->value->floatval < 0 && f == 0)
9592 ctxt->value->floatval = xmlXPathNZERO;
9593 else
9594 ctxt->value->floatval = f;
9595 }
9596
9597 }
9598#endif
9599}
9600
9601/**
9602 * xmlXPathRoundFunction:
9603 * @ctxt: the XPath Parser context
9604 * @nargs: the number of arguments
9605 *
9606 * Implement the round() XPath function
9607 * number round(number)
9608 * The round function returns the number that is closest to the
9609 * argument and that is an integer. If there are two such numbers,
9610 * then the one that is even is returned.
9611 */
9612void
9613xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9614 double f;
9615
9616 CHECK_ARITY(1);
9617 CAST_TO_NUMBER;
9618 CHECK_TYPE(XPATH_NUMBER);
9619
9620 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9621 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9622 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
9623 (ctxt->value->floatval == 0.0))
9624 return;
9625
9626 XTRUNC(f, ctxt->value->floatval);
9627 if (ctxt->value->floatval < 0) {
9628 if (ctxt->value->floatval < f - 0.5)
9629 ctxt->value->floatval = f - 1;
9630 else
9631 ctxt->value->floatval = f;
9632 if (ctxt->value->floatval == 0)
9633 ctxt->value->floatval = xmlXPathNZERO;
9634 } else {
9635 if (ctxt->value->floatval < f + 0.5)
9636 ctxt->value->floatval = f;
9637 else
9638 ctxt->value->floatval = f + 1;
9639 }
9640}
9641
9642/************************************************************************
9643 * *
9644 * The Parser *
9645 * *
9646 ************************************************************************/
9647
9648/*
9649 * a few forward declarations since we use a recursive call based
9650 * implementation.
9651 */
9652static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9653static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9654static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9655static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9656static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9657 int qualified);
9658
9659/**
9660 * xmlXPathCurrentChar:
9661 * @ctxt: the XPath parser context
9662 * @cur: pointer to the beginning of the char
9663 * @len: pointer to the length of the char read
9664 *
9665 * The current char value, if using UTF-8 this may actually span multiple
9666 * bytes in the input buffer.
9667 *
9668 * Returns the current char value and its length
9669 */
9670
9671static int
9672xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9673 unsigned char c;
9674 unsigned int val;
9675 const xmlChar *cur;
9676
9677 if (ctxt == NULL)
9678 return(0);
9679 cur = ctxt->cur;
9680
9681 /*
9682 * We are supposed to handle UTF8, check it's valid
9683 * From rfc2044: encoding of the Unicode values on UTF-8:
9684 *
9685 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9686 * 0000 0000-0000 007F 0xxxxxxx
9687 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
9688 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
9689 *
9690 * Check for the 0x110000 limit too
9691 */
9692 c = *cur;
9693 if (c & 0x80) {
9694 if ((cur[1] & 0xc0) != 0x80)
9695 goto encoding_error;
9696 if ((c & 0xe0) == 0xe0) {
9697
9698 if ((cur[2] & 0xc0) != 0x80)
9699 goto encoding_error;
9700 if ((c & 0xf0) == 0xf0) {
9701 if (((c & 0xf8) != 0xf0) ||
9702 ((cur[3] & 0xc0) != 0x80))
9703 goto encoding_error;
9704 /* 4-byte code */
9705 *len = 4;
9706 val = (cur[0] & 0x7) << 18;
9707 val |= (cur[1] & 0x3f) << 12;
9708 val |= (cur[2] & 0x3f) << 6;
9709 val |= cur[3] & 0x3f;
9710 } else {
9711 /* 3-byte code */
9712 *len = 3;
9713 val = (cur[0] & 0xf) << 12;
9714 val |= (cur[1] & 0x3f) << 6;
9715 val |= cur[2] & 0x3f;
9716 }
9717 } else {
9718 /* 2-byte code */
9719 *len = 2;
9720 val = (cur[0] & 0x1f) << 6;
9721 val |= cur[1] & 0x3f;
9722 }
9723 if (!IS_CHAR(val)) {
9724 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9725 }
9726 return(val);
9727 } else {
9728 /* 1-byte code */
9729 *len = 1;
9730 return((int) *cur);
9731 }
9732encoding_error:
9733 /*
9734 * If we detect an UTF8 error that probably means that the
9735 * input encoding didn't get properly advertised in the
9736 * declaration header. Report the error and switch the encoding
9737 * to ISO-Latin-1 (if you don't like this policy, just declare the
9738 * encoding !)
9739 */
9740 *len = 0;
9741 XP_ERROR0(XPATH_ENCODING_ERROR);
9742}
9743
9744/**
9745 * xmlXPathParseNCName:
9746 * @ctxt: the XPath Parser context
9747 *
9748 * parse an XML namespace non qualified name.
9749 *
9750 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9751 *
9752 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9753 * CombiningChar | Extender
9754 *
9755 * Returns the namespace name or NULL
9756 */
9757
9758xmlChar *
9759xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9760 const xmlChar *in;
9761 xmlChar *ret;
9762 int count = 0;
9763
9764 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9765 /*
9766 * Accelerator for simple ASCII names
9767 */
9768 in = ctxt->cur;
9769 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9770 ((*in >= 0x41) && (*in <= 0x5A)) ||
9771 (*in == '_')) {
9772 in++;
9773 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9774 ((*in >= 0x41) && (*in <= 0x5A)) ||
9775 ((*in >= 0x30) && (*in <= 0x39)) ||
9776 (*in == '_') || (*in == '.') ||
9777 (*in == '-'))
9778 in++;
9779 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9780 (*in == '[') || (*in == ']') || (*in == ':') ||
9781 (*in == '@') || (*in == '*')) {
9782 count = in - ctxt->cur;
9783 if (count == 0)
9784 return(NULL);
9785 ret = xmlStrndup(ctxt->cur, count);
9786 ctxt->cur = in;
9787 return(ret);
9788 }
9789 }
9790 return(xmlXPathParseNameComplex(ctxt, 0));
9791}
9792
9793
9794/**
9795 * xmlXPathParseQName:
9796 * @ctxt: the XPath Parser context
9797 * @prefix: a xmlChar **
9798 *
9799 * parse an XML qualified name
9800 *
9801 * [NS 5] QName ::= (Prefix ':')? LocalPart
9802 *
9803 * [NS 6] Prefix ::= NCName
9804 *
9805 * [NS 7] LocalPart ::= NCName
9806 *
9807 * Returns the function returns the local part, and prefix is updated
9808 * to get the Prefix if any.
9809 */
9810
9811static xmlChar *
9812xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9813 xmlChar *ret = NULL;
9814
9815 *prefix = NULL;
9816 ret = xmlXPathParseNCName(ctxt);
9817 if (CUR == ':') {
9818 *prefix = ret;
9819 NEXT;
9820 ret = xmlXPathParseNCName(ctxt);
9821 }
9822 return(ret);
9823}
9824
9825/**
9826 * xmlXPathParseName:
9827 * @ctxt: the XPath Parser context
9828 *
9829 * parse an XML name
9830 *
9831 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9832 * CombiningChar | Extender
9833 *
9834 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9835 *
9836 * Returns the namespace name or NULL
9837 */
9838
9839xmlChar *
9840xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9841 const xmlChar *in;
9842 xmlChar *ret;
9843 int count = 0;
9844
9845 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9846 /*
9847 * Accelerator for simple ASCII names
9848 */
9849 in = ctxt->cur;
9850 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9851 ((*in >= 0x41) && (*in <= 0x5A)) ||
9852 (*in == '_') || (*in == ':')) {
9853 in++;
9854 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9855 ((*in >= 0x41) && (*in <= 0x5A)) ||
9856 ((*in >= 0x30) && (*in <= 0x39)) ||
9857 (*in == '_') || (*in == '-') ||
9858 (*in == ':') || (*in == '.'))
9859 in++;
9860 if ((*in > 0) && (*in < 0x80)) {
9861 count = in - ctxt->cur;
9862 ret = xmlStrndup(ctxt->cur, count);
9863 ctxt->cur = in;
9864 return(ret);
9865 }
9866 }
9867 return(xmlXPathParseNameComplex(ctxt, 1));
9868}
9869
9870static xmlChar *
9871xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9872 xmlChar buf[XML_MAX_NAMELEN + 5];
9873 int len = 0, l;
9874 int c;
9875
9876 /*
9877 * Handler for more complex cases
9878 */
9879 c = CUR_CHAR(l);
9880 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9881 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9882 (c == '*') || /* accelerators */
9883 (!IS_LETTER(c) && (c != '_') &&
9884 ((qualified) && (c != ':')))) {
9885 return(NULL);
9886 }
9887
9888 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9889 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9890 (c == '.') || (c == '-') ||
9891 (c == '_') || ((qualified) && (c == ':')) ||
9892 (IS_COMBINING(c)) ||
9893 (IS_EXTENDER(c)))) {
9894 COPY_BUF(l,buf,len,c);
9895 NEXTL(l);
9896 c = CUR_CHAR(l);
9897 if (len >= XML_MAX_NAMELEN) {
9898 /*
9899 * Okay someone managed to make a huge name, so he's ready to pay
9900 * for the processing speed.
9901 */
9902 xmlChar *buffer;
9903 int max = len * 2;
9904
9905 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
9906 if (buffer == NULL) {
9907 XP_ERRORNULL(XPATH_MEMORY_ERROR);
9908 }
9909 memcpy(buffer, buf, len);
9910 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9911 (c == '.') || (c == '-') ||
9912 (c == '_') || ((qualified) && (c == ':')) ||
9913 (IS_COMBINING(c)) ||
9914 (IS_EXTENDER(c))) {
9915 if (len + 10 > max) {
9916 max *= 2;
9917 buffer = (xmlChar *) xmlRealloc(buffer,
9918 max * sizeof(xmlChar));
9919 if (buffer == NULL) {
9920 XP_ERRORNULL(XPATH_MEMORY_ERROR);
9921 }
9922 }
9923 COPY_BUF(l,buffer,len,c);
9924 NEXTL(l);
9925 c = CUR_CHAR(l);
9926 }
9927 buffer[len] = 0;
9928 return(buffer);
9929 }
9930 }
9931 if (len == 0)
9932 return(NULL);
9933 return(xmlStrndup(buf, len));
9934}
9935
9936#define MAX_FRAC 20
9937
9938/*
9939 * These are used as divisors for the fractional part of a number.
9940 * Since the table includes 1.0 (representing '0' fractional digits),
9941 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
9942 */
9943static double my_pow10[MAX_FRAC+1] = {
9944 1.0, 10.0, 100.0, 1000.0, 10000.0,
9945 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
9946 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
9947 100000000000000.0,
9948 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
9949 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
9950};
9951
9952/**
9953 * xmlXPathStringEvalNumber:
9954 * @str: A string to scan
9955 *
9956 * [30a] Float ::= Number ('e' Digits?)?
9957 *
9958 * [30] Number ::= Digits ('.' Digits?)?
9959 * | '.' Digits
9960 * [31] Digits ::= [0-9]+
9961 *
9962 * Compile a Number in the string
9963 * In complement of the Number expression, this function also handles
9964 * negative values : '-' Number.
9965 *
9966 * Returns the double value.
9967 */
9968double
9969xmlXPathStringEvalNumber(const xmlChar *str) {
9970 const xmlChar *cur = str;
9971 double ret;
9972 int ok = 0;
9973 int isneg = 0;
9974 int exponent = 0;
9975 int is_exponent_negative = 0;
9976#ifdef __GNUC__
9977 unsigned long tmp = 0;
9978 double temp;
9979#endif
9980 if (cur == NULL) return(0);
9981 while (IS_BLANK_CH(*cur)) cur++;
9982 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9983 return(xmlXPathNAN);
9984 }
9985 if (*cur == '-') {
9986 isneg = 1;
9987 cur++;
9988 }
9989
9990#ifdef __GNUC__
9991 /*
9992 * tmp/temp is a workaround against a gcc compiler bug
9993 * http://veillard.com/gcc.bug
9994 */
9995 ret = 0;
9996 while ((*cur >= '0') && (*cur <= '9')) {
9997 ret = ret * 10;
9998 tmp = (*cur - '0');
9999 ok = 1;
10000 cur++;
10001 temp = (double) tmp;
10002 ret = ret + temp;
10003 }
10004#else
10005 ret = 0;
10006 while ((*cur >= '0') && (*cur <= '9')) {
10007 ret = ret * 10 + (*cur - '0');
10008 ok = 1;
10009 cur++;
10010 }
10011#endif
10012
10013 if (*cur == '.') {
10014 int v, frac = 0;
10015 double fraction = 0;
10016
10017 cur++;
10018 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10019 return(xmlXPathNAN);
10020 }
10021 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
10022 v = (*cur - '0');
10023 fraction = fraction * 10 + v;
10024 frac = frac + 1;
10025 cur++;
10026 }
10027 fraction /= my_pow10[frac];
10028 ret = ret + fraction;
10029 while ((*cur >= '0') && (*cur <= '9'))
10030 cur++;
10031 }
10032 if ((*cur == 'e') || (*cur == 'E')) {
10033 cur++;
10034 if (*cur == '-') {
10035 is_exponent_negative = 1;
10036 cur++;
10037 } else if (*cur == '+') {
10038 cur++;
10039 }
10040 while ((*cur >= '0') && (*cur <= '9')) {
10041 exponent = exponent * 10 + (*cur - '0');
10042 cur++;
10043 }
10044 }
10045 while (IS_BLANK_CH(*cur)) cur++;
10046 if (*cur != 0) return(xmlXPathNAN);
10047 if (isneg) ret = -ret;
10048 if (is_exponent_negative) exponent = -exponent;
10049 ret *= pow(10.0, (double)exponent);
10050 return(ret);
10051}
10052
10053/**
10054 * xmlXPathCompNumber:
10055 * @ctxt: the XPath Parser context
10056 *
10057 * [30] Number ::= Digits ('.' Digits?)?
10058 * | '.' Digits
10059 * [31] Digits ::= [0-9]+
10060 *
10061 * Compile a Number, then push it on the stack
10062 *
10063 */
10064static void
10065xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10066{
10067 double ret = 0.0;
10068 double mult = 1;
10069 int ok = 0;
10070 int exponent = 0;
10071 int is_exponent_negative = 0;
10072#ifdef __GNUC__
10073 unsigned long tmp = 0;
10074 double temp;
10075#endif
10076
10077 CHECK_ERROR;
10078 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10079 XP_ERROR(XPATH_NUMBER_ERROR);
10080 }
10081#ifdef __GNUC__
10082 /*
10083 * tmp/temp is a workaround against a gcc compiler bug
10084 * http://veillard.com/gcc.bug
10085 */
10086 ret = 0;
10087 while ((CUR >= '0') && (CUR <= '9')) {
10088 ret = ret * 10;
10089 tmp = (CUR - '0');
10090 ok = 1;
10091 NEXT;
10092 temp = (double) tmp;
10093 ret = ret + temp;
10094 }
10095#else
10096 ret = 0;
10097 while ((CUR >= '0') && (CUR <= '9')) {
10098 ret = ret * 10 + (CUR - '0');
10099 ok = 1;
10100 NEXT;
10101 }
10102#endif
10103 if (CUR == '.') {
10104 NEXT;
10105 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10106 XP_ERROR(XPATH_NUMBER_ERROR);
10107 }
10108 while ((CUR >= '0') && (CUR <= '9')) {
10109 mult /= 10;
10110 ret = ret + (CUR - '0') * mult;
10111 NEXT;
10112 }
10113 }
10114 if ((CUR == 'e') || (CUR == 'E')) {
10115 NEXT;
10116 if (CUR == '-') {
10117 is_exponent_negative = 1;
10118 NEXT;
10119 } else if (CUR == '+') {
10120 NEXT;
10121 }
10122 while ((CUR >= '0') && (CUR <= '9')) {
10123 exponent = exponent * 10 + (CUR - '0');
10124 NEXT;
10125 }
10126 if (is_exponent_negative)
10127 exponent = -exponent;
10128 ret *= pow(10.0, (double) exponent);
10129 }
10130 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10131 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10132}
10133
10134/**
10135 * xmlXPathParseLiteral:
10136 * @ctxt: the XPath Parser context
10137 *
10138 * Parse a Literal
10139 *
10140 * [29] Literal ::= '"' [^"]* '"'
10141 * | "'" [^']* "'"
10142 *
10143 * Returns the value found or NULL in case of error
10144 */
10145static xmlChar *
10146xmlXPathParseLiteral(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_ERRORNULL(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_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10168 } else {
10169 ret = xmlStrndup(q, CUR_PTR - q);
10170 NEXT;
10171 }
10172 } else {
10173 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10174 }
10175 return(ret);
10176}
10177
10178/**
10179 * xmlXPathCompLiteral:
10180 * @ctxt: the XPath Parser context
10181 *
10182 * Parse a Literal and push it on the stack.
10183 *
10184 * [29] Literal ::= '"' [^"]* '"'
10185 * | "'" [^']* "'"
10186 *
10187 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10188 */
10189static void
10190xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10191 const xmlChar *q;
10192 xmlChar *ret = NULL;
10193
10194 if (CUR == '"') {
10195 NEXT;
10196 q = CUR_PTR;
10197 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10198 NEXT;
10199 if (!IS_CHAR_CH(CUR)) {
10200 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10201 } else {
10202 ret = xmlStrndup(q, CUR_PTR - q);
10203 NEXT;
10204 }
10205 } else if (CUR == '\'') {
10206 NEXT;
10207 q = CUR_PTR;
10208 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10209 NEXT;
10210 if (!IS_CHAR_CH(CUR)) {
10211 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10212 } else {
10213 ret = xmlStrndup(q, CUR_PTR - q);
10214 NEXT;
10215 }
10216 } else {
10217 XP_ERROR(XPATH_START_LITERAL_ERROR);
10218 }
10219 if (ret == NULL) return;
10220 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10221 xmlXPathCacheNewString(ctxt->context, ret), NULL);
10222 xmlFree(ret);
10223}
10224
10225/**
10226 * xmlXPathCompVariableReference:
10227 * @ctxt: the XPath Parser context
10228 *
10229 * Parse a VariableReference, evaluate it and push it on the stack.
10230 *
10231 * The variable bindings consist of a mapping from variable names
10232 * to variable values. The value of a variable is an object, which can be
10233 * of any of the types that are possible for the value of an expression,
10234 * and may also be of additional types not specified here.
10235 *
10236 * Early evaluation is possible since:
10237 * The variable bindings [...] used to evaluate a subexpression are
10238 * always the same as those used to evaluate the containing expression.
10239 *
10240 * [36] VariableReference ::= '$' QName
10241 */
10242static void
10243xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10244 xmlChar *name;
10245 xmlChar *prefix;
10246
10247 SKIP_BLANKS;
10248 if (CUR != '$') {
10249 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10250 }
10251 NEXT;
10252 name = xmlXPathParseQName(ctxt, &prefix);
10253 if (name == NULL) {
10254 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10255 }
10256 ctxt->comp->last = -1;
10257 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10258 name, prefix);
10259 SKIP_BLANKS;
10260 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10261 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
10262 }
10263}
10264
10265/**
10266 * xmlXPathIsNodeType:
10267 * @name: a name string
10268 *
10269 * Is the name given a NodeType one.
10270 *
10271 * [38] NodeType ::= 'comment'
10272 * | 'text'
10273 * | 'processing-instruction'
10274 * | 'node'
10275 *
10276 * Returns 1 if true 0 otherwise
10277 */
10278int
10279xmlXPathIsNodeType(const xmlChar *name) {
10280 if (name == NULL)
10281 return(0);
10282
10283 if (xmlStrEqual(name, BAD_CAST "node"))
10284 return(1);
10285 if (xmlStrEqual(name, BAD_CAST "text"))
10286 return(1);
10287 if (xmlStrEqual(name, BAD_CAST "comment"))
10288 return(1);
10289 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10290 return(1);
10291 return(0);
10292}
10293
10294/**
10295 * xmlXPathCompFunctionCall:
10296 * @ctxt: the XPath Parser context
10297 *
10298 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10299 * [17] Argument ::= Expr
10300 *
10301 * Compile a function call, the evaluation of all arguments are
10302 * pushed on the stack
10303 */
10304static void
10305xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10306 xmlChar *name;
10307 xmlChar *prefix;
10308 int nbargs = 0;
10309 int sort = 1;
10310
10311 name = xmlXPathParseQName(ctxt, &prefix);
10312 if (name == NULL) {
10313 XP_ERROR(XPATH_EXPR_ERROR);
10314 }
10315 SKIP_BLANKS;
10316#ifdef DEBUG_EXPR
10317 if (prefix == NULL)
10318 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10319 name);
10320 else
10321 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10322 prefix, name);
10323#endif
10324
10325 if (CUR != '(') {
10326 XP_ERROR(XPATH_EXPR_ERROR);
10327 }
10328 NEXT;
10329 SKIP_BLANKS;
10330
10331 /*
10332 * Optimization for count(): we don't need the node-set to be sorted.
10333 */
10334 if ((prefix == NULL) && (name[0] == 'c') &&
10335 xmlStrEqual(name, BAD_CAST "count"))
10336 {
10337 sort = 0;
10338 }
10339 ctxt->comp->last = -1;
10340 if (CUR != ')') {
10341 while (CUR != 0) {
10342 int op1 = ctxt->comp->last;
10343 ctxt->comp->last = -1;
10344 xmlXPathCompileExpr(ctxt, sort);
10345 CHECK_ERROR;
10346 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10347 nbargs++;
10348 if (CUR == ')') break;
10349 if (CUR != ',') {
10350 XP_ERROR(XPATH_EXPR_ERROR);
10351 }
10352 NEXT;
10353 SKIP_BLANKS;
10354 }
10355 }
10356 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10357 name, prefix);
10358 NEXT;
10359 SKIP_BLANKS;
10360}
10361
10362/**
10363 * xmlXPathCompPrimaryExpr:
10364 * @ctxt: the XPath Parser context
10365 *
10366 * [15] PrimaryExpr ::= VariableReference
10367 * | '(' Expr ')'
10368 * | Literal
10369 * | Number
10370 * | FunctionCall
10371 *
10372 * Compile a primary expression.
10373 */
10374static void
10375xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10376 SKIP_BLANKS;
10377 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10378 else if (CUR == '(') {
10379 NEXT;
10380 SKIP_BLANKS;
10381 xmlXPathCompileExpr(ctxt, 1);
10382 CHECK_ERROR;
10383 if (CUR != ')') {
10384 XP_ERROR(XPATH_EXPR_ERROR);
10385 }
10386 NEXT;
10387 SKIP_BLANKS;
10388 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10389 xmlXPathCompNumber(ctxt);
10390 } else if ((CUR == '\'') || (CUR == '"')) {
10391 xmlXPathCompLiteral(ctxt);
10392 } else {
10393 xmlXPathCompFunctionCall(ctxt);
10394 }
10395 SKIP_BLANKS;
10396}
10397
10398/**
10399 * xmlXPathCompFilterExpr:
10400 * @ctxt: the XPath Parser context
10401 *
10402 * [20] FilterExpr ::= PrimaryExpr
10403 * | FilterExpr Predicate
10404 *
10405 * Compile a filter expression.
10406 * Square brackets are used to filter expressions in the same way that
10407 * they are used in location paths. It is an error if the expression to
10408 * be filtered does not evaluate to a node-set. The context node list
10409 * used for evaluating the expression in square brackets is the node-set
10410 * to be filtered listed in document order.
10411 */
10412
10413static void
10414xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10415 xmlXPathCompPrimaryExpr(ctxt);
10416 CHECK_ERROR;
10417 SKIP_BLANKS;
10418
10419 while (CUR == '[') {
10420 xmlXPathCompPredicate(ctxt, 1);
10421 SKIP_BLANKS;
10422 }
10423
10424
10425}
10426
10427/**
10428 * xmlXPathScanName:
10429 * @ctxt: the XPath Parser context
10430 *
10431 * Trickery: parse an XML name but without consuming the input flow
10432 * Needed to avoid insanity in the parser state.
10433 *
10434 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10435 * CombiningChar | Extender
10436 *
10437 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10438 *
10439 * [6] Names ::= Name (S Name)*
10440 *
10441 * Returns the Name parsed or NULL
10442 */
10443
10444static xmlChar *
10445xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10446 int len = 0, l;
10447 int c;
10448 const xmlChar *cur;
10449 xmlChar *ret;
10450
10451 cur = ctxt->cur;
10452
10453 c = CUR_CHAR(l);
10454 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10455 (!IS_LETTER(c) && (c != '_') &&
10456 (c != ':'))) {
10457 return(NULL);
10458 }
10459
10460 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10461 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10462 (c == '.') || (c == '-') ||
10463 (c == '_') || (c == ':') ||
10464 (IS_COMBINING(c)) ||
10465 (IS_EXTENDER(c)))) {
10466 len += l;
10467 NEXTL(l);
10468 c = CUR_CHAR(l);
10469 }
10470 ret = xmlStrndup(cur, ctxt->cur - cur);
10471 ctxt->cur = cur;
10472 return(ret);
10473}
10474
10475/**
10476 * xmlXPathCompPathExpr:
10477 * @ctxt: the XPath Parser context
10478 *
10479 * [19] PathExpr ::= LocationPath
10480 * | FilterExpr
10481 * | FilterExpr '/' RelativeLocationPath
10482 * | FilterExpr '//' RelativeLocationPath
10483 *
10484 * Compile a path expression.
10485 * The / operator and // operators combine an arbitrary expression
10486 * and a relative location path. It is an error if the expression
10487 * does not evaluate to a node-set.
10488 * The / operator does composition in the same way as when / is
10489 * used in a location path. As in location paths, // is short for
10490 * /descendant-or-self::node()/.
10491 */
10492
10493static void
10494xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10495 int lc = 1; /* Should we branch to LocationPath ? */
10496 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10497
10498 SKIP_BLANKS;
10499 if ((CUR == '$') || (CUR == '(') ||
10500 (IS_ASCII_DIGIT(CUR)) ||
10501 (CUR == '\'') || (CUR == '"') ||
10502 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10503 lc = 0;
10504 } else if (CUR == '*') {
10505 /* relative or absolute location path */
10506 lc = 1;
10507 } else if (CUR == '/') {
10508 /* relative or absolute location path */
10509 lc = 1;
10510 } else if (CUR == '@') {
10511 /* relative abbreviated attribute location path */
10512 lc = 1;
10513 } else if (CUR == '.') {
10514 /* relative abbreviated attribute location path */
10515 lc = 1;
10516 } else {
10517 /*
10518 * Problem is finding if we have a name here whether it's:
10519 * - a nodetype
10520 * - a function call in which case it's followed by '('
10521 * - an axis in which case it's followed by ':'
10522 * - a element name
10523 * We do an a priori analysis here rather than having to
10524 * maintain parsed token content through the recursive function
10525 * calls. This looks uglier but makes the code easier to
10526 * read/write/debug.
10527 */
10528 SKIP_BLANKS;
10529 name = xmlXPathScanName(ctxt);
10530 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10531#ifdef DEBUG_STEP
10532 xmlGenericError(xmlGenericErrorContext,
10533 "PathExpr: Axis\n");
10534#endif
10535 lc = 1;
10536 xmlFree(name);
10537 } else if (name != NULL) {
10538 int len =xmlStrlen(name);
10539
10540
10541 while (NXT(len) != 0) {
10542 if (NXT(len) == '/') {
10543 /* element name */
10544#ifdef DEBUG_STEP
10545 xmlGenericError(xmlGenericErrorContext,
10546 "PathExpr: AbbrRelLocation\n");
10547#endif
10548 lc = 1;
10549 break;
10550 } else if (IS_BLANK_CH(NXT(len))) {
10551 /* ignore blanks */
10552 ;
10553 } else if (NXT(len) == ':') {
10554#ifdef DEBUG_STEP
10555 xmlGenericError(xmlGenericErrorContext,
10556 "PathExpr: AbbrRelLocation\n");
10557#endif
10558 lc = 1;
10559 break;
10560 } else if ((NXT(len) == '(')) {
10561 /* Note Type or Function */
10562 if (xmlXPathIsNodeType(name)) {
10563#ifdef DEBUG_STEP
10564 xmlGenericError(xmlGenericErrorContext,
10565 "PathExpr: Type search\n");
10566#endif
10567 lc = 1;
10568 } else {
10569#ifdef DEBUG_STEP
10570 xmlGenericError(xmlGenericErrorContext,
10571 "PathExpr: function call\n");
10572#endif
10573 lc = 0;
10574 }
10575 break;
10576 } else if ((NXT(len) == '[')) {
10577 /* element name */
10578#ifdef DEBUG_STEP
10579 xmlGenericError(xmlGenericErrorContext,
10580 "PathExpr: AbbrRelLocation\n");
10581#endif
10582 lc = 1;
10583 break;
10584 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10585 (NXT(len) == '=')) {
10586 lc = 1;
10587 break;
10588 } else {
10589 lc = 1;
10590 break;
10591 }
10592 len++;
10593 }
10594 if (NXT(len) == 0) {
10595#ifdef DEBUG_STEP
10596 xmlGenericError(xmlGenericErrorContext,
10597 "PathExpr: AbbrRelLocation\n");
10598#endif
10599 /* element name */
10600 lc = 1;
10601 }
10602 xmlFree(name);
10603 } else {
10604 /* make sure all cases are covered explicitly */
10605 XP_ERROR(XPATH_EXPR_ERROR);
10606 }
10607 }
10608
10609 if (lc) {
10610 if (CUR == '/') {
10611 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10612 } else {
10613 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10614 }
10615 xmlXPathCompLocationPath(ctxt);
10616 } else {
10617 xmlXPathCompFilterExpr(ctxt);
10618 CHECK_ERROR;
10619 if ((CUR == '/') && (NXT(1) == '/')) {
10620 SKIP(2);
10621 SKIP_BLANKS;
10622
10623 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10624 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10625 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10626
10627 xmlXPathCompRelativeLocationPath(ctxt);
10628 } else if (CUR == '/') {
10629 xmlXPathCompRelativeLocationPath(ctxt);
10630 }
10631 }
10632 SKIP_BLANKS;
10633}
10634
10635/**
10636 * xmlXPathCompUnionExpr:
10637 * @ctxt: the XPath Parser context
10638 *
10639 * [18] UnionExpr ::= PathExpr
10640 * | UnionExpr '|' PathExpr
10641 *
10642 * Compile an union expression.
10643 */
10644
10645static void
10646xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10647 xmlXPathCompPathExpr(ctxt);
10648 CHECK_ERROR;
10649 SKIP_BLANKS;
10650 while (CUR == '|') {
10651 int op1 = ctxt->comp->last;
10652 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10653
10654 NEXT;
10655 SKIP_BLANKS;
10656 xmlXPathCompPathExpr(ctxt);
10657
10658 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10659
10660 SKIP_BLANKS;
10661 }
10662}
10663
10664/**
10665 * xmlXPathCompUnaryExpr:
10666 * @ctxt: the XPath Parser context
10667 *
10668 * [27] UnaryExpr ::= UnionExpr
10669 * | '-' UnaryExpr
10670 *
10671 * Compile an unary expression.
10672 */
10673
10674static void
10675xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10676 int minus = 0;
10677 int found = 0;
10678
10679 SKIP_BLANKS;
10680 while (CUR == '-') {
10681 minus = 1 - minus;
10682 found = 1;
10683 NEXT;
10684 SKIP_BLANKS;
10685 }
10686
10687 xmlXPathCompUnionExpr(ctxt);
10688 CHECK_ERROR;
10689 if (found) {
10690 if (minus)
10691 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10692 else
10693 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10694 }
10695}
10696
10697/**
10698 * xmlXPathCompMultiplicativeExpr:
10699 * @ctxt: the XPath Parser context
10700 *
10701 * [26] MultiplicativeExpr ::= UnaryExpr
10702 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10703 * | MultiplicativeExpr 'div' UnaryExpr
10704 * | MultiplicativeExpr 'mod' UnaryExpr
10705 * [34] MultiplyOperator ::= '*'
10706 *
10707 * Compile an Additive expression.
10708 */
10709
10710static void
10711xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10712 xmlXPathCompUnaryExpr(ctxt);
10713 CHECK_ERROR;
10714 SKIP_BLANKS;
10715 while ((CUR == '*') ||
10716 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10717 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10718 int op = -1;
10719 int op1 = ctxt->comp->last;
10720
10721 if (CUR == '*') {
10722 op = 0;
10723 NEXT;
10724 } else if (CUR == 'd') {
10725 op = 1;
10726 SKIP(3);
10727 } else if (CUR == 'm') {
10728 op = 2;
10729 SKIP(3);
10730 }
10731 SKIP_BLANKS;
10732 xmlXPathCompUnaryExpr(ctxt);
10733 CHECK_ERROR;
10734 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10735 SKIP_BLANKS;
10736 }
10737}
10738
10739/**
10740 * xmlXPathCompAdditiveExpr:
10741 * @ctxt: the XPath Parser context
10742 *
10743 * [25] AdditiveExpr ::= MultiplicativeExpr
10744 * | AdditiveExpr '+' MultiplicativeExpr
10745 * | AdditiveExpr '-' MultiplicativeExpr
10746 *
10747 * Compile an Additive expression.
10748 */
10749
10750static void
10751xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10752
10753 xmlXPathCompMultiplicativeExpr(ctxt);
10754 CHECK_ERROR;
10755 SKIP_BLANKS;
10756 while ((CUR == '+') || (CUR == '-')) {
10757 int plus;
10758 int op1 = ctxt->comp->last;
10759
10760 if (CUR == '+') plus = 1;
10761 else plus = 0;
10762 NEXT;
10763 SKIP_BLANKS;
10764 xmlXPathCompMultiplicativeExpr(ctxt);
10765 CHECK_ERROR;
10766 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10767 SKIP_BLANKS;
10768 }
10769}
10770
10771/**
10772 * xmlXPathCompRelationalExpr:
10773 * @ctxt: the XPath Parser context
10774 *
10775 * [24] RelationalExpr ::= AdditiveExpr
10776 * | RelationalExpr '<' AdditiveExpr
10777 * | RelationalExpr '>' AdditiveExpr
10778 * | RelationalExpr '<=' AdditiveExpr
10779 * | RelationalExpr '>=' AdditiveExpr
10780 *
10781 * A <= B > C is allowed ? Answer from James, yes with
10782 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10783 * which is basically what got implemented.
10784 *
10785 * Compile a Relational expression, then push the result
10786 * on the stack
10787 */
10788
10789static void
10790xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10791 xmlXPathCompAdditiveExpr(ctxt);
10792 CHECK_ERROR;
10793 SKIP_BLANKS;
10794 while ((CUR == '<') ||
10795 (CUR == '>') ||
10796 ((CUR == '<') && (NXT(1) == '=')) ||
10797 ((CUR == '>') && (NXT(1) == '='))) {
10798 int inf, strict;
10799 int op1 = ctxt->comp->last;
10800
10801 if (CUR == '<') inf = 1;
10802 else inf = 0;
10803 if (NXT(1) == '=') strict = 0;
10804 else strict = 1;
10805 NEXT;
10806 if (!strict) NEXT;
10807 SKIP_BLANKS;
10808 xmlXPathCompAdditiveExpr(ctxt);
10809 CHECK_ERROR;
10810 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10811 SKIP_BLANKS;
10812 }
10813}
10814
10815/**
10816 * xmlXPathCompEqualityExpr:
10817 * @ctxt: the XPath Parser context
10818 *
10819 * [23] EqualityExpr ::= RelationalExpr
10820 * | EqualityExpr '=' RelationalExpr
10821 * | EqualityExpr '!=' RelationalExpr
10822 *
10823 * A != B != C is allowed ? Answer from James, yes with
10824 * (RelationalExpr = RelationalExpr) = RelationalExpr
10825 * (RelationalExpr != RelationalExpr) != RelationalExpr
10826 * which is basically what got implemented.
10827 *
10828 * Compile an Equality expression.
10829 *
10830 */
10831static void
10832xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10833 xmlXPathCompRelationalExpr(ctxt);
10834 CHECK_ERROR;
10835 SKIP_BLANKS;
10836 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10837 int eq;
10838 int op1 = ctxt->comp->last;
10839
10840 if (CUR == '=') eq = 1;
10841 else eq = 0;
10842 NEXT;
10843 if (!eq) NEXT;
10844 SKIP_BLANKS;
10845 xmlXPathCompRelationalExpr(ctxt);
10846 CHECK_ERROR;
10847 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10848 SKIP_BLANKS;
10849 }
10850}
10851
10852/**
10853 * xmlXPathCompAndExpr:
10854 * @ctxt: the XPath Parser context
10855 *
10856 * [22] AndExpr ::= EqualityExpr
10857 * | AndExpr 'and' EqualityExpr
10858 *
10859 * Compile an AND expression.
10860 *
10861 */
10862static void
10863xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10864 xmlXPathCompEqualityExpr(ctxt);
10865 CHECK_ERROR;
10866 SKIP_BLANKS;
10867 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10868 int op1 = ctxt->comp->last;
10869 SKIP(3);
10870 SKIP_BLANKS;
10871 xmlXPathCompEqualityExpr(ctxt);
10872 CHECK_ERROR;
10873 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10874 SKIP_BLANKS;
10875 }
10876}
10877
10878/**
10879 * xmlXPathCompileExpr:
10880 * @ctxt: the XPath Parser context
10881 *
10882 * [14] Expr ::= OrExpr
10883 * [21] OrExpr ::= AndExpr
10884 * | OrExpr 'or' AndExpr
10885 *
10886 * Parse and compile an expression
10887 */
10888static void
10889xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10890 xmlXPathCompAndExpr(ctxt);
10891 CHECK_ERROR;
10892 SKIP_BLANKS;
10893 while ((CUR == 'o') && (NXT(1) == 'r')) {
10894 int op1 = ctxt->comp->last;
10895 SKIP(2);
10896 SKIP_BLANKS;
10897 xmlXPathCompAndExpr(ctxt);
10898 CHECK_ERROR;
10899 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10900 op1 = ctxt->comp->nbStep;
10901 SKIP_BLANKS;
10902 }
10903 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10904 /* more ops could be optimized too */
10905 /*
10906 * This is the main place to eliminate sorting for
10907 * operations which don't require a sorted node-set.
10908 * E.g. count().
10909 */
10910 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10911 }
10912}
10913
10914/**
10915 * xmlXPathCompPredicate:
10916 * @ctxt: the XPath Parser context
10917 * @filter: act as a filter
10918 *
10919 * [8] Predicate ::= '[' PredicateExpr ']'
10920 * [9] PredicateExpr ::= Expr
10921 *
10922 * Compile a predicate expression
10923 */
10924static void
10925xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10926 int op1 = ctxt->comp->last;
10927
10928 SKIP_BLANKS;
10929 if (CUR != '[') {
10930 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10931 }
10932 NEXT;
10933 SKIP_BLANKS;
10934
10935 ctxt->comp->last = -1;
10936 /*
10937 * This call to xmlXPathCompileExpr() will deactivate sorting
10938 * of the predicate result.
10939 * TODO: Sorting is still activated for filters, since I'm not
10940 * sure if needed. Normally sorting should not be needed, since
10941 * a filter can only diminish the number of items in a sequence,
10942 * but won't change its order; so if the initial sequence is sorted,
10943 * subsequent sorting is not needed.
10944 */
10945 if (! filter)
10946 xmlXPathCompileExpr(ctxt, 0);
10947 else
10948 xmlXPathCompileExpr(ctxt, 1);
10949 CHECK_ERROR;
10950
10951 if (CUR != ']') {
10952 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10953 }
10954
10955 if (filter)
10956 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10957 else
10958 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
10959
10960 NEXT;
10961 SKIP_BLANKS;
10962}
10963
10964/**
10965 * xmlXPathCompNodeTest:
10966 * @ctxt: the XPath Parser context
10967 * @test: pointer to a xmlXPathTestVal
10968 * @type: pointer to a xmlXPathTypeVal
10969 * @prefix: placeholder for a possible name prefix
10970 *
10971 * [7] NodeTest ::= NameTest
10972 * | NodeType '(' ')'
10973 * | 'processing-instruction' '(' Literal ')'
10974 *
10975 * [37] NameTest ::= '*'
10976 * | NCName ':' '*'
10977 * | QName
10978 * [38] NodeType ::= 'comment'
10979 * | 'text'
10980 * | 'processing-instruction'
10981 * | 'node'
10982 *
10983 * Returns the name found and updates @test, @type and @prefix appropriately
10984 */
10985static xmlChar *
10986xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10987 xmlXPathTypeVal *type, const xmlChar **prefix,
10988 xmlChar *name) {
10989 int blanks;
10990
10991 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10992 STRANGE;
10993 return(NULL);
10994 }
10995 *type = (xmlXPathTypeVal) 0;
10996 *test = (xmlXPathTestVal) 0;
10997 *prefix = NULL;
10998 SKIP_BLANKS;
10999
11000 if ((name == NULL) && (CUR == '*')) {
11001 /*
11002 * All elements
11003 */
11004 NEXT;
11005 *test = NODE_TEST_ALL;
11006 return(NULL);
11007 }
11008
11009 if (name == NULL)
11010 name = xmlXPathParseNCName(ctxt);
11011 if (name == NULL) {
11012 XP_ERRORNULL(XPATH_EXPR_ERROR);
11013 }
11014
11015 blanks = IS_BLANK_CH(CUR);
11016 SKIP_BLANKS;
11017 if (CUR == '(') {
11018 NEXT;
11019 /*
11020 * NodeType or PI search
11021 */
11022 if (xmlStrEqual(name, BAD_CAST "comment"))
11023 *type = NODE_TYPE_COMMENT;
11024 else if (xmlStrEqual(name, BAD_CAST "node"))
11025 *type = NODE_TYPE_NODE;
11026 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11027 *type = NODE_TYPE_PI;
11028 else if (xmlStrEqual(name, BAD_CAST "text"))
11029 *type = NODE_TYPE_TEXT;
11030 else {
11031 if (name != NULL)
11032 xmlFree(name);
11033 XP_ERRORNULL(XPATH_EXPR_ERROR);
11034 }
11035
11036 *test = NODE_TEST_TYPE;
11037
11038 SKIP_BLANKS;
11039 if (*type == NODE_TYPE_PI) {
11040 /*
11041 * Specific case: search a PI by name.
11042 */
11043 if (name != NULL)
11044 xmlFree(name);
11045 name = NULL;
11046 if (CUR != ')') {
11047 name = xmlXPathParseLiteral(ctxt);
11048 CHECK_ERROR NULL;
11049 *test = NODE_TEST_PI;
11050 SKIP_BLANKS;
11051 }
11052 }
11053 if (CUR != ')') {
11054 if (name != NULL)
11055 xmlFree(name);
11056 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11057 }
11058 NEXT;
11059 return(name);
11060 }
11061 *test = NODE_TEST_NAME;
11062 if ((!blanks) && (CUR == ':')) {
11063 NEXT;
11064
11065 /*
11066 * Since currently the parser context don't have a
11067 * namespace list associated:
11068 * The namespace name for this prefix can be computed
11069 * only at evaluation time. The compilation is done
11070 * outside of any context.
11071 */
11072#if 0
11073 *prefix = xmlXPathNsLookup(ctxt->context, name);
11074 if (name != NULL)
11075 xmlFree(name);
11076 if (*prefix == NULL) {
11077 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11078 }
11079#else
11080 *prefix = name;
11081#endif
11082
11083 if (CUR == '*') {
11084 /*
11085 * All elements
11086 */
11087 NEXT;
11088 *test = NODE_TEST_ALL;
11089 return(NULL);
11090 }
11091
11092 name = xmlXPathParseNCName(ctxt);
11093 if (name == NULL) {
11094 XP_ERRORNULL(XPATH_EXPR_ERROR);
11095 }
11096 }
11097 return(name);
11098}
11099
11100/**
11101 * xmlXPathIsAxisName:
11102 * @name: a preparsed name token
11103 *
11104 * [6] AxisName ::= 'ancestor'
11105 * | 'ancestor-or-self'
11106 * | 'attribute'
11107 * | 'child'
11108 * | 'descendant'
11109 * | 'descendant-or-self'
11110 * | 'following'
11111 * | 'following-sibling'
11112 * | 'namespace'
11113 * | 'parent'
11114 * | 'preceding'
11115 * | 'preceding-sibling'
11116 * | 'self'
11117 *
11118 * Returns the axis or 0
11119 */
11120static xmlXPathAxisVal
11121xmlXPathIsAxisName(const xmlChar *name) {
11122 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11123 switch (name[0]) {
11124 case 'a':
11125 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11126 ret = AXIS_ANCESTOR;
11127 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11128 ret = AXIS_ANCESTOR_OR_SELF;
11129 if (xmlStrEqual(name, BAD_CAST "attribute"))
11130 ret = AXIS_ATTRIBUTE;
11131 break;
11132 case 'c':
11133 if (xmlStrEqual(name, BAD_CAST "child"))
11134 ret = AXIS_CHILD;
11135 break;
11136 case 'd':
11137 if (xmlStrEqual(name, BAD_CAST "descendant"))
11138 ret = AXIS_DESCENDANT;
11139 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11140 ret = AXIS_DESCENDANT_OR_SELF;
11141 break;
11142 case 'f':
11143 if (xmlStrEqual(name, BAD_CAST "following"))
11144 ret = AXIS_FOLLOWING;
11145 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11146 ret = AXIS_FOLLOWING_SIBLING;
11147 break;
11148 case 'n':
11149 if (xmlStrEqual(name, BAD_CAST "namespace"))
11150 ret = AXIS_NAMESPACE;
11151 break;
11152 case 'p':
11153 if (xmlStrEqual(name, BAD_CAST "parent"))
11154 ret = AXIS_PARENT;
11155 if (xmlStrEqual(name, BAD_CAST "preceding"))
11156 ret = AXIS_PRECEDING;
11157 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11158 ret = AXIS_PRECEDING_SIBLING;
11159 break;
11160 case 's':
11161 if (xmlStrEqual(name, BAD_CAST "self"))
11162 ret = AXIS_SELF;
11163 break;
11164 }
11165 return(ret);
11166}
11167
11168/**
11169 * xmlXPathCompStep:
11170 * @ctxt: the XPath Parser context
11171 *
11172 * [4] Step ::= AxisSpecifier NodeTest Predicate*
11173 * | AbbreviatedStep
11174 *
11175 * [12] AbbreviatedStep ::= '.' | '..'
11176 *
11177 * [5] AxisSpecifier ::= AxisName '::'
11178 * | AbbreviatedAxisSpecifier
11179 *
11180 * [13] AbbreviatedAxisSpecifier ::= '@'?
11181 *
11182 * Modified for XPtr range support as:
11183 *
11184 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11185 * | AbbreviatedStep
11186 * | 'range-to' '(' Expr ')' Predicate*
11187 *
11188 * Compile one step in a Location Path
11189 * A location step of . is short for self::node(). This is
11190 * particularly useful in conjunction with //. For example, the
11191 * location path .//para is short for
11192 * self::node()/descendant-or-self::node()/child::para
11193 * and so will select all para descendant elements of the context
11194 * node.
11195 * Similarly, a location step of .. is short for parent::node().
11196 * For example, ../title is short for parent::node()/child::title
11197 * and so will select the title children of the parent of the context
11198 * node.
11199 */
11200static void
11201xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11202#ifdef LIBXML_XPTR_ENABLED
11203 int rangeto = 0;
11204 int op2 = -1;
11205#endif
11206
11207 SKIP_BLANKS;
11208 if ((CUR == '.') && (NXT(1) == '.')) {
11209 SKIP(2);
11210 SKIP_BLANKS;
11211 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11212 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11213 } else if (CUR == '.') {
11214 NEXT;
11215 SKIP_BLANKS;
11216 } else {
11217 xmlChar *name = NULL;
11218 const xmlChar *prefix = NULL;
11219 xmlXPathTestVal test = (xmlXPathTestVal) 0;
11220 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11221 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11222 int op1;
11223
11224 /*
11225 * The modification needed for XPointer change to the production
11226 */
11227#ifdef LIBXML_XPTR_ENABLED
11228 if (ctxt->xptr) {
11229 name = xmlXPathParseNCName(ctxt);
11230 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11231 op2 = ctxt->comp->last;
11232 xmlFree(name);
11233 SKIP_BLANKS;
11234 if (CUR != '(') {
11235 XP_ERROR(XPATH_EXPR_ERROR);
11236 }
11237 NEXT;
11238 SKIP_BLANKS;
11239
11240 xmlXPathCompileExpr(ctxt, 1);
11241 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11242 CHECK_ERROR;
11243
11244 SKIP_BLANKS;
11245 if (CUR != ')') {
11246 XP_ERROR(XPATH_EXPR_ERROR);
11247 }
11248 NEXT;
11249 rangeto = 1;
11250 goto eval_predicates;
11251 }
11252 }
11253#endif
11254 if (CUR == '*') {
11255 axis = AXIS_CHILD;
11256 } else {
11257 if (name == NULL)
11258 name = xmlXPathParseNCName(ctxt);
11259 if (name != NULL) {
11260 axis = xmlXPathIsAxisName(name);
11261 if (axis != 0) {
11262 SKIP_BLANKS;
11263 if ((CUR == ':') && (NXT(1) == ':')) {
11264 SKIP(2);
11265 xmlFree(name);
11266 name = NULL;
11267 } else {
11268 /* an element name can conflict with an axis one :-\ */
11269 axis = AXIS_CHILD;
11270 }
11271 } else {
11272 axis = AXIS_CHILD;
11273 }
11274 } else if (CUR == '@') {
11275 NEXT;
11276 axis = AXIS_ATTRIBUTE;
11277 } else {
11278 axis = AXIS_CHILD;
11279 }
11280 }
11281
11282 CHECK_ERROR;
11283
11284 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11285 if (test == 0)
11286 return;
11287
11288 if ((prefix != NULL) && (ctxt->context != NULL) &&
11289 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11290 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11291 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11292 }
11293 }
11294#ifdef DEBUG_STEP
11295 xmlGenericError(xmlGenericErrorContext,
11296 "Basis : computing new set\n");
11297#endif
11298
11299#ifdef DEBUG_STEP
11300 xmlGenericError(xmlGenericErrorContext, "Basis : ");
11301 if (ctxt->value == NULL)
11302 xmlGenericError(xmlGenericErrorContext, "no value\n");
11303 else if (ctxt->value->nodesetval == NULL)
11304 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11305 else
11306 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11307#endif
11308
11309#ifdef LIBXML_XPTR_ENABLED
11310eval_predicates:
11311#endif
11312 op1 = ctxt->comp->last;
11313 ctxt->comp->last = -1;
11314
11315 SKIP_BLANKS;
11316 while (CUR == '[') {
11317 xmlXPathCompPredicate(ctxt, 0);
11318 }
11319
11320#ifdef LIBXML_XPTR_ENABLED
11321 if (rangeto) {
11322 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11323 } else
11324#endif
11325 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11326 test, type, (void *)prefix, (void *)name);
11327
11328 }
11329#ifdef DEBUG_STEP
11330 xmlGenericError(xmlGenericErrorContext, "Step : ");
11331 if (ctxt->value == NULL)
11332 xmlGenericError(xmlGenericErrorContext, "no value\n");
11333 else if (ctxt->value->nodesetval == NULL)
11334 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11335 else
11336 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11337 ctxt->value->nodesetval);
11338#endif
11339}
11340
11341/**
11342 * xmlXPathCompRelativeLocationPath:
11343 * @ctxt: the XPath Parser context
11344 *
11345 * [3] RelativeLocationPath ::= Step
11346 * | RelativeLocationPath '/' Step
11347 * | AbbreviatedRelativeLocationPath
11348 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
11349 *
11350 * Compile a relative location path.
11351 */
11352static void
11353xmlXPathCompRelativeLocationPath
11354(xmlXPathParserContextPtr ctxt) {
11355 SKIP_BLANKS;
11356 if ((CUR == '/') && (NXT(1) == '/')) {
11357 SKIP(2);
11358 SKIP_BLANKS;
11359 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11360 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11361 } else if (CUR == '/') {
11362 NEXT;
11363 SKIP_BLANKS;
11364 }
11365 xmlXPathCompStep(ctxt);
11366 SKIP_BLANKS;
11367 while (CUR == '/') {
11368 if ((CUR == '/') && (NXT(1) == '/')) {
11369 SKIP(2);
11370 SKIP_BLANKS;
11371 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11372 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11373 xmlXPathCompStep(ctxt);
11374 } else if (CUR == '/') {
11375 NEXT;
11376 SKIP_BLANKS;
11377 xmlXPathCompStep(ctxt);
11378 }
11379 SKIP_BLANKS;
11380 }
11381}
11382
11383/**
11384 * xmlXPathCompLocationPath:
11385 * @ctxt: the XPath Parser context
11386 *
11387 * [1] LocationPath ::= RelativeLocationPath
11388 * | AbsoluteLocationPath
11389 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
11390 * | AbbreviatedAbsoluteLocationPath
11391 * [10] AbbreviatedAbsoluteLocationPath ::=
11392 * '//' RelativeLocationPath
11393 *
11394 * Compile a location path
11395 *
11396 * // is short for /descendant-or-self::node()/. For example,
11397 * //para is short for /descendant-or-self::node()/child::para and
11398 * so will select any para element in the document (even a para element
11399 * that is a document element will be selected by //para since the
11400 * document element node is a child of the root node); div//para is
11401 * short for div/descendant-or-self::node()/child::para and so will
11402 * select all para descendants of div children.
11403 */
11404static void
11405xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11406 SKIP_BLANKS;
11407 if (CUR != '/') {
11408 xmlXPathCompRelativeLocationPath(ctxt);
11409 } else {
11410 while (CUR == '/') {
11411 if ((CUR == '/') && (NXT(1) == '/')) {
11412 SKIP(2);
11413 SKIP_BLANKS;
11414 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11415 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11416 xmlXPathCompRelativeLocationPath(ctxt);
11417 } else if (CUR == '/') {
11418 NEXT;
11419 SKIP_BLANKS;
11420 if ((CUR != 0 ) &&
11421 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11422 (CUR == '@') || (CUR == '*')))
11423 xmlXPathCompRelativeLocationPath(ctxt);
11424 }
11425 }
11426 }
11427}
11428
11429/************************************************************************
11430 * *
11431 * XPath precompiled expression evaluation *
11432 * *
11433 ************************************************************************/
11434
11435static int
11436xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11437
11438#ifdef DEBUG_STEP
11439static void
11440xmlXPathDebugDumpStepAxis(xmlXPathAxisVal axis,
11441 xmlXPathTestVal test,
11442 int nbNodes)
11443{
11444 xmlGenericError(xmlGenericErrorContext, "new step : ");
11445 switch (axis) {
11446 case AXIS_ANCESTOR:
11447 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11448 break;
11449 case AXIS_ANCESTOR_OR_SELF:
11450 xmlGenericError(xmlGenericErrorContext,
11451 "axis 'ancestors-or-self' ");
11452 break;
11453 case AXIS_ATTRIBUTE:
11454 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11455 break;
11456 case AXIS_CHILD:
11457 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11458 break;
11459 case AXIS_DESCENDANT:
11460 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11461 break;
11462 case AXIS_DESCENDANT_OR_SELF:
11463 xmlGenericError(xmlGenericErrorContext,
11464 "axis 'descendant-or-self' ");
11465 break;
11466 case AXIS_FOLLOWING:
11467 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11468 break;
11469 case AXIS_FOLLOWING_SIBLING:
11470 xmlGenericError(xmlGenericErrorContext,
11471 "axis 'following-siblings' ");
11472 break;
11473 case AXIS_NAMESPACE:
11474 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11475 break;
11476 case AXIS_PARENT:
11477 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11478 break;
11479 case AXIS_PRECEDING:
11480 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11481 break;
11482 case AXIS_PRECEDING_SIBLING:
11483 xmlGenericError(xmlGenericErrorContext,
11484 "axis 'preceding-sibling' ");
11485 break;
11486 case AXIS_SELF:
11487 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11488 break;
11489 }
11490 xmlGenericError(xmlGenericErrorContext,
11491 " context contains %d nodes\n", nbNodes);
11492 switch (test) {
11493 case NODE_TEST_NONE:
11494 xmlGenericError(xmlGenericErrorContext,
11495 " searching for none !!!\n");
11496 break;
11497 case NODE_TEST_TYPE:
11498 xmlGenericError(xmlGenericErrorContext,
11499 " searching for type %d\n", type);
11500 break;
11501 case NODE_TEST_PI:
11502 xmlGenericError(xmlGenericErrorContext,
11503 " searching for PI !!!\n");
11504 break;
11505 case NODE_TEST_ALL:
11506 xmlGenericError(xmlGenericErrorContext,
11507 " searching for *\n");
11508 break;
11509 case NODE_TEST_NS:
11510 xmlGenericError(xmlGenericErrorContext,
11511 " searching for namespace %s\n",
11512 prefix);
11513 break;
11514 case NODE_TEST_NAME:
11515 xmlGenericError(xmlGenericErrorContext,
11516 " searching for name %s\n", name);
11517 if (prefix != NULL)
11518 xmlGenericError(xmlGenericErrorContext,
11519 " with namespace %s\n", prefix);
11520 break;
11521 }
11522 xmlGenericError(xmlGenericErrorContext, "Testing : ");
11523}
11524#endif /* DEBUG_STEP */
11525
11526static int
11527xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11528 xmlXPathStepOpPtr op,
11529 xmlNodeSetPtr set,
11530 int contextSize,
11531 int hasNsNodes)
11532{
11533 if (op->ch1 != -1) {
11534 xmlXPathCompExprPtr comp = ctxt->comp;
11535 /*
11536 * Process inner predicates first.
11537 */
11538 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11539 /*
11540 * TODO: raise an internal error.
11541 */
11542 }
11543 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11544 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11545 CHECK_ERROR0;
11546 if (contextSize <= 0)
11547 return(0);
11548 }
11549 if (op->ch2 != -1) {
11550 xmlXPathContextPtr xpctxt = ctxt->context;
11551 xmlNodePtr contextNode, oldContextNode;
11552 xmlDocPtr oldContextDoc;
11553 int i, res, contextPos = 0, newContextSize;
11554 xmlXPathStepOpPtr exprOp;
11555 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11556
11557#ifdef LIBXML_XPTR_ENABLED
11558 /*
11559 * URGENT TODO: Check the following:
11560 * We don't expect location sets if evaluating prediates, right?
11561 * Only filters should expect location sets, right?
11562 */
11563#endif
11564 /*
11565 * SPEC XPath 1.0:
11566 * "For each node in the node-set to be filtered, the
11567 * PredicateExpr is evaluated with that node as the
11568 * context node, with the number of nodes in the
11569 * node-set as the context size, and with the proximity
11570 * position of the node in the node-set with respect to
11571 * the axis as the context position;"
11572 * @oldset is the node-set" to be filtered.
11573 *
11574 * SPEC XPath 1.0:
11575 * "only predicates change the context position and
11576 * context size (see [2.4 Predicates])."
11577 * Example:
11578 * node-set context pos
11579 * nA 1
11580 * nB 2
11581 * nC 3
11582 * After applying predicate [position() > 1] :
11583 * node-set context pos
11584 * nB 1
11585 * nC 2
11586 */
11587 oldContextNode = xpctxt->node;
11588 oldContextDoc = xpctxt->doc;
11589 /*
11590 * Get the expression of this predicate.
11591 */
11592 exprOp = &ctxt->comp->steps[op->ch2];
11593 newContextSize = 0;
11594 for (i = 0; i < set->nodeNr; i++) {
11595 if (set->nodeTab[i] == NULL)
11596 continue;
11597
11598 contextNode = set->nodeTab[i];
11599 xpctxt->node = contextNode;
11600 xpctxt->contextSize = contextSize;
11601 xpctxt->proximityPosition = ++contextPos;
11602
11603 /*
11604 * Also set the xpath document in case things like
11605 * key() are evaluated in the predicate.
11606 */
11607 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11608 (contextNode->doc != NULL))
11609 xpctxt->doc = contextNode->doc;
11610 /*
11611 * Evaluate the predicate expression with 1 context node
11612 * at a time; this node is packaged into a node set; this
11613 * node set is handed over to the evaluation mechanism.
11614 */
11615 if (contextObj == NULL)
11616 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11617 else
11618 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11619 contextNode);
11620
11621 valuePush(ctxt, contextObj);
11622
11623 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11624
11625 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11626 xmlXPathNodeSetClear(set, hasNsNodes);
11627 newContextSize = 0;
11628 goto evaluation_exit;
11629 }
11630
11631 if (res != 0) {
11632 newContextSize++;
11633 } else {
11634 /*
11635 * Remove the entry from the initial node set.
11636 */
11637 set->nodeTab[i] = NULL;
11638 if (contextNode->type == XML_NAMESPACE_DECL)
11639 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11640 }
11641 if (ctxt->value == contextObj) {
11642 /*
11643 * Don't free the temporary XPath object holding the
11644 * context node, in order to avoid massive recreation
11645 * inside this loop.
11646 */
11647 valuePop(ctxt);
11648 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11649 } else {
11650 /*
11651 * TODO: The object was lost in the evaluation machinery.
11652 * Can this happen? Maybe in internal-error cases.
11653 */
11654 contextObj = NULL;
11655 }
11656 }
11657
11658 if (contextObj != NULL) {
11659 if (ctxt->value == contextObj)
11660 valuePop(ctxt);
11661 xmlXPathReleaseObject(xpctxt, contextObj);
11662 }
11663evaluation_exit:
11664 if (exprRes != NULL)
11665 xmlXPathReleaseObject(ctxt->context, exprRes);
11666 /*
11667 * Reset/invalidate the context.
11668 */
11669 xpctxt->node = oldContextNode;
11670 xpctxt->doc = oldContextDoc;
11671 xpctxt->contextSize = -1;
11672 xpctxt->proximityPosition = -1;
11673 return(newContextSize);
11674 }
11675 return(contextSize);
11676}
11677
11678static int
11679xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11680 xmlXPathStepOpPtr op,
11681 xmlNodeSetPtr set,
11682 int contextSize,
11683 int minPos,
11684 int maxPos,
11685 int hasNsNodes)
11686{
11687 if (op->ch1 != -1) {
11688 xmlXPathCompExprPtr comp = ctxt->comp;
11689 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11690 /*
11691 * TODO: raise an internal error.
11692 */
11693 }
11694 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11695 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11696 CHECK_ERROR0;
11697 if (contextSize <= 0)
11698 return(0);
11699 }
11700 /*
11701 * Check if the node set contains a sufficient number of nodes for
11702 * the requested range.
11703 */
11704 if (contextSize < minPos) {
11705 xmlXPathNodeSetClear(set, hasNsNodes);
11706 return(0);
11707 }
11708 if (op->ch2 == -1) {
11709 /*
11710 * TODO: Can this ever happen?
11711 */
11712 return (contextSize);
11713 } else {
11714 xmlDocPtr oldContextDoc;
11715 int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11716 xmlXPathStepOpPtr exprOp;
11717 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11718 xmlNodePtr oldContextNode, contextNode = NULL;
11719 xmlXPathContextPtr xpctxt = ctxt->context;
11720 int frame;
11721
11722#ifdef LIBXML_XPTR_ENABLED
11723 /*
11724 * URGENT TODO: Check the following:
11725 * We don't expect location sets if evaluating prediates, right?
11726 * Only filters should expect location sets, right?
11727 */
11728#endif /* LIBXML_XPTR_ENABLED */
11729
11730 /*
11731 * Save old context.
11732 */
11733 oldContextNode = xpctxt->node;
11734 oldContextDoc = xpctxt->doc;
11735 /*
11736 * Get the expression of this predicate.
11737 */
11738 exprOp = &ctxt->comp->steps[op->ch2];
11739 for (i = 0; i < set->nodeNr; i++) {
11740 xmlXPathObjectPtr tmp;
11741
11742 if (set->nodeTab[i] == NULL)
11743 continue;
11744
11745 contextNode = set->nodeTab[i];
11746 xpctxt->node = contextNode;
11747 xpctxt->contextSize = contextSize;
11748 xpctxt->proximityPosition = ++contextPos;
11749
11750 /*
11751 * Initialize the new set.
11752 * Also set the xpath document in case things like
11753 * key() evaluation are attempted on the predicate
11754 */
11755 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11756 (contextNode->doc != NULL))
11757 xpctxt->doc = contextNode->doc;
11758 /*
11759 * Evaluate the predicate expression with 1 context node
11760 * at a time; this node is packaged into a node set; this
11761 * node set is handed over to the evaluation mechanism.
11762 */
11763 if (contextObj == NULL)
11764 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11765 else
11766 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11767 contextNode);
11768
11769 frame = xmlXPathSetFrame(ctxt);
11770 valuePush(ctxt, contextObj);
11771 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11772 tmp = valuePop(ctxt);
11773 xmlXPathPopFrame(ctxt, frame);
11774
11775 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11776 while (tmp != contextObj) {
11777 /*
11778 * Free up the result
11779 * then pop off contextObj, which will be freed later
11780 */
11781 xmlXPathReleaseObject(xpctxt, tmp);
11782 tmp = valuePop(ctxt);
11783 }
11784 goto evaluation_error;
11785 }
11786 /* push the result back onto the stack */
11787 valuePush(ctxt, tmp);
11788
11789 if (res)
11790 pos++;
11791
11792 if (res && (pos >= minPos) && (pos <= maxPos)) {
11793 /*
11794 * Fits in the requested range.
11795 */
11796 newContextSize++;
11797 if (minPos == maxPos) {
11798 /*
11799 * Only 1 node was requested.
11800 */
11801 if (contextNode->type == XML_NAMESPACE_DECL) {
11802 /*
11803 * As always: take care of those nasty
11804 * namespace nodes.
11805 */
11806 set->nodeTab[i] = NULL;
11807 }
11808 xmlXPathNodeSetClear(set, hasNsNodes);
11809 set->nodeNr = 1;
11810 set->nodeTab[0] = contextNode;
11811 goto evaluation_exit;
11812 }
11813 if (pos == maxPos) {
11814 /*
11815 * We are done.
11816 */
11817 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11818 goto evaluation_exit;
11819 }
11820 } else {
11821 /*
11822 * Remove the entry from the initial node set.
11823 */
11824 set->nodeTab[i] = NULL;
11825 if (contextNode->type == XML_NAMESPACE_DECL)
11826 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11827 }
11828 if (exprRes != NULL) {
11829 xmlXPathReleaseObject(ctxt->context, exprRes);
11830 exprRes = NULL;
11831 }
11832 if (ctxt->value == contextObj) {
11833 /*
11834 * Don't free the temporary XPath object holding the
11835 * context node, in order to avoid massive recreation
11836 * inside this loop.
11837 */
11838 valuePop(ctxt);
11839 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11840 } else {
11841 /*
11842 * The object was lost in the evaluation machinery.
11843 * Can this happen? Maybe in case of internal-errors.
11844 */
11845 contextObj = NULL;
11846 }
11847 }
11848 goto evaluation_exit;
11849
11850evaluation_error:
11851 xmlXPathNodeSetClear(set, hasNsNodes);
11852 newContextSize = 0;
11853
11854evaluation_exit:
11855 if (contextObj != NULL) {
11856 if (ctxt->value == contextObj)
11857 valuePop(ctxt);
11858 xmlXPathReleaseObject(xpctxt, contextObj);
11859 }
11860 if (exprRes != NULL)
11861 xmlXPathReleaseObject(ctxt->context, exprRes);
11862 /*
11863 * Reset/invalidate the context.
11864 */
11865 xpctxt->node = oldContextNode;
11866 xpctxt->doc = oldContextDoc;
11867 xpctxt->contextSize = -1;
11868 xpctxt->proximityPosition = -1;
11869 return(newContextSize);
11870 }
11871 return(contextSize);
11872}
11873
11874static int
11875xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11876 xmlXPathStepOpPtr op,
11877 int *maxPos)
11878{
11879
11880 xmlXPathStepOpPtr exprOp;
11881
11882 /*
11883 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11884 */
11885
11886 /*
11887 * If not -1, then ch1 will point to:
11888 * 1) For predicates (XPATH_OP_PREDICATE):
11889 * - an inner predicate operator
11890 * 2) For filters (XPATH_OP_FILTER):
11891 * - an inner filter operater OR
11892 * - an expression selecting the node set.
11893 * E.g. "key('a', 'b')" or "(//foo | //bar)".
11894 */
11895 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11896 return(0);
11897
11898 if (op->ch2 != -1) {
11899 exprOp = &ctxt->comp->steps[op->ch2];
11900 } else
11901 return(0);
11902
11903 if ((exprOp != NULL) &&
11904 (exprOp->op == XPATH_OP_VALUE) &&
11905 (exprOp->value4 != NULL) &&
11906 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11907 {
11908 /*
11909 * We have a "[n]" predicate here.
11910 * TODO: Unfortunately this simplistic test here is not
11911 * able to detect a position() predicate in compound
11912 * expressions like "[@attr = 'a" and position() = 1],
11913 * and even not the usage of position() in
11914 * "[position() = 1]"; thus - obviously - a position-range,
11915 * like it "[position() < 5]", is also not detected.
11916 * Maybe we could rewrite the AST to ease the optimization.
11917 */
11918 *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11919
11920 if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
11921 (float) *maxPos)
11922 {
11923 return(1);
11924 }
11925 }
11926 return(0);
11927}
11928
11929static int
11930xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11931 xmlXPathStepOpPtr op,
11932 xmlNodePtr * first, xmlNodePtr * last,
11933 int toBool)
11934{
11935
11936#define XP_TEST_HIT \
11937 if (hasAxisRange != 0) { \
11938 if (++pos == maxPos) { \
11939 addNode(seq, cur); \
11940 goto axis_range_end; } \
11941 } else { \
11942 addNode(seq, cur); \
11943 if (breakOnFirstHit) goto first_hit; }
11944
11945#define XP_TEST_HIT_NS \
11946 if (hasAxisRange != 0) { \
11947 if (++pos == maxPos) { \
11948 hasNsNodes = 1; \
11949 xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
11950 goto axis_range_end; } \
11951 } else { \
11952 hasNsNodes = 1; \
11953 xmlXPathNodeSetAddNs(seq, \
11954 xpctxt->node, (xmlNsPtr) cur); \
11955 if (breakOnFirstHit) goto first_hit; }
11956
11957 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11958 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11959 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11960 const xmlChar *prefix = op->value4;
11961 const xmlChar *name = op->value5;
11962 const xmlChar *URI = NULL;
11963
11964#ifdef DEBUG_STEP
11965 int nbMatches = 0, prevMatches = 0;
11966#endif
11967 int total = 0, hasNsNodes = 0;
11968 /* The popped object holding the context nodes */
11969 xmlXPathObjectPtr obj;
11970 /* The set of context nodes for the node tests */
11971 xmlNodeSetPtr contextSeq;
11972 int contextIdx;
11973 xmlNodePtr contextNode;
11974 /* The context node for a compound traversal */
11975 xmlNodePtr outerContextNode;
11976 /* The final resulting node set wrt to all context nodes */
11977 xmlNodeSetPtr outSeq;
11978 /*
11979 * The temporary resulting node set wrt 1 context node.
11980 * Used to feed predicate evaluation.
11981 */
11982 xmlNodeSetPtr seq;
11983 xmlNodePtr cur;
11984 /* First predicate operator */
11985 xmlXPathStepOpPtr predOp;
11986 int maxPos; /* The requested position() (when a "[n]" predicate) */
11987 int hasPredicateRange, hasAxisRange, pos, size, newSize;
11988 int breakOnFirstHit;
11989
11990 xmlXPathTraversalFunction next = NULL;
11991 /* compound axis traversal */
11992 xmlXPathTraversalFunctionExt outerNext = NULL;
11993 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
11994 xmlXPathNodeSetMergeFunction mergeAndClear;
11995 xmlNodePtr oldContextNode;
11996 xmlXPathContextPtr xpctxt = ctxt->context;
11997
11998
11999 CHECK_TYPE0(XPATH_NODESET);
12000 obj = valuePop(ctxt);
12001 /*
12002 * Setup namespaces.
12003 */
12004 if (prefix != NULL) {
12005 URI = xmlXPathNsLookup(xpctxt, prefix);
12006 if (URI == NULL) {
12007 xmlXPathReleaseObject(xpctxt, obj);
12008 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12009 }
12010 }
12011 /*
12012 * Setup axis.
12013 *
12014 * MAYBE FUTURE TODO: merging optimizations:
12015 * - If the nodes to be traversed wrt to the initial nodes and
12016 * the current axis cannot overlap, then we could avoid searching
12017 * for duplicates during the merge.
12018 * But the question is how/when to evaluate if they cannot overlap.
12019 * Example: if we know that for two initial nodes, the one is
12020 * not in the ancestor-or-self axis of the other, then we could safely
12021 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12022 * the descendant-or-self axis.
12023 */
12024 addNode = xmlXPathNodeSetAdd;
12025 mergeAndClear = xmlXPathNodeSetMergeAndClear;
12026 switch (axis) {
12027 case AXIS_ANCESTOR:
12028 first = NULL;
12029 next = xmlXPathNextAncestor;
12030 break;
12031 case AXIS_ANCESTOR_OR_SELF:
12032 first = NULL;
12033 next = xmlXPathNextAncestorOrSelf;
12034 break;
12035 case AXIS_ATTRIBUTE:
12036 first = NULL;
12037 last = NULL;
12038 next = xmlXPathNextAttribute;
12039 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12040 break;
12041 case AXIS_CHILD:
12042 last = NULL;
12043 if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
12044 /*
12045 * This iterator will give us only nodes which can
12046 * hold element nodes.
12047 */
12048 outerNext = xmlXPathNextDescendantOrSelfElemParent;
12049 }
12050 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12051 (type == NODE_TYPE_NODE))
12052 {
12053 /*
12054 * Optimization if an element node type is 'element'.
12055 */
12056 next = xmlXPathNextChildElement;
12057 } else
12058 next = xmlXPathNextChild;
12059 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12060 break;
12061 case AXIS_DESCENDANT:
12062 last = NULL;
12063 next = xmlXPathNextDescendant;
12064 break;
12065 case AXIS_DESCENDANT_OR_SELF:
12066 last = NULL;
12067 next = xmlXPathNextDescendantOrSelf;
12068 break;
12069 case AXIS_FOLLOWING:
12070 last = NULL;
12071 next = xmlXPathNextFollowing;
12072 break;
12073 case AXIS_FOLLOWING_SIBLING:
12074 last = NULL;
12075 next = xmlXPathNextFollowingSibling;
12076 break;
12077 case AXIS_NAMESPACE:
12078 first = NULL;
12079 last = NULL;
12080 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12081 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12082 break;
12083 case AXIS_PARENT:
12084 first = NULL;
12085 next = xmlXPathNextParent;
12086 break;
12087 case AXIS_PRECEDING:
12088 first = NULL;
12089 next = xmlXPathNextPrecedingInternal;
12090 break;
12091 case AXIS_PRECEDING_SIBLING:
12092 first = NULL;
12093 next = xmlXPathNextPrecedingSibling;
12094 break;
12095 case AXIS_SELF:
12096 first = NULL;
12097 last = NULL;
12098 next = xmlXPathNextSelf;
12099 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12100 break;
12101 }
12102
12103#ifdef DEBUG_STEP
12104 xmlXPathDebugDumpStepAxis(axis, test,
12105 (obj->nodesetval != NULL) ? obj->nodsetval->nodeNr : 0);
12106#endif
12107
12108 if (next == NULL) {
12109 xmlXPathReleaseObject(xpctxt, obj);
12110 return(0);
12111 }
12112 contextSeq = obj->nodesetval;
12113 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12114 xmlXPathReleaseObject(xpctxt, obj);
12115 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12116 return(0);
12117 }
12118 /*
12119 * Predicate optimization ---------------------------------------------
12120 * If this step has a last predicate, which contains a position(),
12121 * then we'll optimize (although not exactly "position()", but only
12122 * the short-hand form, i.e., "[n]".
12123 *
12124 * Example - expression "/foo[parent::bar][1]":
12125 *
12126 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12127 * ROOT -- op->ch1
12128 * PREDICATE -- op->ch2 (predOp)
12129 * PREDICATE -- predOp->ch1 = [parent::bar]
12130 * SORT
12131 * COLLECT 'parent' 'name' 'node' bar
12132 * NODE
12133 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12134 *
12135 */
12136 maxPos = 0;
12137 predOp = NULL;
12138 hasPredicateRange = 0;
12139 hasAxisRange = 0;
12140 if (op->ch2 != -1) {
12141 /*
12142 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12143 */
12144 predOp = &ctxt->comp->steps[op->ch2];
12145 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12146 if (predOp->ch1 != -1) {
12147 /*
12148 * Use the next inner predicate operator.
12149 */
12150 predOp = &ctxt->comp->steps[predOp->ch1];
12151 hasPredicateRange = 1;
12152 } else {
12153 /*
12154 * There's no other predicate than the [n] predicate.
12155 */
12156 predOp = NULL;
12157 hasAxisRange = 1;
12158 }
12159 }
12160 }
12161 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12162 /*
12163 * Axis traversal -----------------------------------------------------
12164 */
12165 /*
12166 * 2.3 Node Tests
12167 * - For the attribute axis, the principal node type is attribute.
12168 * - For the namespace axis, the principal node type is namespace.
12169 * - For other axes, the principal node type is element.
12170 *
12171 * A node test * is true for any node of the
12172 * principal node type. For example, child::* will
12173 * select all element children of the context node
12174 */
12175 oldContextNode = xpctxt->node;
12176 addNode = xmlXPathNodeSetAddUnique;
12177 outSeq = NULL;
12178 seq = NULL;
12179 outerContextNode = NULL;
12180 contextNode = NULL;
12181 contextIdx = 0;
12182
12183
12184 while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
12185 if (outerNext != NULL) {
12186 /*
12187 * This is a compound traversal.
12188 */
12189 if (contextNode == NULL) {
12190 /*
12191 * Set the context for the outer traversal.
12192 */
12193 outerContextNode = contextSeq->nodeTab[contextIdx++];
12194 contextNode = outerNext(NULL, outerContextNode);
12195 } else
12196 contextNode = outerNext(contextNode, outerContextNode);
12197 if (contextNode == NULL)
12198 continue;
12199 /*
12200 * Set the context for the main traversal.
12201 */
12202 xpctxt->node = contextNode;
12203 } else
12204 xpctxt->node = contextSeq->nodeTab[contextIdx++];
12205
12206 if (seq == NULL) {
12207 seq = xmlXPathNodeSetCreate(NULL);
12208 if (seq == NULL) {
12209 total = 0;
12210 goto error;
12211 }
12212 }
12213 /*
12214 * Traverse the axis and test the nodes.
12215 */
12216 pos = 0;
12217 cur = NULL;
12218 hasNsNodes = 0;
12219 do {
12220 cur = next(ctxt, cur);
12221 if (cur == NULL)
12222 break;
12223
12224 /*
12225 * QUESTION TODO: What does the "first" and "last" stuff do?
12226 */
12227 if ((first != NULL) && (*first != NULL)) {
12228 if (*first == cur)
12229 break;
12230 if (((total % 256) == 0) &&
12231#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12232 (xmlXPathCmpNodesExt(*first, cur) >= 0))
12233#else
12234 (xmlXPathCmpNodes(*first, cur) >= 0))
12235#endif
12236 {
12237 break;
12238 }
12239 }
12240 if ((last != NULL) && (*last != NULL)) {
12241 if (*last == cur)
12242 break;
12243 if (((total % 256) == 0) &&
12244#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12245 (xmlXPathCmpNodesExt(cur, *last) >= 0))
12246#else
12247 (xmlXPathCmpNodes(cur, *last) >= 0))
12248#endif
12249 {
12250 break;
12251 }
12252 }
12253
12254 total++;
12255
12256#ifdef DEBUG_STEP
12257 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12258#endif
12259
12260 switch (test) {
12261 case NODE_TEST_NONE:
12262 total = 0;
12263 STRANGE
12264 goto error;
12265 case NODE_TEST_TYPE:
12266 /*
12267 * TODO: Don't we need to use
12268 * xmlXPathNodeSetAddNs() for namespace nodes here?
12269 * Surprisingly, some c14n tests fail, if we do this.
12270 */
12271 if (type == NODE_TYPE_NODE) {
12272 switch (cur->type) {
12273 case XML_DOCUMENT_NODE:
12274 case XML_HTML_DOCUMENT_NODE:
12275#ifdef LIBXML_DOCB_ENABLED
12276 case XML_DOCB_DOCUMENT_NODE:
12277#endif
12278 case XML_ELEMENT_NODE:
12279 case XML_ATTRIBUTE_NODE:
12280 case XML_PI_NODE:
12281 case XML_COMMENT_NODE:
12282 case XML_CDATA_SECTION_NODE:
12283 case XML_TEXT_NODE:
12284 case XML_NAMESPACE_DECL:
12285 XP_TEST_HIT
12286 break;
12287 default:
12288 break;
12289 }
12290 } else if (cur->type == type) {
12291 if (type == XML_NAMESPACE_DECL)
12292 XP_TEST_HIT_NS
12293 else
12294 XP_TEST_HIT
12295 } else if ((type == NODE_TYPE_TEXT) &&
12296 (cur->type == XML_CDATA_SECTION_NODE))
12297 {
12298 XP_TEST_HIT
12299 }
12300 break;
12301 case NODE_TEST_PI:
12302 if ((cur->type == XML_PI_NODE) &&
12303 ((name == NULL) || xmlStrEqual(name, cur->name)))
12304 {
12305 XP_TEST_HIT
12306 }
12307 break;
12308 case NODE_TEST_ALL:
12309 if (axis == AXIS_ATTRIBUTE) {
12310 if (cur->type == XML_ATTRIBUTE_NODE)
12311 {
12312 XP_TEST_HIT
12313 }
12314 } else if (axis == AXIS_NAMESPACE) {
12315 if (cur->type == XML_NAMESPACE_DECL)
12316 {
12317 XP_TEST_HIT_NS
12318 }
12319 } else {
12320 if (cur->type == XML_ELEMENT_NODE) {
12321 if (prefix == NULL)
12322 {
12323 XP_TEST_HIT
12324
12325 } else if ((cur->ns != NULL) &&
12326 (xmlStrEqual(URI, cur->ns->href)))
12327 {
12328 XP_TEST_HIT
12329 }
12330 }
12331 }
12332 break;
12333 case NODE_TEST_NS:{
12334 TODO;
12335 break;
12336 }
12337 case NODE_TEST_NAME:
12338 if (axis == AXIS_ATTRIBUTE) {
12339 if (cur->type != XML_ATTRIBUTE_NODE)
12340 break;
12341 } else if (axis == AXIS_NAMESPACE) {
12342 if (cur->type != XML_NAMESPACE_DECL)
12343 break;
12344 } else {
12345 if (cur->type != XML_ELEMENT_NODE)
12346 break;
12347 }
12348 switch (cur->type) {
12349 case XML_ELEMENT_NODE:
12350 if (xmlStrEqual(name, cur->name)) {
12351 if (prefix == NULL) {
12352 if (cur->ns == NULL)
12353 {
12354 XP_TEST_HIT
12355 }
12356 } else {
12357 if ((cur->ns != NULL) &&
12358 (xmlStrEqual(URI, cur->ns->href)))
12359 {
12360 XP_TEST_HIT
12361 }
12362 }
12363 }
12364 break;
12365 case XML_ATTRIBUTE_NODE:{
12366 xmlAttrPtr attr = (xmlAttrPtr) cur;
12367
12368 if (xmlStrEqual(name, attr->name)) {
12369 if (prefix == NULL) {
12370 if ((attr->ns == NULL) ||
12371 (attr->ns->prefix == NULL))
12372 {
12373 XP_TEST_HIT
12374 }
12375 } else {
12376 if ((attr->ns != NULL) &&
12377 (xmlStrEqual(URI,
12378 attr->ns->href)))
12379 {
12380 XP_TEST_HIT
12381 }
12382 }
12383 }
12384 break;
12385 }
12386 case XML_NAMESPACE_DECL:
12387 if (cur->type == XML_NAMESPACE_DECL) {
12388 xmlNsPtr ns = (xmlNsPtr) cur;
12389
12390 if ((ns->prefix != NULL) && (name != NULL)
12391 && (xmlStrEqual(ns->prefix, name)))
12392 {
12393 XP_TEST_HIT_NS
12394 }
12395 }
12396 break;
12397 default:
12398 break;
12399 }
12400 break;
12401 } /* switch(test) */
12402 } while (cur != NULL);
12403
12404 goto apply_predicates;
12405
12406axis_range_end: /* ----------------------------------------------------- */
12407 /*
12408 * We have a "/foo[n]", and position() = n was reached.
12409 * Note that we can have as well "/foo/::parent::foo[1]", so
12410 * a duplicate-aware merge is still needed.
12411 * Merge with the result.
12412 */
12413 if (outSeq == NULL) {
12414 outSeq = seq;
12415 seq = NULL;
12416 } else
12417 outSeq = mergeAndClear(outSeq, seq, 0);
12418 /*
12419 * Break if only a true/false result was requested.
12420 */
12421 if (toBool)
12422 break;
12423 continue;
12424
12425first_hit: /* ---------------------------------------------------------- */
12426 /*
12427 * Break if only a true/false result was requested and
12428 * no predicates existed and a node test succeeded.
12429 */
12430 if (outSeq == NULL) {
12431 outSeq = seq;
12432 seq = NULL;
12433 } else
12434 outSeq = mergeAndClear(outSeq, seq, 0);
12435 break;
12436
12437#ifdef DEBUG_STEP
12438 if (seq != NULL)
12439 nbMatches += seq->nodeNr;
12440#endif
12441
12442apply_predicates: /* --------------------------------------------------- */
12443 /*
12444 * Apply predicates.
12445 */
12446 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12447 /*
12448 * E.g. when we have a "/foo[some expression][n]".
12449 */
12450 /*
12451 * QUESTION TODO: The old predicate evaluation took into
12452 * account location-sets.
12453 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12454 * Do we expect such a set here?
12455 * All what I learned now from the evaluation semantics
12456 * does not indicate that a location-set will be processed
12457 * here, so this looks OK.
12458 */
12459 /*
12460 * Iterate over all predicates, starting with the outermost
12461 * predicate.
12462 * TODO: Problem: we cannot execute the inner predicates first
12463 * since we cannot go back *up* the operator tree!
12464 * Options we have:
12465 * 1) Use of recursive functions (like is it currently done
12466 * via xmlXPathCompOpEval())
12467 * 2) Add a predicate evaluation information stack to the
12468 * context struct
12469 * 3) Change the way the operators are linked; we need a
12470 * "parent" field on xmlXPathStepOp
12471 *
12472 * For the moment, I'll try to solve this with a recursive
12473 * function: xmlXPathCompOpEvalPredicate().
12474 */
12475 size = seq->nodeNr;
12476 if (hasPredicateRange != 0)
12477 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12478 predOp, seq, size, maxPos, maxPos, hasNsNodes);
12479 else
12480 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12481 predOp, seq, size, hasNsNodes);
12482
12483 if (ctxt->error != XPATH_EXPRESSION_OK) {
12484 total = 0;
12485 goto error;
12486 }
12487 /*
12488 * Add the filtered set of nodes to the result node set.
12489 */
12490 if (newSize == 0) {
12491 /*
12492 * The predicates filtered all nodes out.
12493 */
12494 xmlXPathNodeSetClear(seq, hasNsNodes);
12495 } else if (seq->nodeNr > 0) {
12496 /*
12497 * Add to result set.
12498 */
12499 if (outSeq == NULL) {
12500 if (size != newSize) {
12501 /*
12502 * We need to merge and clear here, since
12503 * the sequence will contained NULLed entries.
12504 */
12505 outSeq = mergeAndClear(NULL, seq, 1);
12506 } else {
12507 outSeq = seq;
12508 seq = NULL;
12509 }
12510 } else
12511 outSeq = mergeAndClear(outSeq, seq,
12512 (size != newSize) ? 1: 0);
12513 /*
12514 * Break if only a true/false result was requested.
12515 */
12516 if (toBool)
12517 break;
12518 }
12519 } else if (seq->nodeNr > 0) {
12520 /*
12521 * Add to result set.
12522 */
12523 if (outSeq == NULL) {
12524 outSeq = seq;
12525 seq = NULL;
12526 } else {
12527 outSeq = mergeAndClear(outSeq, seq, 0);
12528 }
12529 }
12530 }
12531
12532error:
12533 if ((obj->boolval) && (obj->user != NULL)) {
12534 /*
12535 * QUESTION TODO: What does this do and why?
12536 * TODO: Do we have to do this also for the "error"
12537 * cleanup further down?
12538 */
12539 ctxt->value->boolval = 1;
12540 ctxt->value->user = obj->user;
12541 obj->user = NULL;
12542 obj->boolval = 0;
12543 }
12544 xmlXPathReleaseObject(xpctxt, obj);
12545
12546 /*
12547 * Ensure we return at least an emtpy set.
12548 */
12549 if (outSeq == NULL) {
12550 if ((seq != NULL) && (seq->nodeNr == 0))
12551 outSeq = seq;
12552 else
12553 outSeq = xmlXPathNodeSetCreate(NULL);
12554 }
12555 if ((seq != NULL) && (seq != outSeq)) {
12556 xmlXPathFreeNodeSet(seq);
12557 }
12558 /*
12559 * Hand over the result. Better to push the set also in
12560 * case of errors.
12561 */
12562 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12563 /*
12564 * Reset the context node.
12565 */
12566 xpctxt->node = oldContextNode;
12567
12568#ifdef DEBUG_STEP
12569 xmlGenericError(xmlGenericErrorContext,
12570 "\nExamined %d nodes, found %d nodes at that step\n",
12571 total, nbMatches);
12572#endif
12573
12574 return(total);
12575}
12576
12577static int
12578xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12579 xmlXPathStepOpPtr op, xmlNodePtr * first);
12580
12581/**
12582 * xmlXPathCompOpEvalFirst:
12583 * @ctxt: the XPath parser context with the compiled expression
12584 * @op: an XPath compiled operation
12585 * @first: the first elem found so far
12586 *
12587 * Evaluate the Precompiled XPath operation searching only the first
12588 * element in document order
12589 *
12590 * Returns the number of examined objects.
12591 */
12592static int
12593xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12594 xmlXPathStepOpPtr op, xmlNodePtr * first)
12595{
12596 int total = 0, cur;
12597 xmlXPathCompExprPtr comp;
12598 xmlXPathObjectPtr arg1, arg2;
12599
12600 CHECK_ERROR0;
12601 comp = ctxt->comp;
12602 switch (op->op) {
12603 case XPATH_OP_END:
12604 return (0);
12605 case XPATH_OP_UNION:
12606 total =
12607 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12608 first);
12609 CHECK_ERROR0;
12610 if ((ctxt->value != NULL)
12611 && (ctxt->value->type == XPATH_NODESET)
12612 && (ctxt->value->nodesetval != NULL)
12613 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12614 /*
12615 * limit tree traversing to first node in the result
12616 */
12617 /*
12618 * OPTIMIZE TODO: This implicitely sorts
12619 * the result, even if not needed. E.g. if the argument
12620 * of the count() function, no sorting is needed.
12621 * OPTIMIZE TODO: How do we know if the node-list wasn't
12622 * aready sorted?
12623 */
12624 if (ctxt->value->nodesetval->nodeNr > 1)
12625 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12626 *first = ctxt->value->nodesetval->nodeTab[0];
12627 }
12628 cur =
12629 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12630 first);
12631 CHECK_ERROR0;
12632 CHECK_TYPE0(XPATH_NODESET);
12633 arg2 = valuePop(ctxt);
12634
12635 CHECK_TYPE0(XPATH_NODESET);
12636 arg1 = valuePop(ctxt);
12637
12638 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12639 arg2->nodesetval);
12640 valuePush(ctxt, arg1);
12641 xmlXPathReleaseObject(ctxt->context, arg2);
12642 /* optimizer */
12643 if (total > cur)
12644 xmlXPathCompSwap(op);
12645 return (total + cur);
12646 case XPATH_OP_ROOT:
12647 xmlXPathRoot(ctxt);
12648 return (0);
12649 case XPATH_OP_NODE:
12650 if (op->ch1 != -1)
12651 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12652 CHECK_ERROR0;
12653 if (op->ch2 != -1)
12654 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12655 CHECK_ERROR0;
12656 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12657 ctxt->context->node));
12658 return (total);
12659 case XPATH_OP_RESET:
12660 if (op->ch1 != -1)
12661 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12662 CHECK_ERROR0;
12663 if (op->ch2 != -1)
12664 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12665 CHECK_ERROR0;
12666 ctxt->context->node = NULL;
12667 return (total);
12668 case XPATH_OP_COLLECT:{
12669 if (op->ch1 == -1)
12670 return (total);
12671
12672 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12673 CHECK_ERROR0;
12674
12675 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12676 return (total);
12677 }
12678 case XPATH_OP_VALUE:
12679 valuePush(ctxt,
12680 xmlXPathCacheObjectCopy(ctxt->context,
12681 (xmlXPathObjectPtr) op->value4));
12682 return (0);
12683 case XPATH_OP_SORT:
12684 if (op->ch1 != -1)
12685 total +=
12686 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12687 first);
12688 CHECK_ERROR0;
12689 if ((ctxt->value != NULL)
12690 && (ctxt->value->type == XPATH_NODESET)
12691 && (ctxt->value->nodesetval != NULL)
12692 && (ctxt->value->nodesetval->nodeNr > 1))
12693 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12694 return (total);
12695#ifdef XP_OPTIMIZED_FILTER_FIRST
12696 case XPATH_OP_FILTER:
12697 total =+ xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12698 return (total);
12699#endif
12700 default:
12701 return (xmlXPathCompOpEval(ctxt, op));
12702 }
12703}
12704
12705/**
12706 * xmlXPathCompOpEvalLast:
12707 * @ctxt: the XPath parser context with the compiled expression
12708 * @op: an XPath compiled operation
12709 * @last: the last elem found so far
12710 *
12711 * Evaluate the Precompiled XPath operation searching only the last
12712 * element in document order
12713 *
12714 * Returns the number of nodes traversed
12715 */
12716static int
12717xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12718 xmlNodePtr * last)
12719{
12720 int total = 0, cur;
12721 xmlXPathCompExprPtr comp;
12722 xmlXPathObjectPtr arg1, arg2;
12723 xmlNodePtr bak;
12724 xmlDocPtr bakd;
12725 int pp;
12726 int cs;
12727
12728 CHECK_ERROR0;
12729 comp = ctxt->comp;
12730 switch (op->op) {
12731 case XPATH_OP_END:
12732 return (0);
12733 case XPATH_OP_UNION:
12734 bakd = ctxt->context->doc;
12735 bak = ctxt->context->node;
12736 pp = ctxt->context->proximityPosition;
12737 cs = ctxt->context->contextSize;
12738 total =
12739 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12740 CHECK_ERROR0;
12741 if ((ctxt->value != NULL)
12742 && (ctxt->value->type == XPATH_NODESET)
12743 && (ctxt->value->nodesetval != NULL)
12744 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12745 /*
12746 * limit tree traversing to first node in the result
12747 */
12748 if (ctxt->value->nodesetval->nodeNr > 1)
12749 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12750 *last =
12751 ctxt->value->nodesetval->nodeTab[ctxt->value->
12752 nodesetval->nodeNr -
12753 1];
12754 }
12755 ctxt->context->doc = bakd;
12756 ctxt->context->node = bak;
12757 ctxt->context->proximityPosition = pp;
12758 ctxt->context->contextSize = cs;
12759 cur =
12760 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12761 CHECK_ERROR0;
12762 if ((ctxt->value != NULL)
12763 && (ctxt->value->type == XPATH_NODESET)
12764 && (ctxt->value->nodesetval != NULL)
12765 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12766 }
12767 CHECK_TYPE0(XPATH_NODESET);
12768 arg2 = valuePop(ctxt);
12769
12770 CHECK_TYPE0(XPATH_NODESET);
12771 arg1 = valuePop(ctxt);
12772
12773 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12774 arg2->nodesetval);
12775 valuePush(ctxt, arg1);
12776 xmlXPathReleaseObject(ctxt->context, arg2);
12777 /* optimizer */
12778 if (total > cur)
12779 xmlXPathCompSwap(op);
12780 return (total + cur);
12781 case XPATH_OP_ROOT:
12782 xmlXPathRoot(ctxt);
12783 return (0);
12784 case XPATH_OP_NODE:
12785 if (op->ch1 != -1)
12786 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12787 CHECK_ERROR0;
12788 if (op->ch2 != -1)
12789 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12790 CHECK_ERROR0;
12791 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12792 ctxt->context->node));
12793 return (total);
12794 case XPATH_OP_RESET:
12795 if (op->ch1 != -1)
12796 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12797 CHECK_ERROR0;
12798 if (op->ch2 != -1)
12799 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12800 CHECK_ERROR0;
12801 ctxt->context->node = NULL;
12802 return (total);
12803 case XPATH_OP_COLLECT:{
12804 if (op->ch1 == -1)
12805 return (0);
12806
12807 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12808 CHECK_ERROR0;
12809
12810 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12811 return (total);
12812 }
12813 case XPATH_OP_VALUE:
12814 valuePush(ctxt,
12815 xmlXPathCacheObjectCopy(ctxt->context,
12816 (xmlXPathObjectPtr) op->value4));
12817 return (0);
12818 case XPATH_OP_SORT:
12819 if (op->ch1 != -1)
12820 total +=
12821 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12822 last);
12823 CHECK_ERROR0;
12824 if ((ctxt->value != NULL)
12825 && (ctxt->value->type == XPATH_NODESET)
12826 && (ctxt->value->nodesetval != NULL)
12827 && (ctxt->value->nodesetval->nodeNr > 1))
12828 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12829 return (total);
12830 default:
12831 return (xmlXPathCompOpEval(ctxt, op));
12832 }
12833}
12834
12835#ifdef XP_OPTIMIZED_FILTER_FIRST
12836static int
12837xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12838 xmlXPathStepOpPtr op, xmlNodePtr * first)
12839{
12840 int total = 0;
12841 xmlXPathCompExprPtr comp;
12842 xmlXPathObjectPtr res;
12843 xmlXPathObjectPtr obj;
12844 xmlNodeSetPtr oldset;
12845 xmlNodePtr oldnode;
12846 xmlDocPtr oldDoc;
12847 int i;
12848
12849 CHECK_ERROR0;
12850 comp = ctxt->comp;
12851 /*
12852 * Optimization for ()[last()] selection i.e. the last elem
12853 */
12854 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12855 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12856 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12857 int f = comp->steps[op->ch2].ch1;
12858
12859 if ((f != -1) &&
12860 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12861 (comp->steps[f].value5 == NULL) &&
12862 (comp->steps[f].value == 0) &&
12863 (comp->steps[f].value4 != NULL) &&
12864 (xmlStrEqual
12865 (comp->steps[f].value4, BAD_CAST "last"))) {
12866 xmlNodePtr last = NULL;
12867
12868 total +=
12869 xmlXPathCompOpEvalLast(ctxt,
12870 &comp->steps[op->ch1],
12871 &last);
12872 CHECK_ERROR0;
12873 /*
12874 * The nodeset should be in document order,
12875 * Keep only the last value
12876 */
12877 if ((ctxt->value != NULL) &&
12878 (ctxt->value->type == XPATH_NODESET) &&
12879 (ctxt->value->nodesetval != NULL) &&
12880 (ctxt->value->nodesetval->nodeTab != NULL) &&
12881 (ctxt->value->nodesetval->nodeNr > 1)) {
12882 ctxt->value->nodesetval->nodeTab[0] =
12883 ctxt->value->nodesetval->nodeTab[ctxt->
12884 value->
12885 nodesetval->
12886 nodeNr -
12887 1];
12888 ctxt->value->nodesetval->nodeNr = 1;
12889 *first = *(ctxt->value->nodesetval->nodeTab);
12890 }
12891 return (total);
12892 }
12893 }
12894
12895 if (op->ch1 != -1)
12896 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12897 CHECK_ERROR0;
12898 if (op->ch2 == -1)
12899 return (total);
12900 if (ctxt->value == NULL)
12901 return (total);
12902
12903#ifdef LIBXML_XPTR_ENABLED
12904 oldnode = ctxt->context->node;
12905 /*
12906 * Hum are we filtering the result of an XPointer expression
12907 */
12908 if (ctxt->value->type == XPATH_LOCATIONSET) {
12909 xmlXPathObjectPtr tmp = NULL;
12910 xmlLocationSetPtr newlocset = NULL;
12911 xmlLocationSetPtr oldlocset;
12912
12913 /*
12914 * Extract the old locset, and then evaluate the result of the
12915 * expression for all the element in the locset. use it to grow
12916 * up a new locset.
12917 */
12918 CHECK_TYPE0(XPATH_LOCATIONSET);
12919 obj = valuePop(ctxt);
12920 oldlocset = obj->user;
12921 ctxt->context->node = NULL;
12922
12923 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12924 ctxt->context->contextSize = 0;
12925 ctxt->context->proximityPosition = 0;
12926 if (op->ch2 != -1)
12927 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12928 res = valuePop(ctxt);
12929 if (res != NULL) {
12930 xmlXPathReleaseObject(ctxt->context, res);
12931 }
12932 valuePush(ctxt, obj);
12933 CHECK_ERROR0;
12934 return (total);
12935 }
12936 newlocset = xmlXPtrLocationSetCreate(NULL);
12937
12938 for (i = 0; i < oldlocset->locNr; i++) {
12939 /*
12940 * Run the evaluation with a node list made of a
12941 * single item in the nodelocset.
12942 */
12943 ctxt->context->node = oldlocset->locTab[i]->user;
12944 ctxt->context->contextSize = oldlocset->locNr;
12945 ctxt->context->proximityPosition = i + 1;
12946 if (tmp == NULL) {
12947 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12948 ctxt->context->node);
12949 } else {
12950 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12951 ctxt->context->node);
12952 }
12953 valuePush(ctxt, tmp);
12954 if (op->ch2 != -1)
12955 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12956 if (ctxt->error != XPATH_EXPRESSION_OK) {
12957 xmlXPathFreeObject(obj);
12958 return(0);
12959 }
12960 /*
12961 * The result of the evaluation need to be tested to
12962 * decided whether the filter succeeded or not
12963 */
12964 res = valuePop(ctxt);
12965 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12966 xmlXPtrLocationSetAdd(newlocset,
12967 xmlXPathCacheObjectCopy(ctxt->context,
12968 oldlocset->locTab[i]));
12969 }
12970 /*
12971 * Cleanup
12972 */
12973 if (res != NULL) {
12974 xmlXPathReleaseObject(ctxt->context, res);
12975 }
12976 if (ctxt->value == tmp) {
12977 valuePop(ctxt);
12978 xmlXPathNodeSetClear(tmp->nodesetval, 1);
12979 /*
12980 * REVISIT TODO: Don't create a temporary nodeset
12981 * for everly iteration.
12982 */
12983 /* OLD: xmlXPathFreeObject(res); */
12984 } else
12985 tmp = NULL;
12986 ctxt->context->node = NULL;
12987 /*
12988 * Only put the first node in the result, then leave.
12989 */
12990 if (newlocset->locNr > 0) {
12991 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
12992 break;
12993 }
12994 }
12995 if (tmp != NULL) {
12996 xmlXPathReleaseObject(ctxt->context, tmp);
12997 }
12998 /*
12999 * The result is used as the new evaluation locset.
13000 */
13001 xmlXPathReleaseObject(ctxt->context, obj);
13002 ctxt->context->node = NULL;
13003 ctxt->context->contextSize = -1;
13004 ctxt->context->proximityPosition = -1;
13005 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13006 ctxt->context->node = oldnode;
13007 return (total);
13008 }
13009#endif /* LIBXML_XPTR_ENABLED */
13010
13011 /*
13012 * Extract the old set, and then evaluate the result of the
13013 * expression for all the element in the set. use it to grow
13014 * up a new set.
13015 */
13016 CHECK_TYPE0(XPATH_NODESET);
13017 obj = valuePop(ctxt);
13018 oldset = obj->nodesetval;
13019
13020 oldnode = ctxt->context->node;
13021 oldDoc = ctxt->context->doc;
13022 ctxt->context->node = NULL;
13023
13024 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13025 ctxt->context->contextSize = 0;
13026 ctxt->context->proximityPosition = 0;
13027 /* QUESTION TODO: Why was this code commented out?
13028 if (op->ch2 != -1)
13029 total +=
13030 xmlXPathCompOpEval(ctxt,
13031 &comp->steps[op->ch2]);
13032 CHECK_ERROR0;
13033 res = valuePop(ctxt);
13034 if (res != NULL)
13035 xmlXPathFreeObject(res);
13036 */
13037 valuePush(ctxt, obj);
13038 ctxt->context->node = oldnode;
13039 CHECK_ERROR0;
13040 } else {
13041 xmlNodeSetPtr newset;
13042 xmlXPathObjectPtr tmp = NULL;
13043 /*
13044 * Initialize the new set.
13045 * Also set the xpath document in case things like
13046 * key() evaluation are attempted on the predicate
13047 */
13048 newset = xmlXPathNodeSetCreate(NULL);
13049
13050 for (i = 0; i < oldset->nodeNr; i++) {
13051 /*
13052 * Run the evaluation with a node list made of
13053 * a single item in the nodeset.
13054 */
13055 ctxt->context->node = oldset->nodeTab[i];
13056 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13057 (oldset->nodeTab[i]->doc != NULL))
13058 ctxt->context->doc = oldset->nodeTab[i]->doc;
13059 if (tmp == NULL) {
13060 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13061 ctxt->context->node);
13062 } else {
13063 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13064 ctxt->context->node);
13065 }
13066 valuePush(ctxt, tmp);
13067 ctxt->context->contextSize = oldset->nodeNr;
13068 ctxt->context->proximityPosition = i + 1;
13069 if (op->ch2 != -1)
13070 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13071 if (ctxt->error != XPATH_EXPRESSION_OK) {
13072 xmlXPathFreeNodeSet(newset);
13073 xmlXPathFreeObject(obj);
13074 return(0);
13075 }
13076 /*
13077 * The result of the evaluation needs to be tested to
13078 * decide whether the filter succeeded or not
13079 */
13080 res = valuePop(ctxt);
13081 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13082 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13083 }
13084 /*
13085 * Cleanup
13086 */
13087 if (res != NULL) {
13088 xmlXPathReleaseObject(ctxt->context, res);
13089 }
13090 if (ctxt->value == tmp) {
13091 valuePop(ctxt);
13092 /*
13093 * Don't free the temporary nodeset
13094 * in order to avoid massive recreation inside this
13095 * loop.
13096 */
13097 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13098 } else
13099 tmp = NULL;
13100 ctxt->context->node = NULL;
13101 /*
13102 * Only put the first node in the result, then leave.
13103 */
13104 if (newset->nodeNr > 0) {
13105 *first = *(newset->nodeTab);
13106 break;
13107 }
13108 }
13109 if (tmp != NULL) {
13110 xmlXPathReleaseObject(ctxt->context, tmp);
13111 }
13112 /*
13113 * The result is used as the new evaluation set.
13114 */
13115 xmlXPathReleaseObject(ctxt->context, obj);
13116 ctxt->context->node = NULL;
13117 ctxt->context->contextSize = -1;
13118 ctxt->context->proximityPosition = -1;
13119 /* may want to move this past the '}' later */
13120 ctxt->context->doc = oldDoc;
13121 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13122 }
13123 ctxt->context->node = oldnode;
13124 return(total);
13125}
13126#endif /* XP_OPTIMIZED_FILTER_FIRST */
13127
13128/**
13129 * xmlXPathCompOpEval:
13130 * @ctxt: the XPath parser context with the compiled expression
13131 * @op: an XPath compiled operation
13132 *
13133 * Evaluate the Precompiled XPath operation
13134 * Returns the number of nodes traversed
13135 */
13136static int
13137xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13138{
13139 int total = 0;
13140 int equal, ret;
13141 xmlXPathCompExprPtr comp;
13142 xmlXPathObjectPtr arg1, arg2;
13143 xmlNodePtr bak;
13144 xmlDocPtr bakd;
13145 int pp;
13146 int cs;
13147
13148 CHECK_ERROR0;
13149 comp = ctxt->comp;
13150 switch (op->op) {
13151 case XPATH_OP_END:
13152 return (0);
13153 case XPATH_OP_AND:
13154 bakd = ctxt->context->doc;
13155 bak = ctxt->context->node;
13156 pp = ctxt->context->proximityPosition;
13157 cs = ctxt->context->contextSize;
13158 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13159 CHECK_ERROR0;
13160 xmlXPathBooleanFunction(ctxt, 1);
13161 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13162 return (total);
13163 arg2 = valuePop(ctxt);
13164 ctxt->context->doc = bakd;
13165 ctxt->context->node = bak;
13166 ctxt->context->proximityPosition = pp;
13167 ctxt->context->contextSize = cs;
13168 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13169 if (ctxt->error) {
13170 xmlXPathFreeObject(arg2);
13171 return(0);
13172 }
13173 xmlXPathBooleanFunction(ctxt, 1);
13174 arg1 = valuePop(ctxt);
13175 arg1->boolval &= arg2->boolval;
13176 valuePush(ctxt, arg1);
13177 xmlXPathReleaseObject(ctxt->context, arg2);
13178 return (total);
13179 case XPATH_OP_OR:
13180 bakd = ctxt->context->doc;
13181 bak = ctxt->context->node;
13182 pp = ctxt->context->proximityPosition;
13183 cs = ctxt->context->contextSize;
13184 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13185 CHECK_ERROR0;
13186 xmlXPathBooleanFunction(ctxt, 1);
13187 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13188 return (total);
13189 arg2 = valuePop(ctxt);
13190 ctxt->context->doc = bakd;
13191 ctxt->context->node = bak;
13192 ctxt->context->proximityPosition = pp;
13193 ctxt->context->contextSize = cs;
13194 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13195 if (ctxt->error) {
13196 xmlXPathFreeObject(arg2);
13197 return(0);
13198 }
13199 xmlXPathBooleanFunction(ctxt, 1);
13200 arg1 = valuePop(ctxt);
13201 arg1->boolval |= arg2->boolval;
13202 valuePush(ctxt, arg1);
13203 xmlXPathReleaseObject(ctxt->context, arg2);
13204 return (total);
13205 case XPATH_OP_EQUAL:
13206 bakd = ctxt->context->doc;
13207 bak = ctxt->context->node;
13208 pp = ctxt->context->proximityPosition;
13209 cs = ctxt->context->contextSize;
13210 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13211 CHECK_ERROR0;
13212 ctxt->context->doc = bakd;
13213 ctxt->context->node = bak;
13214 ctxt->context->proximityPosition = pp;
13215 ctxt->context->contextSize = cs;
13216 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13217 CHECK_ERROR0;
13218 if (op->value)
13219 equal = xmlXPathEqualValues(ctxt);
13220 else
13221 equal = xmlXPathNotEqualValues(ctxt);
13222 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13223 return (total);
13224 case XPATH_OP_CMP:
13225 bakd = ctxt->context->doc;
13226 bak = ctxt->context->node;
13227 pp = ctxt->context->proximityPosition;
13228 cs = ctxt->context->contextSize;
13229 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13230 CHECK_ERROR0;
13231 ctxt->context->doc = bakd;
13232 ctxt->context->node = bak;
13233 ctxt->context->proximityPosition = pp;
13234 ctxt->context->contextSize = cs;
13235 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13236 CHECK_ERROR0;
13237 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13238 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13239 return (total);
13240 case XPATH_OP_PLUS:
13241 bakd = ctxt->context->doc;
13242 bak = ctxt->context->node;
13243 pp = ctxt->context->proximityPosition;
13244 cs = ctxt->context->contextSize;
13245 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13246 CHECK_ERROR0;
13247 if (op->ch2 != -1) {
13248 ctxt->context->doc = bakd;
13249 ctxt->context->node = bak;
13250 ctxt->context->proximityPosition = pp;
13251 ctxt->context->contextSize = cs;
13252 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13253 }
13254 CHECK_ERROR0;
13255 if (op->value == 0)
13256 xmlXPathSubValues(ctxt);
13257 else if (op->value == 1)
13258 xmlXPathAddValues(ctxt);
13259 else if (op->value == 2)
13260 xmlXPathValueFlipSign(ctxt);
13261 else if (op->value == 3) {
13262 CAST_TO_NUMBER;
13263 CHECK_TYPE0(XPATH_NUMBER);
13264 }
13265 return (total);
13266 case XPATH_OP_MULT:
13267 bakd = ctxt->context->doc;
13268 bak = ctxt->context->node;
13269 pp = ctxt->context->proximityPosition;
13270 cs = ctxt->context->contextSize;
13271 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13272 CHECK_ERROR0;
13273 ctxt->context->doc = bakd;
13274 ctxt->context->node = bak;
13275 ctxt->context->proximityPosition = pp;
13276 ctxt->context->contextSize = cs;
13277 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13278 CHECK_ERROR0;
13279 if (op->value == 0)
13280 xmlXPathMultValues(ctxt);
13281 else if (op->value == 1)
13282 xmlXPathDivValues(ctxt);
13283 else if (op->value == 2)
13284 xmlXPathModValues(ctxt);
13285 return (total);
13286 case XPATH_OP_UNION:
13287 bakd = ctxt->context->doc;
13288 bak = ctxt->context->node;
13289 pp = ctxt->context->proximityPosition;
13290 cs = ctxt->context->contextSize;
13291 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13292 CHECK_ERROR0;
13293 ctxt->context->doc = bakd;
13294 ctxt->context->node = bak;
13295 ctxt->context->proximityPosition = pp;
13296 ctxt->context->contextSize = cs;
13297 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13298 CHECK_ERROR0;
13299 CHECK_TYPE0(XPATH_NODESET);
13300 arg2 = valuePop(ctxt);
13301
13302 CHECK_TYPE0(XPATH_NODESET);
13303 arg1 = valuePop(ctxt);
13304
13305 if ((arg1->nodesetval == NULL) ||
13306 ((arg2->nodesetval != NULL) &&
13307 (arg2->nodesetval->nodeNr != 0)))
13308 {
13309 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13310 arg2->nodesetval);
13311 }
13312
13313 valuePush(ctxt, arg1);
13314 xmlXPathReleaseObject(ctxt->context, arg2);
13315 return (total);
13316 case XPATH_OP_ROOT:
13317 xmlXPathRoot(ctxt);
13318 return (total);
13319 case XPATH_OP_NODE:
13320 if (op->ch1 != -1)
13321 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13322 CHECK_ERROR0;
13323 if (op->ch2 != -1)
13324 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13325 CHECK_ERROR0;
13326 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13327 ctxt->context->node));
13328 return (total);
13329 case XPATH_OP_RESET:
13330 if (op->ch1 != -1)
13331 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13332 CHECK_ERROR0;
13333 if (op->ch2 != -1)
13334 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13335 CHECK_ERROR0;
13336 ctxt->context->node = NULL;
13337 return (total);
13338 case XPATH_OP_COLLECT:{
13339 if (op->ch1 == -1)
13340 return (total);
13341
13342 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13343 CHECK_ERROR0;
13344
13345 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13346 return (total);
13347 }
13348 case XPATH_OP_VALUE:
13349 valuePush(ctxt,
13350 xmlXPathCacheObjectCopy(ctxt->context,
13351 (xmlXPathObjectPtr) op->value4));
13352 return (total);
13353 case XPATH_OP_VARIABLE:{
13354 xmlXPathObjectPtr val;
13355
13356 if (op->ch1 != -1)
13357 total +=
13358 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13359 if (op->value5 == NULL) {
13360 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13361 if (val == NULL) {
13362 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13363 return(0);
13364 }
13365 valuePush(ctxt, val);
13366 } else {
13367 const xmlChar *URI;
13368
13369 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13370 if (URI == NULL) {
13371 xmlGenericError(xmlGenericErrorContext,
13372 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13373 op->value4, op->value5);
13374 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13375 return (total);
13376 }
13377 val = xmlXPathVariableLookupNS(ctxt->context,
13378 op->value4, URI);
13379 if (val == NULL) {
13380 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13381 return(0);
13382 }
13383 valuePush(ctxt, val);
13384 }
13385 return (total);
13386 }
13387 case XPATH_OP_FUNCTION:{
13388 xmlXPathFunction func;
13389 const xmlChar *oldFunc, *oldFuncURI;
13390 int i;
13391 int frame;
13392
13393 frame = xmlXPathSetFrame(ctxt);
13394 if (op->ch1 != -1)
13395 total +=
13396 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13397 if (ctxt->valueNr < op->value) {
13398 xmlGenericError(xmlGenericErrorContext,
13399 "xmlXPathCompOpEval: parameter error\n");
13400 ctxt->error = XPATH_INVALID_OPERAND;
13401 xmlXPathPopFrame(ctxt, frame);
13402 return (total);
13403 }
13404 for (i = 0; i < op->value; i++) {
13405 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13406 xmlGenericError(xmlGenericErrorContext,
13407 "xmlXPathCompOpEval: parameter error\n");
13408 ctxt->error = XPATH_INVALID_OPERAND;
13409 xmlXPathPopFrame(ctxt, frame);
13410 return (total);
13411 }
13412 }
13413 if (op->cache != NULL)
13414 XML_CAST_FPTR(func) = op->cache;
13415 else {
13416 const xmlChar *URI = NULL;
13417
13418 if (op->value5 == NULL)
13419 func =
13420 xmlXPathFunctionLookup(ctxt->context,
13421 op->value4);
13422 else {
13423 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13424 if (URI == NULL) {
13425 xmlGenericError(xmlGenericErrorContext,
13426 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13427 op->value4, op->value5);
13428 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13429 return (total);
13430 }
13431 func = xmlXPathFunctionLookupNS(ctxt->context,
13432 op->value4, URI);
13433 }
13434 if (func == NULL) {
13435 xmlGenericError(xmlGenericErrorContext,
13436 "xmlXPathCompOpEval: function %s not found\n",
13437 op->value4);
13438 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13439 }
13440 op->cache = XML_CAST_FPTR(func);
13441 op->cacheURI = (void *) URI;
13442 }
13443 oldFunc = ctxt->context->function;
13444 oldFuncURI = ctxt->context->functionURI;
13445 ctxt->context->function = op->value4;
13446 ctxt->context->functionURI = op->cacheURI;
13447 func(ctxt, op->value);
13448 ctxt->context->function = oldFunc;
13449 ctxt->context->functionURI = oldFuncURI;
13450 xmlXPathPopFrame(ctxt, frame);
13451 return (total);
13452 }
13453 case XPATH_OP_ARG:
13454 bakd = ctxt->context->doc;
13455 bak = ctxt->context->node;
13456 pp = ctxt->context->proximityPosition;
13457 cs = ctxt->context->contextSize;
13458 if (op->ch1 != -1)
13459 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13460 ctxt->context->contextSize = cs;
13461 ctxt->context->proximityPosition = pp;
13462 ctxt->context->node = bak;
13463 ctxt->context->doc = bakd;
13464 CHECK_ERROR0;
13465 if (op->ch2 != -1) {
13466 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13467 ctxt->context->doc = bakd;
13468 ctxt->context->node = bak;
13469 CHECK_ERROR0;
13470 }
13471 return (total);
13472 case XPATH_OP_PREDICATE:
13473 case XPATH_OP_FILTER:{
13474 xmlXPathObjectPtr res;
13475 xmlXPathObjectPtr obj, tmp;
13476 xmlNodeSetPtr newset = NULL;
13477 xmlNodeSetPtr oldset;
13478 xmlNodePtr oldnode;
13479 xmlDocPtr oldDoc;
13480 int i;
13481
13482 /*
13483 * Optimization for ()[1] selection i.e. the first elem
13484 */
13485 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13486#ifdef XP_OPTIMIZED_FILTER_FIRST
13487 /*
13488 * FILTER TODO: Can we assume that the inner processing
13489 * will result in an ordered list if we have an
13490 * XPATH_OP_FILTER?
13491 * What about an additional field or flag on
13492 * xmlXPathObject like @sorted ? This way we wouln'd need
13493 * to assume anything, so it would be more robust and
13494 * easier to optimize.
13495 */
13496 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13497 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13498#else
13499 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13500#endif
13501 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13502 xmlXPathObjectPtr val;
13503
13504 val = comp->steps[op->ch2].value4;
13505 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13506 (val->floatval == 1.0)) {
13507 xmlNodePtr first = NULL;
13508
13509 total +=
13510 xmlXPathCompOpEvalFirst(ctxt,
13511 &comp->steps[op->ch1],
13512 &first);
13513 CHECK_ERROR0;
13514 /*
13515 * The nodeset should be in document order,
13516 * Keep only the first value
13517 */
13518 if ((ctxt->value != NULL) &&
13519 (ctxt->value->type == XPATH_NODESET) &&
13520 (ctxt->value->nodesetval != NULL) &&
13521 (ctxt->value->nodesetval->nodeNr > 1))
13522 ctxt->value->nodesetval->nodeNr = 1;
13523 return (total);
13524 }
13525 }
13526 /*
13527 * Optimization for ()[last()] selection i.e. the last elem
13528 */
13529 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13530 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13531 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13532 int f = comp->steps[op->ch2].ch1;
13533
13534 if ((f != -1) &&
13535 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13536 (comp->steps[f].value5 == NULL) &&
13537 (comp->steps[f].value == 0) &&
13538 (comp->steps[f].value4 != NULL) &&
13539 (xmlStrEqual
13540 (comp->steps[f].value4, BAD_CAST "last"))) {
13541 xmlNodePtr last = NULL;
13542
13543 total +=
13544 xmlXPathCompOpEvalLast(ctxt,
13545 &comp->steps[op->ch1],
13546 &last);
13547 CHECK_ERROR0;
13548 /*
13549 * The nodeset should be in document order,
13550 * Keep only the last value
13551 */
13552 if ((ctxt->value != NULL) &&
13553 (ctxt->value->type == XPATH_NODESET) &&
13554 (ctxt->value->nodesetval != NULL) &&
13555 (ctxt->value->nodesetval->nodeTab != NULL) &&
13556 (ctxt->value->nodesetval->nodeNr > 1)) {
13557 ctxt->value->nodesetval->nodeTab[0] =
13558 ctxt->value->nodesetval->nodeTab[ctxt->
13559 value->
13560 nodesetval->
13561 nodeNr -
13562 1];
13563 ctxt->value->nodesetval->nodeNr = 1;
13564 }
13565 return (total);
13566 }
13567 }
13568 /*
13569 * Process inner predicates first.
13570 * Example "index[parent::book][1]":
13571 * ...
13572 * PREDICATE <-- we are here "[1]"
13573 * PREDICATE <-- process "[parent::book]" first
13574 * SORT
13575 * COLLECT 'parent' 'name' 'node' book
13576 * NODE
13577 * ELEM Object is a number : 1
13578 */
13579 if (op->ch1 != -1)
13580 total +=
13581 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13582 CHECK_ERROR0;
13583 if (op->ch2 == -1)
13584 return (total);
13585 if (ctxt->value == NULL)
13586 return (total);
13587
13588 oldnode = ctxt->context->node;
13589
13590#ifdef LIBXML_XPTR_ENABLED
13591 /*
13592 * Hum are we filtering the result of an XPointer expression
13593 */
13594 if (ctxt->value->type == XPATH_LOCATIONSET) {
13595 xmlLocationSetPtr newlocset = NULL;
13596 xmlLocationSetPtr oldlocset;
13597
13598 /*
13599 * Extract the old locset, and then evaluate the result of the
13600 * expression for all the element in the locset. use it to grow
13601 * up a new locset.
13602 */
13603 CHECK_TYPE0(XPATH_LOCATIONSET);
13604 obj = valuePop(ctxt);
13605 oldlocset = obj->user;
13606 ctxt->context->node = NULL;
13607
13608 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13609 ctxt->context->contextSize = 0;
13610 ctxt->context->proximityPosition = 0;
13611 if (op->ch2 != -1)
13612 total +=
13613 xmlXPathCompOpEval(ctxt,
13614 &comp->steps[op->ch2]);
13615 res = valuePop(ctxt);
13616 if (res != NULL) {
13617 xmlXPathReleaseObject(ctxt->context, res);
13618 }
13619 valuePush(ctxt, obj);
13620 CHECK_ERROR0;
13621 return (total);
13622 }
13623 newlocset = xmlXPtrLocationSetCreate(NULL);
13624
13625 for (i = 0; i < oldlocset->locNr; i++) {
13626 /*
13627 * Run the evaluation with a node list made of a
13628 * single item in the nodelocset.
13629 */
13630 ctxt->context->node = oldlocset->locTab[i]->user;
13631 ctxt->context->contextSize = oldlocset->locNr;
13632 ctxt->context->proximityPosition = i + 1;
13633 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13634 ctxt->context->node);
13635 valuePush(ctxt, tmp);
13636
13637 if (op->ch2 != -1)
13638 total +=
13639 xmlXPathCompOpEval(ctxt,
13640 &comp->steps[op->ch2]);
13641 if (ctxt->error != XPATH_EXPRESSION_OK) {
13642 xmlXPathFreeObject(obj);
13643 return(0);
13644 }
13645
13646 /*
13647 * The result of the evaluation need to be tested to
13648 * decided whether the filter succeeded or not
13649 */
13650 res = valuePop(ctxt);
13651 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13652 xmlXPtrLocationSetAdd(newlocset,
13653 xmlXPathObjectCopy
13654 (oldlocset->locTab[i]));
13655 }
13656
13657 /*
13658 * Cleanup
13659 */
13660 if (res != NULL) {
13661 xmlXPathReleaseObject(ctxt->context, res);
13662 }
13663 if (ctxt->value == tmp) {
13664 res = valuePop(ctxt);
13665 xmlXPathReleaseObject(ctxt->context, res);
13666 }
13667
13668 ctxt->context->node = NULL;
13669 }
13670
13671 /*
13672 * The result is used as the new evaluation locset.
13673 */
13674 xmlXPathReleaseObject(ctxt->context, obj);
13675 ctxt->context->node = NULL;
13676 ctxt->context->contextSize = -1;
13677 ctxt->context->proximityPosition = -1;
13678 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13679 ctxt->context->node = oldnode;
13680 return (total);
13681 }
13682#endif /* LIBXML_XPTR_ENABLED */
13683
13684 /*
13685 * Extract the old set, and then evaluate the result of the
13686 * expression for all the element in the set. use it to grow
13687 * up a new set.
13688 */
13689 CHECK_TYPE0(XPATH_NODESET);
13690 obj = valuePop(ctxt);
13691 oldset = obj->nodesetval;
13692
13693 oldnode = ctxt->context->node;
13694 oldDoc = ctxt->context->doc;
13695 ctxt->context->node = NULL;
13696
13697 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13698 ctxt->context->contextSize = 0;
13699 ctxt->context->proximityPosition = 0;
13700/*
13701 if (op->ch2 != -1)
13702 total +=
13703 xmlXPathCompOpEval(ctxt,
13704 &comp->steps[op->ch2]);
13705 CHECK_ERROR0;
13706 res = valuePop(ctxt);
13707 if (res != NULL)
13708 xmlXPathFreeObject(res);
13709*/
13710 valuePush(ctxt, obj);
13711 ctxt->context->node = oldnode;
13712 CHECK_ERROR0;
13713 } else {
13714 tmp = NULL;
13715 /*
13716 * Initialize the new set.
13717 * Also set the xpath document in case things like
13718 * key() evaluation are attempted on the predicate
13719 */
13720 newset = xmlXPathNodeSetCreate(NULL);
13721 /*
13722 * SPEC XPath 1.0:
13723 * "For each node in the node-set to be filtered, the
13724 * PredicateExpr is evaluated with that node as the
13725 * context node, with the number of nodes in the
13726 * node-set as the context size, and with the proximity
13727 * position of the node in the node-set with respect to
13728 * the axis as the context position;"
13729 * @oldset is the node-set" to be filtered.
13730 *
13731 * SPEC XPath 1.0:
13732 * "only predicates change the context position and
13733 * context size (see [2.4 Predicates])."
13734 * Example:
13735 * node-set context pos
13736 * nA 1
13737 * nB 2
13738 * nC 3
13739 * After applying predicate [position() > 1] :
13740 * node-set context pos
13741 * nB 1
13742 * nC 2
13743 *
13744 * removed the first node in the node-set, then
13745 * the context position of the
13746 */
13747 for (i = 0; i < oldset->nodeNr; i++) {
13748 /*
13749 * Run the evaluation with a node list made of
13750 * a single item in the nodeset.
13751 */
13752 ctxt->context->node = oldset->nodeTab[i];
13753 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13754 (oldset->nodeTab[i]->doc != NULL))
13755 ctxt->context->doc = oldset->nodeTab[i]->doc;
13756 if (tmp == NULL) {
13757 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13758 ctxt->context->node);
13759 } else {
13760 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13761 ctxt->context->node);
13762 }
13763 valuePush(ctxt, tmp);
13764 ctxt->context->contextSize = oldset->nodeNr;
13765 ctxt->context->proximityPosition = i + 1;
13766 /*
13767 * Evaluate the predicate against the context node.
13768 * Can/should we optimize position() predicates
13769 * here (e.g. "[1]")?
13770 */
13771 if (op->ch2 != -1)
13772 total +=
13773 xmlXPathCompOpEval(ctxt,
13774 &comp->steps[op->ch2]);
13775 if (ctxt->error != XPATH_EXPRESSION_OK) {
13776 xmlXPathFreeNodeSet(newset);
13777 xmlXPathFreeObject(obj);
13778 return(0);
13779 }
13780
13781 /*
13782 * The result of the evaluation needs to be tested to
13783 * decide whether the filter succeeded or not
13784 */
13785 /*
13786 * OPTIMIZE TODO: Can we use
13787 * xmlXPathNodeSetAdd*Unique()* instead?
13788 */
13789 res = valuePop(ctxt);
13790 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13791 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13792 }
13793
13794 /*
13795 * Cleanup
13796 */
13797 if (res != NULL) {
13798 xmlXPathReleaseObject(ctxt->context, res);
13799 }
13800 if (ctxt->value == tmp) {
13801 valuePop(ctxt);
13802 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13803 /*
13804 * Don't free the temporary nodeset
13805 * in order to avoid massive recreation inside this
13806 * loop.
13807 */
13808 } else
13809 tmp = NULL;
13810 ctxt->context->node = NULL;
13811 }
13812 if (tmp != NULL)
13813 xmlXPathReleaseObject(ctxt->context, tmp);
13814 /*
13815 * The result is used as the new evaluation set.
13816 */
13817 xmlXPathReleaseObject(ctxt->context, obj);
13818 ctxt->context->node = NULL;
13819 ctxt->context->contextSize = -1;
13820 ctxt->context->proximityPosition = -1;
13821 /* may want to move this past the '}' later */
13822 ctxt->context->doc = oldDoc;
13823 valuePush(ctxt,
13824 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13825 }
13826 ctxt->context->node = oldnode;
13827 return (total);
13828 }
13829 case XPATH_OP_SORT:
13830 if (op->ch1 != -1)
13831 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13832 CHECK_ERROR0;
13833 if ((ctxt->value != NULL) &&
13834 (ctxt->value->type == XPATH_NODESET) &&
13835 (ctxt->value->nodesetval != NULL) &&
13836 (ctxt->value->nodesetval->nodeNr > 1))
13837 {
13838 xmlXPathNodeSetSort(ctxt->value->nodesetval);
13839 }
13840 return (total);
13841#ifdef LIBXML_XPTR_ENABLED
13842 case XPATH_OP_RANGETO:{
13843 xmlXPathObjectPtr range;
13844 xmlXPathObjectPtr res, obj;
13845 xmlXPathObjectPtr tmp;
13846 xmlLocationSetPtr newlocset = NULL;
13847 xmlLocationSetPtr oldlocset;
13848 xmlNodeSetPtr oldset;
13849 int i, j;
13850
13851 if (op->ch1 != -1)
13852 total +=
13853 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13854 if (op->ch2 == -1)
13855 return (total);
13856
13857 if (ctxt->value->type == XPATH_LOCATIONSET) {
13858 /*
13859 * Extract the old locset, and then evaluate the result of the
13860 * expression for all the element in the locset. use it to grow
13861 * up a new locset.
13862 */
13863 CHECK_TYPE0(XPATH_LOCATIONSET);
13864 obj = valuePop(ctxt);
13865 oldlocset = obj->user;
13866
13867 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13868 ctxt->context->node = NULL;
13869 ctxt->context->contextSize = 0;
13870 ctxt->context->proximityPosition = 0;
13871 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13872 res = valuePop(ctxt);
13873 if (res != NULL) {
13874 xmlXPathReleaseObject(ctxt->context, res);
13875 }
13876 valuePush(ctxt, obj);
13877 CHECK_ERROR0;
13878 return (total);
13879 }
13880 newlocset = xmlXPtrLocationSetCreate(NULL);
13881
13882 for (i = 0; i < oldlocset->locNr; i++) {
13883 /*
13884 * Run the evaluation with a node list made of a
13885 * single item in the nodelocset.
13886 */
13887 ctxt->context->node = oldlocset->locTab[i]->user;
13888 ctxt->context->contextSize = oldlocset->locNr;
13889 ctxt->context->proximityPosition = i + 1;
13890 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13891 ctxt->context->node);
13892 valuePush(ctxt, tmp);
13893
13894 if (op->ch2 != -1)
13895 total +=
13896 xmlXPathCompOpEval(ctxt,
13897 &comp->steps[op->ch2]);
13898 if (ctxt->error != XPATH_EXPRESSION_OK) {
13899 xmlXPathFreeObject(obj);
13900 return(0);
13901 }
13902
13903 res = valuePop(ctxt);
13904 if (res->type == XPATH_LOCATIONSET) {
13905 xmlLocationSetPtr rloc =
13906 (xmlLocationSetPtr)res->user;
13907 for (j=0; j<rloc->locNr; j++) {
13908 range = xmlXPtrNewRange(
13909 oldlocset->locTab[i]->user,
13910 oldlocset->locTab[i]->index,
13911 rloc->locTab[j]->user2,
13912 rloc->locTab[j]->index2);
13913 if (range != NULL) {
13914 xmlXPtrLocationSetAdd(newlocset, range);
13915 }
13916 }
13917 } else {
13918 range = xmlXPtrNewRangeNodeObject(
13919 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13920 if (range != NULL) {
13921 xmlXPtrLocationSetAdd(newlocset,range);
13922 }
13923 }
13924
13925 /*
13926 * Cleanup
13927 */
13928 if (res != NULL) {
13929 xmlXPathReleaseObject(ctxt->context, res);
13930 }
13931 if (ctxt->value == tmp) {
13932 res = valuePop(ctxt);
13933 xmlXPathReleaseObject(ctxt->context, res);
13934 }
13935
13936 ctxt->context->node = NULL;
13937 }
13938 } else { /* Not a location set */
13939 CHECK_TYPE0(XPATH_NODESET);
13940 obj = valuePop(ctxt);
13941 oldset = obj->nodesetval;
13942 ctxt->context->node = NULL;
13943
13944 newlocset = xmlXPtrLocationSetCreate(NULL);
13945
13946 if (oldset != NULL) {
13947 for (i = 0; i < oldset->nodeNr; i++) {
13948 /*
13949 * Run the evaluation with a node list made of a single item
13950 * in the nodeset.
13951 */
13952 ctxt->context->node = oldset->nodeTab[i];
13953 /*
13954 * OPTIMIZE TODO: Avoid recreation for every iteration.
13955 */
13956 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13957 ctxt->context->node);
13958 valuePush(ctxt, tmp);
13959
13960 if (op->ch2 != -1)
13961 total +=
13962 xmlXPathCompOpEval(ctxt,
13963 &comp->steps[op->ch2]);
13964 if (ctxt->error != XPATH_EXPRESSION_OK) {
13965 xmlXPathFreeObject(obj);
13966 return(0);
13967 }
13968
13969 res = valuePop(ctxt);
13970 range =
13971 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13972 res);
13973 if (range != NULL) {
13974 xmlXPtrLocationSetAdd(newlocset, range);
13975 }
13976
13977 /*
13978 * Cleanup
13979 */
13980 if (res != NULL) {
13981 xmlXPathReleaseObject(ctxt->context, res);
13982 }
13983 if (ctxt->value == tmp) {
13984 res = valuePop(ctxt);
13985 xmlXPathReleaseObject(ctxt->context, res);
13986 }
13987
13988 ctxt->context->node = NULL;
13989 }
13990 }
13991 }
13992
13993 /*
13994 * The result is used as the new evaluation set.
13995 */
13996 xmlXPathReleaseObject(ctxt->context, obj);
13997 ctxt->context->node = NULL;
13998 ctxt->context->contextSize = -1;
13999 ctxt->context->proximityPosition = -1;
14000 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
14001 return (total);
14002 }
14003#endif /* LIBXML_XPTR_ENABLED */
14004 }
14005 xmlGenericError(xmlGenericErrorContext,
14006 "XPath: unknown precompiled operation %d\n", op->op);
14007 ctxt->error = XPATH_INVALID_OPERAND;
14008 return (total);
14009}
14010
14011/**
14012 * xmlXPathCompOpEvalToBoolean:
14013 * @ctxt: the XPath parser context
14014 *
14015 * Evaluates if the expression evaluates to true.
14016 *
14017 * Returns 1 if true, 0 if false and -1 on API or internal errors.
14018 */
14019static int
14020xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
14021 xmlXPathStepOpPtr op,
14022 int isPredicate)
14023{
14024 xmlXPathObjectPtr resObj = NULL;
14025
14026start:
14027 /* comp = ctxt->comp; */
14028 switch (op->op) {
14029 case XPATH_OP_END:
14030 return (0);
14031 case XPATH_OP_VALUE:
14032 resObj = (xmlXPathObjectPtr) op->value4;
14033 if (isPredicate)
14034 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14035 return(xmlXPathCastToBoolean(resObj));
14036 case XPATH_OP_SORT:
14037 /*
14038 * We don't need sorting for boolean results. Skip this one.
14039 */
14040 if (op->ch1 != -1) {
14041 op = &ctxt->comp->steps[op->ch1];
14042 goto start;
14043 }
14044 return(0);
14045 case XPATH_OP_COLLECT:
14046 if (op->ch1 == -1)
14047 return(0);
14048
14049 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14050 if (ctxt->error != XPATH_EXPRESSION_OK)
14051 return(-1);
14052
14053 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14054 if (ctxt->error != XPATH_EXPRESSION_OK)
14055 return(-1);
14056
14057 resObj = valuePop(ctxt);
14058 if (resObj == NULL)
14059 return(-1);
14060 break;
14061 default:
14062 /*
14063 * Fallback to call xmlXPathCompOpEval().
14064 */
14065 xmlXPathCompOpEval(ctxt, op);
14066 if (ctxt->error != XPATH_EXPRESSION_OK)
14067 return(-1);
14068
14069 resObj = valuePop(ctxt);
14070 if (resObj == NULL)
14071 return(-1);
14072 break;
14073 }
14074
14075 if (resObj) {
14076 int res;
14077
14078 if (resObj->type == XPATH_BOOLEAN) {
14079 res = resObj->boolval;
14080 } else if (isPredicate) {
14081 /*
14082 * For predicates a result of type "number" is handled
14083 * differently:
14084 * SPEC XPath 1.0:
14085 * "If the result is a number, the result will be converted
14086 * to true if the number is equal to the context position
14087 * and will be converted to false otherwise;"
14088 */
14089 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14090 } else {
14091 res = xmlXPathCastToBoolean(resObj);
14092 }
14093 xmlXPathReleaseObject(ctxt->context, resObj);
14094 return(res);
14095 }
14096
14097 return(0);
14098}
14099
14100#ifdef XPATH_STREAMING
14101/**
14102 * xmlXPathRunStreamEval:
14103 * @ctxt: the XPath parser context with the compiled expression
14104 *
14105 * Evaluate the Precompiled Streamable XPath expression in the given context.
14106 */
14107static int
14108xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14109 xmlXPathObjectPtr *resultSeq, int toBool)
14110{
14111 int max_depth, min_depth;
14112 int from_root;
14113 int ret, depth;
14114 int eval_all_nodes;
14115 xmlNodePtr cur = NULL, limit = NULL;
14116 xmlStreamCtxtPtr patstream = NULL;
14117
14118 int nb_nodes = 0;
14119
14120 if ((ctxt == NULL) || (comp == NULL))
14121 return(-1);
14122 max_depth = xmlPatternMaxDepth(comp);
14123 if (max_depth == -1)
14124 return(-1);
14125 if (max_depth == -2)
14126 max_depth = 10000;
14127 min_depth = xmlPatternMinDepth(comp);
14128 if (min_depth == -1)
14129 return(-1);
14130 from_root = xmlPatternFromRoot(comp);
14131 if (from_root < 0)
14132 return(-1);
14133#if 0
14134 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14135#endif
14136
14137 if (! toBool) {
14138 if (resultSeq == NULL)
14139 return(-1);
14140 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14141 if (*resultSeq == NULL)
14142 return(-1);
14143 }
14144
14145 /*
14146 * handle the special cases of "/" amd "." being matched
14147 */
14148 if (min_depth == 0) {
14149 if (from_root) {
14150 /* Select "/" */
14151 if (toBool)
14152 return(1);
14153 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14154 (xmlNodePtr) ctxt->doc);
14155 } else {
14156 /* Select "self::node()" */
14157 if (toBool)
14158 return(1);
14159 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14160 }
14161 }
14162 if (max_depth == 0) {
14163 return(0);
14164 }
14165
14166 if (from_root) {
14167 cur = (xmlNodePtr)ctxt->doc;
14168 } else if (ctxt->node != NULL) {
14169 switch (ctxt->node->type) {
14170 case XML_ELEMENT_NODE:
14171 case XML_DOCUMENT_NODE:
14172 case XML_DOCUMENT_FRAG_NODE:
14173 case XML_HTML_DOCUMENT_NODE:
14174#ifdef LIBXML_DOCB_ENABLED
14175 case XML_DOCB_DOCUMENT_NODE:
14176#endif
14177 cur = ctxt->node;
14178 break;
14179 case XML_ATTRIBUTE_NODE:
14180 case XML_TEXT_NODE:
14181 case XML_CDATA_SECTION_NODE:
14182 case XML_ENTITY_REF_NODE:
14183 case XML_ENTITY_NODE:
14184 case XML_PI_NODE:
14185 case XML_COMMENT_NODE:
14186 case XML_NOTATION_NODE:
14187 case XML_DTD_NODE:
14188 case XML_DOCUMENT_TYPE_NODE:
14189 case XML_ELEMENT_DECL:
14190 case XML_ATTRIBUTE_DECL:
14191 case XML_ENTITY_DECL:
14192 case XML_NAMESPACE_DECL:
14193 case XML_XINCLUDE_START:
14194 case XML_XINCLUDE_END:
14195 break;
14196 }
14197 limit = cur;
14198 }
14199 if (cur == NULL) {
14200 return(0);
14201 }
14202
14203 patstream = xmlPatternGetStreamCtxt(comp);
14204 if (patstream == NULL) {
14205 /*
14206 * QUESTION TODO: Is this an error?
14207 */
14208 return(0);
14209 }
14210
14211 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14212
14213 if (from_root) {
14214 ret = xmlStreamPush(patstream, NULL, NULL);
14215 if (ret < 0) {
14216 } else if (ret == 1) {
14217 if (toBool)
14218 goto return_1;
14219 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14220 }
14221 }
14222 depth = 0;
14223 goto scan_children;
14224next_node:
14225 do {
14226 nb_nodes++;
14227
14228 switch (cur->type) {
14229 case XML_ELEMENT_NODE:
14230 case XML_TEXT_NODE:
14231 case XML_CDATA_SECTION_NODE:
14232 case XML_COMMENT_NODE:
14233 case XML_PI_NODE:
14234 if (cur->type == XML_ELEMENT_NODE) {
14235 ret = xmlStreamPush(patstream, cur->name,
14236 (cur->ns ? cur->ns->href : NULL));
14237 } else if (eval_all_nodes)
14238 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14239 else
14240 break;
14241
14242 if (ret < 0) {
14243 /* NOP. */
14244 } else if (ret == 1) {
14245 if (toBool)
14246 goto return_1;
14247 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14248 }
14249 if ((cur->children == NULL) || (depth >= max_depth)) {
14250 ret = xmlStreamPop(patstream);
14251 while (cur->next != NULL) {
14252 cur = cur->next;
14253 if ((cur->type != XML_ENTITY_DECL) &&
14254 (cur->type != XML_DTD_NODE))
14255 goto next_node;
14256 }
14257 }
14258 default:
14259 break;
14260 }
14261
14262scan_children:
14263 if ((cur->children != NULL) && (depth < max_depth)) {
14264 /*
14265 * Do not descend on entities declarations
14266 */
14267 if (cur->children->type != XML_ENTITY_DECL) {
14268 cur = cur->children;
14269 depth++;
14270 /*
14271 * Skip DTDs
14272 */
14273 if (cur->type != XML_DTD_NODE)
14274 continue;
14275 }
14276 }
14277
14278 if (cur == limit)
14279 break;
14280
14281 while (cur->next != NULL) {
14282 cur = cur->next;
14283 if ((cur->type != XML_ENTITY_DECL) &&
14284 (cur->type != XML_DTD_NODE))
14285 goto next_node;
14286 }
14287
14288 do {
14289 cur = cur->parent;
14290 depth--;
14291 if ((cur == NULL) || (cur == limit))
14292 goto done;
14293 if (cur->type == XML_ELEMENT_NODE) {
14294 ret = xmlStreamPop(patstream);
14295 } else if ((eval_all_nodes) &&
14296 ((cur->type == XML_TEXT_NODE) ||
14297 (cur->type == XML_CDATA_SECTION_NODE) ||
14298 (cur->type == XML_COMMENT_NODE) ||
14299 (cur->type == XML_PI_NODE)))
14300 {
14301 ret = xmlStreamPop(patstream);
14302 }
14303 if (cur->next != NULL) {
14304 cur = cur->next;
14305 break;
14306 }
14307 } while (cur != NULL);
14308
14309 } while ((cur != NULL) && (depth >= 0));
14310
14311done:
14312
14313#if 0
14314 printf("stream eval: checked %d nodes selected %d\n",
14315 nb_nodes, retObj->nodesetval->nodeNr);
14316#endif
14317
14318 if (patstream)
14319 xmlFreeStreamCtxt(patstream);
14320 return(0);
14321
14322return_1:
14323 if (patstream)
14324 xmlFreeStreamCtxt(patstream);
14325 return(1);
14326}
14327#endif /* XPATH_STREAMING */
14328
14329/**
14330 * xmlXPathRunEval:
14331 * @ctxt: the XPath parser context with the compiled expression
14332 * @toBool: evaluate to a boolean result
14333 *
14334 * Evaluate the Precompiled XPath expression in the given context.
14335 */
14336static int
14337xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14338{
14339 xmlXPathCompExprPtr comp;
14340
14341 if ((ctxt == NULL) || (ctxt->comp == NULL))
14342 return(-1);
14343
14344 if (ctxt->valueTab == NULL) {
14345 /* Allocate the value stack */
14346 ctxt->valueTab = (xmlXPathObjectPtr *)
14347 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14348 if (ctxt->valueTab == NULL) {
14349 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14350 xmlFree(ctxt);
14351 }
14352 ctxt->valueNr = 0;
14353 ctxt->valueMax = 10;
14354 ctxt->value = NULL;
14355 ctxt->valueFrame = 0;
14356 }
14357#ifdef XPATH_STREAMING
14358 if (ctxt->comp->stream) {
14359 int res;
14360
14361 if (toBool) {
14362 /*
14363 * Evaluation to boolean result.
14364 */
14365 res = xmlXPathRunStreamEval(ctxt->context,
14366 ctxt->comp->stream, NULL, 1);
14367 if (res != -1)
14368 return(res);
14369 } else {
14370 xmlXPathObjectPtr resObj = NULL;
14371
14372 /*
14373 * Evaluation to a sequence.
14374 */
14375 res = xmlXPathRunStreamEval(ctxt->context,
14376 ctxt->comp->stream, &resObj, 0);
14377
14378 if ((res != -1) && (resObj != NULL)) {
14379 valuePush(ctxt, resObj);
14380 return(0);
14381 }
14382 if (resObj != NULL)
14383 xmlXPathReleaseObject(ctxt->context, resObj);
14384 }
14385 /*
14386 * QUESTION TODO: This falls back to normal XPath evaluation
14387 * if res == -1. Is this intended?
14388 */
14389 }
14390#endif
14391 comp = ctxt->comp;
14392 if (comp->last < 0) {
14393 xmlGenericError(xmlGenericErrorContext,
14394 "xmlXPathRunEval: last is less than zero\n");
14395 return(-1);
14396 }
14397 if (toBool)
14398 return(xmlXPathCompOpEvalToBoolean(ctxt,
14399 &comp->steps[comp->last], 0));
14400 else
14401 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14402
14403 return(0);
14404}
14405
14406/************************************************************************
14407 * *
14408 * Public interfaces *
14409 * *
14410 ************************************************************************/
14411
14412/**
14413 * xmlXPathEvalPredicate:
14414 * @ctxt: the XPath context
14415 * @res: the Predicate Expression evaluation result
14416 *
14417 * Evaluate a predicate result for the current node.
14418 * A PredicateExpr is evaluated by evaluating the Expr and converting
14419 * the result to a boolean. If the result is a number, the result will
14420 * be converted to true if the number is equal to the position of the
14421 * context node in the context node list (as returned by the position
14422 * function) and will be converted to false otherwise; if the result
14423 * is not a number, then the result will be converted as if by a call
14424 * to the boolean function.
14425 *
14426 * Returns 1 if predicate is true, 0 otherwise
14427 */
14428int
14429xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14430 if ((ctxt == NULL) || (res == NULL)) return(0);
14431 switch (res->type) {
14432 case XPATH_BOOLEAN:
14433 return(res->boolval);
14434 case XPATH_NUMBER:
14435 return(res->floatval == ctxt->proximityPosition);
14436 case XPATH_NODESET:
14437 case XPATH_XSLT_TREE:
14438 if (res->nodesetval == NULL)
14439 return(0);
14440 return(res->nodesetval->nodeNr != 0);
14441 case XPATH_STRING:
14442 return((res->stringval != NULL) &&
14443 (xmlStrlen(res->stringval) != 0));
14444 default:
14445 STRANGE
14446 }
14447 return(0);
14448}
14449
14450/**
14451 * xmlXPathEvaluatePredicateResult:
14452 * @ctxt: the XPath Parser context
14453 * @res: the Predicate Expression evaluation result
14454 *
14455 * Evaluate a predicate result for the current node.
14456 * A PredicateExpr is evaluated by evaluating the Expr and converting
14457 * the result to a boolean. If the result is a number, the result will
14458 * be converted to true if the number is equal to the position of the
14459 * context node in the context node list (as returned by the position
14460 * function) and will be converted to false otherwise; if the result
14461 * is not a number, then the result will be converted as if by a call
14462 * to the boolean function.
14463 *
14464 * Returns 1 if predicate is true, 0 otherwise
14465 */
14466int
14467xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14468 xmlXPathObjectPtr res) {
14469 if ((ctxt == NULL) || (res == NULL)) return(0);
14470 switch (res->type) {
14471 case XPATH_BOOLEAN:
14472 return(res->boolval);
14473 case XPATH_NUMBER:
14474#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14475 return((res->floatval == ctxt->context->proximityPosition) &&
14476 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14477#else
14478 return(res->floatval == ctxt->context->proximityPosition);
14479#endif
14480 case XPATH_NODESET:
14481 case XPATH_XSLT_TREE:
14482 if (res->nodesetval == NULL)
14483 return(0);
14484 return(res->nodesetval->nodeNr != 0);
14485 case XPATH_STRING:
14486 return((res->stringval != NULL) && (res->stringval[0] != 0));
14487#ifdef LIBXML_XPTR_ENABLED
14488 case XPATH_LOCATIONSET:{
14489 xmlLocationSetPtr ptr = res->user;
14490 if (ptr == NULL)
14491 return(0);
14492 return (ptr->locNr != 0);
14493 }
14494#endif
14495 default:
14496 STRANGE
14497 }
14498 return(0);
14499}
14500
14501#ifdef XPATH_STREAMING
14502/**
14503 * xmlXPathTryStreamCompile:
14504 * @ctxt: an XPath context
14505 * @str: the XPath expression
14506 *
14507 * Try to compile the XPath expression as a streamable subset.
14508 *
14509 * Returns the compiled expression or NULL if failed to compile.
14510 */
14511static xmlXPathCompExprPtr
14512xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14513 /*
14514 * Optimization: use streaming patterns when the XPath expression can
14515 * be compiled to a stream lookup
14516 */
14517 xmlPatternPtr stream;
14518 xmlXPathCompExprPtr comp;
14519 xmlDictPtr dict = NULL;
14520 const xmlChar **namespaces = NULL;
14521 xmlNsPtr ns;
14522 int i, j;
14523
14524 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14525 (!xmlStrchr(str, '@'))) {
14526 const xmlChar *tmp;
14527
14528 /*
14529 * We don't try to handle expressions using the verbose axis
14530 * specifiers ("::"), just the simplied form at this point.
14531 * Additionally, if there is no list of namespaces available and
14532 * there's a ":" in the expression, indicating a prefixed QName,
14533 * then we won't try to compile either. xmlPatterncompile() needs
14534 * to have a list of namespaces at compilation time in order to
14535 * compile prefixed name tests.
14536 */
14537 tmp = xmlStrchr(str, ':');
14538 if ((tmp != NULL) &&
14539 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14540 return(NULL);
14541
14542 if (ctxt != NULL) {
14543 dict = ctxt->dict;
14544 if (ctxt->nsNr > 0) {
14545 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14546 if (namespaces == NULL) {
14547 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14548 return(NULL);
14549 }
14550 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14551 ns = ctxt->namespaces[j];
14552 namespaces[i++] = ns->href;
14553 namespaces[i++] = ns->prefix;
14554 }
14555 namespaces[i++] = NULL;
14556 namespaces[i++] = NULL;
14557 }
14558 }
14559
14560 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14561 &namespaces[0]);
14562 if (namespaces != NULL) {
14563 xmlFree((xmlChar **)namespaces);
14564 }
14565 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14566 comp = xmlXPathNewCompExpr();
14567 if (comp == NULL) {
14568 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14569 return(NULL);
14570 }
14571 comp->stream = stream;
14572 comp->dict = dict;
14573 if (comp->dict)
14574 xmlDictReference(comp->dict);
14575 return(comp);
14576 }
14577 xmlFreePattern(stream);
14578 }
14579 return(NULL);
14580}
14581#endif /* XPATH_STREAMING */
14582
14583static int
14584xmlXPathCanRewriteDosExpression(xmlChar *expr)
14585{
14586 if (expr == NULL)
14587 return(0);
14588 do {
14589 if ((*expr == '/') && (*(++expr) == '/'))
14590 return(1);
14591 } while (*expr++);
14592 return(0);
14593}
14594static void
14595xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14596{
14597 /*
14598 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14599 * internal representation.
14600 */
14601 if (op->ch1 != -1) {
14602 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14603 ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
14604 ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14605 ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14606 {
14607 /*
14608 * This is a "child::foo"
14609 */
14610 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14611
14612 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14613 (prevop->ch1 != -1) &&
14614 ((xmlXPathAxisVal) prevop->value ==
14615 AXIS_DESCENDANT_OR_SELF) &&
14616 (prevop->ch2 == -1) &&
14617 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14618 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
14619 (comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
14620 {
14621 /*
14622 * This is a "/descendant-or-self::node()" without predicates.
14623 * Eliminate it.
14624 */
14625 op->ch1 = prevop->ch1;
14626 op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
14627 }
14628 }
14629 if (op->ch1 != -1)
14630 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14631 }
14632 if (op->ch2 != -1)
14633 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14634}
14635
14636/**
14637 * xmlXPathCtxtCompile:
14638 * @ctxt: an XPath context
14639 * @str: the XPath expression
14640 *
14641 * Compile an XPath expression
14642 *
14643 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14644 * the caller has to free the object.
14645 */
14646xmlXPathCompExprPtr
14647xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14648 xmlXPathParserContextPtr pctxt;
14649 xmlXPathCompExprPtr comp;
14650
14651#ifdef XPATH_STREAMING
14652 comp = xmlXPathTryStreamCompile(ctxt, str);
14653 if (comp != NULL)
14654 return(comp);
14655#endif
14656
14657 xmlXPathInit();
14658
14659 pctxt = xmlXPathNewParserContext(str, ctxt);
14660 if (pctxt == NULL)
14661 return NULL;
14662 xmlXPathCompileExpr(pctxt, 1);
14663
14664 if( pctxt->error != XPATH_EXPRESSION_OK )
14665 {
14666 xmlXPathFreeParserContext(pctxt);
14667 return(NULL);
14668 }
14669
14670 if (*pctxt->cur != 0) {
14671 /*
14672 * aleksey: in some cases this line prints *second* error message
14673 * (see bug #78858) and probably this should be fixed.
14674 * However, we are not sure that all error messages are printed
14675 * out in other places. It's not critical so we leave it as-is for now
14676 */
14677 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14678 comp = NULL;
14679 } else {
14680 comp = pctxt->comp;
14681 pctxt->comp = NULL;
14682 }
14683 xmlXPathFreeParserContext(pctxt);
14684
14685 if (comp != NULL) {
14686 comp->expr = xmlStrdup(str);
14687#ifdef DEBUG_EVAL_COUNTS
14688 comp->string = xmlStrdup(str);
14689 comp->nb = 0;
14690#endif
14691 if ((comp->expr != NULL) &&
14692 (comp->nbStep > 2) &&
14693 (comp->last >= 0) &&
14694 (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14695 {
14696 xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
14697 }
14698 }
14699 return(comp);
14700}
14701
14702/**
14703 * xmlXPathCompile:
14704 * @str: the XPath expression
14705 *
14706 * Compile an XPath expression
14707 *
14708 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14709 * the caller has to free the object.
14710 */
14711xmlXPathCompExprPtr
14712xmlXPathCompile(const xmlChar *str) {
14713 return(xmlXPathCtxtCompile(NULL, str));
14714}
14715
14716/**
14717 * xmlXPathCompiledEvalInternal:
14718 * @comp: the compiled XPath expression
14719 * @ctxt: the XPath context
14720 * @resObj: the resulting XPath object or NULL
14721 * @toBool: 1 if only a boolean result is requested
14722 *
14723 * Evaluate the Precompiled XPath expression in the given context.
14724 * The caller has to free @resObj.
14725 *
14726 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14727 * the caller has to free the object.
14728 */
14729static int
14730xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14731 xmlXPathContextPtr ctxt,
14732 xmlXPathObjectPtr *resObj,
14733 int toBool)
14734{
14735 xmlXPathParserContextPtr pctxt;
14736#ifndef LIBXML_THREAD_ENABLED
14737 static int reentance = 0;
14738#endif
14739 int res;
14740
14741 CHECK_CTXT_NEG(ctxt)
14742
14743 if (comp == NULL)
14744 return(-1);
14745 xmlXPathInit();
14746
14747#ifndef LIBXML_THREAD_ENABLED
14748 reentance++;
14749 if (reentance > 1)
14750 xmlXPathDisableOptimizer = 1;
14751#endif
14752
14753#ifdef DEBUG_EVAL_COUNTS
14754 comp->nb++;
14755 if ((comp->string != NULL) && (comp->nb > 100)) {
14756 fprintf(stderr, "100 x %s\n", comp->string);
14757 comp->nb = 0;
14758 }
14759#endif
14760 pctxt = xmlXPathCompParserContext(comp, ctxt);
14761 res = xmlXPathRunEval(pctxt, toBool);
14762
14763 if (resObj) {
14764 if (pctxt->value == NULL) {
14765 xmlGenericError(xmlGenericErrorContext,
14766 "xmlXPathCompiledEval: evaluation failed\n");
14767 *resObj = NULL;
14768 } else {
14769 *resObj = valuePop(pctxt);
14770 }
14771 }
14772
14773 /*
14774 * Pop all remaining objects from the stack.
14775 */
14776 if (pctxt->valueNr > 0) {
14777 xmlXPathObjectPtr tmp;
14778 int stack = 0;
14779
14780 do {
14781 tmp = valuePop(pctxt);
14782 if (tmp != NULL) {
14783 stack++;
14784 xmlXPathReleaseObject(ctxt, tmp);
14785 }
14786 } while (tmp != NULL);
14787 if ((stack != 0) &&
14788 ((toBool) || ((resObj) && (*resObj))))
14789 {
14790 xmlGenericError(xmlGenericErrorContext,
14791 "xmlXPathCompiledEval: %d objects left on the stack.\n",
14792 stack);
14793 }
14794 }
14795
14796 if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14797 xmlXPathFreeObject(*resObj);
14798 *resObj = NULL;
14799 }
14800 pctxt->comp = NULL;
14801 xmlXPathFreeParserContext(pctxt);
14802#ifndef LIBXML_THREAD_ENABLED
14803 reentance--;
14804#endif
14805
14806 return(res);
14807}
14808
14809/**
14810 * xmlXPathCompiledEval:
14811 * @comp: the compiled XPath expression
14812 * @ctx: the XPath context
14813 *
14814 * Evaluate the Precompiled XPath expression in the given context.
14815 *
14816 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14817 * the caller has to free the object.
14818 */
14819xmlXPathObjectPtr
14820xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14821{
14822 xmlXPathObjectPtr res = NULL;
14823
14824 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14825 return(res);
14826}
14827
14828/**
14829 * xmlXPathCompiledEvalToBoolean:
14830 * @comp: the compiled XPath expression
14831 * @ctxt: the XPath context
14832 *
14833 * Applies the XPath boolean() function on the result of the given
14834 * compiled expression.
14835 *
14836 * Returns 1 if the expression evaluated to true, 0 if to false and
14837 * -1 in API and internal errors.
14838 */
14839int
14840xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14841 xmlXPathContextPtr ctxt)
14842{
14843 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14844}
14845
14846/**
14847 * xmlXPathEvalExpr:
14848 * @ctxt: the XPath Parser context
14849 *
14850 * Parse and evaluate an XPath expression in the given context,
14851 * then push the result on the context stack
14852 */
14853void
14854xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14855#ifdef XPATH_STREAMING
14856 xmlXPathCompExprPtr comp;
14857#endif
14858
14859 if (ctxt == NULL) return;
14860
14861#ifdef XPATH_STREAMING
14862 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14863 if (comp != NULL) {
14864 if (ctxt->comp != NULL)
14865 xmlXPathFreeCompExpr(ctxt->comp);
14866 ctxt->comp = comp;
14867 if (ctxt->cur != NULL)
14868 while (*ctxt->cur != 0) ctxt->cur++;
14869 } else
14870#endif
14871 {
14872 xmlXPathCompileExpr(ctxt, 1);
14873 /*
14874 * In this scenario the expression string will sit in ctxt->base.
14875 */
14876 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14877 (ctxt->comp != NULL) &&
14878 (ctxt->base != NULL) &&
14879 (ctxt->comp->nbStep > 2) &&
14880 (ctxt->comp->last >= 0) &&
14881 (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
14882 {
14883 xmlXPathRewriteDOSExpression(ctxt->comp,
14884 &ctxt->comp->steps[ctxt->comp->last]);
14885 }
14886 }
14887 CHECK_ERROR;
14888 xmlXPathRunEval(ctxt, 0);
14889}
14890
14891/**
14892 * xmlXPathEval:
14893 * @str: the XPath expression
14894 * @ctx: the XPath context
14895 *
14896 * Evaluate the XPath Location Path in the given context.
14897 *
14898 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14899 * the caller has to free the object.
14900 */
14901xmlXPathObjectPtr
14902xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14903 xmlXPathParserContextPtr ctxt;
14904 xmlXPathObjectPtr res, tmp, init = NULL;
14905 int stack = 0;
14906
14907 CHECK_CTXT(ctx)
14908
14909 xmlXPathInit();
14910
14911 ctxt = xmlXPathNewParserContext(str, ctx);
14912 if (ctxt == NULL)
14913 return NULL;
14914 xmlXPathEvalExpr(ctxt);
14915
14916 if (ctxt->value == NULL) {
14917 xmlGenericError(xmlGenericErrorContext,
14918 "xmlXPathEval: evaluation failed\n");
14919 res = NULL;
14920 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
14921#ifdef XPATH_STREAMING
14922 && (ctxt->comp->stream == NULL)
14923#endif
14924 ) {
14925 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14926 res = NULL;
14927 } else {
14928 res = valuePop(ctxt);
14929 }
14930
14931 do {
14932 tmp = valuePop(ctxt);
14933 if (tmp != NULL) {
14934 if (tmp != init)
14935 stack++;
14936 xmlXPathReleaseObject(ctx, tmp);
14937 }
14938 } while (tmp != NULL);
14939 if ((stack != 0) && (res != NULL)) {
14940 xmlGenericError(xmlGenericErrorContext,
14941 "xmlXPathEval: %d object left on the stack\n",
14942 stack);
14943 }
14944 if (ctxt->error != XPATH_EXPRESSION_OK) {
14945 xmlXPathFreeObject(res);
14946 res = NULL;
14947 }
14948
14949 xmlXPathFreeParserContext(ctxt);
14950 return(res);
14951}
14952
14953/**
14954 * xmlXPathEvalExpression:
14955 * @str: the XPath expression
14956 * @ctxt: the XPath context
14957 *
14958 * Evaluate the XPath expression in the given context.
14959 *
14960 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14961 * the caller has to free the object.
14962 */
14963xmlXPathObjectPtr
14964xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14965 xmlXPathParserContextPtr pctxt;
14966 xmlXPathObjectPtr res, tmp;
14967 int stack = 0;
14968
14969 CHECK_CTXT(ctxt)
14970
14971 xmlXPathInit();
14972
14973 pctxt = xmlXPathNewParserContext(str, ctxt);
14974 if (pctxt == NULL)
14975 return NULL;
14976 xmlXPathEvalExpr(pctxt);
14977
14978 if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
14979 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14980 res = NULL;
14981 } else {
14982 res = valuePop(pctxt);
14983 }
14984 do {
14985 tmp = valuePop(pctxt);
14986 if (tmp != NULL) {
14987 xmlXPathReleaseObject(ctxt, tmp);
14988 stack++;
14989 }
14990 } while (tmp != NULL);
14991 if ((stack != 0) && (res != NULL)) {
14992 xmlGenericError(xmlGenericErrorContext,
14993 "xmlXPathEvalExpression: %d object left on the stack\n",
14994 stack);
14995 }
14996 xmlXPathFreeParserContext(pctxt);
14997 return(res);
14998}
14999
15000/************************************************************************
15001 * *
15002 * Extra functions not pertaining to the XPath spec *
15003 * *
15004 ************************************************************************/
15005/**
15006 * xmlXPathEscapeUriFunction:
15007 * @ctxt: the XPath Parser context
15008 * @nargs: the number of arguments
15009 *
15010 * Implement the escape-uri() XPath function
15011 * string escape-uri(string $str, bool $escape-reserved)
15012 *
15013 * This function applies the URI escaping rules defined in section 2 of [RFC
15014 * 2396] to the string supplied as $uri-part, which typically represents all
15015 * or part of a URI. The effect of the function is to replace any special
15016 * character in the string by an escape sequence of the form %xx%yy...,
15017 * where xxyy... is the hexadecimal representation of the octets used to
15018 * represent the character in UTF-8.
15019 *
15020 * The set of characters that are escaped depends on the setting of the
15021 * boolean argument $escape-reserved.
15022 *
15023 * If $escape-reserved is true, all characters are escaped other than lower
15024 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15025 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15026 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15027 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15028 * A-F).
15029 *
15030 * If $escape-reserved is false, the behavior differs in that characters
15031 * referred to in [RFC 2396] as reserved characters are not escaped. These
15032 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
15033 *
15034 * [RFC 2396] does not define whether escaped URIs should use lower case or
15035 * upper case for hexadecimal digits. To ensure that escaped URIs can be
15036 * compared using string comparison functions, this function must always use
15037 * the upper-case letters A-F.
15038 *
15039 * Generally, $escape-reserved should be set to true when escaping a string
15040 * that is to form a single part of a URI, and to false when escaping an
15041 * entire URI or URI reference.
15042 *
15043 * In the case of non-ascii characters, the string is encoded according to
15044 * utf-8 and then converted according to RFC 2396.
15045 *
15046 * Examples
15047 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
15048 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15049 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15050 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15051 *
15052 */
15053static void
15054xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15055 xmlXPathObjectPtr str;
15056 int escape_reserved;
15057 xmlBufferPtr target;
15058 xmlChar *cptr;
15059 xmlChar escape[4];
15060
15061 CHECK_ARITY(2);
15062
15063 escape_reserved = xmlXPathPopBoolean(ctxt);
15064
15065 CAST_TO_STRING;
15066 str = valuePop(ctxt);
15067
15068 target = xmlBufferCreate();
15069
15070 escape[0] = '%';
15071 escape[3] = 0;
15072
15073 if (target) {
15074 for (cptr = str->stringval; *cptr; cptr++) {
15075 if ((*cptr >= 'A' && *cptr <= 'Z') ||
15076 (*cptr >= 'a' && *cptr <= 'z') ||
15077 (*cptr >= '0' && *cptr <= '9') ||
15078 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
15079 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
15080 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
15081 (*cptr == '%' &&
15082 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15083 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15084 (cptr[1] >= '0' && cptr[1] <= '9')) &&
15085 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15086 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15087 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15088 (!escape_reserved &&
15089 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15090 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15091 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15092 *cptr == ','))) {
15093 xmlBufferAdd(target, cptr, 1);
15094 } else {
15095 if ((*cptr >> 4) < 10)
15096 escape[1] = '0' + (*cptr >> 4);
15097 else
15098 escape[1] = 'A' - 10 + (*cptr >> 4);
15099 if ((*cptr & 0xF) < 10)
15100 escape[2] = '0' + (*cptr & 0xF);
15101 else
15102 escape[2] = 'A' - 10 + (*cptr & 0xF);
15103
15104 xmlBufferAdd(target, &escape[0], 3);
15105 }
15106 }
15107 }
15108 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15109 xmlBufferContent(target)));
15110 xmlBufferFree(target);
15111 xmlXPathReleaseObject(ctxt->context, str);
15112}
15113
15114/**
15115 * xmlXPathRegisterAllFunctions:
15116 * @ctxt: the XPath context
15117 *
15118 * Registers all default XPath functions in this context
15119 */
15120void
15121xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15122{
15123 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15124 xmlXPathBooleanFunction);
15125 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15126 xmlXPathCeilingFunction);
15127 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15128 xmlXPathCountFunction);
15129 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15130 xmlXPathConcatFunction);
15131 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15132 xmlXPathContainsFunction);
15133 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15134 xmlXPathIdFunction);
15135 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15136 xmlXPathFalseFunction);
15137 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15138 xmlXPathFloorFunction);
15139 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15140 xmlXPathLastFunction);
15141 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15142 xmlXPathLangFunction);
15143 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15144 xmlXPathLocalNameFunction);
15145 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15146 xmlXPathNotFunction);
15147 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15148 xmlXPathNameFunction);
15149 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15150 xmlXPathNamespaceURIFunction);
15151 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15152 xmlXPathNormalizeFunction);
15153 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15154 xmlXPathNumberFunction);
15155 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15156 xmlXPathPositionFunction);
15157 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15158 xmlXPathRoundFunction);
15159 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15160 xmlXPathStringFunction);
15161 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15162 xmlXPathStringLengthFunction);
15163 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15164 xmlXPathStartsWithFunction);
15165 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15166 xmlXPathSubstringFunction);
15167 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15168 xmlXPathSubstringBeforeFunction);
15169 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15170 xmlXPathSubstringAfterFunction);
15171 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15172 xmlXPathSumFunction);
15173 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15174 xmlXPathTrueFunction);
15175 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15176 xmlXPathTranslateFunction);
15177
15178 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15179 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15180 xmlXPathEscapeUriFunction);
15181}
15182
15183#endif /* LIBXML_XPATH_ENABLED */
15184#define bottom_xpath
15185#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