Annotation of embedaddon/libxml2/xpath.c, revision 1.1.1.2
1.1 misho 1: /*
2: * xpath.c: XML Path Language implementation
3: * XPath is a language for addressing parts of an XML document,
4: * designed to be used by both XSLT and XPointer
5: *f
6: * Reference: W3C Recommendation 16 November 1999
7: * http://www.w3.org/TR/1999/REC-xpath-19991116
8: * Public reference:
9: * http://www.w3.org/TR/xpath
10: *
11: * See Copyright for the status of this software
12: *
13: * Author: daniel@veillard.com
14: *
15: */
16:
17: #define IN_LIBXML
18: #include "libxml.h"
19:
20: #include <string.h>
21:
22: #ifdef HAVE_SYS_TYPES_H
23: #include <sys/types.h>
24: #endif
25: #ifdef HAVE_MATH_H
26: #include <math.h>
27: #endif
28: #ifdef HAVE_FLOAT_H
29: #include <float.h>
30: #endif
31: #ifdef HAVE_CTYPE_H
32: #include <ctype.h>
33: #endif
34: #ifdef HAVE_SIGNAL_H
35: #include <signal.h>
36: #endif
37:
38: #include <libxml/xmlmemory.h>
39: #include <libxml/tree.h>
40: #include <libxml/valid.h>
41: #include <libxml/xpath.h>
42: #include <libxml/xpathInternals.h>
43: #include <libxml/parserInternals.h>
44: #include <libxml/hash.h>
45: #ifdef LIBXML_XPTR_ENABLED
46: #include <libxml/xpointer.h>
47: #endif
48: #ifdef LIBXML_DEBUG_ENABLED
49: #include <libxml/debugXML.h>
50: #endif
51: #include <libxml/xmlerror.h>
52: #include <libxml/threads.h>
53: #include <libxml/globals.h>
54: #ifdef LIBXML_PATTERN_ENABLED
55: #include <libxml/pattern.h>
56: #endif
57:
58: #ifdef LIBXML_PATTERN_ENABLED
59: #define XPATH_STREAMING
60: #endif
61:
62: #define TODO \
63: xmlGenericError(xmlGenericErrorContext, \
64: "Unimplemented block at %s:%d\n", \
65: __FILE__, __LINE__);
66:
67: /*
68: * XP_OPTIMIZED_NON_ELEM_COMPARISON:
69: * If defined, this will use xmlXPathCmpNodesExt() instead of
70: * xmlXPathCmpNodes(). The new function is optimized comparison of
71: * non-element nodes; actually it will speed up comparison only if
72: * xmlXPathOrderDocElems() was called in order to index the elements of
73: * a tree in document order; Libxslt does such an indexing, thus it will
74: * benefit from this optimization.
75: */
76: #define XP_OPTIMIZED_NON_ELEM_COMPARISON
77:
78: /*
79: * XP_OPTIMIZED_FILTER_FIRST:
80: * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
81: * in a way, that it stop evaluation at the first node.
82: */
83: #define XP_OPTIMIZED_FILTER_FIRST
84:
85: /*
86: * XP_DEBUG_OBJ_USAGE:
87: * Internal flag to enable tracking of how much XPath objects have been
88: * created.
89: */
90: /* #define XP_DEBUG_OBJ_USAGE */
91:
92: /*
93: * TODO:
94: * There are a few spots where some tests are done which depend upon ascii
95: * data. These should be enhanced for full UTF8 support (see particularly
96: * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
97: */
98:
99: #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
100:
101: /************************************************************************
102: * *
103: * Floating point stuff *
104: * *
105: ************************************************************************/
106:
107: #ifndef TRIO_REPLACE_STDIO
108: #define TRIO_PUBLIC static
109: #endif
110: #include "trionan.c"
111:
112: /*
113: * The lack of portability of this section of the libc is annoying !
114: */
115: double xmlXPathNAN = 0;
116: double xmlXPathPINF = 1;
117: double xmlXPathNINF = -1;
118: static double xmlXPathNZERO = 0; /* not exported from headers */
119: static int xmlXPathInitialized = 0;
120:
121: /**
122: * xmlXPathInit:
123: *
124: * Initialize the XPath environment
125: */
126: void
127: xmlXPathInit(void) {
128: if (xmlXPathInitialized) return;
129:
130: xmlXPathPINF = trio_pinf();
131: xmlXPathNINF = trio_ninf();
132: xmlXPathNAN = trio_nan();
133: xmlXPathNZERO = trio_nzero();
134:
135: xmlXPathInitialized = 1;
136: }
137:
138: /**
139: * xmlXPathIsNaN:
140: * @val: a double value
141: *
142: * Provides a portable isnan() function to detect whether a double
143: * is a NotaNumber. Based on trio code
144: * http://sourceforge.net/projects/ctrio/
145: *
146: * Returns 1 if the value is a NaN, 0 otherwise
147: */
148: int
149: xmlXPathIsNaN(double val) {
150: return(trio_isnan(val));
151: }
152:
153: /**
154: * xmlXPathIsInf:
155: * @val: a double value
156: *
157: * Provides a portable isinf() function to detect whether a double
158: * is a +Infinite or -Infinite. Based on trio code
159: * http://sourceforge.net/projects/ctrio/
160: *
161: * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
162: */
163: int
164: xmlXPathIsInf(double val) {
165: return(trio_isinf(val));
166: }
167:
168: #endif /* SCHEMAS or XPATH */
169: #ifdef LIBXML_XPATH_ENABLED
170: /**
171: * xmlXPathGetSign:
172: * @val: a double value
173: *
174: * Provides a portable function to detect the sign of a double
175: * Modified from trio code
176: * http://sourceforge.net/projects/ctrio/
177: *
178: * Returns 1 if the value is Negative, 0 if positive
179: */
180: static int
181: xmlXPathGetSign(double val) {
182: return(trio_signbit(val));
183: }
184:
185:
186: /*
187: * TODO: when compatibility allows remove all "fake node libxslt" strings
188: * the test should just be name[0] = ' '
189: */
190: #ifdef DEBUG_XPATH_EXPRESSION
191: #define DEBUG_STEP
192: #define DEBUG_EXPR
193: #define DEBUG_EVAL_COUNTS
194: #endif
195:
196: static xmlNs xmlXPathXMLNamespaceStruct = {
197: NULL,
198: XML_NAMESPACE_DECL,
199: XML_XML_NAMESPACE,
200: BAD_CAST "xml",
201: NULL,
202: NULL
203: };
204: static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
205: #ifndef LIBXML_THREAD_ENABLED
206: /*
207: * Optimizer is disabled only when threaded apps are detected while
208: * the library ain't compiled for thread safety.
209: */
210: static int xmlXPathDisableOptimizer = 0;
211: #endif
212:
213: /************************************************************************
214: * *
215: * Error handling routines *
216: * *
217: ************************************************************************/
218:
219: /**
220: * XP_ERRORNULL:
221: * @X: the error code
222: *
223: * Macro to raise an XPath error and return NULL.
224: */
225: #define XP_ERRORNULL(X) \
226: { xmlXPathErr(ctxt, X); return(NULL); }
227:
228: /*
229: * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
230: */
231: static const char *xmlXPathErrorMessages[] = {
232: "Ok\n",
233: "Number encoding\n",
234: "Unfinished literal\n",
235: "Start of literal\n",
236: "Expected $ for variable reference\n",
237: "Undefined variable\n",
238: "Invalid predicate\n",
239: "Invalid expression\n",
240: "Missing closing curly brace\n",
241: "Unregistered function\n",
242: "Invalid operand\n",
243: "Invalid type\n",
244: "Invalid number of arguments\n",
245: "Invalid context size\n",
246: "Invalid context position\n",
247: "Memory allocation error\n",
248: "Syntax error\n",
249: "Resource error\n",
250: "Sub resource error\n",
251: "Undefined namespace prefix\n",
252: "Encoding error\n",
253: "Char out of XML range\n",
254: "Invalid or incomplete context\n",
1.1.1.2 ! misho 255: "Stack usage errror\n",
1.1 misho 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: */
267: static void
268: xmlXPathErrMemory(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: */
309: static void
310: xmlXPathPErrMemory(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: */
327: void
328: xmlXPathErr(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: "%s", 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: "%s", 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: "%s", 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: */
387: void
388: xmlXPatherror(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: */
404: typedef struct _xmlPointerList xmlPointerList;
405: typedef xmlPointerList *xmlPointerListPtr;
406: struct _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: */
415: static int
416: xmlPointerListAddSize(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: */
454: static xmlPointerListPtr
455: xmlPointerListCreate(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: */
479: static void
480: xmlPointerListFree(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:
499: typedef 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:
524: typedef 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:
540: typedef 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:
549: typedef 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:
558: typedef struct _xmlXPathStepOp xmlXPathStepOp;
559: typedef xmlXPathStepOp *xmlXPathStepOpPtr;
560: struct _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:
574: struct _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: ************************************************************************/
595: static void
596: xmlXPathFreeValueTree(xmlNodeSetPtr obj);
597: static void
598: xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
599: static int
600: xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
601: xmlXPathStepOpPtr op, xmlNodePtr *first);
602: static int
603: xmlXPathCompOpEvalToBoolean(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: */
620: static xmlXPathCompExprPtr
621: xmlXPathNewCompExpr(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: */
653: void
654: xmlXPathFreeCompExpr(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: */
719: static int
720: xmlXPathCompExprAdd(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: */
774: static void
775: xmlXPathCompSwap(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) \
801: xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
802:
803: #define PUSH_UNARY_EXPR(op, ch, val, val2) \
804: xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
805:
806: #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
807: xmlXPathCompExprAdd(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:
820: typedef struct _xmlXPathContextCache xmlXPathContextCache;
821: typedef xmlXPathContextCache *xmlXPathContextCachePtr;
822: struct _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
874: static void
875: xmlXPathDebugDumpNode(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, "%s", 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, "%s", 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: }
898: static void
899: xmlXPathDebugDumpNodeList(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, "%s", 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:
921: static void
922: xmlXPathDebugDumpNodeSet(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, "%s", 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, "%s", shift);
941: fprintf(output, "%d", i + 1);
942: xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
943: }
944: }
945: }
946:
947: static void
948: xmlXPathDebugDumpValueTree(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, "%s", shift);
958: fprintf(output, "Value Tree is NULL !\n");
959: return;
960:
961: }
962:
963: fprintf(output, "%s", shift);
964: fprintf(output, "%d", i + 1);
965: xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
966: }
967: #if defined(LIBXML_XPTR_ENABLED)
968: static void
969: xmlXPathDebugDumpLocationSet(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, "%s", shift);
979: fprintf(output, "LocationSet is NULL !\n");
980: return;
981:
982: }
983:
984: for (i = 0;i < cur->locNr;i++) {
985: fprintf(output, "%s", 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: */
1000: void
1001: xmlXPathDebugDumpObject(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, "%s", 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, "%s", 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, "%s", 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, "%s", 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:
1105: static void
1106: xmlXPathDebugDumpStepOp(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, "%s", 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");
1275: finish:
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: */
1290: void
1291: xmlXPathDebugDumpCompExpr(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, "%s", 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: */
1315: static int xmlXPathDebugObjCounterUndefined = 0;
1316: static int xmlXPathDebugObjCounterNodeset = 0;
1317: static int xmlXPathDebugObjCounterBool = 0;
1318: static int xmlXPathDebugObjCounterNumber = 0;
1319: static int xmlXPathDebugObjCounterString = 0;
1320: static int xmlXPathDebugObjCounterPoint = 0;
1321: static int xmlXPathDebugObjCounterRange = 0;
1322: static int xmlXPathDebugObjCounterLocset = 0;
1323: static int xmlXPathDebugObjCounterUsers = 0;
1324: static int xmlXPathDebugObjCounterXSLTTree = 0;
1325: static int xmlXPathDebugObjCounterAll = 0;
1326:
1327: static int xmlXPathDebugObjTotalUndefined = 0;
1328: static int xmlXPathDebugObjTotalNodeset = 0;
1329: static int xmlXPathDebugObjTotalBool = 0;
1330: static int xmlXPathDebugObjTotalNumber = 0;
1331: static int xmlXPathDebugObjTotalString = 0;
1332: static int xmlXPathDebugObjTotalPoint = 0;
1333: static int xmlXPathDebugObjTotalRange = 0;
1334: static int xmlXPathDebugObjTotalLocset = 0;
1335: static int xmlXPathDebugObjTotalUsers = 0;
1336: static int xmlXPathDebugObjTotalXSLTTree = 0;
1337: static int xmlXPathDebugObjTotalAll = 0;
1338:
1339: static int xmlXPathDebugObjMaxUndefined = 0;
1340: static int xmlXPathDebugObjMaxNodeset = 0;
1341: static int xmlXPathDebugObjMaxBool = 0;
1342: static int xmlXPathDebugObjMaxNumber = 0;
1343: static int xmlXPathDebugObjMaxString = 0;
1344: static int xmlXPathDebugObjMaxPoint = 0;
1345: static int xmlXPathDebugObjMaxRange = 0;
1346: static int xmlXPathDebugObjMaxLocset = 0;
1347: static int xmlXPathDebugObjMaxUsers = 0;
1348: static int xmlXPathDebugObjMaxXSLTTree = 0;
1349: static int xmlXPathDebugObjMaxAll = 0;
1350:
1351: /* REVISIT TODO: Make this static when committing */
1352: static void
1353: xmlXPathDebugObjUsageReset(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:
1424: static void
1425: xmlXPathDebugObjUsageRequested(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:
1578: static void
1579: xmlXPathDebugObjUsageReleased(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 */
1667: static void
1668: xmlXPathDebugObjUsageDisplay(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: */
1791: static xmlXPathContextCachePtr
1792: xmlXPathNewCache(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:
1810: static void
1811: xmlXPathCacheFreeObjectList(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:
1838: static void
1839: xmlXPathFreeCache(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: */
1878: int
1879: xmlXPathContextSetCache(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: */
1921: static xmlXPathObjectPtr
1922: xmlXPathCacheWrapNodeSet(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: */
1958: static xmlXPathObjectPtr
1959: xmlXPathCacheWrapString(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: */
2010: static xmlXPathObjectPtr
2011: xmlXPathCacheNewNodeSet(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: */
2074: static xmlXPathObjectPtr
2075: xmlXPathCacheNewCString(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: */
2123: static xmlXPathObjectPtr
2124: xmlXPathCacheNewString(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: */
2177: static xmlXPathObjectPtr
2178: xmlXPathCacheNewBoolean(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: */
2225: static xmlXPathObjectPtr
2226: xmlXPathCacheNewFloat(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:
2275: static xmlXPathObjectPtr
2276: xmlXPathCacheConvertString(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: */
2323: static xmlXPathObjectPtr
2324: xmlXPathCacheObjectCopy(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: */
2358: static xmlXPathObjectPtr
2359: xmlXPathCacheConvertBoolean(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: */
2382: static xmlXPathObjectPtr
2383: xmlXPathCacheConvertNumber(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: /**
1.1.1.2 ! misho 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: */
! 2409: static int
! 2410: xmlXPathSetFrame(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: */
! 2427: static void
! 2428: xmlXPathPopFrame(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: /**
1.1 misho 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: */
2445: xmlXPathObjectPtr
2446: valuePop(xmlXPathParserContextPtr ctxt)
2447: {
2448: xmlXPathObjectPtr ret;
2449:
2450: if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2451: return (NULL);
1.1.1.2 ! misho 2452:
! 2453: if (ctxt->valueNr <= ctxt->valueFrame) {
! 2454: xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
! 2455: return (NULL);
! 2456: }
! 2457:
1.1 misho 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: */
2476: int
2477: valuePush(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");
1.1.1.2 ! misho 2488: ctxt->error = XPATH_MEMORY_ERROR;
1.1 misho 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: */
2508: int
2509: xmlXPathPopBoolean (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: */
2535: double
2536: xmlXPathPopNumber (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: */
2562: xmlChar *
2563: xmlXPathPopString (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: */
2589: xmlNodeSetPtr
2590: xmlXPathPopNodeSet (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: */
2624: void *
2625: xmlXPathPopExternal (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: */
2709: static void
2710: xmlXPathFormatNumber(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: */
2839: long
2840: xmlXPathOrderDocElems(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: */
2886: int
2887: xmlXPathCmpNodes(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: */
3035: static int
3036: xmlXPathCmpNodesExt(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:
3240: turtle_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: */
3321: void
3322: xmlXPathNodeSetSort(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: */
3366: static xmlNodePtr
3367: xmlXPathNodeSetDupNs(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: */
3401: void
3402: xmlXPathNodeSetFreeNs(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: */
3423: xmlNodeSetPtr
3424: xmlXPathNodeSetCreate(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: */
3463: static xmlNodeSetPtr
3464: xmlXPathNodeSetCreateSize(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: */
3495: int
3496: xmlXPathNodeSetContains (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: */
3531: void
3532: xmlXPathNodeSetAddNs(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:
1.1.1.2 ! misho 3569: temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
1.1 misho 3570: sizeof(xmlNodePtr));
3571: if (temp == NULL) {
3572: xmlXPathErrMemory(NULL, "growing nodeset\n");
3573: return;
3574: }
1.1.1.2 ! misho 3575: cur->nodeMax *= 2;
1.1 misho 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: */
3588: void
3589: xmlXPathNodeSetAdd(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:
1.1.1.2 ! misho 3622: temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
1.1 misho 3623: sizeof(xmlNodePtr));
3624: if (temp == NULL) {
3625: xmlXPathErrMemory(NULL, "growing nodeset\n");
3626: return;
3627: }
1.1.1.2 ! misho 3628: cur->nodeMax *= 2;
1.1 misho 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: */
3648: void
3649: xmlXPathNodeSetAddUnique(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:
1.1.1.2 ! misho 3674: temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
1.1 misho 3675: sizeof(xmlNodePtr));
3676: if (temp == NULL) {
3677: xmlXPathErrMemory(NULL, "growing nodeset\n");
3678: return;
3679: }
3680: cur->nodeTab = temp;
1.1.1.2 ! misho 3681: cur->nodeMax *= 2;
1.1 misho 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: */
3702: xmlNodeSetPtr
3703: xmlXPathNodeSetMerge(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 (val1 == NULL)
3711: return (NULL);
3712: #if 0
3713: /*
3714: * TODO: The optimization won't work in every case, since
3715: * those nasty namespace nodes need to be added with
3716: * xmlXPathNodeSetDupNs() to the set; thus a pure
3717: * memcpy is not possible.
3718: * If there was a flag on the nodesetval, indicating that
3719: * some temporary nodes are in, that would be helpfull.
3720: */
3721: /*
3722: * Optimization: Create an equally sized node-set
3723: * and memcpy the content.
3724: */
3725: val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3726: if (val1 == NULL)
3727: return(NULL);
3728: if (val2->nodeNr != 0) {
3729: if (val2->nodeNr == 1)
3730: *(val1->nodeTab) = *(val2->nodeTab);
3731: else {
3732: memcpy(val1->nodeTab, val2->nodeTab,
3733: val2->nodeNr * sizeof(xmlNodePtr));
3734: }
3735: val1->nodeNr = val2->nodeNr;
3736: }
3737: return(val1);
3738: #endif
3739: }
3740:
3741: /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3742: initNr = val1->nodeNr;
3743:
3744: for (i = 0;i < val2->nodeNr;i++) {
3745: n2 = val2->nodeTab[i];
3746: /*
3747: * check against duplicates
3748: */
3749: skip = 0;
3750: for (j = 0; j < initNr; j++) {
3751: n1 = val1->nodeTab[j];
3752: if (n1 == n2) {
3753: skip = 1;
3754: break;
3755: } else if ((n1->type == XML_NAMESPACE_DECL) &&
3756: (n2->type == XML_NAMESPACE_DECL)) {
3757: if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3758: (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3759: ((xmlNsPtr) n2)->prefix)))
3760: {
3761: skip = 1;
3762: break;
3763: }
3764: }
3765: }
3766: if (skip)
3767: continue;
3768:
3769: /*
3770: * grow the nodeTab if needed
3771: */
3772: if (val1->nodeMax == 0) {
3773: val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3774: sizeof(xmlNodePtr));
3775: if (val1->nodeTab == NULL) {
3776: xmlXPathErrMemory(NULL, "merging nodeset\n");
3777: return(NULL);
3778: }
3779: memset(val1->nodeTab, 0 ,
3780: XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3781: val1->nodeMax = XML_NODESET_DEFAULT;
3782: } else if (val1->nodeNr == val1->nodeMax) {
3783: xmlNodePtr *temp;
3784:
1.1.1.2 ! misho 3785: temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
1.1 misho 3786: sizeof(xmlNodePtr));
3787: if (temp == NULL) {
3788: xmlXPathErrMemory(NULL, "merging nodeset\n");
3789: return(NULL);
3790: }
3791: val1->nodeTab = temp;
1.1.1.2 ! misho 3792: val1->nodeMax *= 2;
1.1 misho 3793: }
3794: if (n2->type == XML_NAMESPACE_DECL) {
3795: xmlNsPtr ns = (xmlNsPtr) n2;
3796:
3797: val1->nodeTab[val1->nodeNr++] =
3798: xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3799: } else
3800: val1->nodeTab[val1->nodeNr++] = n2;
3801: }
3802:
3803: return(val1);
3804: }
3805:
3806: #if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3807: /**
3808: * xmlXPathNodeSetMergeUnique:
3809: * @val1: the first NodeSet or NULL
3810: * @val2: the second NodeSet
3811: *
3812: * Merges two nodesets, all nodes from @val2 are added to @val1
3813: * if @val1 is NULL, a new set is created and copied from @val2
3814: *
3815: * Returns @val1 once extended or NULL in case of error.
3816: */
3817: static xmlNodeSetPtr
3818: xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3819: int i;
3820:
3821: if (val2 == NULL) return(val1);
3822: if (val1 == NULL) {
3823: val1 = xmlXPathNodeSetCreate(NULL);
3824: }
3825: if (val1 == NULL)
3826: return (NULL);
3827:
3828: /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3829:
3830: for (i = 0;i < val2->nodeNr;i++) {
3831: /*
3832: * grow the nodeTab if needed
3833: */
3834: if (val1->nodeMax == 0) {
3835: val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3836: sizeof(xmlNodePtr));
3837: if (val1->nodeTab == NULL) {
3838: xmlXPathErrMemory(NULL, "merging nodeset\n");
3839: return(NULL);
3840: }
3841: memset(val1->nodeTab, 0 ,
3842: XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3843: val1->nodeMax = XML_NODESET_DEFAULT;
3844: } else if (val1->nodeNr == val1->nodeMax) {
3845: xmlNodePtr *temp;
3846:
3847: val1->nodeMax *= 2;
3848: temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3849: sizeof(xmlNodePtr));
3850: if (temp == NULL) {
3851: xmlXPathErrMemory(NULL, "merging nodeset\n");
3852: return(NULL);
3853: }
3854: val1->nodeTab = temp;
3855: }
3856: if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3857: xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
3858:
3859: val1->nodeTab[val1->nodeNr++] =
3860: xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3861: } else
3862: val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
3863: }
3864:
3865: return(val1);
3866: }
3867: #endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3868:
3869: /**
3870: * xmlXPathNodeSetMergeAndClear:
3871: * @set1: the first NodeSet or NULL
3872: * @set2: the second NodeSet
3873: * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3874: *
3875: * Merges two nodesets, all nodes from @set2 are added to @set1
3876: * if @set1 is NULL, a new set is created and copied from @set2.
3877: * Checks for duplicate nodes. Clears set2.
3878: *
3879: * Returns @set1 once extended or NULL in case of error.
3880: */
3881: static xmlNodeSetPtr
3882: xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3883: int hasNullEntries)
3884: {
3885: if ((set1 == NULL) && (hasNullEntries == 0)) {
3886: /*
3887: * Note that doing a memcpy of the list, namespace nodes are
3888: * just assigned to set1, since set2 is cleared anyway.
3889: */
3890: set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3891: if (set1 == NULL)
3892: return(NULL);
3893: if (set2->nodeNr != 0) {
3894: memcpy(set1->nodeTab, set2->nodeTab,
3895: set2->nodeNr * sizeof(xmlNodePtr));
3896: set1->nodeNr = set2->nodeNr;
3897: }
3898: } else {
3899: int i, j, initNbSet1;
3900: xmlNodePtr n1, n2;
3901:
3902: if (set1 == NULL)
3903: set1 = xmlXPathNodeSetCreate(NULL);
3904: if (set1 == NULL)
3905: return (NULL);
3906:
3907: initNbSet1 = set1->nodeNr;
3908: for (i = 0;i < set2->nodeNr;i++) {
3909: n2 = set2->nodeTab[i];
3910: /*
3911: * Skip NULLed entries.
3912: */
3913: if (n2 == NULL)
3914: continue;
3915: /*
3916: * Skip duplicates.
3917: */
3918: for (j = 0; j < initNbSet1; j++) {
3919: n1 = set1->nodeTab[j];
3920: if (n1 == n2) {
3921: goto skip_node;
3922: } else if ((n1->type == XML_NAMESPACE_DECL) &&
3923: (n2->type == XML_NAMESPACE_DECL))
3924: {
3925: if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3926: (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3927: ((xmlNsPtr) n2)->prefix)))
3928: {
3929: /*
3930: * Free the namespace node.
3931: */
3932: set2->nodeTab[i] = NULL;
3933: xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3934: goto skip_node;
3935: }
3936: }
3937: }
3938: /*
3939: * grow the nodeTab if needed
3940: */
3941: if (set1->nodeMax == 0) {
3942: set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3943: XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3944: if (set1->nodeTab == NULL) {
3945: xmlXPathErrMemory(NULL, "merging nodeset\n");
3946: return(NULL);
3947: }
3948: memset(set1->nodeTab, 0,
3949: XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3950: set1->nodeMax = XML_NODESET_DEFAULT;
3951: } else if (set1->nodeNr >= set1->nodeMax) {
3952: xmlNodePtr *temp;
3953:
3954: temp = (xmlNodePtr *) xmlRealloc(
1.1.1.2 ! misho 3955: set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
1.1 misho 3956: if (temp == NULL) {
3957: xmlXPathErrMemory(NULL, "merging nodeset\n");
3958: return(NULL);
3959: }
3960: set1->nodeTab = temp;
1.1.1.2 ! misho 3961: set1->nodeMax *= 2;
1.1 misho 3962: }
3963: if (n2->type == XML_NAMESPACE_DECL) {
3964: xmlNsPtr ns = (xmlNsPtr) n2;
3965:
3966: set1->nodeTab[set1->nodeNr++] =
3967: xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3968: } else
3969: set1->nodeTab[set1->nodeNr++] = n2;
3970: skip_node:
3971: {}
3972: }
3973: }
3974: set2->nodeNr = 0;
3975: return(set1);
3976: }
3977:
3978: /**
3979: * xmlXPathNodeSetMergeAndClearNoDupls:
3980: * @set1: the first NodeSet or NULL
3981: * @set2: the second NodeSet
3982: * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3983: *
3984: * Merges two nodesets, all nodes from @set2 are added to @set1
3985: * if @set1 is NULL, a new set is created and copied from @set2.
3986: * Doesn't chack for duplicate nodes. Clears set2.
3987: *
3988: * Returns @set1 once extended or NULL in case of error.
3989: */
3990: static xmlNodeSetPtr
3991: xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3992: int hasNullEntries)
3993: {
3994: if (set2 == NULL)
3995: return(set1);
3996: if ((set1 == NULL) && (hasNullEntries == 0)) {
3997: /*
3998: * Note that doing a memcpy of the list, namespace nodes are
3999: * just assigned to set1, since set2 is cleared anyway.
4000: */
4001: set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
4002: if (set1 == NULL)
4003: return(NULL);
4004: if (set2->nodeNr != 0) {
4005: memcpy(set1->nodeTab, set2->nodeTab,
4006: set2->nodeNr * sizeof(xmlNodePtr));
4007: set1->nodeNr = set2->nodeNr;
4008: }
4009: } else {
4010: int i;
4011: xmlNodePtr n2;
4012:
4013: if (set1 == NULL)
4014: set1 = xmlXPathNodeSetCreate(NULL);
4015: if (set1 == NULL)
4016: return (NULL);
4017:
4018: for (i = 0;i < set2->nodeNr;i++) {
4019: n2 = set2->nodeTab[i];
4020: /*
4021: * Skip NULLed entries.
4022: */
4023: if (n2 == NULL)
4024: continue;
4025: if (set1->nodeMax == 0) {
4026: set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4027: XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4028: if (set1->nodeTab == NULL) {
4029: xmlXPathErrMemory(NULL, "merging nodeset\n");
4030: return(NULL);
4031: }
4032: memset(set1->nodeTab, 0,
4033: XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4034: set1->nodeMax = XML_NODESET_DEFAULT;
4035: } else if (set1->nodeNr >= set1->nodeMax) {
4036: xmlNodePtr *temp;
4037:
4038: temp = (xmlNodePtr *) xmlRealloc(
1.1.1.2 ! misho 4039: set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
1.1 misho 4040: if (temp == NULL) {
4041: xmlXPathErrMemory(NULL, "merging nodeset\n");
4042: return(NULL);
4043: }
4044: set1->nodeTab = temp;
1.1.1.2 ! misho 4045: set1->nodeMax *= 2;
1.1 misho 4046: }
4047: set1->nodeTab[set1->nodeNr++] = n2;
4048: }
4049: }
4050: set2->nodeNr = 0;
4051: return(set1);
4052: }
4053:
4054: /**
4055: * xmlXPathNodeSetDel:
4056: * @cur: the initial node set
4057: * @val: an xmlNodePtr
4058: *
4059: * Removes an xmlNodePtr from an existing NodeSet
4060: */
4061: void
4062: xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4063: int i;
4064:
4065: if (cur == NULL) return;
4066: if (val == NULL) return;
4067:
4068: /*
4069: * find node in nodeTab
4070: */
4071: for (i = 0;i < cur->nodeNr;i++)
4072: if (cur->nodeTab[i] == val) break;
4073:
4074: if (i >= cur->nodeNr) { /* not found */
4075: #ifdef DEBUG
4076: xmlGenericError(xmlGenericErrorContext,
4077: "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4078: val->name);
4079: #endif
4080: return;
4081: }
4082: if ((cur->nodeTab[i] != NULL) &&
4083: (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4084: xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4085: cur->nodeNr--;
4086: for (;i < cur->nodeNr;i++)
4087: cur->nodeTab[i] = cur->nodeTab[i + 1];
4088: cur->nodeTab[cur->nodeNr] = NULL;
4089: }
4090:
4091: /**
4092: * xmlXPathNodeSetRemove:
4093: * @cur: the initial node set
4094: * @val: the index to remove
4095: *
4096: * Removes an entry from an existing NodeSet list.
4097: */
4098: void
4099: xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4100: if (cur == NULL) return;
4101: if (val >= cur->nodeNr) return;
4102: if ((cur->nodeTab[val] != NULL) &&
4103: (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4104: xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4105: cur->nodeNr--;
4106: for (;val < cur->nodeNr;val++)
4107: cur->nodeTab[val] = cur->nodeTab[val + 1];
4108: cur->nodeTab[cur->nodeNr] = NULL;
4109: }
4110:
4111: /**
4112: * xmlXPathFreeNodeSet:
4113: * @obj: the xmlNodeSetPtr to free
4114: *
4115: * Free the NodeSet compound (not the actual nodes !).
4116: */
4117: void
4118: xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4119: if (obj == NULL) return;
4120: if (obj->nodeTab != NULL) {
4121: int i;
4122:
4123: /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4124: for (i = 0;i < obj->nodeNr;i++)
4125: if ((obj->nodeTab[i] != NULL) &&
4126: (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4127: xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4128: xmlFree(obj->nodeTab);
4129: }
4130: xmlFree(obj);
4131: }
4132:
4133: /**
4134: * xmlXPathNodeSetClear:
4135: * @set: the node set to clear
4136: *
4137: * Clears the list from all temporary XPath objects (e.g. namespace nodes
4138: * are feed), but does *not* free the list itself. Sets the length of the
4139: * list to 0.
4140: */
4141: static void
4142: xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4143: {
4144: if ((set == NULL) || (set->nodeNr <= 0))
4145: return;
4146: else if (hasNsNodes) {
4147: int i;
4148: xmlNodePtr node;
4149:
4150: for (i = 0; i < set->nodeNr; i++) {
4151: node = set->nodeTab[i];
4152: if ((node != NULL) &&
4153: (node->type == XML_NAMESPACE_DECL))
4154: xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4155: }
4156: }
4157: set->nodeNr = 0;
4158: }
4159:
4160: /**
4161: * xmlXPathNodeSetClearFromPos:
4162: * @set: the node set to be cleared
4163: * @pos: the start position to clear from
4164: *
4165: * Clears the list from temporary XPath objects (e.g. namespace nodes
4166: * are feed) starting with the entry at @pos, but does *not* free the list
4167: * itself. Sets the length of the list to @pos.
4168: */
4169: static void
4170: xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4171: {
4172: if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4173: return;
4174: else if ((hasNsNodes)) {
4175: int i;
4176: xmlNodePtr node;
4177:
4178: for (i = pos; i < set->nodeNr; i++) {
4179: node = set->nodeTab[i];
4180: if ((node != NULL) &&
4181: (node->type == XML_NAMESPACE_DECL))
4182: xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4183: }
4184: }
4185: set->nodeNr = pos;
4186: }
4187:
4188: /**
4189: * xmlXPathFreeValueTree:
4190: * @obj: the xmlNodeSetPtr to free
4191: *
4192: * Free the NodeSet compound and the actual tree, this is different
4193: * from xmlXPathFreeNodeSet()
4194: */
4195: static void
4196: xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4197: int i;
4198:
4199: if (obj == NULL) return;
4200:
4201: if (obj->nodeTab != NULL) {
4202: for (i = 0;i < obj->nodeNr;i++) {
4203: if (obj->nodeTab[i] != NULL) {
4204: if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4205: xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4206: } else {
4207: xmlFreeNodeList(obj->nodeTab[i]);
4208: }
4209: }
4210: }
4211: xmlFree(obj->nodeTab);
4212: }
4213: xmlFree(obj);
4214: }
4215:
4216: #if defined(DEBUG) || defined(DEBUG_STEP)
4217: /**
4218: * xmlGenericErrorContextNodeSet:
4219: * @output: a FILE * for the output
4220: * @obj: the xmlNodeSetPtr to display
4221: *
4222: * Quick display of a NodeSet
4223: */
4224: void
4225: xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4226: int i;
4227:
4228: if (output == NULL) output = xmlGenericErrorContext;
4229: if (obj == NULL) {
4230: fprintf(output, "NodeSet == NULL !\n");
4231: return;
4232: }
4233: if (obj->nodeNr == 0) {
4234: fprintf(output, "NodeSet is empty\n");
4235: return;
4236: }
4237: if (obj->nodeTab == NULL) {
4238: fprintf(output, " nodeTab == NULL !\n");
4239: return;
4240: }
4241: for (i = 0; i < obj->nodeNr; i++) {
4242: if (obj->nodeTab[i] == NULL) {
4243: fprintf(output, " NULL !\n");
4244: return;
4245: }
4246: if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4247: (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4248: fprintf(output, " /");
4249: else if (obj->nodeTab[i]->name == NULL)
4250: fprintf(output, " noname!");
4251: else fprintf(output, " %s", obj->nodeTab[i]->name);
4252: }
4253: fprintf(output, "\n");
4254: }
4255: #endif
4256:
4257: /**
4258: * xmlXPathNewNodeSet:
4259: * @val: the NodePtr value
4260: *
4261: * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4262: * it with the single Node @val
4263: *
4264: * Returns the newly created object.
4265: */
4266: xmlXPathObjectPtr
4267: xmlXPathNewNodeSet(xmlNodePtr val) {
4268: xmlXPathObjectPtr ret;
4269:
4270: ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4271: if (ret == NULL) {
4272: xmlXPathErrMemory(NULL, "creating nodeset\n");
4273: return(NULL);
4274: }
4275: memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4276: ret->type = XPATH_NODESET;
4277: ret->boolval = 0;
4278: ret->nodesetval = xmlXPathNodeSetCreate(val);
4279: /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4280: #ifdef XP_DEBUG_OBJ_USAGE
4281: xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4282: #endif
4283: return(ret);
4284: }
4285:
4286: /**
4287: * xmlXPathNewValueTree:
4288: * @val: the NodePtr value
4289: *
4290: * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4291: * it with the tree root @val
4292: *
4293: * Returns the newly created object.
4294: */
4295: xmlXPathObjectPtr
4296: xmlXPathNewValueTree(xmlNodePtr val) {
4297: xmlXPathObjectPtr ret;
4298:
4299: ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4300: if (ret == NULL) {
4301: xmlXPathErrMemory(NULL, "creating result value tree\n");
4302: return(NULL);
4303: }
4304: memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4305: ret->type = XPATH_XSLT_TREE;
4306: ret->boolval = 1;
4307: ret->user = (void *) val;
4308: ret->nodesetval = xmlXPathNodeSetCreate(val);
4309: #ifdef XP_DEBUG_OBJ_USAGE
4310: xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4311: #endif
4312: return(ret);
4313: }
4314:
4315: /**
4316: * xmlXPathNewNodeSetList:
4317: * @val: an existing NodeSet
4318: *
4319: * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4320: * it with the Nodeset @val
4321: *
4322: * Returns the newly created object.
4323: */
4324: xmlXPathObjectPtr
4325: xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4326: {
4327: xmlXPathObjectPtr ret;
4328: int i;
4329:
4330: if (val == NULL)
4331: ret = NULL;
4332: else if (val->nodeTab == NULL)
4333: ret = xmlXPathNewNodeSet(NULL);
4334: else {
4335: ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4336: if (ret)
4337: for (i = 1; i < val->nodeNr; ++i)
4338: xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
4339: }
4340:
4341: return (ret);
4342: }
4343:
4344: /**
4345: * xmlXPathWrapNodeSet:
4346: * @val: the NodePtr value
4347: *
4348: * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4349: *
4350: * Returns the newly created object.
4351: */
4352: xmlXPathObjectPtr
4353: xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4354: xmlXPathObjectPtr ret;
4355:
4356: ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4357: if (ret == NULL) {
4358: xmlXPathErrMemory(NULL, "creating node set object\n");
4359: return(NULL);
4360: }
4361: memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4362: ret->type = XPATH_NODESET;
4363: ret->nodesetval = val;
4364: #ifdef XP_DEBUG_OBJ_USAGE
4365: xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4366: #endif
4367: return(ret);
4368: }
4369:
4370: /**
4371: * xmlXPathFreeNodeSetList:
4372: * @obj: an existing NodeSetList object
4373: *
4374: * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4375: * the list contrary to xmlXPathFreeObject().
4376: */
4377: void
4378: xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4379: if (obj == NULL) return;
4380: #ifdef XP_DEBUG_OBJ_USAGE
4381: xmlXPathDebugObjUsageReleased(NULL, obj->type);
4382: #endif
4383: xmlFree(obj);
4384: }
4385:
4386: /**
4387: * xmlXPathDifference:
4388: * @nodes1: a node-set
4389: * @nodes2: a node-set
4390: *
4391: * Implements the EXSLT - Sets difference() function:
4392: * node-set set:difference (node-set, node-set)
4393: *
4394: * Returns the difference between the two node sets, or nodes1 if
4395: * nodes2 is empty
4396: */
4397: xmlNodeSetPtr
4398: xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4399: xmlNodeSetPtr ret;
4400: int i, l1;
4401: xmlNodePtr cur;
4402:
4403: if (xmlXPathNodeSetIsEmpty(nodes2))
4404: return(nodes1);
4405:
4406: ret = xmlXPathNodeSetCreate(NULL);
4407: if (xmlXPathNodeSetIsEmpty(nodes1))
4408: return(ret);
4409:
4410: l1 = xmlXPathNodeSetGetLength(nodes1);
4411:
4412: for (i = 0; i < l1; i++) {
4413: cur = xmlXPathNodeSetItem(nodes1, i);
4414: if (!xmlXPathNodeSetContains(nodes2, cur))
4415: xmlXPathNodeSetAddUnique(ret, cur);
4416: }
4417: return(ret);
4418: }
4419:
4420: /**
4421: * xmlXPathIntersection:
4422: * @nodes1: a node-set
4423: * @nodes2: a node-set
4424: *
4425: * Implements the EXSLT - Sets intersection() function:
4426: * node-set set:intersection (node-set, node-set)
4427: *
4428: * Returns a node set comprising the nodes that are within both the
4429: * node sets passed as arguments
4430: */
4431: xmlNodeSetPtr
4432: xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4433: xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4434: int i, l1;
4435: xmlNodePtr cur;
4436:
4437: if (ret == NULL)
4438: return(ret);
4439: if (xmlXPathNodeSetIsEmpty(nodes1))
4440: return(ret);
4441: if (xmlXPathNodeSetIsEmpty(nodes2))
4442: return(ret);
4443:
4444: l1 = xmlXPathNodeSetGetLength(nodes1);
4445:
4446: for (i = 0; i < l1; i++) {
4447: cur = xmlXPathNodeSetItem(nodes1, i);
4448: if (xmlXPathNodeSetContains(nodes2, cur))
4449: xmlXPathNodeSetAddUnique(ret, cur);
4450: }
4451: return(ret);
4452: }
4453:
4454: /**
4455: * xmlXPathDistinctSorted:
4456: * @nodes: a node-set, sorted by document order
4457: *
4458: * Implements the EXSLT - Sets distinct() function:
4459: * node-set set:distinct (node-set)
4460: *
4461: * Returns a subset of the nodes contained in @nodes, or @nodes if
4462: * it is empty
4463: */
4464: xmlNodeSetPtr
4465: xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4466: xmlNodeSetPtr ret;
4467: xmlHashTablePtr hash;
4468: int i, l;
4469: xmlChar * strval;
4470: xmlNodePtr cur;
4471:
4472: if (xmlXPathNodeSetIsEmpty(nodes))
4473: return(nodes);
4474:
4475: ret = xmlXPathNodeSetCreate(NULL);
4476: if (ret == NULL)
4477: return(ret);
4478: l = xmlXPathNodeSetGetLength(nodes);
4479: hash = xmlHashCreate (l);
4480: for (i = 0; i < l; i++) {
4481: cur = xmlXPathNodeSetItem(nodes, i);
4482: strval = xmlXPathCastNodeToString(cur);
4483: if (xmlHashLookup(hash, strval) == NULL) {
4484: xmlHashAddEntry(hash, strval, strval);
4485: xmlXPathNodeSetAddUnique(ret, cur);
4486: } else {
4487: xmlFree(strval);
4488: }
4489: }
4490: xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4491: return(ret);
4492: }
4493:
4494: /**
4495: * xmlXPathDistinct:
4496: * @nodes: a node-set
4497: *
4498: * Implements the EXSLT - Sets distinct() function:
4499: * node-set set:distinct (node-set)
4500: * @nodes is sorted by document order, then #exslSetsDistinctSorted
4501: * is called with the sorted node-set
4502: *
4503: * Returns a subset of the nodes contained in @nodes, or @nodes if
4504: * it is empty
4505: */
4506: xmlNodeSetPtr
4507: xmlXPathDistinct (xmlNodeSetPtr nodes) {
4508: if (xmlXPathNodeSetIsEmpty(nodes))
4509: return(nodes);
4510:
4511: xmlXPathNodeSetSort(nodes);
4512: return(xmlXPathDistinctSorted(nodes));
4513: }
4514:
4515: /**
4516: * xmlXPathHasSameNodes:
4517: * @nodes1: a node-set
4518: * @nodes2: a node-set
4519: *
4520: * Implements the EXSLT - Sets has-same-nodes function:
4521: * boolean set:has-same-node(node-set, node-set)
4522: *
4523: * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4524: * otherwise
4525: */
4526: int
4527: xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4528: int i, l;
4529: xmlNodePtr cur;
4530:
4531: if (xmlXPathNodeSetIsEmpty(nodes1) ||
4532: xmlXPathNodeSetIsEmpty(nodes2))
4533: return(0);
4534:
4535: l = xmlXPathNodeSetGetLength(nodes1);
4536: for (i = 0; i < l; i++) {
4537: cur = xmlXPathNodeSetItem(nodes1, i);
4538: if (xmlXPathNodeSetContains(nodes2, cur))
4539: return(1);
4540: }
4541: return(0);
4542: }
4543:
4544: /**
4545: * xmlXPathNodeLeadingSorted:
4546: * @nodes: a node-set, sorted by document order
4547: * @node: a node
4548: *
4549: * Implements the EXSLT - Sets leading() function:
4550: * node-set set:leading (node-set, node-set)
4551: *
4552: * Returns the nodes in @nodes that precede @node in document order,
4553: * @nodes if @node is NULL or an empty node-set if @nodes
4554: * doesn't contain @node
4555: */
4556: xmlNodeSetPtr
4557: xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4558: int i, l;
4559: xmlNodePtr cur;
4560: xmlNodeSetPtr ret;
4561:
4562: if (node == NULL)
4563: return(nodes);
4564:
4565: ret = xmlXPathNodeSetCreate(NULL);
4566: if (ret == NULL)
4567: return(ret);
4568: if (xmlXPathNodeSetIsEmpty(nodes) ||
4569: (!xmlXPathNodeSetContains(nodes, node)))
4570: return(ret);
4571:
4572: l = xmlXPathNodeSetGetLength(nodes);
4573: for (i = 0; i < l; i++) {
4574: cur = xmlXPathNodeSetItem(nodes, i);
4575: if (cur == node)
4576: break;
4577: xmlXPathNodeSetAddUnique(ret, cur);
4578: }
4579: return(ret);
4580: }
4581:
4582: /**
4583: * xmlXPathNodeLeading:
4584: * @nodes: a node-set
4585: * @node: a node
4586: *
4587: * Implements the EXSLT - Sets leading() function:
4588: * node-set set:leading (node-set, node-set)
4589: * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4590: * is called.
4591: *
4592: * Returns the nodes in @nodes that precede @node in document order,
4593: * @nodes if @node is NULL or an empty node-set if @nodes
4594: * doesn't contain @node
4595: */
4596: xmlNodeSetPtr
4597: xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4598: xmlXPathNodeSetSort(nodes);
4599: return(xmlXPathNodeLeadingSorted(nodes, node));
4600: }
4601:
4602: /**
4603: * xmlXPathLeadingSorted:
4604: * @nodes1: a node-set, sorted by document order
4605: * @nodes2: a node-set, sorted by document order
4606: *
4607: * Implements the EXSLT - Sets leading() function:
4608: * node-set set:leading (node-set, node-set)
4609: *
4610: * Returns the nodes in @nodes1 that precede the first node in @nodes2
4611: * in document order, @nodes1 if @nodes2 is NULL or empty or
4612: * an empty node-set if @nodes1 doesn't contain @nodes2
4613: */
4614: xmlNodeSetPtr
4615: xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4616: if (xmlXPathNodeSetIsEmpty(nodes2))
4617: return(nodes1);
4618: return(xmlXPathNodeLeadingSorted(nodes1,
4619: xmlXPathNodeSetItem(nodes2, 1)));
4620: }
4621:
4622: /**
4623: * xmlXPathLeading:
4624: * @nodes1: a node-set
4625: * @nodes2: a node-set
4626: *
4627: * Implements the EXSLT - Sets leading() function:
4628: * node-set set:leading (node-set, node-set)
4629: * @nodes1 and @nodes2 are sorted by document order, then
4630: * #exslSetsLeadingSorted is called.
4631: *
4632: * Returns the nodes in @nodes1 that precede the first node in @nodes2
4633: * in document order, @nodes1 if @nodes2 is NULL or empty or
4634: * an empty node-set if @nodes1 doesn't contain @nodes2
4635: */
4636: xmlNodeSetPtr
4637: xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4638: if (xmlXPathNodeSetIsEmpty(nodes2))
4639: return(nodes1);
4640: if (xmlXPathNodeSetIsEmpty(nodes1))
4641: return(xmlXPathNodeSetCreate(NULL));
4642: xmlXPathNodeSetSort(nodes1);
4643: xmlXPathNodeSetSort(nodes2);
4644: return(xmlXPathNodeLeadingSorted(nodes1,
4645: xmlXPathNodeSetItem(nodes2, 1)));
4646: }
4647:
4648: /**
4649: * xmlXPathNodeTrailingSorted:
4650: * @nodes: a node-set, sorted by document order
4651: * @node: a node
4652: *
4653: * Implements the EXSLT - Sets trailing() function:
4654: * node-set set:trailing (node-set, node-set)
4655: *
4656: * Returns the nodes in @nodes that follow @node in document order,
4657: * @nodes if @node is NULL or an empty node-set if @nodes
4658: * doesn't contain @node
4659: */
4660: xmlNodeSetPtr
4661: xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4662: int i, l;
4663: xmlNodePtr cur;
4664: xmlNodeSetPtr ret;
4665:
4666: if (node == NULL)
4667: return(nodes);
4668:
4669: ret = xmlXPathNodeSetCreate(NULL);
4670: if (ret == NULL)
4671: return(ret);
4672: if (xmlXPathNodeSetIsEmpty(nodes) ||
4673: (!xmlXPathNodeSetContains(nodes, node)))
4674: return(ret);
4675:
4676: l = xmlXPathNodeSetGetLength(nodes);
4677: for (i = l - 1; i >= 0; i--) {
4678: cur = xmlXPathNodeSetItem(nodes, i);
4679: if (cur == node)
4680: break;
4681: xmlXPathNodeSetAddUnique(ret, cur);
4682: }
4683: xmlXPathNodeSetSort(ret); /* bug 413451 */
4684: return(ret);
4685: }
4686:
4687: /**
4688: * xmlXPathNodeTrailing:
4689: * @nodes: a node-set
4690: * @node: a node
4691: *
4692: * Implements the EXSLT - Sets trailing() function:
4693: * node-set set:trailing (node-set, node-set)
4694: * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4695: * is called.
4696: *
4697: * Returns the nodes in @nodes that follow @node in document order,
4698: * @nodes if @node is NULL or an empty node-set if @nodes
4699: * doesn't contain @node
4700: */
4701: xmlNodeSetPtr
4702: xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4703: xmlXPathNodeSetSort(nodes);
4704: return(xmlXPathNodeTrailingSorted(nodes, node));
4705: }
4706:
4707: /**
4708: * xmlXPathTrailingSorted:
4709: * @nodes1: a node-set, sorted by document order
4710: * @nodes2: a node-set, sorted by document order
4711: *
4712: * Implements the EXSLT - Sets trailing() function:
4713: * node-set set:trailing (node-set, node-set)
4714: *
4715: * Returns the nodes in @nodes1 that follow the first node in @nodes2
4716: * in document order, @nodes1 if @nodes2 is NULL or empty or
4717: * an empty node-set if @nodes1 doesn't contain @nodes2
4718: */
4719: xmlNodeSetPtr
4720: xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4721: if (xmlXPathNodeSetIsEmpty(nodes2))
4722: return(nodes1);
4723: return(xmlXPathNodeTrailingSorted(nodes1,
4724: xmlXPathNodeSetItem(nodes2, 0)));
4725: }
4726:
4727: /**
4728: * xmlXPathTrailing:
4729: * @nodes1: a node-set
4730: * @nodes2: a node-set
4731: *
4732: * Implements the EXSLT - Sets trailing() function:
4733: * node-set set:trailing (node-set, node-set)
4734: * @nodes1 and @nodes2 are sorted by document order, then
4735: * #xmlXPathTrailingSorted is called.
4736: *
4737: * Returns the nodes in @nodes1 that follow the first node in @nodes2
4738: * in document order, @nodes1 if @nodes2 is NULL or empty or
4739: * an empty node-set if @nodes1 doesn't contain @nodes2
4740: */
4741: xmlNodeSetPtr
4742: xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4743: if (xmlXPathNodeSetIsEmpty(nodes2))
4744: return(nodes1);
4745: if (xmlXPathNodeSetIsEmpty(nodes1))
4746: return(xmlXPathNodeSetCreate(NULL));
4747: xmlXPathNodeSetSort(nodes1);
4748: xmlXPathNodeSetSort(nodes2);
4749: return(xmlXPathNodeTrailingSorted(nodes1,
4750: xmlXPathNodeSetItem(nodes2, 0)));
4751: }
4752:
4753: /************************************************************************
4754: * *
4755: * Routines to handle extra functions *
4756: * *
4757: ************************************************************************/
4758:
4759: /**
4760: * xmlXPathRegisterFunc:
4761: * @ctxt: the XPath context
4762: * @name: the function name
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: */
4769: int
4770: xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4771: xmlXPathFunction f) {
4772: return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4773: }
4774:
4775: /**
4776: * xmlXPathRegisterFuncNS:
4777: * @ctxt: the XPath context
4778: * @name: the function name
4779: * @ns_uri: the function namespace URI
4780: * @f: the function implementation or NULL
4781: *
4782: * Register a new function. If @f is NULL it unregisters the function
4783: *
4784: * Returns 0 in case of success, -1 in case of error
4785: */
4786: int
4787: xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4788: const xmlChar *ns_uri, xmlXPathFunction f) {
4789: if (ctxt == NULL)
4790: return(-1);
4791: if (name == NULL)
4792: return(-1);
4793:
4794: if (ctxt->funcHash == NULL)
4795: ctxt->funcHash = xmlHashCreate(0);
4796: if (ctxt->funcHash == NULL)
4797: return(-1);
4798: if (f == NULL)
4799: return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4800: return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
4801: }
4802:
4803: /**
4804: * xmlXPathRegisterFuncLookup:
4805: * @ctxt: the XPath context
4806: * @f: the lookup function
4807: * @funcCtxt: the lookup data
4808: *
4809: * Registers an external mechanism to do function lookup.
4810: */
4811: void
4812: xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4813: xmlXPathFuncLookupFunc f,
4814: void *funcCtxt) {
4815: if (ctxt == NULL)
4816: return;
4817: ctxt->funcLookupFunc = f;
4818: ctxt->funcLookupData = funcCtxt;
4819: }
4820:
4821: /**
4822: * xmlXPathFunctionLookup:
4823: * @ctxt: the XPath context
4824: * @name: the function name
4825: *
4826: * Search in the Function array of the context for the given
4827: * function.
4828: *
4829: * Returns the xmlXPathFunction or NULL if not found
4830: */
4831: xmlXPathFunction
4832: xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4833: if (ctxt == NULL)
4834: return (NULL);
4835:
4836: if (ctxt->funcLookupFunc != NULL) {
4837: xmlXPathFunction ret;
4838: xmlXPathFuncLookupFunc f;
4839:
4840: f = ctxt->funcLookupFunc;
4841: ret = f(ctxt->funcLookupData, name, NULL);
4842: if (ret != NULL)
4843: return(ret);
4844: }
4845: return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4846: }
4847:
4848: /**
4849: * xmlXPathFunctionLookupNS:
4850: * @ctxt: the XPath context
4851: * @name: the function name
4852: * @ns_uri: the function namespace URI
4853: *
4854: * Search in the Function array of the context for the given
4855: * function.
4856: *
4857: * Returns the xmlXPathFunction or NULL if not found
4858: */
4859: xmlXPathFunction
4860: xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4861: const xmlChar *ns_uri) {
4862: xmlXPathFunction ret;
4863:
4864: if (ctxt == NULL)
4865: return(NULL);
4866: if (name == NULL)
4867: return(NULL);
4868:
4869: if (ctxt->funcLookupFunc != NULL) {
4870: xmlXPathFuncLookupFunc f;
4871:
4872: f = ctxt->funcLookupFunc;
4873: ret = f(ctxt->funcLookupData, name, ns_uri);
4874: if (ret != NULL)
4875: return(ret);
4876: }
4877:
4878: if (ctxt->funcHash == NULL)
4879: return(NULL);
4880:
4881: XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4882: return(ret);
4883: }
4884:
4885: /**
4886: * xmlXPathRegisteredFuncsCleanup:
4887: * @ctxt: the XPath context
4888: *
4889: * Cleanup the XPath context data associated to registered functions
4890: */
4891: void
4892: xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4893: if (ctxt == NULL)
4894: return;
4895:
4896: xmlHashFree(ctxt->funcHash, NULL);
4897: ctxt->funcHash = NULL;
4898: }
4899:
4900: /************************************************************************
4901: * *
4902: * Routines to handle Variables *
4903: * *
4904: ************************************************************************/
4905:
4906: /**
4907: * xmlXPathRegisterVariable:
4908: * @ctxt: the XPath context
4909: * @name: the variable name
4910: * @value: the variable value or NULL
4911: *
4912: * Register a new variable value. If @value is NULL it unregisters
4913: * the variable
4914: *
4915: * Returns 0 in case of success, -1 in case of error
4916: */
4917: int
4918: xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4919: xmlXPathObjectPtr value) {
4920: return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4921: }
4922:
4923: /**
4924: * xmlXPathRegisterVariableNS:
4925: * @ctxt: the XPath context
4926: * @name: the variable name
4927: * @ns_uri: the variable namespace URI
4928: * @value: the variable value or NULL
4929: *
4930: * Register a new variable value. If @value is NULL it unregisters
4931: * the variable
4932: *
4933: * Returns 0 in case of success, -1 in case of error
4934: */
4935: int
4936: xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4937: const xmlChar *ns_uri,
4938: xmlXPathObjectPtr value) {
4939: if (ctxt == NULL)
4940: return(-1);
4941: if (name == NULL)
4942: return(-1);
4943:
4944: if (ctxt->varHash == NULL)
4945: ctxt->varHash = xmlHashCreate(0);
4946: if (ctxt->varHash == NULL)
4947: return(-1);
4948: if (value == NULL)
4949: return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4950: (xmlHashDeallocator)xmlXPathFreeObject));
4951: return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4952: (void *) value,
4953: (xmlHashDeallocator)xmlXPathFreeObject));
4954: }
4955:
4956: /**
4957: * xmlXPathRegisterVariableLookup:
4958: * @ctxt: the XPath context
4959: * @f: the lookup function
4960: * @data: the lookup data
4961: *
4962: * register an external mechanism to do variable lookup
4963: */
4964: void
4965: xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4966: xmlXPathVariableLookupFunc f, void *data) {
4967: if (ctxt == NULL)
4968: return;
4969: ctxt->varLookupFunc = f;
4970: ctxt->varLookupData = data;
4971: }
4972:
4973: /**
4974: * xmlXPathVariableLookup:
4975: * @ctxt: the XPath context
4976: * @name: the variable name
4977: *
4978: * Search in the Variable array of the context for the given
4979: * variable value.
4980: *
4981: * Returns a copy of the value or NULL if not found
4982: */
4983: xmlXPathObjectPtr
4984: xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4985: if (ctxt == NULL)
4986: return(NULL);
4987:
4988: if (ctxt->varLookupFunc != NULL) {
4989: xmlXPathObjectPtr ret;
4990:
4991: ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4992: (ctxt->varLookupData, name, NULL);
4993: return(ret);
4994: }
4995: return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4996: }
4997:
4998: /**
4999: * xmlXPathVariableLookupNS:
5000: * @ctxt: the XPath context
5001: * @name: the variable name
5002: * @ns_uri: the variable namespace URI
5003: *
5004: * Search in the Variable array of the context for the given
5005: * variable value.
5006: *
5007: * Returns the a copy of the value or NULL if not found
5008: */
5009: xmlXPathObjectPtr
5010: xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5011: const xmlChar *ns_uri) {
5012: if (ctxt == NULL)
5013: return(NULL);
5014:
5015: if (ctxt->varLookupFunc != NULL) {
5016: xmlXPathObjectPtr ret;
5017:
5018: ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5019: (ctxt->varLookupData, name, ns_uri);
5020: if (ret != NULL) return(ret);
5021: }
5022:
5023: if (ctxt->varHash == NULL)
5024: return(NULL);
5025: if (name == NULL)
5026: return(NULL);
5027:
5028: return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5029: xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5030: }
5031:
5032: /**
5033: * xmlXPathRegisteredVariablesCleanup:
5034: * @ctxt: the XPath context
5035: *
5036: * Cleanup the XPath context data associated to registered variables
5037: */
5038: void
5039: xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5040: if (ctxt == NULL)
5041: return;
5042:
5043: xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
5044: ctxt->varHash = NULL;
5045: }
5046:
5047: /**
5048: * xmlXPathRegisterNs:
5049: * @ctxt: the XPath context
5050: * @prefix: the namespace prefix cannot be NULL or empty string
5051: * @ns_uri: the namespace name
5052: *
5053: * Register a new namespace. If @ns_uri is NULL it unregisters
5054: * the namespace
5055: *
5056: * Returns 0 in case of success, -1 in case of error
5057: */
5058: int
5059: xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5060: const xmlChar *ns_uri) {
5061: if (ctxt == NULL)
5062: return(-1);
5063: if (prefix == NULL)
5064: return(-1);
5065: if (prefix[0] == 0)
5066: return(-1);
5067:
5068: if (ctxt->nsHash == NULL)
5069: ctxt->nsHash = xmlHashCreate(10);
5070: if (ctxt->nsHash == NULL)
5071: return(-1);
5072: if (ns_uri == NULL)
5073: return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5074: (xmlHashDeallocator)xmlFree));
5075: return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5076: (xmlHashDeallocator)xmlFree));
5077: }
5078:
5079: /**
5080: * xmlXPathNsLookup:
5081: * @ctxt: the XPath context
5082: * @prefix: the namespace prefix value
5083: *
5084: * Search in the namespace declaration array of the context for the given
5085: * namespace name associated to the given prefix
5086: *
5087: * Returns the value or NULL if not found
5088: */
5089: const xmlChar *
5090: xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5091: if (ctxt == NULL)
5092: return(NULL);
5093: if (prefix == NULL)
5094: return(NULL);
5095:
5096: #ifdef XML_XML_NAMESPACE
5097: if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5098: return(XML_XML_NAMESPACE);
5099: #endif
5100:
5101: if (ctxt->namespaces != NULL) {
5102: int i;
5103:
5104: for (i = 0;i < ctxt->nsNr;i++) {
5105: if ((ctxt->namespaces[i] != NULL) &&
5106: (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5107: return(ctxt->namespaces[i]->href);
5108: }
5109: }
5110:
5111: return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5112: }
5113:
5114: /**
5115: * xmlXPathRegisteredNsCleanup:
5116: * @ctxt: the XPath context
5117: *
5118: * Cleanup the XPath context data associated to registered variables
5119: */
5120: void
5121: xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5122: if (ctxt == NULL)
5123: return;
5124:
5125: xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
5126: ctxt->nsHash = NULL;
5127: }
5128:
5129: /************************************************************************
5130: * *
5131: * Routines to handle Values *
5132: * *
5133: ************************************************************************/
5134:
5135: /* Allocations are terrible, one needs to optimize all this !!! */
5136:
5137: /**
5138: * xmlXPathNewFloat:
5139: * @val: the double value
5140: *
5141: * Create a new xmlXPathObjectPtr of type double and of value @val
5142: *
5143: * Returns the newly created object.
5144: */
5145: xmlXPathObjectPtr
5146: xmlXPathNewFloat(double val) {
5147: xmlXPathObjectPtr ret;
5148:
5149: ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5150: if (ret == NULL) {
5151: xmlXPathErrMemory(NULL, "creating float object\n");
5152: return(NULL);
5153: }
5154: memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5155: ret->type = XPATH_NUMBER;
5156: ret->floatval = val;
5157: #ifdef XP_DEBUG_OBJ_USAGE
5158: xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5159: #endif
5160: return(ret);
5161: }
5162:
5163: /**
5164: * xmlXPathNewBoolean:
5165: * @val: the boolean value
5166: *
5167: * Create a new xmlXPathObjectPtr of type boolean and of value @val
5168: *
5169: * Returns the newly created object.
5170: */
5171: xmlXPathObjectPtr
5172: xmlXPathNewBoolean(int val) {
5173: xmlXPathObjectPtr ret;
5174:
5175: ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5176: if (ret == NULL) {
5177: xmlXPathErrMemory(NULL, "creating boolean object\n");
5178: return(NULL);
5179: }
5180: memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5181: ret->type = XPATH_BOOLEAN;
5182: ret->boolval = (val != 0);
5183: #ifdef XP_DEBUG_OBJ_USAGE
5184: xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5185: #endif
5186: return(ret);
5187: }
5188:
5189: /**
5190: * xmlXPathNewString:
5191: * @val: the xmlChar * value
5192: *
5193: * Create a new xmlXPathObjectPtr of type string and of value @val
5194: *
5195: * Returns the newly created object.
5196: */
5197: xmlXPathObjectPtr
5198: xmlXPathNewString(const xmlChar *val) {
5199: xmlXPathObjectPtr ret;
5200:
5201: ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5202: if (ret == NULL) {
5203: xmlXPathErrMemory(NULL, "creating string object\n");
5204: return(NULL);
5205: }
5206: memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5207: ret->type = XPATH_STRING;
5208: if (val != NULL)
5209: ret->stringval = xmlStrdup(val);
5210: else
5211: ret->stringval = xmlStrdup((const xmlChar *)"");
5212: #ifdef XP_DEBUG_OBJ_USAGE
5213: xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5214: #endif
5215: return(ret);
5216: }
5217:
5218: /**
5219: * xmlXPathWrapString:
5220: * @val: the xmlChar * value
5221: *
5222: * Wraps the @val string into an XPath object.
5223: *
5224: * Returns the newly created object.
5225: */
5226: xmlXPathObjectPtr
5227: xmlXPathWrapString (xmlChar *val) {
5228: xmlXPathObjectPtr ret;
5229:
5230: ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5231: if (ret == NULL) {
5232: xmlXPathErrMemory(NULL, "creating string object\n");
5233: return(NULL);
5234: }
5235: memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5236: ret->type = XPATH_STRING;
5237: ret->stringval = val;
5238: #ifdef XP_DEBUG_OBJ_USAGE
5239: xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5240: #endif
5241: return(ret);
5242: }
5243:
5244: /**
5245: * xmlXPathNewCString:
5246: * @val: the char * value
5247: *
5248: * Create a new xmlXPathObjectPtr of type string and of value @val
5249: *
5250: * Returns the newly created object.
5251: */
5252: xmlXPathObjectPtr
5253: xmlXPathNewCString(const char *val) {
5254: xmlXPathObjectPtr ret;
5255:
5256: ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5257: if (ret == NULL) {
5258: xmlXPathErrMemory(NULL, "creating string object\n");
5259: return(NULL);
5260: }
5261: memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5262: ret->type = XPATH_STRING;
5263: ret->stringval = xmlStrdup(BAD_CAST val);
5264: #ifdef XP_DEBUG_OBJ_USAGE
5265: xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5266: #endif
5267: return(ret);
5268: }
5269:
5270: /**
5271: * xmlXPathWrapCString:
5272: * @val: the char * value
5273: *
5274: * Wraps a string into an XPath object.
5275: *
5276: * Returns the newly created object.
5277: */
5278: xmlXPathObjectPtr
5279: xmlXPathWrapCString (char * val) {
5280: return(xmlXPathWrapString((xmlChar *)(val)));
5281: }
5282:
5283: /**
5284: * xmlXPathWrapExternal:
5285: * @val: the user data
5286: *
5287: * Wraps the @val data into an XPath object.
5288: *
5289: * Returns the newly created object.
5290: */
5291: xmlXPathObjectPtr
5292: xmlXPathWrapExternal (void *val) {
5293: xmlXPathObjectPtr ret;
5294:
5295: ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5296: if (ret == NULL) {
5297: xmlXPathErrMemory(NULL, "creating user object\n");
5298: return(NULL);
5299: }
5300: memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5301: ret->type = XPATH_USERS;
5302: ret->user = val;
5303: #ifdef XP_DEBUG_OBJ_USAGE
5304: xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5305: #endif
5306: return(ret);
5307: }
5308:
5309: /**
5310: * xmlXPathObjectCopy:
5311: * @val: the original object
5312: *
5313: * allocate a new copy of a given object
5314: *
5315: * Returns the newly created object.
5316: */
5317: xmlXPathObjectPtr
5318: xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5319: xmlXPathObjectPtr ret;
5320:
5321: if (val == NULL)
5322: return(NULL);
5323:
5324: ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5325: if (ret == NULL) {
5326: xmlXPathErrMemory(NULL, "copying object\n");
5327: return(NULL);
5328: }
5329: memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5330: #ifdef XP_DEBUG_OBJ_USAGE
5331: xmlXPathDebugObjUsageRequested(NULL, val->type);
5332: #endif
5333: switch (val->type) {
5334: case XPATH_BOOLEAN:
5335: case XPATH_NUMBER:
5336: case XPATH_POINT:
5337: case XPATH_RANGE:
5338: break;
5339: case XPATH_STRING:
5340: ret->stringval = xmlStrdup(val->stringval);
5341: break;
5342: case XPATH_XSLT_TREE:
5343: #if 0
5344: /*
5345: Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5346: this previous handling is no longer correct, and can cause some serious
5347: problems (ref. bug 145547)
5348: */
5349: if ((val->nodesetval != NULL) &&
5350: (val->nodesetval->nodeTab != NULL)) {
5351: xmlNodePtr cur, tmp;
5352: xmlDocPtr top;
5353:
5354: ret->boolval = 1;
5355: top = xmlNewDoc(NULL);
5356: top->name = (char *)
5357: xmlStrdup(val->nodesetval->nodeTab[0]->name);
5358: ret->user = top;
5359: if (top != NULL) {
5360: top->doc = top;
5361: cur = val->nodesetval->nodeTab[0]->children;
5362: while (cur != NULL) {
5363: tmp = xmlDocCopyNode(cur, top, 1);
5364: xmlAddChild((xmlNodePtr) top, tmp);
5365: cur = cur->next;
5366: }
5367: }
5368:
5369: ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5370: } else
5371: ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5372: /* Deallocate the copied tree value */
5373: break;
5374: #endif
5375: case XPATH_NODESET:
5376: ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5377: /* Do not deallocate the copied tree value */
5378: ret->boolval = 0;
5379: break;
5380: case XPATH_LOCATIONSET:
5381: #ifdef LIBXML_XPTR_ENABLED
5382: {
5383: xmlLocationSetPtr loc = val->user;
5384: ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5385: break;
5386: }
5387: #endif
5388: case XPATH_USERS:
5389: ret->user = val->user;
5390: break;
5391: case XPATH_UNDEFINED:
5392: xmlGenericError(xmlGenericErrorContext,
5393: "xmlXPathObjectCopy: unsupported type %d\n",
5394: val->type);
5395: break;
5396: }
5397: return(ret);
5398: }
5399:
5400: /**
5401: * xmlXPathFreeObject:
5402: * @obj: the object to free
5403: *
5404: * Free up an xmlXPathObjectPtr object.
5405: */
5406: void
5407: xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5408: if (obj == NULL) return;
5409: if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5410: if (obj->boolval) {
5411: #if 0
5412: if (obj->user != NULL) {
5413: xmlXPathFreeNodeSet(obj->nodesetval);
5414: xmlFreeNodeList((xmlNodePtr) obj->user);
5415: } else
5416: #endif
5417: obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5418: if (obj->nodesetval != NULL)
5419: xmlXPathFreeValueTree(obj->nodesetval);
5420: } else {
5421: if (obj->nodesetval != NULL)
5422: xmlXPathFreeNodeSet(obj->nodesetval);
5423: }
5424: #ifdef LIBXML_XPTR_ENABLED
5425: } else if (obj->type == XPATH_LOCATIONSET) {
5426: if (obj->user != NULL)
5427: xmlXPtrFreeLocationSet(obj->user);
5428: #endif
5429: } else if (obj->type == XPATH_STRING) {
5430: if (obj->stringval != NULL)
5431: xmlFree(obj->stringval);
5432: }
5433: #ifdef XP_DEBUG_OBJ_USAGE
5434: xmlXPathDebugObjUsageReleased(NULL, obj->type);
5435: #endif
5436: xmlFree(obj);
5437: }
5438:
5439: /**
5440: * xmlXPathReleaseObject:
5441: * @obj: the xmlXPathObjectPtr to free or to cache
5442: *
5443: * Depending on the state of the cache this frees the given
5444: * XPath object or stores it in the cache.
5445: */
5446: static void
5447: xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5448: {
5449: #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5450: sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5451: if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5452:
5453: #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5454:
5455: if (obj == NULL)
5456: return;
5457: if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5458: xmlXPathFreeObject(obj);
5459: } else {
5460: xmlXPathContextCachePtr cache =
5461: (xmlXPathContextCachePtr) ctxt->cache;
5462:
5463: switch (obj->type) {
5464: case XPATH_NODESET:
5465: case XPATH_XSLT_TREE:
5466: if (obj->nodesetval != NULL) {
5467: if (obj->boolval) {
5468: /*
5469: * It looks like the @boolval is used for
5470: * evaluation if this an XSLT Result Tree Fragment.
5471: * TODO: Check if this assumption is correct.
5472: */
5473: obj->type = XPATH_XSLT_TREE; /* just for debugging */
5474: xmlXPathFreeValueTree(obj->nodesetval);
5475: obj->nodesetval = NULL;
5476: } else if ((obj->nodesetval->nodeMax <= 40) &&
5477: (XP_CACHE_WANTS(cache->nodesetObjs,
5478: cache->maxNodeset)))
5479: {
5480: XP_CACHE_ADD(cache->nodesetObjs, obj);
5481: goto obj_cached;
5482: } else {
5483: xmlXPathFreeNodeSet(obj->nodesetval);
5484: obj->nodesetval = NULL;
5485: }
5486: }
5487: break;
5488: case XPATH_STRING:
5489: if (obj->stringval != NULL)
5490: xmlFree(obj->stringval);
5491:
5492: if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5493: XP_CACHE_ADD(cache->stringObjs, obj);
5494: goto obj_cached;
5495: }
5496: break;
5497: case XPATH_BOOLEAN:
5498: if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5499: XP_CACHE_ADD(cache->booleanObjs, obj);
5500: goto obj_cached;
5501: }
5502: break;
5503: case XPATH_NUMBER:
5504: if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5505: XP_CACHE_ADD(cache->numberObjs, obj);
5506: goto obj_cached;
5507: }
5508: break;
5509: #ifdef LIBXML_XPTR_ENABLED
5510: case XPATH_LOCATIONSET:
5511: if (obj->user != NULL) {
5512: xmlXPtrFreeLocationSet(obj->user);
5513: }
5514: goto free_obj;
5515: #endif
5516: default:
5517: goto free_obj;
5518: }
5519:
5520: /*
5521: * Fallback to adding to the misc-objects slot.
5522: */
5523: if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5524: XP_CACHE_ADD(cache->miscObjs, obj);
5525: } else
5526: goto free_obj;
5527:
5528: obj_cached:
5529:
5530: #ifdef XP_DEBUG_OBJ_USAGE
5531: xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5532: #endif
5533:
5534: if (obj->nodesetval != NULL) {
5535: xmlNodeSetPtr tmpset = obj->nodesetval;
5536:
5537: /*
5538: * TODO: Due to those nasty ns-nodes, we need to traverse
5539: * the list and free the ns-nodes.
5540: * URGENT TODO: Check if it's actually slowing things down.
5541: * Maybe we shouldn't try to preserve the list.
5542: */
5543: if (tmpset->nodeNr > 1) {
5544: int i;
5545: xmlNodePtr node;
5546:
5547: for (i = 0; i < tmpset->nodeNr; i++) {
5548: node = tmpset->nodeTab[i];
5549: if ((node != NULL) &&
5550: (node->type == XML_NAMESPACE_DECL))
5551: {
5552: xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5553: }
5554: }
5555: } else if (tmpset->nodeNr == 1) {
5556: if ((tmpset->nodeTab[0] != NULL) &&
5557: (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5558: xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5559: }
5560: tmpset->nodeNr = 0;
5561: memset(obj, 0, sizeof(xmlXPathObject));
5562: obj->nodesetval = tmpset;
5563: } else
5564: memset(obj, 0, sizeof(xmlXPathObject));
5565:
5566: return;
5567:
5568: free_obj:
5569: /*
5570: * Cache is full; free the object.
5571: */
5572: if (obj->nodesetval != NULL)
5573: xmlXPathFreeNodeSet(obj->nodesetval);
5574: #ifdef XP_DEBUG_OBJ_USAGE
5575: xmlXPathDebugObjUsageReleased(NULL, obj->type);
5576: #endif
5577: xmlFree(obj);
5578: }
5579: return;
5580: }
5581:
5582:
5583: /************************************************************************
5584: * *
5585: * Type Casting Routines *
5586: * *
5587: ************************************************************************/
5588:
5589: /**
5590: * xmlXPathCastBooleanToString:
5591: * @val: a boolean
5592: *
5593: * Converts a boolean to its string value.
5594: *
5595: * Returns a newly allocated string.
5596: */
5597: xmlChar *
5598: xmlXPathCastBooleanToString (int val) {
5599: xmlChar *ret;
5600: if (val)
5601: ret = xmlStrdup((const xmlChar *) "true");
5602: else
5603: ret = xmlStrdup((const xmlChar *) "false");
5604: return(ret);
5605: }
5606:
5607: /**
5608: * xmlXPathCastNumberToString:
5609: * @val: a number
5610: *
5611: * Converts a number to its string value.
5612: *
5613: * Returns a newly allocated string.
5614: */
5615: xmlChar *
5616: xmlXPathCastNumberToString (double val) {
5617: xmlChar *ret;
5618: switch (xmlXPathIsInf(val)) {
5619: case 1:
5620: ret = xmlStrdup((const xmlChar *) "Infinity");
5621: break;
5622: case -1:
5623: ret = xmlStrdup((const xmlChar *) "-Infinity");
5624: break;
5625: default:
5626: if (xmlXPathIsNaN(val)) {
5627: ret = xmlStrdup((const xmlChar *) "NaN");
5628: } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5629: ret = xmlStrdup((const xmlChar *) "0");
5630: } else {
5631: /* could be improved */
5632: char buf[100];
5633: xmlXPathFormatNumber(val, buf, 99);
5634: buf[99] = 0;
5635: ret = xmlStrdup((const xmlChar *) buf);
5636: }
5637: }
5638: return(ret);
5639: }
5640:
5641: /**
5642: * xmlXPathCastNodeToString:
5643: * @node: a node
5644: *
5645: * Converts a node to its string value.
5646: *
5647: * Returns a newly allocated string.
5648: */
5649: xmlChar *
5650: xmlXPathCastNodeToString (xmlNodePtr node) {
5651: xmlChar *ret;
5652: if ((ret = xmlNodeGetContent(node)) == NULL)
5653: ret = xmlStrdup((const xmlChar *) "");
5654: return(ret);
5655: }
5656:
5657: /**
5658: * xmlXPathCastNodeSetToString:
5659: * @ns: a node-set
5660: *
5661: * Converts a node-set to its string value.
5662: *
5663: * Returns a newly allocated string.
5664: */
5665: xmlChar *
5666: xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5667: if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5668: return(xmlStrdup((const xmlChar *) ""));
5669:
5670: if (ns->nodeNr > 1)
5671: xmlXPathNodeSetSort(ns);
5672: return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5673: }
5674:
5675: /**
5676: * xmlXPathCastToString:
5677: * @val: an XPath object
5678: *
5679: * Converts an existing object to its string() equivalent
5680: *
5681: * Returns the allocated string value of the object, NULL in case of error.
5682: * It's up to the caller to free the string memory with xmlFree().
5683: */
5684: xmlChar *
5685: xmlXPathCastToString(xmlXPathObjectPtr val) {
5686: xmlChar *ret = NULL;
5687:
5688: if (val == NULL)
5689: return(xmlStrdup((const xmlChar *) ""));
5690: switch (val->type) {
5691: case XPATH_UNDEFINED:
5692: #ifdef DEBUG_EXPR
5693: xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5694: #endif
5695: ret = xmlStrdup((const xmlChar *) "");
5696: break;
5697: case XPATH_NODESET:
5698: case XPATH_XSLT_TREE:
5699: ret = xmlXPathCastNodeSetToString(val->nodesetval);
5700: break;
5701: case XPATH_STRING:
5702: return(xmlStrdup(val->stringval));
5703: case XPATH_BOOLEAN:
5704: ret = xmlXPathCastBooleanToString(val->boolval);
5705: break;
5706: case XPATH_NUMBER: {
5707: ret = xmlXPathCastNumberToString(val->floatval);
5708: break;
5709: }
5710: case XPATH_USERS:
5711: case XPATH_POINT:
5712: case XPATH_RANGE:
5713: case XPATH_LOCATIONSET:
5714: TODO
5715: ret = xmlStrdup((const xmlChar *) "");
5716: break;
5717: }
5718: return(ret);
5719: }
5720:
5721: /**
5722: * xmlXPathConvertString:
5723: * @val: an XPath object
5724: *
5725: * Converts an existing object to its string() equivalent
5726: *
5727: * Returns the new object, the old one is freed (or the operation
5728: * is done directly on @val)
5729: */
5730: xmlXPathObjectPtr
5731: xmlXPathConvertString(xmlXPathObjectPtr val) {
5732: xmlChar *res = NULL;
5733:
5734: if (val == NULL)
5735: return(xmlXPathNewCString(""));
5736:
5737: switch (val->type) {
5738: case XPATH_UNDEFINED:
5739: #ifdef DEBUG_EXPR
5740: xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5741: #endif
5742: break;
5743: case XPATH_NODESET:
5744: case XPATH_XSLT_TREE:
5745: res = xmlXPathCastNodeSetToString(val->nodesetval);
5746: break;
5747: case XPATH_STRING:
5748: return(val);
5749: case XPATH_BOOLEAN:
5750: res = xmlXPathCastBooleanToString(val->boolval);
5751: break;
5752: case XPATH_NUMBER:
5753: res = xmlXPathCastNumberToString(val->floatval);
5754: break;
5755: case XPATH_USERS:
5756: case XPATH_POINT:
5757: case XPATH_RANGE:
5758: case XPATH_LOCATIONSET:
5759: TODO;
5760: break;
5761: }
5762: xmlXPathFreeObject(val);
5763: if (res == NULL)
5764: return(xmlXPathNewCString(""));
5765: return(xmlXPathWrapString(res));
5766: }
5767:
5768: /**
5769: * xmlXPathCastBooleanToNumber:
5770: * @val: a boolean
5771: *
5772: * Converts a boolean to its number value
5773: *
5774: * Returns the number value
5775: */
5776: double
5777: xmlXPathCastBooleanToNumber(int val) {
5778: if (val)
5779: return(1.0);
5780: return(0.0);
5781: }
5782:
5783: /**
5784: * xmlXPathCastStringToNumber:
5785: * @val: a string
5786: *
5787: * Converts a string to its number value
5788: *
5789: * Returns the number value
5790: */
5791: double
5792: xmlXPathCastStringToNumber(const xmlChar * val) {
5793: return(xmlXPathStringEvalNumber(val));
5794: }
5795:
5796: /**
5797: * xmlXPathCastNodeToNumber:
5798: * @node: a node
5799: *
5800: * Converts a node to its number value
5801: *
5802: * Returns the number value
5803: */
5804: double
5805: xmlXPathCastNodeToNumber (xmlNodePtr node) {
5806: xmlChar *strval;
5807: double ret;
5808:
5809: if (node == NULL)
5810: return(xmlXPathNAN);
5811: strval = xmlXPathCastNodeToString(node);
5812: if (strval == NULL)
5813: return(xmlXPathNAN);
5814: ret = xmlXPathCastStringToNumber(strval);
5815: xmlFree(strval);
5816:
5817: return(ret);
5818: }
5819:
5820: /**
5821: * xmlXPathCastNodeSetToNumber:
5822: * @ns: a node-set
5823: *
5824: * Converts a node-set to its number value
5825: *
5826: * Returns the number value
5827: */
5828: double
5829: xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5830: xmlChar *str;
5831: double ret;
5832:
5833: if (ns == NULL)
5834: return(xmlXPathNAN);
5835: str = xmlXPathCastNodeSetToString(ns);
5836: ret = xmlXPathCastStringToNumber(str);
5837: xmlFree(str);
5838: return(ret);
5839: }
5840:
5841: /**
5842: * xmlXPathCastToNumber:
5843: * @val: an XPath object
5844: *
5845: * Converts an XPath object to its number value
5846: *
5847: * Returns the number value
5848: */
5849: double
5850: xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5851: double ret = 0.0;
5852:
5853: if (val == NULL)
5854: return(xmlXPathNAN);
5855: switch (val->type) {
5856: case XPATH_UNDEFINED:
5857: #ifdef DEGUB_EXPR
5858: xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5859: #endif
5860: ret = xmlXPathNAN;
5861: break;
5862: case XPATH_NODESET:
5863: case XPATH_XSLT_TREE:
5864: ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5865: break;
5866: case XPATH_STRING:
5867: ret = xmlXPathCastStringToNumber(val->stringval);
5868: break;
5869: case XPATH_NUMBER:
5870: ret = val->floatval;
5871: break;
5872: case XPATH_BOOLEAN:
5873: ret = xmlXPathCastBooleanToNumber(val->boolval);
5874: break;
5875: case XPATH_USERS:
5876: case XPATH_POINT:
5877: case XPATH_RANGE:
5878: case XPATH_LOCATIONSET:
5879: TODO;
5880: ret = xmlXPathNAN;
5881: break;
5882: }
5883: return(ret);
5884: }
5885:
5886: /**
5887: * xmlXPathConvertNumber:
5888: * @val: an XPath object
5889: *
5890: * Converts an existing object to its number() equivalent
5891: *
5892: * Returns the new object, the old one is freed (or the operation
5893: * is done directly on @val)
5894: */
5895: xmlXPathObjectPtr
5896: xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5897: xmlXPathObjectPtr ret;
5898:
5899: if (val == NULL)
5900: return(xmlXPathNewFloat(0.0));
5901: if (val->type == XPATH_NUMBER)
5902: return(val);
5903: ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5904: xmlXPathFreeObject(val);
5905: return(ret);
5906: }
5907:
5908: /**
5909: * xmlXPathCastNumberToBoolean:
5910: * @val: a number
5911: *
5912: * Converts a number to its boolean value
5913: *
5914: * Returns the boolean value
5915: */
5916: int
5917: xmlXPathCastNumberToBoolean (double val) {
5918: if (xmlXPathIsNaN(val) || (val == 0.0))
5919: return(0);
5920: return(1);
5921: }
5922:
5923: /**
5924: * xmlXPathCastStringToBoolean:
5925: * @val: a string
5926: *
5927: * Converts a string to its boolean value
5928: *
5929: * Returns the boolean value
5930: */
5931: int
5932: xmlXPathCastStringToBoolean (const xmlChar *val) {
5933: if ((val == NULL) || (xmlStrlen(val) == 0))
5934: return(0);
5935: return(1);
5936: }
5937:
5938: /**
5939: * xmlXPathCastNodeSetToBoolean:
5940: * @ns: a node-set
5941: *
5942: * Converts a node-set to its boolean value
5943: *
5944: * Returns the boolean value
5945: */
5946: int
5947: xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5948: if ((ns == NULL) || (ns->nodeNr == 0))
5949: return(0);
5950: return(1);
5951: }
5952:
5953: /**
5954: * xmlXPathCastToBoolean:
5955: * @val: an XPath object
5956: *
5957: * Converts an XPath object to its boolean value
5958: *
5959: * Returns the boolean value
5960: */
5961: int
5962: xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5963: int ret = 0;
5964:
5965: if (val == NULL)
5966: return(0);
5967: switch (val->type) {
5968: case XPATH_UNDEFINED:
5969: #ifdef DEBUG_EXPR
5970: xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
5971: #endif
5972: ret = 0;
5973: break;
5974: case XPATH_NODESET:
5975: case XPATH_XSLT_TREE:
5976: ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5977: break;
5978: case XPATH_STRING:
5979: ret = xmlXPathCastStringToBoolean(val->stringval);
5980: break;
5981: case XPATH_NUMBER:
5982: ret = xmlXPathCastNumberToBoolean(val->floatval);
5983: break;
5984: case XPATH_BOOLEAN:
5985: ret = val->boolval;
5986: break;
5987: case XPATH_USERS:
5988: case XPATH_POINT:
5989: case XPATH_RANGE:
5990: case XPATH_LOCATIONSET:
5991: TODO;
5992: ret = 0;
5993: break;
5994: }
5995: return(ret);
5996: }
5997:
5998:
5999: /**
6000: * xmlXPathConvertBoolean:
6001: * @val: an XPath object
6002: *
6003: * Converts an existing object to its boolean() equivalent
6004: *
6005: * Returns the new object, the old one is freed (or the operation
6006: * is done directly on @val)
6007: */
6008: xmlXPathObjectPtr
6009: xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6010: xmlXPathObjectPtr ret;
6011:
6012: if (val == NULL)
6013: return(xmlXPathNewBoolean(0));
6014: if (val->type == XPATH_BOOLEAN)
6015: return(val);
6016: ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6017: xmlXPathFreeObject(val);
6018: return(ret);
6019: }
6020:
6021: /************************************************************************
6022: * *
6023: * Routines to handle XPath contexts *
6024: * *
6025: ************************************************************************/
6026:
6027: /**
6028: * xmlXPathNewContext:
6029: * @doc: the XML document
6030: *
6031: * Create a new xmlXPathContext
6032: *
6033: * Returns the xmlXPathContext just allocated. The caller will need to free it.
6034: */
6035: xmlXPathContextPtr
6036: xmlXPathNewContext(xmlDocPtr doc) {
6037: xmlXPathContextPtr ret;
6038:
6039: ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6040: if (ret == NULL) {
6041: xmlXPathErrMemory(NULL, "creating context\n");
6042: return(NULL);
6043: }
6044: memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6045: ret->doc = doc;
6046: ret->node = NULL;
6047:
6048: ret->varHash = NULL;
6049:
6050: ret->nb_types = 0;
6051: ret->max_types = 0;
6052: ret->types = NULL;
6053:
6054: ret->funcHash = xmlHashCreate(0);
6055:
6056: ret->nb_axis = 0;
6057: ret->max_axis = 0;
6058: ret->axis = NULL;
6059:
6060: ret->nsHash = NULL;
6061: ret->user = NULL;
6062:
6063: ret->contextSize = -1;
6064: ret->proximityPosition = -1;
6065:
6066: #ifdef XP_DEFAULT_CACHE_ON
6067: if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6068: xmlXPathFreeContext(ret);
6069: return(NULL);
6070: }
6071: #endif
6072:
6073: xmlXPathRegisterAllFunctions(ret);
6074:
6075: return(ret);
6076: }
6077:
6078: /**
6079: * xmlXPathFreeContext:
6080: * @ctxt: the context to free
6081: *
6082: * Free up an xmlXPathContext
6083: */
6084: void
6085: xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6086: if (ctxt == NULL) return;
6087:
6088: if (ctxt->cache != NULL)
6089: xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6090: xmlXPathRegisteredNsCleanup(ctxt);
6091: xmlXPathRegisteredFuncsCleanup(ctxt);
6092: xmlXPathRegisteredVariablesCleanup(ctxt);
6093: xmlResetError(&ctxt->lastError);
6094: xmlFree(ctxt);
6095: }
6096:
6097: /************************************************************************
6098: * *
6099: * Routines to handle XPath parser contexts *
6100: * *
6101: ************************************************************************/
6102:
6103: #define CHECK_CTXT(ctxt) \
6104: if (ctxt == NULL) { \
6105: __xmlRaiseError(NULL, NULL, NULL, \
6106: NULL, NULL, XML_FROM_XPATH, \
6107: XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6108: __FILE__, __LINE__, \
6109: NULL, NULL, NULL, 0, 0, \
6110: "NULL context pointer\n"); \
6111: return(NULL); \
6112: } \
6113:
6114: #define CHECK_CTXT_NEG(ctxt) \
6115: if (ctxt == NULL) { \
6116: __xmlRaiseError(NULL, NULL, NULL, \
6117: NULL, NULL, XML_FROM_XPATH, \
6118: XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6119: __FILE__, __LINE__, \
6120: NULL, NULL, NULL, 0, 0, \
6121: "NULL context pointer\n"); \
6122: return(-1); \
6123: } \
6124:
6125:
6126: #define CHECK_CONTEXT(ctxt) \
6127: if ((ctxt == NULL) || (ctxt->doc == NULL) || \
6128: (ctxt->doc->children == NULL)) { \
6129: xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
6130: return(NULL); \
6131: }
6132:
6133:
6134: /**
6135: * xmlXPathNewParserContext:
6136: * @str: the XPath expression
6137: * @ctxt: the XPath context
6138: *
6139: * Create a new xmlXPathParserContext
6140: *
6141: * Returns the xmlXPathParserContext just allocated.
6142: */
6143: xmlXPathParserContextPtr
6144: xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6145: xmlXPathParserContextPtr ret;
6146:
6147: ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6148: if (ret == NULL) {
6149: xmlXPathErrMemory(ctxt, "creating parser context\n");
6150: return(NULL);
6151: }
6152: memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6153: ret->cur = ret->base = str;
6154: ret->context = ctxt;
6155:
6156: ret->comp = xmlXPathNewCompExpr();
6157: if (ret->comp == NULL) {
6158: xmlFree(ret->valueTab);
6159: xmlFree(ret);
6160: return(NULL);
6161: }
6162: if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6163: ret->comp->dict = ctxt->dict;
6164: xmlDictReference(ret->comp->dict);
6165: }
6166:
6167: return(ret);
6168: }
6169:
6170: /**
6171: * xmlXPathCompParserContext:
6172: * @comp: the XPath compiled expression
6173: * @ctxt: the XPath context
6174: *
6175: * Create a new xmlXPathParserContext when processing a compiled expression
6176: *
6177: * Returns the xmlXPathParserContext just allocated.
6178: */
6179: static xmlXPathParserContextPtr
6180: xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6181: xmlXPathParserContextPtr ret;
6182:
6183: ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6184: if (ret == NULL) {
6185: xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6186: return(NULL);
6187: }
6188: memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6189:
6190: /* Allocate the value stack */
6191: ret->valueTab = (xmlXPathObjectPtr *)
6192: xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6193: if (ret->valueTab == NULL) {
6194: xmlFree(ret);
6195: xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6196: return(NULL);
6197: }
6198: ret->valueNr = 0;
6199: ret->valueMax = 10;
6200: ret->value = NULL;
1.1.1.2 ! misho 6201: ret->valueFrame = 0;
1.1 misho 6202:
6203: ret->context = ctxt;
6204: ret->comp = comp;
6205:
6206: return(ret);
6207: }
6208:
6209: /**
6210: * xmlXPathFreeParserContext:
6211: * @ctxt: the context to free
6212: *
6213: * Free up an xmlXPathParserContext
6214: */
6215: void
6216: xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6217: if (ctxt->valueTab != NULL) {
6218: xmlFree(ctxt->valueTab);
6219: }
6220: if (ctxt->comp != NULL) {
6221: #ifdef XPATH_STREAMING
6222: if (ctxt->comp->stream != NULL) {
6223: xmlFreePatternList(ctxt->comp->stream);
6224: ctxt->comp->stream = NULL;
6225: }
6226: #endif
6227: xmlXPathFreeCompExpr(ctxt->comp);
6228: }
6229: xmlFree(ctxt);
6230: }
6231:
6232: /************************************************************************
6233: * *
6234: * The implicit core function library *
6235: * *
6236: ************************************************************************/
6237:
6238: /**
6239: * xmlXPathNodeValHash:
6240: * @node: a node pointer
6241: *
6242: * Function computing the beginning of the string value of the node,
6243: * used to speed up comparisons
6244: *
6245: * Returns an int usable as a hash
6246: */
6247: static unsigned int
6248: xmlXPathNodeValHash(xmlNodePtr node) {
6249: int len = 2;
6250: const xmlChar * string = NULL;
6251: xmlNodePtr tmp = NULL;
6252: unsigned int ret = 0;
6253:
6254: if (node == NULL)
6255: return(0);
6256:
6257: if (node->type == XML_DOCUMENT_NODE) {
6258: tmp = xmlDocGetRootElement((xmlDocPtr) node);
6259: if (tmp == NULL)
6260: node = node->children;
6261: else
6262: node = tmp;
6263:
6264: if (node == NULL)
6265: return(0);
6266: }
6267:
6268: switch (node->type) {
6269: case XML_COMMENT_NODE:
6270: case XML_PI_NODE:
6271: case XML_CDATA_SECTION_NODE:
6272: case XML_TEXT_NODE:
6273: string = node->content;
6274: if (string == NULL)
6275: return(0);
6276: if (string[0] == 0)
6277: return(0);
6278: return(((unsigned int) string[0]) +
6279: (((unsigned int) string[1]) << 8));
6280: case XML_NAMESPACE_DECL:
6281: string = ((xmlNsPtr)node)->href;
6282: if (string == NULL)
6283: return(0);
6284: if (string[0] == 0)
6285: return(0);
6286: return(((unsigned int) string[0]) +
6287: (((unsigned int) string[1]) << 8));
6288: case XML_ATTRIBUTE_NODE:
6289: tmp = ((xmlAttrPtr) node)->children;
6290: break;
6291: case XML_ELEMENT_NODE:
6292: tmp = node->children;
6293: break;
6294: default:
6295: return(0);
6296: }
6297: while (tmp != NULL) {
6298: switch (tmp->type) {
6299: case XML_COMMENT_NODE:
6300: case XML_PI_NODE:
6301: case XML_CDATA_SECTION_NODE:
6302: case XML_TEXT_NODE:
6303: string = tmp->content;
6304: break;
6305: case XML_NAMESPACE_DECL:
6306: string = ((xmlNsPtr)tmp)->href;
6307: break;
6308: default:
6309: break;
6310: }
6311: if ((string != NULL) && (string[0] != 0)) {
6312: if (len == 1) {
6313: return(ret + (((unsigned int) string[0]) << 8));
6314: }
6315: if (string[1] == 0) {
6316: len = 1;
6317: ret = (unsigned int) string[0];
6318: } else {
6319: return(((unsigned int) string[0]) +
6320: (((unsigned int) string[1]) << 8));
6321: }
6322: }
6323: /*
6324: * Skip to next node
6325: */
6326: if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6327: if (tmp->children->type != XML_ENTITY_DECL) {
6328: tmp = tmp->children;
6329: continue;
6330: }
6331: }
6332: if (tmp == node)
6333: break;
6334:
6335: if (tmp->next != NULL) {
6336: tmp = tmp->next;
6337: continue;
6338: }
6339:
6340: do {
6341: tmp = tmp->parent;
6342: if (tmp == NULL)
6343: break;
6344: if (tmp == node) {
6345: tmp = NULL;
6346: break;
6347: }
6348: if (tmp->next != NULL) {
6349: tmp = tmp->next;
6350: break;
6351: }
6352: } while (tmp != NULL);
6353: }
6354: return(ret);
6355: }
6356:
6357: /**
6358: * xmlXPathStringHash:
6359: * @string: a string
6360: *
6361: * Function computing the beginning of the string value of the node,
6362: * used to speed up comparisons
6363: *
6364: * Returns an int usable as a hash
6365: */
6366: static unsigned int
6367: xmlXPathStringHash(const xmlChar * string) {
6368: if (string == NULL)
6369: return((unsigned int) 0);
6370: if (string[0] == 0)
6371: return(0);
6372: return(((unsigned int) string[0]) +
6373: (((unsigned int) string[1]) << 8));
6374: }
6375:
6376: /**
6377: * xmlXPathCompareNodeSetFloat:
6378: * @ctxt: the XPath Parser context
6379: * @inf: less than (1) or greater than (0)
6380: * @strict: is the comparison strict
6381: * @arg: the node set
6382: * @f: the value
6383: *
6384: * Implement the compare operation between a nodeset and a number
6385: * @ns < @val (1, 1, ...
6386: * @ns <= @val (1, 0, ...
6387: * @ns > @val (0, 1, ...
6388: * @ns >= @val (0, 0, ...
6389: *
6390: * If one object to be compared is a node-set and the other is a number,
6391: * then the comparison will be true if and only if there is a node in the
6392: * node-set such that the result of performing the comparison on the number
6393: * to be compared and on the result of converting the string-value of that
6394: * node to a number using the number function is true.
6395: *
6396: * Returns 0 or 1 depending on the results of the test.
6397: */
6398: static int
6399: xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6400: xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6401: int i, ret = 0;
6402: xmlNodeSetPtr ns;
6403: xmlChar *str2;
6404:
6405: if ((f == NULL) || (arg == NULL) ||
6406: ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6407: xmlXPathReleaseObject(ctxt->context, arg);
6408: xmlXPathReleaseObject(ctxt->context, f);
6409: return(0);
6410: }
6411: ns = arg->nodesetval;
6412: if (ns != NULL) {
6413: for (i = 0;i < ns->nodeNr;i++) {
6414: str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6415: if (str2 != NULL) {
6416: valuePush(ctxt,
6417: xmlXPathCacheNewString(ctxt->context, str2));
6418: xmlFree(str2);
6419: xmlXPathNumberFunction(ctxt, 1);
6420: valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6421: ret = xmlXPathCompareValues(ctxt, inf, strict);
6422: if (ret)
6423: break;
6424: }
6425: }
6426: }
6427: xmlXPathReleaseObject(ctxt->context, arg);
6428: xmlXPathReleaseObject(ctxt->context, f);
6429: return(ret);
6430: }
6431:
6432: /**
6433: * xmlXPathCompareNodeSetString:
6434: * @ctxt: the XPath Parser context
6435: * @inf: less than (1) or greater than (0)
6436: * @strict: is the comparison strict
6437: * @arg: the node set
6438: * @s: the value
6439: *
6440: * Implement the compare operation between a nodeset and a string
6441: * @ns < @val (1, 1, ...
6442: * @ns <= @val (1, 0, ...
6443: * @ns > @val (0, 1, ...
6444: * @ns >= @val (0, 0, ...
6445: *
6446: * If one object to be compared is a node-set and the other is a string,
6447: * then the comparison will be true if and only if there is a node in
6448: * the node-set such that the result of performing the comparison on the
6449: * string-value of the node and the other string is true.
6450: *
6451: * Returns 0 or 1 depending on the results of the test.
6452: */
6453: static int
6454: xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6455: xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6456: int i, ret = 0;
6457: xmlNodeSetPtr ns;
6458: xmlChar *str2;
6459:
6460: if ((s == NULL) || (arg == NULL) ||
6461: ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6462: xmlXPathReleaseObject(ctxt->context, arg);
6463: xmlXPathReleaseObject(ctxt->context, s);
6464: return(0);
6465: }
6466: ns = arg->nodesetval;
6467: if (ns != NULL) {
6468: for (i = 0;i < ns->nodeNr;i++) {
6469: str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6470: if (str2 != NULL) {
6471: valuePush(ctxt,
6472: xmlXPathCacheNewString(ctxt->context, str2));
6473: xmlFree(str2);
6474: valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6475: ret = xmlXPathCompareValues(ctxt, inf, strict);
6476: if (ret)
6477: break;
6478: }
6479: }
6480: }
6481: xmlXPathReleaseObject(ctxt->context, arg);
6482: xmlXPathReleaseObject(ctxt->context, s);
6483: return(ret);
6484: }
6485:
6486: /**
6487: * xmlXPathCompareNodeSets:
6488: * @inf: less than (1) or greater than (0)
6489: * @strict: is the comparison strict
6490: * @arg1: the first node set object
6491: * @arg2: the second node set object
6492: *
6493: * Implement the compare operation on nodesets:
6494: *
6495: * If both objects to be compared are node-sets, then the comparison
6496: * will be true if and only if there is a node in the first node-set
6497: * and a node in the second node-set such that the result of performing
6498: * the comparison on the string-values of the two nodes is true.
6499: * ....
6500: * When neither object to be compared is a node-set and the operator
6501: * is <=, <, >= or >, then the objects are compared by converting both
6502: * objects to numbers and comparing the numbers according to IEEE 754.
6503: * ....
6504: * The number function converts its argument to a number as follows:
6505: * - a string that consists of optional whitespace followed by an
6506: * optional minus sign followed by a Number followed by whitespace
6507: * is converted to the IEEE 754 number that is nearest (according
6508: * to the IEEE 754 round-to-nearest rule) to the mathematical value
6509: * represented by the string; any other string is converted to NaN
6510: *
6511: * Conclusion all nodes need to be converted first to their string value
6512: * and then the comparison must be done when possible
6513: */
6514: static int
6515: xmlXPathCompareNodeSets(int inf, int strict,
6516: xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6517: int i, j, init = 0;
6518: double val1;
6519: double *values2;
6520: int ret = 0;
6521: xmlNodeSetPtr ns1;
6522: xmlNodeSetPtr ns2;
6523:
6524: if ((arg1 == NULL) ||
6525: ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6526: xmlXPathFreeObject(arg2);
6527: return(0);
6528: }
6529: if ((arg2 == NULL) ||
6530: ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6531: xmlXPathFreeObject(arg1);
6532: xmlXPathFreeObject(arg2);
6533: return(0);
6534: }
6535:
6536: ns1 = arg1->nodesetval;
6537: ns2 = arg2->nodesetval;
6538:
6539: if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6540: xmlXPathFreeObject(arg1);
6541: xmlXPathFreeObject(arg2);
6542: return(0);
6543: }
6544: if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6545: xmlXPathFreeObject(arg1);
6546: xmlXPathFreeObject(arg2);
6547: return(0);
6548: }
6549:
6550: values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6551: if (values2 == NULL) {
6552: xmlXPathErrMemory(NULL, "comparing nodesets\n");
6553: xmlXPathFreeObject(arg1);
6554: xmlXPathFreeObject(arg2);
6555: return(0);
6556: }
6557: for (i = 0;i < ns1->nodeNr;i++) {
6558: val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6559: if (xmlXPathIsNaN(val1))
6560: continue;
6561: for (j = 0;j < ns2->nodeNr;j++) {
6562: if (init == 0) {
6563: values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6564: }
6565: if (xmlXPathIsNaN(values2[j]))
6566: continue;
6567: if (inf && strict)
6568: ret = (val1 < values2[j]);
6569: else if (inf && !strict)
6570: ret = (val1 <= values2[j]);
6571: else if (!inf && strict)
6572: ret = (val1 > values2[j]);
6573: else if (!inf && !strict)
6574: ret = (val1 >= values2[j]);
6575: if (ret)
6576: break;
6577: }
6578: if (ret)
6579: break;
6580: init = 1;
6581: }
6582: xmlFree(values2);
6583: xmlXPathFreeObject(arg1);
6584: xmlXPathFreeObject(arg2);
6585: return(ret);
6586: }
6587:
6588: /**
6589: * xmlXPathCompareNodeSetValue:
6590: * @ctxt: the XPath Parser context
6591: * @inf: less than (1) or greater than (0)
6592: * @strict: is the comparison strict
6593: * @arg: the node set
6594: * @val: the value
6595: *
6596: * Implement the compare operation between a nodeset and a value
6597: * @ns < @val (1, 1, ...
6598: * @ns <= @val (1, 0, ...
6599: * @ns > @val (0, 1, ...
6600: * @ns >= @val (0, 0, ...
6601: *
6602: * If one object to be compared is a node-set and the other is a boolean,
6603: * then the comparison will be true if and only if the result of performing
6604: * the comparison on the boolean and on the result of converting
6605: * the node-set to a boolean using the boolean function is true.
6606: *
6607: * Returns 0 or 1 depending on the results of the test.
6608: */
6609: static int
6610: xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6611: xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6612: if ((val == NULL) || (arg == NULL) ||
6613: ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6614: return(0);
6615:
6616: switch(val->type) {
6617: case XPATH_NUMBER:
6618: return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6619: case XPATH_NODESET:
6620: case XPATH_XSLT_TREE:
6621: return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6622: case XPATH_STRING:
6623: return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6624: case XPATH_BOOLEAN:
6625: valuePush(ctxt, arg);
6626: xmlXPathBooleanFunction(ctxt, 1);
6627: valuePush(ctxt, val);
6628: return(xmlXPathCompareValues(ctxt, inf, strict));
6629: default:
6630: TODO
6631: }
6632: return(0);
6633: }
6634:
6635: /**
6636: * xmlXPathEqualNodeSetString:
6637: * @arg: the nodeset object argument
6638: * @str: the string to compare to.
6639: * @neq: flag to show whether for '=' (0) or '!=' (1)
6640: *
6641: * Implement the equal operation on XPath objects content: @arg1 == @arg2
6642: * If one object to be compared is a node-set and the other is a string,
6643: * then the comparison will be true if and only if there is a node in
6644: * the node-set such that the result of performing the comparison on the
6645: * string-value of the node and the other string is true.
6646: *
6647: * Returns 0 or 1 depending on the results of the test.
6648: */
6649: static int
6650: xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6651: {
6652: int i;
6653: xmlNodeSetPtr ns;
6654: xmlChar *str2;
6655: unsigned int hash;
6656:
6657: if ((str == NULL) || (arg == NULL) ||
6658: ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6659: return (0);
6660: ns = arg->nodesetval;
6661: /*
6662: * A NULL nodeset compared with a string is always false
6663: * (since there is no node equal, and no node not equal)
6664: */
6665: if ((ns == NULL) || (ns->nodeNr <= 0) )
6666: return (0);
6667: hash = xmlXPathStringHash(str);
6668: for (i = 0; i < ns->nodeNr; i++) {
6669: if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6670: str2 = xmlNodeGetContent(ns->nodeTab[i]);
6671: if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6672: xmlFree(str2);
6673: if (neq)
6674: continue;
6675: return (1);
6676: } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6677: if (neq)
6678: continue;
6679: return (1);
6680: } else if (neq) {
6681: if (str2 != NULL)
6682: xmlFree(str2);
6683: return (1);
6684: }
6685: if (str2 != NULL)
6686: xmlFree(str2);
6687: } else if (neq)
6688: return (1);
6689: }
6690: return (0);
6691: }
6692:
6693: /**
6694: * xmlXPathEqualNodeSetFloat:
6695: * @arg: the nodeset object argument
6696: * @f: the float to compare to
6697: * @neq: flag to show whether to compare '=' (0) or '!=' (1)
6698: *
6699: * Implement the equal operation on XPath objects content: @arg1 == @arg2
6700: * If one object to be compared is a node-set and the other is a number,
6701: * then the comparison will be true if and only if there is a node in
6702: * the node-set such that the result of performing the comparison on the
6703: * number to be compared and on the result of converting the string-value
6704: * of that node to a number using the number function is true.
6705: *
6706: * Returns 0 or 1 depending on the results of the test.
6707: */
6708: static int
6709: xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6710: xmlXPathObjectPtr arg, double f, int neq) {
6711: int i, ret=0;
6712: xmlNodeSetPtr ns;
6713: xmlChar *str2;
6714: xmlXPathObjectPtr val;
6715: double v;
6716:
6717: if ((arg == NULL) ||
6718: ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6719: return(0);
6720:
6721: ns = arg->nodesetval;
6722: if (ns != NULL) {
6723: for (i=0;i<ns->nodeNr;i++) {
6724: str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6725: if (str2 != NULL) {
6726: valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6727: xmlFree(str2);
6728: xmlXPathNumberFunction(ctxt, 1);
6729: val = valuePop(ctxt);
6730: v = val->floatval;
6731: xmlXPathReleaseObject(ctxt->context, val);
6732: if (!xmlXPathIsNaN(v)) {
6733: if ((!neq) && (v==f)) {
6734: ret = 1;
6735: break;
6736: } else if ((neq) && (v!=f)) {
6737: ret = 1;
6738: break;
6739: }
6740: } else { /* NaN is unequal to any value */
6741: if (neq)
6742: ret = 1;
6743: }
6744: }
6745: }
6746: }
6747:
6748: return(ret);
6749: }
6750:
6751:
6752: /**
6753: * xmlXPathEqualNodeSets:
6754: * @arg1: first nodeset object argument
6755: * @arg2: second nodeset object argument
6756: * @neq: flag to show whether to test '=' (0) or '!=' (1)
6757: *
6758: * Implement the equal / not equal operation on XPath nodesets:
6759: * @arg1 == @arg2 or @arg1 != @arg2
6760: * If both objects to be compared are node-sets, then the comparison
6761: * will be true if and only if there is a node in the first node-set and
6762: * a node in the second node-set such that the result of performing the
6763: * comparison on the string-values of the two nodes is true.
6764: *
6765: * (needless to say, this is a costly operation)
6766: *
6767: * Returns 0 or 1 depending on the results of the test.
6768: */
6769: static int
6770: xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6771: int i, j;
6772: unsigned int *hashs1;
6773: unsigned int *hashs2;
6774: xmlChar **values1;
6775: xmlChar **values2;
6776: int ret = 0;
6777: xmlNodeSetPtr ns1;
6778: xmlNodeSetPtr ns2;
6779:
6780: if ((arg1 == NULL) ||
6781: ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6782: return(0);
6783: if ((arg2 == NULL) ||
6784: ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6785: return(0);
6786:
6787: ns1 = arg1->nodesetval;
6788: ns2 = arg2->nodesetval;
6789:
6790: if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6791: return(0);
6792: if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6793: return(0);
6794:
6795: /*
6796: * for equal, check if there is a node pertaining to both sets
6797: */
6798: if (neq == 0)
6799: for (i = 0;i < ns1->nodeNr;i++)
6800: for (j = 0;j < ns2->nodeNr;j++)
6801: if (ns1->nodeTab[i] == ns2->nodeTab[j])
6802: return(1);
6803:
6804: values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6805: if (values1 == NULL) {
6806: xmlXPathErrMemory(NULL, "comparing nodesets\n");
6807: return(0);
6808: }
6809: hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6810: if (hashs1 == NULL) {
6811: xmlXPathErrMemory(NULL, "comparing nodesets\n");
6812: xmlFree(values1);
6813: return(0);
6814: }
6815: memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6816: values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6817: if (values2 == NULL) {
6818: xmlXPathErrMemory(NULL, "comparing nodesets\n");
6819: xmlFree(hashs1);
6820: xmlFree(values1);
6821: return(0);
6822: }
6823: hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6824: if (hashs2 == NULL) {
6825: xmlXPathErrMemory(NULL, "comparing nodesets\n");
6826: xmlFree(hashs1);
6827: xmlFree(values1);
6828: xmlFree(values2);
6829: return(0);
6830: }
6831: memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6832: for (i = 0;i < ns1->nodeNr;i++) {
6833: hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6834: for (j = 0;j < ns2->nodeNr;j++) {
6835: if (i == 0)
6836: hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6837: if (hashs1[i] != hashs2[j]) {
6838: if (neq) {
6839: ret = 1;
6840: break;
6841: }
6842: }
6843: else {
6844: if (values1[i] == NULL)
6845: values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6846: if (values2[j] == NULL)
6847: values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6848: ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6849: if (ret)
6850: break;
6851: }
6852: }
6853: if (ret)
6854: break;
6855: }
6856: for (i = 0;i < ns1->nodeNr;i++)
6857: if (values1[i] != NULL)
6858: xmlFree(values1[i]);
6859: for (j = 0;j < ns2->nodeNr;j++)
6860: if (values2[j] != NULL)
6861: xmlFree(values2[j]);
6862: xmlFree(values1);
6863: xmlFree(values2);
6864: xmlFree(hashs1);
6865: xmlFree(hashs2);
6866: return(ret);
6867: }
6868:
6869: static int
6870: xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6871: xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6872: int ret = 0;
6873: /*
6874: *At this point we are assured neither arg1 nor arg2
6875: *is a nodeset, so we can just pick the appropriate routine.
6876: */
6877: switch (arg1->type) {
6878: case XPATH_UNDEFINED:
6879: #ifdef DEBUG_EXPR
6880: xmlGenericError(xmlGenericErrorContext,
6881: "Equal: undefined\n");
6882: #endif
6883: break;
6884: case XPATH_BOOLEAN:
6885: switch (arg2->type) {
6886: case XPATH_UNDEFINED:
6887: #ifdef DEBUG_EXPR
6888: xmlGenericError(xmlGenericErrorContext,
6889: "Equal: undefined\n");
6890: #endif
6891: break;
6892: case XPATH_BOOLEAN:
6893: #ifdef DEBUG_EXPR
6894: xmlGenericError(xmlGenericErrorContext,
6895: "Equal: %d boolean %d \n",
6896: arg1->boolval, arg2->boolval);
6897: #endif
6898: ret = (arg1->boolval == arg2->boolval);
6899: break;
6900: case XPATH_NUMBER:
6901: ret = (arg1->boolval ==
6902: xmlXPathCastNumberToBoolean(arg2->floatval));
6903: break;
6904: case XPATH_STRING:
6905: if ((arg2->stringval == NULL) ||
6906: (arg2->stringval[0] == 0)) ret = 0;
6907: else
6908: ret = 1;
6909: ret = (arg1->boolval == ret);
6910: break;
6911: case XPATH_USERS:
6912: case XPATH_POINT:
6913: case XPATH_RANGE:
6914: case XPATH_LOCATIONSET:
6915: TODO
6916: break;
6917: case XPATH_NODESET:
6918: case XPATH_XSLT_TREE:
6919: break;
6920: }
6921: break;
6922: case XPATH_NUMBER:
6923: switch (arg2->type) {
6924: case XPATH_UNDEFINED:
6925: #ifdef DEBUG_EXPR
6926: xmlGenericError(xmlGenericErrorContext,
6927: "Equal: undefined\n");
6928: #endif
6929: break;
6930: case XPATH_BOOLEAN:
6931: ret = (arg2->boolval==
6932: xmlXPathCastNumberToBoolean(arg1->floatval));
6933: break;
6934: case XPATH_STRING:
6935: valuePush(ctxt, arg2);
6936: xmlXPathNumberFunction(ctxt, 1);
6937: arg2 = valuePop(ctxt);
6938: /* no break on purpose */
6939: case XPATH_NUMBER:
6940: /* Hand check NaN and Infinity equalities */
6941: if (xmlXPathIsNaN(arg1->floatval) ||
6942: xmlXPathIsNaN(arg2->floatval)) {
6943: ret = 0;
6944: } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6945: if (xmlXPathIsInf(arg2->floatval) == 1)
6946: ret = 1;
6947: else
6948: ret = 0;
6949: } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6950: if (xmlXPathIsInf(arg2->floatval) == -1)
6951: ret = 1;
6952: else
6953: ret = 0;
6954: } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6955: if (xmlXPathIsInf(arg1->floatval) == 1)
6956: ret = 1;
6957: else
6958: ret = 0;
6959: } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6960: if (xmlXPathIsInf(arg1->floatval) == -1)
6961: ret = 1;
6962: else
6963: ret = 0;
6964: } else {
6965: ret = (arg1->floatval == arg2->floatval);
6966: }
6967: break;
6968: case XPATH_USERS:
6969: case XPATH_POINT:
6970: case XPATH_RANGE:
6971: case XPATH_LOCATIONSET:
6972: TODO
6973: break;
6974: case XPATH_NODESET:
6975: case XPATH_XSLT_TREE:
6976: break;
6977: }
6978: break;
6979: case XPATH_STRING:
6980: switch (arg2->type) {
6981: case XPATH_UNDEFINED:
6982: #ifdef DEBUG_EXPR
6983: xmlGenericError(xmlGenericErrorContext,
6984: "Equal: undefined\n");
6985: #endif
6986: break;
6987: case XPATH_BOOLEAN:
6988: if ((arg1->stringval == NULL) ||
6989: (arg1->stringval[0] == 0)) ret = 0;
6990: else
6991: ret = 1;
6992: ret = (arg2->boolval == ret);
6993: break;
6994: case XPATH_STRING:
6995: ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6996: break;
6997: case XPATH_NUMBER:
6998: valuePush(ctxt, arg1);
6999: xmlXPathNumberFunction(ctxt, 1);
7000: arg1 = valuePop(ctxt);
7001: /* Hand check NaN and Infinity equalities */
7002: if (xmlXPathIsNaN(arg1->floatval) ||
7003: xmlXPathIsNaN(arg2->floatval)) {
7004: ret = 0;
7005: } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7006: if (xmlXPathIsInf(arg2->floatval) == 1)
7007: ret = 1;
7008: else
7009: ret = 0;
7010: } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7011: if (xmlXPathIsInf(arg2->floatval) == -1)
7012: ret = 1;
7013: else
7014: ret = 0;
7015: } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7016: if (xmlXPathIsInf(arg1->floatval) == 1)
7017: ret = 1;
7018: else
7019: ret = 0;
7020: } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7021: if (xmlXPathIsInf(arg1->floatval) == -1)
7022: ret = 1;
7023: else
7024: ret = 0;
7025: } else {
7026: ret = (arg1->floatval == arg2->floatval);
7027: }
7028: break;
7029: case XPATH_USERS:
7030: case XPATH_POINT:
7031: case XPATH_RANGE:
7032: case XPATH_LOCATIONSET:
7033: TODO
7034: break;
7035: case XPATH_NODESET:
7036: case XPATH_XSLT_TREE:
7037: break;
7038: }
7039: break;
7040: case XPATH_USERS:
7041: case XPATH_POINT:
7042: case XPATH_RANGE:
7043: case XPATH_LOCATIONSET:
7044: TODO
7045: break;
7046: case XPATH_NODESET:
7047: case XPATH_XSLT_TREE:
7048: break;
7049: }
7050: xmlXPathReleaseObject(ctxt->context, arg1);
7051: xmlXPathReleaseObject(ctxt->context, arg2);
7052: return(ret);
7053: }
7054:
7055: /**
7056: * xmlXPathEqualValues:
7057: * @ctxt: the XPath Parser context
7058: *
7059: * Implement the equal operation on XPath objects content: @arg1 == @arg2
7060: *
7061: * Returns 0 or 1 depending on the results of the test.
7062: */
7063: int
7064: xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7065: xmlXPathObjectPtr arg1, arg2, argtmp;
7066: int ret = 0;
7067:
7068: if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7069: arg2 = valuePop(ctxt);
7070: arg1 = valuePop(ctxt);
7071: if ((arg1 == NULL) || (arg2 == NULL)) {
7072: if (arg1 != NULL)
7073: xmlXPathReleaseObject(ctxt->context, arg1);
7074: else
7075: xmlXPathReleaseObject(ctxt->context, arg2);
7076: XP_ERROR0(XPATH_INVALID_OPERAND);
7077: }
7078:
7079: if (arg1 == arg2) {
7080: #ifdef DEBUG_EXPR
7081: xmlGenericError(xmlGenericErrorContext,
7082: "Equal: by pointer\n");
7083: #endif
7084: xmlXPathFreeObject(arg1);
7085: return(1);
7086: }
7087:
7088: /*
7089: *If either argument is a nodeset, it's a 'special case'
7090: */
7091: if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7092: (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7093: /*
7094: *Hack it to assure arg1 is the nodeset
7095: */
7096: if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7097: argtmp = arg2;
7098: arg2 = arg1;
7099: arg1 = argtmp;
7100: }
7101: switch (arg2->type) {
7102: case XPATH_UNDEFINED:
7103: #ifdef DEBUG_EXPR
7104: xmlGenericError(xmlGenericErrorContext,
7105: "Equal: undefined\n");
7106: #endif
7107: break;
7108: case XPATH_NODESET:
7109: case XPATH_XSLT_TREE:
7110: ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7111: break;
7112: case XPATH_BOOLEAN:
7113: if ((arg1->nodesetval == NULL) ||
7114: (arg1->nodesetval->nodeNr == 0)) ret = 0;
7115: else
7116: ret = 1;
7117: ret = (ret == arg2->boolval);
7118: break;
7119: case XPATH_NUMBER:
7120: ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7121: break;
7122: case XPATH_STRING:
7123: ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7124: break;
7125: case XPATH_USERS:
7126: case XPATH_POINT:
7127: case XPATH_RANGE:
7128: case XPATH_LOCATIONSET:
7129: TODO
7130: break;
7131: }
7132: xmlXPathReleaseObject(ctxt->context, arg1);
7133: xmlXPathReleaseObject(ctxt->context, arg2);
7134: return(ret);
7135: }
7136:
7137: return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7138: }
7139:
7140: /**
7141: * xmlXPathNotEqualValues:
7142: * @ctxt: the XPath Parser context
7143: *
7144: * Implement the equal operation on XPath objects content: @arg1 == @arg2
7145: *
7146: * Returns 0 or 1 depending on the results of the test.
7147: */
7148: int
7149: xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7150: xmlXPathObjectPtr arg1, arg2, argtmp;
7151: int ret = 0;
7152:
7153: if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7154: arg2 = valuePop(ctxt);
7155: arg1 = valuePop(ctxt);
7156: if ((arg1 == NULL) || (arg2 == NULL)) {
7157: if (arg1 != NULL)
7158: xmlXPathReleaseObject(ctxt->context, arg1);
7159: else
7160: xmlXPathReleaseObject(ctxt->context, arg2);
7161: XP_ERROR0(XPATH_INVALID_OPERAND);
7162: }
7163:
7164: if (arg1 == arg2) {
7165: #ifdef DEBUG_EXPR
7166: xmlGenericError(xmlGenericErrorContext,
7167: "NotEqual: by pointer\n");
7168: #endif
7169: xmlXPathReleaseObject(ctxt->context, arg1);
7170: return(0);
7171: }
7172:
7173: /*
7174: *If either argument is a nodeset, it's a 'special case'
7175: */
7176: if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7177: (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7178: /*
7179: *Hack it to assure arg1 is the nodeset
7180: */
7181: if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7182: argtmp = arg2;
7183: arg2 = arg1;
7184: arg1 = argtmp;
7185: }
7186: switch (arg2->type) {
7187: case XPATH_UNDEFINED:
7188: #ifdef DEBUG_EXPR
7189: xmlGenericError(xmlGenericErrorContext,
7190: "NotEqual: undefined\n");
7191: #endif
7192: break;
7193: case XPATH_NODESET:
7194: case XPATH_XSLT_TREE:
7195: ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7196: break;
7197: case XPATH_BOOLEAN:
7198: if ((arg1->nodesetval == NULL) ||
7199: (arg1->nodesetval->nodeNr == 0)) ret = 0;
7200: else
7201: ret = 1;
7202: ret = (ret != arg2->boolval);
7203: break;
7204: case XPATH_NUMBER:
7205: ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7206: break;
7207: case XPATH_STRING:
7208: ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7209: break;
7210: case XPATH_USERS:
7211: case XPATH_POINT:
7212: case XPATH_RANGE:
7213: case XPATH_LOCATIONSET:
7214: TODO
7215: break;
7216: }
7217: xmlXPathReleaseObject(ctxt->context, arg1);
7218: xmlXPathReleaseObject(ctxt->context, arg2);
7219: return(ret);
7220: }
7221:
7222: return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7223: }
7224:
7225: /**
7226: * xmlXPathCompareValues:
7227: * @ctxt: the XPath Parser context
7228: * @inf: less than (1) or greater than (0)
7229: * @strict: is the comparison strict
7230: *
7231: * Implement the compare operation on XPath objects:
7232: * @arg1 < @arg2 (1, 1, ...
7233: * @arg1 <= @arg2 (1, 0, ...
7234: * @arg1 > @arg2 (0, 1, ...
7235: * @arg1 >= @arg2 (0, 0, ...
7236: *
7237: * When neither object to be compared is a node-set and the operator is
7238: * <=, <, >=, >, then the objects are compared by converted both objects
7239: * to numbers and comparing the numbers according to IEEE 754. The <
7240: * comparison will be true if and only if the first number is less than the
7241: * second number. The <= comparison will be true if and only if the first
7242: * number is less than or equal to the second number. The > comparison
7243: * will be true if and only if the first number is greater than the second
7244: * number. The >= comparison will be true if and only if the first number
7245: * is greater than or equal to the second number.
7246: *
7247: * Returns 1 if the comparison succeeded, 0 if it failed
7248: */
7249: int
7250: xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7251: int ret = 0, arg1i = 0, arg2i = 0;
7252: xmlXPathObjectPtr arg1, arg2;
7253:
7254: if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7255: arg2 = valuePop(ctxt);
7256: arg1 = valuePop(ctxt);
7257: if ((arg1 == NULL) || (arg2 == NULL)) {
7258: if (arg1 != NULL)
7259: xmlXPathReleaseObject(ctxt->context, arg1);
7260: else
7261: xmlXPathReleaseObject(ctxt->context, arg2);
7262: XP_ERROR0(XPATH_INVALID_OPERAND);
7263: }
7264:
7265: if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7266: (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7267: /*
7268: * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7269: * are not freed from within this routine; they will be freed from the
7270: * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7271: */
7272: if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7273: ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7274: ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7275: } else {
7276: if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7277: ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7278: arg1, arg2);
7279: } else {
7280: ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7281: arg2, arg1);
7282: }
7283: }
7284: return(ret);
7285: }
7286:
7287: if (arg1->type != XPATH_NUMBER) {
7288: valuePush(ctxt, arg1);
7289: xmlXPathNumberFunction(ctxt, 1);
7290: arg1 = valuePop(ctxt);
7291: }
7292: if (arg1->type != XPATH_NUMBER) {
7293: xmlXPathFreeObject(arg1);
7294: xmlXPathFreeObject(arg2);
7295: XP_ERROR0(XPATH_INVALID_OPERAND);
7296: }
7297: if (arg2->type != XPATH_NUMBER) {
7298: valuePush(ctxt, arg2);
7299: xmlXPathNumberFunction(ctxt, 1);
7300: arg2 = valuePop(ctxt);
7301: }
7302: if (arg2->type != XPATH_NUMBER) {
7303: xmlXPathReleaseObject(ctxt->context, arg1);
7304: xmlXPathReleaseObject(ctxt->context, arg2);
7305: XP_ERROR0(XPATH_INVALID_OPERAND);
7306: }
7307: /*
7308: * Add tests for infinity and nan
7309: * => feedback on 3.4 for Inf and NaN
7310: */
7311: /* Hand check NaN and Infinity comparisons */
7312: if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7313: ret=0;
7314: } else {
7315: arg1i=xmlXPathIsInf(arg1->floatval);
7316: arg2i=xmlXPathIsInf(arg2->floatval);
7317: 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: else if (!inf && strict) {
7337: if ((arg1i == 1 && arg2i != 1) ||
7338: (arg2i == -1 && arg1i != -1)) {
7339: ret = 1;
7340: } else if (arg1i == 0 && arg2i == 0) {
7341: ret = (arg1->floatval > arg2->floatval);
7342: } else {
7343: ret = 0;
7344: }
7345: }
7346: else if (!inf && !strict) {
7347: if (arg1i == 1 || arg2i == -1) {
7348: ret = 1;
7349: } else if (arg1i == 0 && arg2i == 0) {
7350: ret = (arg1->floatval >= arg2->floatval);
7351: } else {
7352: ret = 0;
7353: }
7354: }
7355: }
7356: xmlXPathReleaseObject(ctxt->context, arg1);
7357: xmlXPathReleaseObject(ctxt->context, arg2);
7358: return(ret);
7359: }
7360:
7361: /**
7362: * xmlXPathValueFlipSign:
7363: * @ctxt: the XPath Parser context
7364: *
7365: * Implement the unary - operation on an XPath object
7366: * The numeric operators convert their operands to numbers as if
7367: * by calling the number function.
7368: */
7369: void
7370: xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7371: if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7372: CAST_TO_NUMBER;
7373: CHECK_TYPE(XPATH_NUMBER);
7374: if (xmlXPathIsNaN(ctxt->value->floatval))
7375: ctxt->value->floatval=xmlXPathNAN;
7376: else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7377: ctxt->value->floatval=xmlXPathNINF;
7378: else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7379: ctxt->value->floatval=xmlXPathPINF;
7380: else if (ctxt->value->floatval == 0) {
7381: if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7382: ctxt->value->floatval = xmlXPathNZERO;
7383: else
7384: ctxt->value->floatval = 0;
7385: }
7386: else
7387: ctxt->value->floatval = - ctxt->value->floatval;
7388: }
7389:
7390: /**
7391: * xmlXPathAddValues:
7392: * @ctxt: the XPath Parser context
7393: *
7394: * Implement the add operation on XPath objects:
7395: * The numeric operators convert their operands to numbers as if
7396: * by calling the number function.
7397: */
7398: void
7399: xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7400: xmlXPathObjectPtr arg;
7401: double val;
7402:
7403: arg = valuePop(ctxt);
7404: if (arg == NULL)
7405: XP_ERROR(XPATH_INVALID_OPERAND);
7406: val = xmlXPathCastToNumber(arg);
7407: xmlXPathReleaseObject(ctxt->context, arg);
7408: CAST_TO_NUMBER;
7409: CHECK_TYPE(XPATH_NUMBER);
7410: ctxt->value->floatval += val;
7411: }
7412:
7413: /**
7414: * xmlXPathSubValues:
7415: * @ctxt: the XPath Parser context
7416: *
7417: * Implement the subtraction operation on XPath objects:
7418: * The numeric operators convert their operands to numbers as if
7419: * by calling the number function.
7420: */
7421: void
7422: xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7423: xmlXPathObjectPtr arg;
7424: double val;
7425:
7426: arg = valuePop(ctxt);
7427: if (arg == NULL)
7428: XP_ERROR(XPATH_INVALID_OPERAND);
7429: val = xmlXPathCastToNumber(arg);
7430: xmlXPathReleaseObject(ctxt->context, arg);
7431: CAST_TO_NUMBER;
7432: CHECK_TYPE(XPATH_NUMBER);
7433: ctxt->value->floatval -= val;
7434: }
7435:
7436: /**
7437: * xmlXPathMultValues:
7438: * @ctxt: the XPath Parser context
7439: *
7440: * Implement the multiply operation on XPath objects:
7441: * The numeric operators convert their operands to numbers as if
7442: * by calling the number function.
7443: */
7444: void
7445: xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7446: xmlXPathObjectPtr arg;
7447: double val;
7448:
7449: arg = valuePop(ctxt);
7450: if (arg == NULL)
7451: XP_ERROR(XPATH_INVALID_OPERAND);
7452: val = xmlXPathCastToNumber(arg);
7453: xmlXPathReleaseObject(ctxt->context, arg);
7454: CAST_TO_NUMBER;
7455: CHECK_TYPE(XPATH_NUMBER);
7456: ctxt->value->floatval *= val;
7457: }
7458:
7459: /**
7460: * xmlXPathDivValues:
7461: * @ctxt: the XPath Parser context
7462: *
7463: * Implement the div operation on XPath objects @arg1 / @arg2:
7464: * The numeric operators convert their operands to numbers as if
7465: * by calling the number function.
7466: */
7467: void
7468: xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7469: xmlXPathObjectPtr arg;
7470: double val;
7471:
7472: arg = valuePop(ctxt);
7473: if (arg == NULL)
7474: XP_ERROR(XPATH_INVALID_OPERAND);
7475: val = xmlXPathCastToNumber(arg);
7476: xmlXPathReleaseObject(ctxt->context, arg);
7477: CAST_TO_NUMBER;
7478: CHECK_TYPE(XPATH_NUMBER);
7479: if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7480: ctxt->value->floatval = xmlXPathNAN;
7481: else if (val == 0 && xmlXPathGetSign(val) != 0) {
7482: if (ctxt->value->floatval == 0)
7483: ctxt->value->floatval = xmlXPathNAN;
7484: else if (ctxt->value->floatval > 0)
7485: ctxt->value->floatval = xmlXPathNINF;
7486: else if (ctxt->value->floatval < 0)
7487: ctxt->value->floatval = xmlXPathPINF;
7488: }
7489: else if (val == 0) {
7490: if (ctxt->value->floatval == 0)
7491: ctxt->value->floatval = xmlXPathNAN;
7492: else if (ctxt->value->floatval > 0)
7493: ctxt->value->floatval = xmlXPathPINF;
7494: else if (ctxt->value->floatval < 0)
7495: ctxt->value->floatval = xmlXPathNINF;
7496: } else
7497: ctxt->value->floatval /= val;
7498: }
7499:
7500: /**
7501: * xmlXPathModValues:
7502: * @ctxt: the XPath Parser context
7503: *
7504: * Implement the mod operation on XPath objects: @arg1 / @arg2
7505: * The numeric operators convert their operands to numbers as if
7506: * by calling the number function.
7507: */
7508: void
7509: xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7510: xmlXPathObjectPtr arg;
7511: double arg1, arg2;
7512:
7513: arg = valuePop(ctxt);
7514: if (arg == NULL)
7515: XP_ERROR(XPATH_INVALID_OPERAND);
7516: arg2 = xmlXPathCastToNumber(arg);
7517: xmlXPathReleaseObject(ctxt->context, arg);
7518: CAST_TO_NUMBER;
7519: CHECK_TYPE(XPATH_NUMBER);
7520: arg1 = ctxt->value->floatval;
7521: if (arg2 == 0)
7522: ctxt->value->floatval = xmlXPathNAN;
7523: else {
7524: ctxt->value->floatval = fmod(arg1, arg2);
7525: }
7526: }
7527:
7528: /************************************************************************
7529: * *
7530: * The traversal functions *
7531: * *
7532: ************************************************************************/
7533:
7534: /*
7535: * A traversal function enumerates nodes along an axis.
7536: * Initially it must be called with NULL, and it indicates
7537: * termination on the axis by returning NULL.
7538: */
7539: typedef xmlNodePtr (*xmlXPathTraversalFunction)
7540: (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7541:
7542: /*
7543: * xmlXPathTraversalFunctionExt:
7544: * A traversal function enumerates nodes along an axis.
7545: * Initially it must be called with NULL, and it indicates
7546: * termination on the axis by returning NULL.
7547: * The context node of the traversal is specified via @contextNode.
7548: */
7549: typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7550: (xmlNodePtr cur, xmlNodePtr contextNode);
7551:
7552: /*
7553: * xmlXPathNodeSetMergeFunction:
7554: * Used for merging node sets in xmlXPathCollectAndTest().
7555: */
7556: typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7557: (xmlNodeSetPtr, xmlNodeSetPtr, int);
7558:
7559:
7560: /**
7561: * xmlXPathNextSelf:
7562: * @ctxt: the XPath Parser context
7563: * @cur: the current node in the traversal
7564: *
7565: * Traversal function for the "self" direction
7566: * The self axis contains just the context node itself
7567: *
7568: * Returns the next element following that axis
7569: */
7570: xmlNodePtr
7571: xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7572: if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7573: if (cur == NULL)
7574: return(ctxt->context->node);
7575: return(NULL);
7576: }
7577:
7578: /**
7579: * xmlXPathNextChild:
7580: * @ctxt: the XPath Parser context
7581: * @cur: the current node in the traversal
7582: *
7583: * Traversal function for the "child" direction
7584: * The child axis contains the children of the context node in document order.
7585: *
7586: * Returns the next element following that axis
7587: */
7588: xmlNodePtr
7589: xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7590: if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7591: if (cur == NULL) {
7592: if (ctxt->context->node == NULL) return(NULL);
7593: switch (ctxt->context->node->type) {
7594: case XML_ELEMENT_NODE:
7595: case XML_TEXT_NODE:
7596: case XML_CDATA_SECTION_NODE:
7597: case XML_ENTITY_REF_NODE:
7598: case XML_ENTITY_NODE:
7599: case XML_PI_NODE:
7600: case XML_COMMENT_NODE:
7601: case XML_NOTATION_NODE:
7602: case XML_DTD_NODE:
7603: return(ctxt->context->node->children);
7604: case XML_DOCUMENT_NODE:
7605: case XML_DOCUMENT_TYPE_NODE:
7606: case XML_DOCUMENT_FRAG_NODE:
7607: case XML_HTML_DOCUMENT_NODE:
7608: #ifdef LIBXML_DOCB_ENABLED
7609: case XML_DOCB_DOCUMENT_NODE:
7610: #endif
7611: return(((xmlDocPtr) ctxt->context->node)->children);
7612: case XML_ELEMENT_DECL:
7613: case XML_ATTRIBUTE_DECL:
7614: case XML_ENTITY_DECL:
7615: case XML_ATTRIBUTE_NODE:
7616: case XML_NAMESPACE_DECL:
7617: case XML_XINCLUDE_START:
7618: case XML_XINCLUDE_END:
7619: return(NULL);
7620: }
7621: return(NULL);
7622: }
7623: if ((cur->type == XML_DOCUMENT_NODE) ||
7624: (cur->type == XML_HTML_DOCUMENT_NODE))
7625: return(NULL);
7626: return(cur->next);
7627: }
7628:
7629: /**
7630: * xmlXPathNextChildElement:
7631: * @ctxt: the XPath Parser context
7632: * @cur: the current node in the traversal
7633: *
7634: * Traversal function for the "child" direction and nodes of type element.
7635: * The child axis contains the children of the context node in document order.
7636: *
7637: * Returns the next element following that axis
7638: */
7639: static xmlNodePtr
7640: xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7641: if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7642: if (cur == NULL) {
7643: cur = ctxt->context->node;
7644: if (cur == NULL) return(NULL);
7645: /*
7646: * Get the first element child.
7647: */
7648: switch (cur->type) {
7649: case XML_ELEMENT_NODE:
7650: case XML_DOCUMENT_FRAG_NODE:
7651: case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7652: case XML_ENTITY_NODE:
7653: cur = cur->children;
7654: if (cur != NULL) {
7655: if (cur->type == XML_ELEMENT_NODE)
7656: return(cur);
7657: do {
7658: cur = cur->next;
7659: } while ((cur != NULL) &&
7660: (cur->type != XML_ELEMENT_NODE));
7661: return(cur);
7662: }
7663: return(NULL);
7664: case XML_DOCUMENT_NODE:
7665: case XML_HTML_DOCUMENT_NODE:
7666: #ifdef LIBXML_DOCB_ENABLED
7667: case XML_DOCB_DOCUMENT_NODE:
7668: #endif
7669: return(xmlDocGetRootElement((xmlDocPtr) cur));
7670: default:
7671: return(NULL);
7672: }
7673: return(NULL);
7674: }
7675: /*
7676: * Get the next sibling element node.
7677: */
7678: switch (cur->type) {
7679: case XML_ELEMENT_NODE:
7680: case XML_TEXT_NODE:
7681: case XML_ENTITY_REF_NODE:
7682: case XML_ENTITY_NODE:
7683: case XML_CDATA_SECTION_NODE:
7684: case XML_PI_NODE:
7685: case XML_COMMENT_NODE:
7686: case XML_XINCLUDE_END:
7687: break;
7688: /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7689: default:
7690: return(NULL);
7691: }
7692: if (cur->next != NULL) {
7693: if (cur->next->type == XML_ELEMENT_NODE)
7694: return(cur->next);
7695: cur = cur->next;
7696: do {
7697: cur = cur->next;
7698: } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7699: return(cur);
7700: }
7701: return(NULL);
7702: }
7703:
7704: /**
7705: * xmlXPathNextDescendantOrSelfElemParent:
7706: * @ctxt: the XPath Parser context
7707: * @cur: the current node in the traversal
7708: *
7709: * Traversal function for the "descendant-or-self" axis.
7710: * Additionally it returns only nodes which can be parents of
7711: * element nodes.
7712: *
7713: *
7714: * Returns the next element following that axis
7715: */
7716: static xmlNodePtr
7717: xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7718: xmlNodePtr contextNode)
7719: {
7720: if (cur == NULL) {
7721: if (contextNode == NULL)
7722: return(NULL);
7723: switch (contextNode->type) {
7724: case XML_ELEMENT_NODE:
7725: case XML_XINCLUDE_START:
7726: case XML_DOCUMENT_FRAG_NODE:
7727: case XML_DOCUMENT_NODE:
7728: #ifdef LIBXML_DOCB_ENABLED
7729: case XML_DOCB_DOCUMENT_NODE:
7730: #endif
7731: case XML_HTML_DOCUMENT_NODE:
7732: return(contextNode);
7733: default:
7734: return(NULL);
7735: }
7736: return(NULL);
7737: } else {
7738: xmlNodePtr start = cur;
7739:
7740: while (cur != NULL) {
7741: switch (cur->type) {
7742: case XML_ELEMENT_NODE:
7743: /* TODO: OK to have XInclude here? */
7744: case XML_XINCLUDE_START:
7745: case XML_DOCUMENT_FRAG_NODE:
7746: if (cur != start)
7747: return(cur);
7748: if (cur->children != NULL) {
7749: cur = cur->children;
7750: continue;
7751: }
7752: break;
7753: /* Not sure if we need those here. */
7754: case XML_DOCUMENT_NODE:
7755: #ifdef LIBXML_DOCB_ENABLED
7756: case XML_DOCB_DOCUMENT_NODE:
7757: #endif
7758: case XML_HTML_DOCUMENT_NODE:
7759: if (cur != start)
7760: return(cur);
7761: return(xmlDocGetRootElement((xmlDocPtr) cur));
7762: default:
7763: break;
7764: }
7765:
7766: next_sibling:
7767: if ((cur == NULL) || (cur == contextNode))
7768: return(NULL);
7769: if (cur->next != NULL) {
7770: cur = cur->next;
7771: } else {
7772: cur = cur->parent;
7773: goto next_sibling;
7774: }
7775: }
7776: }
7777: return(NULL);
7778: }
7779:
7780: /**
7781: * xmlXPathNextDescendant:
7782: * @ctxt: the XPath Parser context
7783: * @cur: the current node in the traversal
7784: *
7785: * Traversal function for the "descendant" direction
7786: * the descendant axis contains the descendants of the context node in document
7787: * order; a descendant is a child or a child of a child and so on.
7788: *
7789: * Returns the next element following that axis
7790: */
7791: xmlNodePtr
7792: xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7793: if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7794: if (cur == NULL) {
7795: if (ctxt->context->node == NULL)
7796: return(NULL);
7797: if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7798: (ctxt->context->node->type == XML_NAMESPACE_DECL))
7799: return(NULL);
7800:
7801: if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7802: return(ctxt->context->doc->children);
7803: return(ctxt->context->node->children);
7804: }
7805:
7806: if (cur->children != NULL) {
7807: /*
7808: * Do not descend on entities declarations
7809: */
7810: if (cur->children->type != XML_ENTITY_DECL) {
7811: cur = cur->children;
7812: /*
7813: * Skip DTDs
7814: */
7815: if (cur->type != XML_DTD_NODE)
7816: return(cur);
7817: }
7818: }
7819:
7820: if (cur == ctxt->context->node) return(NULL);
7821:
7822: while (cur->next != NULL) {
7823: cur = cur->next;
7824: if ((cur->type != XML_ENTITY_DECL) &&
7825: (cur->type != XML_DTD_NODE))
7826: return(cur);
7827: }
7828:
7829: do {
7830: cur = cur->parent;
7831: if (cur == NULL) break;
7832: if (cur == ctxt->context->node) return(NULL);
7833: if (cur->next != NULL) {
7834: cur = cur->next;
7835: return(cur);
7836: }
7837: } while (cur != NULL);
7838: return(cur);
7839: }
7840:
7841: /**
7842: * xmlXPathNextDescendantOrSelf:
7843: * @ctxt: the XPath Parser context
7844: * @cur: the current node in the traversal
7845: *
7846: * Traversal function for the "descendant-or-self" direction
7847: * the descendant-or-self axis contains the context node and the descendants
7848: * of the context node in document order; thus the context node is the first
7849: * node on the axis, and the first child of the context node is the second node
7850: * on the axis
7851: *
7852: * Returns the next element following that axis
7853: */
7854: xmlNodePtr
7855: xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7856: if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7857: if (cur == NULL) {
7858: if (ctxt->context->node == NULL)
7859: return(NULL);
7860: if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7861: (ctxt->context->node->type == XML_NAMESPACE_DECL))
7862: return(NULL);
7863: return(ctxt->context->node);
7864: }
7865:
7866: return(xmlXPathNextDescendant(ctxt, cur));
7867: }
7868:
7869: /**
7870: * xmlXPathNextParent:
7871: * @ctxt: the XPath Parser context
7872: * @cur: the current node in the traversal
7873: *
7874: * Traversal function for the "parent" direction
7875: * The parent axis contains the parent of the context node, if there is one.
7876: *
7877: * Returns the next element following that axis
7878: */
7879: xmlNodePtr
7880: xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7881: if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7882: /*
7883: * the parent of an attribute or namespace node is the element
7884: * to which the attribute or namespace node is attached
7885: * Namespace handling !!!
7886: */
7887: if (cur == NULL) {
7888: if (ctxt->context->node == NULL) return(NULL);
7889: switch (ctxt->context->node->type) {
7890: case XML_ELEMENT_NODE:
7891: case XML_TEXT_NODE:
7892: case XML_CDATA_SECTION_NODE:
7893: case XML_ENTITY_REF_NODE:
7894: case XML_ENTITY_NODE:
7895: case XML_PI_NODE:
7896: case XML_COMMENT_NODE:
7897: case XML_NOTATION_NODE:
7898: case XML_DTD_NODE:
7899: case XML_ELEMENT_DECL:
7900: case XML_ATTRIBUTE_DECL:
7901: case XML_XINCLUDE_START:
7902: case XML_XINCLUDE_END:
7903: case XML_ENTITY_DECL:
7904: if (ctxt->context->node->parent == NULL)
7905: return((xmlNodePtr) ctxt->context->doc);
7906: if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7907: ((ctxt->context->node->parent->name[0] == ' ') ||
7908: (xmlStrEqual(ctxt->context->node->parent->name,
7909: BAD_CAST "fake node libxslt"))))
7910: return(NULL);
7911: return(ctxt->context->node->parent);
7912: case XML_ATTRIBUTE_NODE: {
7913: xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7914:
7915: return(att->parent);
7916: }
7917: case XML_DOCUMENT_NODE:
7918: case XML_DOCUMENT_TYPE_NODE:
7919: case XML_DOCUMENT_FRAG_NODE:
7920: case XML_HTML_DOCUMENT_NODE:
7921: #ifdef LIBXML_DOCB_ENABLED
7922: case XML_DOCB_DOCUMENT_NODE:
7923: #endif
7924: return(NULL);
7925: case XML_NAMESPACE_DECL: {
7926: xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7927:
7928: if ((ns->next != NULL) &&
7929: (ns->next->type != XML_NAMESPACE_DECL))
7930: return((xmlNodePtr) ns->next);
7931: return(NULL);
7932: }
7933: }
7934: }
7935: return(NULL);
7936: }
7937:
7938: /**
7939: * xmlXPathNextAncestor:
7940: * @ctxt: the XPath Parser context
7941: * @cur: the current node in the traversal
7942: *
7943: * Traversal function for the "ancestor" direction
7944: * the ancestor axis contains the ancestors of the context node; the ancestors
7945: * of the context node consist of the parent of context node and the parent's
7946: * parent and so on; the nodes are ordered in reverse document order; thus the
7947: * parent is the first node on the axis, and the parent's parent is the second
7948: * node on the axis
7949: *
7950: * Returns the next element following that axis
7951: */
7952: xmlNodePtr
7953: xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7954: if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7955: /*
7956: * the parent of an attribute or namespace node is the element
7957: * to which the attribute or namespace node is attached
7958: * !!!!!!!!!!!!!
7959: */
7960: if (cur == NULL) {
7961: if (ctxt->context->node == NULL) return(NULL);
7962: switch (ctxt->context->node->type) {
7963: case XML_ELEMENT_NODE:
7964: case XML_TEXT_NODE:
7965: case XML_CDATA_SECTION_NODE:
7966: case XML_ENTITY_REF_NODE:
7967: case XML_ENTITY_NODE:
7968: case XML_PI_NODE:
7969: case XML_COMMENT_NODE:
7970: case XML_DTD_NODE:
7971: case XML_ELEMENT_DECL:
7972: case XML_ATTRIBUTE_DECL:
7973: case XML_ENTITY_DECL:
7974: case XML_NOTATION_NODE:
7975: case XML_XINCLUDE_START:
7976: case XML_XINCLUDE_END:
7977: if (ctxt->context->node->parent == NULL)
7978: return((xmlNodePtr) ctxt->context->doc);
7979: if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7980: ((ctxt->context->node->parent->name[0] == ' ') ||
7981: (xmlStrEqual(ctxt->context->node->parent->name,
7982: BAD_CAST "fake node libxslt"))))
7983: return(NULL);
7984: return(ctxt->context->node->parent);
7985: case XML_ATTRIBUTE_NODE: {
7986: xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
7987:
7988: return(tmp->parent);
7989: }
7990: case XML_DOCUMENT_NODE:
7991: case XML_DOCUMENT_TYPE_NODE:
7992: case XML_DOCUMENT_FRAG_NODE:
7993: case XML_HTML_DOCUMENT_NODE:
7994: #ifdef LIBXML_DOCB_ENABLED
7995: case XML_DOCB_DOCUMENT_NODE:
7996: #endif
7997: return(NULL);
7998: case XML_NAMESPACE_DECL: {
7999: xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8000:
8001: if ((ns->next != NULL) &&
8002: (ns->next->type != XML_NAMESPACE_DECL))
8003: return((xmlNodePtr) ns->next);
8004: /* Bad, how did that namespace end up here ? */
8005: return(NULL);
8006: }
8007: }
8008: return(NULL);
8009: }
8010: if (cur == ctxt->context->doc->children)
8011: return((xmlNodePtr) ctxt->context->doc);
8012: if (cur == (xmlNodePtr) ctxt->context->doc)
8013: return(NULL);
8014: switch (cur->type) {
8015: case XML_ELEMENT_NODE:
8016: case XML_TEXT_NODE:
8017: case XML_CDATA_SECTION_NODE:
8018: case XML_ENTITY_REF_NODE:
8019: case XML_ENTITY_NODE:
8020: case XML_PI_NODE:
8021: case XML_COMMENT_NODE:
8022: case XML_NOTATION_NODE:
8023: case XML_DTD_NODE:
8024: case XML_ELEMENT_DECL:
8025: case XML_ATTRIBUTE_DECL:
8026: case XML_ENTITY_DECL:
8027: case XML_XINCLUDE_START:
8028: case XML_XINCLUDE_END:
8029: if (cur->parent == NULL)
8030: return(NULL);
8031: if ((cur->parent->type == XML_ELEMENT_NODE) &&
8032: ((cur->parent->name[0] == ' ') ||
8033: (xmlStrEqual(cur->parent->name,
8034: BAD_CAST "fake node libxslt"))))
8035: return(NULL);
8036: return(cur->parent);
8037: case XML_ATTRIBUTE_NODE: {
8038: xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
8039:
8040: return(att->parent);
8041: }
8042: case XML_NAMESPACE_DECL: {
8043: xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8044:
8045: if ((ns->next != NULL) &&
8046: (ns->next->type != XML_NAMESPACE_DECL))
8047: return((xmlNodePtr) ns->next);
8048: /* Bad, how did that namespace end up here ? */
8049: return(NULL);
8050: }
8051: case XML_DOCUMENT_NODE:
8052: case XML_DOCUMENT_TYPE_NODE:
8053: case XML_DOCUMENT_FRAG_NODE:
8054: case XML_HTML_DOCUMENT_NODE:
8055: #ifdef LIBXML_DOCB_ENABLED
8056: case XML_DOCB_DOCUMENT_NODE:
8057: #endif
8058: return(NULL);
8059: }
8060: return(NULL);
8061: }
8062:
8063: /**
8064: * xmlXPathNextAncestorOrSelf:
8065: * @ctxt: the XPath Parser context
8066: * @cur: the current node in the traversal
8067: *
8068: * Traversal function for the "ancestor-or-self" direction
8069: * he ancestor-or-self axis contains the context node and ancestors of
8070: * the context node in reverse document order; thus the context node is
8071: * the first node on the axis, and the context node's parent the second;
8072: * parent here is defined the same as with the parent axis.
8073: *
8074: * Returns the next element following that axis
8075: */
8076: xmlNodePtr
8077: xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8078: if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8079: if (cur == NULL)
8080: return(ctxt->context->node);
8081: return(xmlXPathNextAncestor(ctxt, cur));
8082: }
8083:
8084: /**
8085: * xmlXPathNextFollowingSibling:
8086: * @ctxt: the XPath Parser context
8087: * @cur: the current node in the traversal
8088: *
8089: * Traversal function for the "following-sibling" direction
8090: * The following-sibling axis contains the following siblings of the context
8091: * node in document order.
8092: *
8093: * Returns the next element following that axis
8094: */
8095: xmlNodePtr
8096: xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8097: if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8098: if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8099: (ctxt->context->node->type == XML_NAMESPACE_DECL))
8100: return(NULL);
8101: if (cur == (xmlNodePtr) ctxt->context->doc)
8102: return(NULL);
8103: if (cur == NULL)
8104: return(ctxt->context->node->next);
8105: return(cur->next);
8106: }
8107:
8108: /**
8109: * xmlXPathNextPrecedingSibling:
8110: * @ctxt: the XPath Parser context
8111: * @cur: the current node in the traversal
8112: *
8113: * Traversal function for the "preceding-sibling" direction
8114: * The preceding-sibling axis contains the preceding siblings of the context
8115: * node in reverse document order; the first preceding sibling is first on the
8116: * axis; the sibling preceding that node is the second on the axis and so on.
8117: *
8118: * Returns the next element following that axis
8119: */
8120: xmlNodePtr
8121: xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8122: if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8123: if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8124: (ctxt->context->node->type == XML_NAMESPACE_DECL))
8125: return(NULL);
8126: if (cur == (xmlNodePtr) ctxt->context->doc)
8127: return(NULL);
8128: if (cur == NULL)
8129: return(ctxt->context->node->prev);
8130: if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8131: cur = cur->prev;
8132: if (cur == NULL)
8133: return(ctxt->context->node->prev);
8134: }
8135: return(cur->prev);
8136: }
8137:
8138: /**
8139: * xmlXPathNextFollowing:
8140: * @ctxt: the XPath Parser context
8141: * @cur: the current node in the traversal
8142: *
8143: * Traversal function for the "following" direction
8144: * The following axis contains all nodes in the same document as the context
8145: * node that are after the context node in document order, excluding any
8146: * descendants and excluding attribute nodes and namespace nodes; the nodes
8147: * are ordered in document order
8148: *
8149: * Returns the next element following that axis
8150: */
8151: xmlNodePtr
8152: xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8153: if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8154: if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
8155: (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8156: return(cur->children);
8157:
8158: if (cur == NULL) {
8159: cur = ctxt->context->node;
8160: if (cur->type == XML_NAMESPACE_DECL)
8161: return(NULL);
8162: if (cur->type == XML_ATTRIBUTE_NODE)
8163: cur = cur->parent;
8164: }
8165: if (cur == NULL) return(NULL) ; /* ERROR */
8166: if (cur->next != NULL) return(cur->next) ;
8167: do {
8168: cur = cur->parent;
8169: if (cur == NULL) break;
8170: if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8171: if (cur->next != NULL) return(cur->next);
8172: } while (cur != NULL);
8173: return(cur);
8174: }
8175:
8176: /*
8177: * xmlXPathIsAncestor:
8178: * @ancestor: the ancestor node
8179: * @node: the current node
8180: *
8181: * Check that @ancestor is a @node's ancestor
8182: *
8183: * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8184: */
8185: static int
8186: xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8187: if ((ancestor == NULL) || (node == NULL)) return(0);
8188: /* nodes need to be in the same document */
8189: if (ancestor->doc != node->doc) return(0);
8190: /* avoid searching if ancestor or node is the root node */
8191: if (ancestor == (xmlNodePtr) node->doc) return(1);
8192: if (node == (xmlNodePtr) ancestor->doc) return(0);
8193: while (node->parent != NULL) {
8194: if (node->parent == ancestor)
8195: return(1);
8196: node = node->parent;
8197: }
8198: return(0);
8199: }
8200:
8201: /**
8202: * xmlXPathNextPreceding:
8203: * @ctxt: the XPath Parser context
8204: * @cur: the current node in the traversal
8205: *
8206: * Traversal function for the "preceding" direction
8207: * the preceding axis contains all nodes in the same document as the context
8208: * node that are before the context node in document order, excluding any
8209: * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8210: * ordered in reverse document order
8211: *
8212: * Returns the next element following that axis
8213: */
8214: xmlNodePtr
8215: xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8216: {
8217: if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8218: if (cur == NULL) {
8219: cur = ctxt->context->node;
8220: if (cur->type == XML_NAMESPACE_DECL)
8221: return(NULL);
8222: if (cur->type == XML_ATTRIBUTE_NODE)
8223: return(cur->parent);
8224: }
8225: if (cur == NULL)
8226: return (NULL);
8227: if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8228: cur = cur->prev;
8229: do {
8230: if (cur->prev != NULL) {
8231: for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8232: return (cur);
8233: }
8234:
8235: cur = cur->parent;
8236: if (cur == NULL)
8237: return (NULL);
8238: if (cur == ctxt->context->doc->children)
8239: return (NULL);
8240: } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8241: return (cur);
8242: }
8243:
8244: /**
8245: * xmlXPathNextPrecedingInternal:
8246: * @ctxt: the XPath Parser context
8247: * @cur: the current node in the traversal
8248: *
8249: * Traversal function for the "preceding" direction
8250: * the preceding axis contains all nodes in the same document as the context
8251: * node that are before the context node in document order, excluding any
8252: * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8253: * ordered in reverse document order
8254: * This is a faster implementation but internal only since it requires a
8255: * state kept in the parser context: ctxt->ancestor.
8256: *
8257: * Returns the next element following that axis
8258: */
8259: static xmlNodePtr
8260: xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8261: xmlNodePtr cur)
8262: {
8263: if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8264: if (cur == NULL) {
8265: cur = ctxt->context->node;
8266: if (cur == NULL)
8267: return (NULL);
8268: if (cur->type == XML_NAMESPACE_DECL)
8269: return (NULL);
8270: ctxt->ancestor = cur->parent;
8271: }
8272: if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8273: cur = cur->prev;
8274: while (cur->prev == NULL) {
8275: cur = cur->parent;
8276: if (cur == NULL)
8277: return (NULL);
8278: if (cur == ctxt->context->doc->children)
8279: return (NULL);
8280: if (cur != ctxt->ancestor)
8281: return (cur);
8282: ctxt->ancestor = cur->parent;
8283: }
8284: cur = cur->prev;
8285: while (cur->last != NULL)
8286: cur = cur->last;
8287: return (cur);
8288: }
8289:
8290: /**
8291: * xmlXPathNextNamespace:
8292: * @ctxt: the XPath Parser context
8293: * @cur: the current attribute in the traversal
8294: *
8295: * Traversal function for the "namespace" direction
8296: * the namespace axis contains the namespace nodes of the context node;
8297: * the order of nodes on this axis is implementation-defined; the axis will
8298: * be empty unless the context node is an element
8299: *
8300: * We keep the XML namespace node at the end of the list.
8301: *
8302: * Returns the next element following that axis
8303: */
8304: xmlNodePtr
8305: xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8306: if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8307: if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8308: if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
8309: if (ctxt->context->tmpNsList != NULL)
8310: xmlFree(ctxt->context->tmpNsList);
8311: ctxt->context->tmpNsList =
8312: xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8313: ctxt->context->tmpNsNr = 0;
8314: if (ctxt->context->tmpNsList != NULL) {
8315: while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8316: ctxt->context->tmpNsNr++;
8317: }
8318: }
8319: return((xmlNodePtr) xmlXPathXMLNamespace);
8320: }
8321: if (ctxt->context->tmpNsNr > 0) {
8322: return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8323: } else {
8324: if (ctxt->context->tmpNsList != NULL)
8325: xmlFree(ctxt->context->tmpNsList);
8326: ctxt->context->tmpNsList = NULL;
8327: return(NULL);
8328: }
8329: }
8330:
8331: /**
8332: * xmlXPathNextAttribute:
8333: * @ctxt: the XPath Parser context
8334: * @cur: the current attribute in the traversal
8335: *
8336: * Traversal function for the "attribute" direction
8337: * TODO: support DTD inherited default attributes
8338: *
8339: * Returns the next element following that axis
8340: */
8341: xmlNodePtr
8342: xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8343: if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8344: if (ctxt->context->node == NULL)
8345: return(NULL);
8346: if (ctxt->context->node->type != XML_ELEMENT_NODE)
8347: return(NULL);
8348: if (cur == NULL) {
8349: if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8350: return(NULL);
8351: return((xmlNodePtr)ctxt->context->node->properties);
8352: }
8353: return((xmlNodePtr)cur->next);
8354: }
8355:
8356: /************************************************************************
8357: * *
8358: * NodeTest Functions *
8359: * *
8360: ************************************************************************/
8361:
8362: #define IS_FUNCTION 200
8363:
8364:
8365: /************************************************************************
8366: * *
8367: * Implicit tree core function library *
8368: * *
8369: ************************************************************************/
8370:
8371: /**
8372: * xmlXPathRoot:
8373: * @ctxt: the XPath Parser context
8374: *
8375: * Initialize the context to the root of the document
8376: */
8377: void
8378: xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8379: if ((ctxt == NULL) || (ctxt->context == NULL))
8380: return;
8381: ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
8382: valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8383: ctxt->context->node));
8384: }
8385:
8386: /************************************************************************
8387: * *
8388: * The explicit core function library *
8389: *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8390: * *
8391: ************************************************************************/
8392:
8393:
8394: /**
8395: * xmlXPathLastFunction:
8396: * @ctxt: the XPath Parser context
8397: * @nargs: the number of arguments
8398: *
8399: * Implement the last() XPath function
8400: * number last()
8401: * The last function returns the number of nodes in the context node list.
8402: */
8403: void
8404: xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8405: CHECK_ARITY(0);
8406: if (ctxt->context->contextSize >= 0) {
8407: valuePush(ctxt,
8408: xmlXPathCacheNewFloat(ctxt->context,
8409: (double) ctxt->context->contextSize));
8410: #ifdef DEBUG_EXPR
8411: xmlGenericError(xmlGenericErrorContext,
8412: "last() : %d\n", ctxt->context->contextSize);
8413: #endif
8414: } else {
8415: XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8416: }
8417: }
8418:
8419: /**
8420: * xmlXPathPositionFunction:
8421: * @ctxt: the XPath Parser context
8422: * @nargs: the number of arguments
8423: *
8424: * Implement the position() XPath function
8425: * number position()
8426: * The position function returns the position of the context node in the
8427: * context node list. The first position is 1, and so the last position
8428: * will be equal to last().
8429: */
8430: void
8431: xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8432: CHECK_ARITY(0);
8433: if (ctxt->context->proximityPosition >= 0) {
8434: valuePush(ctxt,
8435: xmlXPathCacheNewFloat(ctxt->context,
8436: (double) ctxt->context->proximityPosition));
8437: #ifdef DEBUG_EXPR
8438: xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8439: ctxt->context->proximityPosition);
8440: #endif
8441: } else {
8442: XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8443: }
8444: }
8445:
8446: /**
8447: * xmlXPathCountFunction:
8448: * @ctxt: the XPath Parser context
8449: * @nargs: the number of arguments
8450: *
8451: * Implement the count() XPath function
8452: * number count(node-set)
8453: */
8454: void
8455: xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8456: xmlXPathObjectPtr cur;
8457:
8458: CHECK_ARITY(1);
8459: if ((ctxt->value == NULL) ||
8460: ((ctxt->value->type != XPATH_NODESET) &&
8461: (ctxt->value->type != XPATH_XSLT_TREE)))
8462: XP_ERROR(XPATH_INVALID_TYPE);
8463: cur = valuePop(ctxt);
8464:
8465: if ((cur == NULL) || (cur->nodesetval == NULL))
8466: valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8467: else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8468: valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8469: (double) cur->nodesetval->nodeNr));
8470: } else {
8471: if ((cur->nodesetval->nodeNr != 1) ||
8472: (cur->nodesetval->nodeTab == NULL)) {
8473: valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8474: } else {
8475: xmlNodePtr tmp;
8476: int i = 0;
8477:
8478: tmp = cur->nodesetval->nodeTab[0];
8479: if (tmp != NULL) {
8480: tmp = tmp->children;
8481: while (tmp != NULL) {
8482: tmp = tmp->next;
8483: i++;
8484: }
8485: }
8486: valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8487: }
8488: }
8489: xmlXPathReleaseObject(ctxt->context, cur);
8490: }
8491:
8492: /**
8493: * xmlXPathGetElementsByIds:
8494: * @doc: the document
8495: * @ids: a whitespace separated list of IDs
8496: *
8497: * Selects elements by their unique ID.
8498: *
8499: * Returns a node-set of selected elements.
8500: */
8501: static xmlNodeSetPtr
8502: xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8503: xmlNodeSetPtr ret;
8504: const xmlChar *cur = ids;
8505: xmlChar *ID;
8506: xmlAttrPtr attr;
8507: xmlNodePtr elem = NULL;
8508:
8509: if (ids == NULL) return(NULL);
8510:
8511: ret = xmlXPathNodeSetCreate(NULL);
8512: if (ret == NULL)
8513: return(ret);
8514:
8515: while (IS_BLANK_CH(*cur)) cur++;
8516: while (*cur != 0) {
8517: while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8518: cur++;
8519:
8520: ID = xmlStrndup(ids, cur - ids);
8521: if (ID != NULL) {
8522: /*
8523: * We used to check the fact that the value passed
8524: * was an NCName, but this generated much troubles for
8525: * me and Aleksey Sanin, people blatantly violated that
8526: * constaint, like Visa3D spec.
8527: * if (xmlValidateNCName(ID, 1) == 0)
8528: */
8529: attr = xmlGetID(doc, ID);
8530: if (attr != NULL) {
8531: if (attr->type == XML_ATTRIBUTE_NODE)
8532: elem = attr->parent;
8533: else if (attr->type == XML_ELEMENT_NODE)
8534: elem = (xmlNodePtr) attr;
8535: else
8536: elem = NULL;
8537: if (elem != NULL)
8538: xmlXPathNodeSetAdd(ret, elem);
8539: }
8540: xmlFree(ID);
8541: }
8542:
8543: while (IS_BLANK_CH(*cur)) cur++;
8544: ids = cur;
8545: }
8546: return(ret);
8547: }
8548:
8549: /**
8550: * xmlXPathIdFunction:
8551: * @ctxt: the XPath Parser context
8552: * @nargs: the number of arguments
8553: *
8554: * Implement the id() XPath function
8555: * node-set id(object)
8556: * The id function selects elements by their unique ID
8557: * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8558: * then the result is the union of the result of applying id to the
8559: * string value of each of the nodes in the argument node-set. When the
8560: * argument to id is of any other type, the argument is converted to a
8561: * string as if by a call to the string function; the string is split
8562: * into a whitespace-separated list of tokens (whitespace is any sequence
8563: * of characters matching the production S); the result is a node-set
8564: * containing the elements in the same document as the context node that
8565: * have a unique ID equal to any of the tokens in the list.
8566: */
8567: void
8568: xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8569: xmlChar *tokens;
8570: xmlNodeSetPtr ret;
8571: xmlXPathObjectPtr obj;
8572:
8573: CHECK_ARITY(1);
8574: obj = valuePop(ctxt);
8575: if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8576: if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8577: xmlNodeSetPtr ns;
8578: int i;
8579:
8580: ret = xmlXPathNodeSetCreate(NULL);
8581: /*
8582: * FIXME -- in an out-of-memory condition this will behave badly.
8583: * The solution is not clear -- we already popped an item from
8584: * ctxt, so the object is in a corrupt state.
8585: */
8586:
8587: if (obj->nodesetval != NULL) {
8588: for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8589: tokens =
8590: xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8591: ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8592: ret = xmlXPathNodeSetMerge(ret, ns);
8593: xmlXPathFreeNodeSet(ns);
8594: if (tokens != NULL)
8595: xmlFree(tokens);
8596: }
8597: }
8598: xmlXPathReleaseObject(ctxt->context, obj);
8599: valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8600: return;
8601: }
8602: obj = xmlXPathCacheConvertString(ctxt->context, obj);
8603: ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8604: valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8605: xmlXPathReleaseObject(ctxt->context, obj);
8606: return;
8607: }
8608:
8609: /**
8610: * xmlXPathLocalNameFunction:
8611: * @ctxt: the XPath Parser context
8612: * @nargs: the number of arguments
8613: *
8614: * Implement the local-name() XPath function
8615: * string local-name(node-set?)
8616: * The local-name function returns a string containing the local part
8617: * of the name of the node in the argument node-set that is first in
8618: * document order. If the node-set is empty or the first node has no
8619: * name, an empty string is returned. If the argument is omitted it
8620: * defaults to the context node.
8621: */
8622: void
8623: xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8624: xmlXPathObjectPtr cur;
8625:
8626: if (ctxt == NULL) return;
8627:
8628: if (nargs == 0) {
8629: valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8630: ctxt->context->node));
8631: nargs = 1;
8632: }
8633:
8634: CHECK_ARITY(1);
8635: if ((ctxt->value == NULL) ||
8636: ((ctxt->value->type != XPATH_NODESET) &&
8637: (ctxt->value->type != XPATH_XSLT_TREE)))
8638: XP_ERROR(XPATH_INVALID_TYPE);
8639: cur = valuePop(ctxt);
8640:
8641: if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8642: valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8643: } else {
8644: int i = 0; /* Should be first in document order !!!!! */
8645: switch (cur->nodesetval->nodeTab[i]->type) {
8646: case XML_ELEMENT_NODE:
8647: case XML_ATTRIBUTE_NODE:
8648: case XML_PI_NODE:
8649: if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8650: valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8651: else
8652: valuePush(ctxt,
8653: xmlXPathCacheNewString(ctxt->context,
8654: cur->nodesetval->nodeTab[i]->name));
8655: break;
8656: case XML_NAMESPACE_DECL:
8657: valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8658: ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8659: break;
8660: default:
8661: valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8662: }
8663: }
8664: xmlXPathReleaseObject(ctxt->context, cur);
8665: }
8666:
8667: /**
8668: * xmlXPathNamespaceURIFunction:
8669: * @ctxt: the XPath Parser context
8670: * @nargs: the number of arguments
8671: *
8672: * Implement the namespace-uri() XPath function
8673: * string namespace-uri(node-set?)
8674: * The namespace-uri function returns a string containing the
8675: * namespace URI of the expanded name of the node in the argument
8676: * node-set that is first in document order. If the node-set is empty,
8677: * the first node has no name, or the expanded name has no namespace
8678: * URI, an empty string is returned. If the argument is omitted it
8679: * defaults to the context node.
8680: */
8681: void
8682: xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8683: xmlXPathObjectPtr cur;
8684:
8685: if (ctxt == NULL) return;
8686:
8687: if (nargs == 0) {
8688: valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8689: ctxt->context->node));
8690: nargs = 1;
8691: }
8692: CHECK_ARITY(1);
8693: if ((ctxt->value == NULL) ||
8694: ((ctxt->value->type != XPATH_NODESET) &&
8695: (ctxt->value->type != XPATH_XSLT_TREE)))
8696: XP_ERROR(XPATH_INVALID_TYPE);
8697: cur = valuePop(ctxt);
8698:
8699: if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8700: valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8701: } else {
8702: int i = 0; /* Should be first in document order !!!!! */
8703: switch (cur->nodesetval->nodeTab[i]->type) {
8704: case XML_ELEMENT_NODE:
8705: case XML_ATTRIBUTE_NODE:
8706: if (cur->nodesetval->nodeTab[i]->ns == NULL)
8707: valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8708: else
8709: valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8710: cur->nodesetval->nodeTab[i]->ns->href));
8711: break;
8712: default:
8713: valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8714: }
8715: }
8716: xmlXPathReleaseObject(ctxt->context, cur);
8717: }
8718:
8719: /**
8720: * xmlXPathNameFunction:
8721: * @ctxt: the XPath Parser context
8722: * @nargs: the number of arguments
8723: *
8724: * Implement the name() XPath function
8725: * string name(node-set?)
8726: * The name function returns a string containing a QName representing
8727: * the name of the node in the argument node-set that is first in document
8728: * order. The QName must represent the name with respect to the namespace
8729: * declarations in effect on the node whose name is being represented.
8730: * Typically, this will be the form in which the name occurred in the XML
8731: * source. This need not be the case if there are namespace declarations
8732: * in effect on the node that associate multiple prefixes with the same
8733: * namespace. However, an implementation may include information about
8734: * the original prefix in its representation of nodes; in this case, an
8735: * implementation can ensure that the returned string is always the same
8736: * as the QName used in the XML source. If the argument it omitted it
8737: * defaults to the context node.
8738: * Libxml keep the original prefix so the "real qualified name" used is
8739: * returned.
8740: */
8741: static void
8742: xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8743: {
8744: xmlXPathObjectPtr cur;
8745:
8746: if (nargs == 0) {
8747: valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8748: ctxt->context->node));
8749: nargs = 1;
8750: }
8751:
8752: CHECK_ARITY(1);
8753: if ((ctxt->value == NULL) ||
8754: ((ctxt->value->type != XPATH_NODESET) &&
8755: (ctxt->value->type != XPATH_XSLT_TREE)))
8756: XP_ERROR(XPATH_INVALID_TYPE);
8757: cur = valuePop(ctxt);
8758:
8759: if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8760: valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8761: } else {
8762: int i = 0; /* Should be first in document order !!!!! */
8763:
8764: switch (cur->nodesetval->nodeTab[i]->type) {
8765: case XML_ELEMENT_NODE:
8766: case XML_ATTRIBUTE_NODE:
8767: if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8768: valuePush(ctxt,
8769: xmlXPathCacheNewCString(ctxt->context, ""));
8770: else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8771: (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8772: valuePush(ctxt,
8773: xmlXPathCacheNewString(ctxt->context,
8774: cur->nodesetval->nodeTab[i]->name));
8775: } else {
8776: xmlChar *fullname;
8777:
8778: fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8779: cur->nodesetval->nodeTab[i]->ns->prefix,
8780: NULL, 0);
8781: if (fullname == cur->nodesetval->nodeTab[i]->name)
8782: fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8783: if (fullname == NULL) {
8784: XP_ERROR(XPATH_MEMORY_ERROR);
8785: }
8786: valuePush(ctxt, xmlXPathCacheWrapString(
8787: ctxt->context, fullname));
8788: }
8789: break;
8790: default:
8791: valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8792: cur->nodesetval->nodeTab[i]));
8793: xmlXPathLocalNameFunction(ctxt, 1);
8794: }
8795: }
8796: xmlXPathReleaseObject(ctxt->context, cur);
8797: }
8798:
8799:
8800: /**
8801: * xmlXPathStringFunction:
8802: * @ctxt: the XPath Parser context
8803: * @nargs: the number of arguments
8804: *
8805: * Implement the string() XPath function
8806: * string string(object?)
8807: * The string function converts an object to a string as follows:
8808: * - A node-set is converted to a string by returning the value of
8809: * the node in the node-set that is first in document order.
8810: * If the node-set is empty, an empty string is returned.
8811: * - A number is converted to a string as follows
8812: * + NaN is converted to the string NaN
8813: * + positive zero is converted to the string 0
8814: * + negative zero is converted to the string 0
8815: * + positive infinity is converted to the string Infinity
8816: * + negative infinity is converted to the string -Infinity
8817: * + if the number is an integer, the number is represented in
8818: * decimal form as a Number with no decimal point and no leading
8819: * zeros, preceded by a minus sign (-) if the number is negative
8820: * + otherwise, the number is represented in decimal form as a
8821: * Number including a decimal point with at least one digit
8822: * before the decimal point and at least one digit after the
8823: * decimal point, preceded by a minus sign (-) if the number
8824: * is negative; there must be no leading zeros before the decimal
8825: * point apart possibly from the one required digit immediately
8826: * before the decimal point; beyond the one required digit
8827: * after the decimal point there must be as many, but only as
8828: * many, more digits as are needed to uniquely distinguish the
8829: * number from all other IEEE 754 numeric values.
8830: * - The boolean false value is converted to the string false.
8831: * The boolean true value is converted to the string true.
8832: *
8833: * If the argument is omitted, it defaults to a node-set with the
8834: * context node as its only member.
8835: */
8836: void
8837: xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8838: xmlXPathObjectPtr cur;
8839:
8840: if (ctxt == NULL) return;
8841: if (nargs == 0) {
8842: valuePush(ctxt,
8843: xmlXPathCacheWrapString(ctxt->context,
8844: xmlXPathCastNodeToString(ctxt->context->node)));
8845: return;
8846: }
8847:
8848: CHECK_ARITY(1);
8849: cur = valuePop(ctxt);
8850: if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8851: valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8852: }
8853:
8854: /**
8855: * xmlXPathStringLengthFunction:
8856: * @ctxt: the XPath Parser context
8857: * @nargs: the number of arguments
8858: *
8859: * Implement the string-length() XPath function
8860: * number string-length(string?)
8861: * The string-length returns the number of characters in the string
8862: * (see [3.6 Strings]). If the argument is omitted, it defaults to
8863: * the context node converted to a string, in other words the value
8864: * of the context node.
8865: */
8866: void
8867: xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8868: xmlXPathObjectPtr cur;
8869:
8870: if (nargs == 0) {
8871: if ((ctxt == NULL) || (ctxt->context == NULL))
8872: return;
8873: if (ctxt->context->node == NULL) {
8874: valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8875: } else {
8876: xmlChar *content;
8877:
8878: content = xmlXPathCastNodeToString(ctxt->context->node);
8879: valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8880: xmlUTF8Strlen(content)));
8881: xmlFree(content);
8882: }
8883: return;
8884: }
8885: CHECK_ARITY(1);
8886: CAST_TO_STRING;
8887: CHECK_TYPE(XPATH_STRING);
8888: cur = valuePop(ctxt);
8889: valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8890: xmlUTF8Strlen(cur->stringval)));
8891: xmlXPathReleaseObject(ctxt->context, cur);
8892: }
8893:
8894: /**
8895: * xmlXPathConcatFunction:
8896: * @ctxt: the XPath Parser context
8897: * @nargs: the number of arguments
8898: *
8899: * Implement the concat() XPath function
8900: * string concat(string, string, string*)
8901: * The concat function returns the concatenation of its arguments.
8902: */
8903: void
8904: xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8905: xmlXPathObjectPtr cur, newobj;
8906: xmlChar *tmp;
8907:
8908: if (ctxt == NULL) return;
8909: if (nargs < 2) {
8910: CHECK_ARITY(2);
8911: }
8912:
8913: CAST_TO_STRING;
8914: cur = valuePop(ctxt);
8915: if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8916: xmlXPathReleaseObject(ctxt->context, cur);
8917: return;
8918: }
8919: nargs--;
8920:
8921: while (nargs > 0) {
8922: CAST_TO_STRING;
8923: newobj = valuePop(ctxt);
8924: if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8925: xmlXPathReleaseObject(ctxt->context, newobj);
8926: xmlXPathReleaseObject(ctxt->context, cur);
8927: XP_ERROR(XPATH_INVALID_TYPE);
8928: }
8929: tmp = xmlStrcat(newobj->stringval, cur->stringval);
8930: newobj->stringval = cur->stringval;
8931: cur->stringval = tmp;
8932: xmlXPathReleaseObject(ctxt->context, newobj);
8933: nargs--;
8934: }
8935: valuePush(ctxt, cur);
8936: }
8937:
8938: /**
8939: * xmlXPathContainsFunction:
8940: * @ctxt: the XPath Parser context
8941: * @nargs: the number of arguments
8942: *
8943: * Implement the contains() XPath function
8944: * boolean contains(string, string)
8945: * The contains function returns true if the first argument string
8946: * contains the second argument string, and otherwise returns false.
8947: */
8948: void
8949: xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8950: xmlXPathObjectPtr hay, needle;
8951:
8952: CHECK_ARITY(2);
8953: CAST_TO_STRING;
8954: CHECK_TYPE(XPATH_STRING);
8955: needle = valuePop(ctxt);
8956: CAST_TO_STRING;
8957: hay = valuePop(ctxt);
8958:
8959: if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8960: xmlXPathReleaseObject(ctxt->context, hay);
8961: xmlXPathReleaseObject(ctxt->context, needle);
8962: XP_ERROR(XPATH_INVALID_TYPE);
8963: }
8964: if (xmlStrstr(hay->stringval, needle->stringval))
8965: valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8966: else
8967: valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8968: xmlXPathReleaseObject(ctxt->context, hay);
8969: xmlXPathReleaseObject(ctxt->context, needle);
8970: }
8971:
8972: /**
8973: * xmlXPathStartsWithFunction:
8974: * @ctxt: the XPath Parser context
8975: * @nargs: the number of arguments
8976: *
8977: * Implement the starts-with() XPath function
8978: * boolean starts-with(string, string)
8979: * The starts-with function returns true if the first argument string
8980: * starts with the second argument string, and otherwise returns false.
8981: */
8982: void
8983: xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8984: xmlXPathObjectPtr hay, needle;
8985: int n;
8986:
8987: CHECK_ARITY(2);
8988: CAST_TO_STRING;
8989: CHECK_TYPE(XPATH_STRING);
8990: needle = valuePop(ctxt);
8991: CAST_TO_STRING;
8992: hay = valuePop(ctxt);
8993:
8994: if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8995: xmlXPathReleaseObject(ctxt->context, hay);
8996: xmlXPathReleaseObject(ctxt->context, needle);
8997: XP_ERROR(XPATH_INVALID_TYPE);
8998: }
8999: n = xmlStrlen(needle->stringval);
9000: if (xmlStrncmp(hay->stringval, needle->stringval, n))
9001: valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9002: else
9003: valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9004: xmlXPathReleaseObject(ctxt->context, hay);
9005: xmlXPathReleaseObject(ctxt->context, needle);
9006: }
9007:
9008: /**
9009: * xmlXPathSubstringFunction:
9010: * @ctxt: the XPath Parser context
9011: * @nargs: the number of arguments
9012: *
9013: * Implement the substring() XPath function
9014: * string substring(string, number, number?)
9015: * The substring function returns the substring of the first argument
9016: * starting at the position specified in the second argument with
9017: * length specified in the third argument. For example,
9018: * substring("12345",2,3) returns "234". If the third argument is not
9019: * specified, it returns the substring starting at the position specified
9020: * in the second argument and continuing to the end of the string. For
9021: * example, substring("12345",2) returns "2345". More precisely, each
9022: * character in the string (see [3.6 Strings]) is considered to have a
9023: * numeric position: the position of the first character is 1, the position
9024: * of the second character is 2 and so on. The returned substring contains
9025: * those characters for which the position of the character is greater than
9026: * or equal to the second argument and, if the third argument is specified,
9027: * less than the sum of the second and third arguments; the comparisons
9028: * and addition used for the above follow the standard IEEE 754 rules. Thus:
9029: * - substring("12345", 1.5, 2.6) returns "234"
9030: * - substring("12345", 0, 3) returns "12"
9031: * - substring("12345", 0 div 0, 3) returns ""
9032: * - substring("12345", 1, 0 div 0) returns ""
9033: * - substring("12345", -42, 1 div 0) returns "12345"
9034: * - substring("12345", -1 div 0, 1 div 0) returns ""
9035: */
9036: void
9037: xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9038: xmlXPathObjectPtr str, start, len;
9039: double le=0, in;
9040: int i, l, m;
9041: xmlChar *ret;
9042:
9043: if (nargs < 2) {
9044: CHECK_ARITY(2);
9045: }
9046: if (nargs > 3) {
9047: CHECK_ARITY(3);
9048: }
9049: /*
9050: * take care of possible last (position) argument
9051: */
9052: if (nargs == 3) {
9053: CAST_TO_NUMBER;
9054: CHECK_TYPE(XPATH_NUMBER);
9055: len = valuePop(ctxt);
9056: le = len->floatval;
9057: xmlXPathReleaseObject(ctxt->context, len);
9058: }
9059:
9060: CAST_TO_NUMBER;
9061: CHECK_TYPE(XPATH_NUMBER);
9062: start = valuePop(ctxt);
9063: in = start->floatval;
9064: xmlXPathReleaseObject(ctxt->context, start);
9065: CAST_TO_STRING;
9066: CHECK_TYPE(XPATH_STRING);
9067: str = valuePop(ctxt);
9068: m = xmlUTF8Strlen((const unsigned char *)str->stringval);
9069:
9070: /*
9071: * If last pos not present, calculate last position
9072: */
9073: if (nargs != 3) {
9074: le = (double)m;
9075: if (in < 1.0)
9076: in = 1.0;
9077: }
9078:
9079: /* Need to check for the special cases where either
9080: * the index is NaN, the length is NaN, or both
9081: * arguments are infinity (relying on Inf + -Inf = NaN)
9082: */
9083: if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
9084: /*
9085: * To meet the requirements of the spec, the arguments
9086: * must be converted to integer format before
9087: * initial index calculations are done
9088: *
9089: * First we go to integer form, rounding up
9090: * and checking for special cases
9091: */
9092: i = (int) in;
9093: if (((double)i)+0.5 <= in) i++;
9094:
9095: if (xmlXPathIsInf(le) == 1) {
9096: l = m;
9097: if (i < 1)
9098: i = 1;
9099: }
9100: else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9101: l = 0;
9102: else {
9103: l = (int) le;
9104: if (((double)l)+0.5 <= le) l++;
9105: }
9106:
9107: /* Now we normalize inidices */
9108: i -= 1;
9109: l += i;
9110: if (i < 0)
9111: i = 0;
9112: if (l > m)
9113: l = m;
9114:
9115: /* number of chars to copy */
9116: l -= i;
9117:
9118: ret = xmlUTF8Strsub(str->stringval, i, l);
9119: }
9120: else {
9121: ret = NULL;
9122: }
9123: if (ret == NULL)
9124: valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9125: else {
9126: valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9127: xmlFree(ret);
9128: }
9129: xmlXPathReleaseObject(ctxt->context, str);
9130: }
9131:
9132: /**
9133: * xmlXPathSubstringBeforeFunction:
9134: * @ctxt: the XPath Parser context
9135: * @nargs: the number of arguments
9136: *
9137: * Implement the substring-before() XPath function
9138: * string substring-before(string, string)
9139: * The substring-before function returns the substring of the first
9140: * argument string that precedes the first occurrence of the second
9141: * argument string in the first argument string, or the empty string
9142: * if the first argument string does not contain the second argument
9143: * string. For example, substring-before("1999/04/01","/") returns 1999.
9144: */
9145: void
9146: xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9147: xmlXPathObjectPtr str;
9148: xmlXPathObjectPtr find;
9149: xmlBufferPtr target;
9150: const xmlChar *point;
9151: int offset;
9152:
9153: CHECK_ARITY(2);
9154: CAST_TO_STRING;
9155: find = valuePop(ctxt);
9156: CAST_TO_STRING;
9157: str = valuePop(ctxt);
9158:
9159: target = xmlBufferCreate();
9160: if (target) {
9161: point = xmlStrstr(str->stringval, find->stringval);
9162: if (point) {
9163: offset = (int)(point - str->stringval);
9164: xmlBufferAdd(target, str->stringval, offset);
9165: }
9166: valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9167: xmlBufferContent(target)));
9168: xmlBufferFree(target);
9169: }
9170: xmlXPathReleaseObject(ctxt->context, str);
9171: xmlXPathReleaseObject(ctxt->context, find);
9172: }
9173:
9174: /**
9175: * xmlXPathSubstringAfterFunction:
9176: * @ctxt: the XPath Parser context
9177: * @nargs: the number of arguments
9178: *
9179: * Implement the substring-after() XPath function
9180: * string substring-after(string, string)
9181: * The substring-after function returns the substring of the first
9182: * argument string that follows the first occurrence of the second
9183: * argument string in the first argument string, or the empty stringi
9184: * if the first argument string does not contain the second argument
9185: * string. For example, substring-after("1999/04/01","/") returns 04/01,
9186: * and substring-after("1999/04/01","19") returns 99/04/01.
9187: */
9188: void
9189: xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9190: xmlXPathObjectPtr str;
9191: xmlXPathObjectPtr find;
9192: xmlBufferPtr target;
9193: const xmlChar *point;
9194: int offset;
9195:
9196: CHECK_ARITY(2);
9197: CAST_TO_STRING;
9198: find = valuePop(ctxt);
9199: CAST_TO_STRING;
9200: str = valuePop(ctxt);
9201:
9202: target = xmlBufferCreate();
9203: if (target) {
9204: point = xmlStrstr(str->stringval, find->stringval);
9205: if (point) {
9206: offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9207: xmlBufferAdd(target, &str->stringval[offset],
9208: xmlStrlen(str->stringval) - offset);
9209: }
9210: valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9211: xmlBufferContent(target)));
9212: xmlBufferFree(target);
9213: }
9214: xmlXPathReleaseObject(ctxt->context, str);
9215: xmlXPathReleaseObject(ctxt->context, find);
9216: }
9217:
9218: /**
9219: * xmlXPathNormalizeFunction:
9220: * @ctxt: the XPath Parser context
9221: * @nargs: the number of arguments
9222: *
9223: * Implement the normalize-space() XPath function
9224: * string normalize-space(string?)
9225: * The normalize-space function returns the argument string with white
9226: * space normalized by stripping leading and trailing whitespace
9227: * and replacing sequences of whitespace characters by a single
9228: * space. Whitespace characters are the same allowed by the S production
9229: * in XML. If the argument is omitted, it defaults to the context
9230: * node converted to a string, in other words the value of the context node.
9231: */
9232: void
9233: xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9234: xmlXPathObjectPtr obj = NULL;
9235: xmlChar *source = NULL;
9236: xmlBufferPtr target;
9237: xmlChar blank;
9238:
9239: if (ctxt == NULL) return;
9240: if (nargs == 0) {
9241: /* Use current context node */
9242: valuePush(ctxt,
9243: xmlXPathCacheWrapString(ctxt->context,
9244: xmlXPathCastNodeToString(ctxt->context->node)));
9245: nargs = 1;
9246: }
9247:
9248: CHECK_ARITY(1);
9249: CAST_TO_STRING;
9250: CHECK_TYPE(XPATH_STRING);
9251: obj = valuePop(ctxt);
9252: source = obj->stringval;
9253:
9254: target = xmlBufferCreate();
9255: if (target && source) {
9256:
9257: /* Skip leading whitespaces */
9258: while (IS_BLANK_CH(*source))
9259: source++;
9260:
9261: /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9262: blank = 0;
9263: while (*source) {
9264: if (IS_BLANK_CH(*source)) {
9265: blank = 0x20;
9266: } else {
9267: if (blank) {
9268: xmlBufferAdd(target, &blank, 1);
9269: blank = 0;
9270: }
9271: xmlBufferAdd(target, source, 1);
9272: }
9273: source++;
9274: }
9275: valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9276: xmlBufferContent(target)));
9277: xmlBufferFree(target);
9278: }
9279: xmlXPathReleaseObject(ctxt->context, obj);
9280: }
9281:
9282: /**
9283: * xmlXPathTranslateFunction:
9284: * @ctxt: the XPath Parser context
9285: * @nargs: the number of arguments
9286: *
9287: * Implement the translate() XPath function
9288: * string translate(string, string, string)
9289: * The translate function returns the first argument string with
9290: * occurrences of characters in the second argument string replaced
9291: * by the character at the corresponding position in the third argument
9292: * string. For example, translate("bar","abc","ABC") returns the string
9293: * BAr. If there is a character in the second argument string with no
9294: * character at a corresponding position in the third argument string
9295: * (because the second argument string is longer than the third argument
9296: * string), then occurrences of that character in the first argument
9297: * string are removed. For example, translate("--aaa--","abc-","ABC")
9298: * returns "AAA". If a character occurs more than once in second
9299: * argument string, then the first occurrence determines the replacement
9300: * character. If the third argument string is longer than the second
9301: * argument string, then excess characters are ignored.
9302: */
9303: void
9304: xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9305: xmlXPathObjectPtr str;
9306: xmlXPathObjectPtr from;
9307: xmlXPathObjectPtr to;
9308: xmlBufferPtr target;
9309: int offset, max;
9310: xmlChar ch;
9311: const xmlChar *point;
9312: xmlChar *cptr;
9313:
9314: CHECK_ARITY(3);
9315:
9316: CAST_TO_STRING;
9317: to = valuePop(ctxt);
9318: CAST_TO_STRING;
9319: from = valuePop(ctxt);
9320: CAST_TO_STRING;
9321: str = valuePop(ctxt);
9322:
9323: target = xmlBufferCreate();
9324: if (target) {
9325: max = xmlUTF8Strlen(to->stringval);
9326: for (cptr = str->stringval; (ch=*cptr); ) {
9327: offset = xmlUTF8Strloc(from->stringval, cptr);
9328: if (offset >= 0) {
9329: if (offset < max) {
9330: point = xmlUTF8Strpos(to->stringval, offset);
9331: if (point)
9332: xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
9333: }
9334: } else
9335: xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9336:
9337: /* Step to next character in input */
9338: cptr++;
9339: if ( ch & 0x80 ) {
9340: /* if not simple ascii, verify proper format */
9341: if ( (ch & 0xc0) != 0xc0 ) {
9342: xmlGenericError(xmlGenericErrorContext,
9343: "xmlXPathTranslateFunction: Invalid UTF8 string\n");
1.1.1.2 ! misho 9344: /* not asserting an XPath error is probably better */
1.1 misho 9345: break;
9346: }
9347: /* then skip over remaining bytes for this char */
9348: while ( (ch <<= 1) & 0x80 )
9349: if ( (*cptr++ & 0xc0) != 0x80 ) {
9350: xmlGenericError(xmlGenericErrorContext,
9351: "xmlXPathTranslateFunction: Invalid UTF8 string\n");
1.1.1.2 ! misho 9352: /* not asserting an XPath error is probably better */
1.1 misho 9353: break;
9354: }
9355: if (ch & 0x80) /* must have had error encountered */
9356: break;
9357: }
9358: }
9359: }
9360: valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9361: xmlBufferContent(target)));
9362: xmlBufferFree(target);
9363: xmlXPathReleaseObject(ctxt->context, str);
9364: xmlXPathReleaseObject(ctxt->context, from);
9365: xmlXPathReleaseObject(ctxt->context, to);
9366: }
9367:
9368: /**
9369: * xmlXPathBooleanFunction:
9370: * @ctxt: the XPath Parser context
9371: * @nargs: the number of arguments
9372: *
9373: * Implement the boolean() XPath function
9374: * boolean boolean(object)
9375: * The boolean function converts its argument to a boolean as follows:
9376: * - a number is true if and only if it is neither positive or
9377: * negative zero nor NaN
9378: * - a node-set is true if and only if it is non-empty
9379: * - a string is true if and only if its length is non-zero
9380: */
9381: void
9382: xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9383: xmlXPathObjectPtr cur;
9384:
9385: CHECK_ARITY(1);
9386: cur = valuePop(ctxt);
9387: if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9388: cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9389: valuePush(ctxt, cur);
9390: }
9391:
9392: /**
9393: * xmlXPathNotFunction:
9394: * @ctxt: the XPath Parser context
9395: * @nargs: the number of arguments
9396: *
9397: * Implement the not() XPath function
9398: * boolean not(boolean)
9399: * The not function returns true if its argument is false,
9400: * and false otherwise.
9401: */
9402: void
9403: xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9404: CHECK_ARITY(1);
9405: CAST_TO_BOOLEAN;
9406: CHECK_TYPE(XPATH_BOOLEAN);
9407: ctxt->value->boolval = ! ctxt->value->boolval;
9408: }
9409:
9410: /**
9411: * xmlXPathTrueFunction:
9412: * @ctxt: the XPath Parser context
9413: * @nargs: the number of arguments
9414: *
9415: * Implement the true() XPath function
9416: * boolean true()
9417: */
9418: void
9419: xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9420: CHECK_ARITY(0);
9421: valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9422: }
9423:
9424: /**
9425: * xmlXPathFalseFunction:
9426: * @ctxt: the XPath Parser context
9427: * @nargs: the number of arguments
9428: *
9429: * Implement the false() XPath function
9430: * boolean false()
9431: */
9432: void
9433: xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9434: CHECK_ARITY(0);
9435: valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9436: }
9437:
9438: /**
9439: * xmlXPathLangFunction:
9440: * @ctxt: the XPath Parser context
9441: * @nargs: the number of arguments
9442: *
9443: * Implement the lang() XPath function
9444: * boolean lang(string)
9445: * The lang function returns true or false depending on whether the
9446: * language of the context node as specified by xml:lang attributes
9447: * is the same as or is a sublanguage of the language specified by
9448: * the argument string. The language of the context node is determined
9449: * by the value of the xml:lang attribute on the context node, or, if
9450: * the context node has no xml:lang attribute, by the value of the
9451: * xml:lang attribute on the nearest ancestor of the context node that
9452: * has an xml:lang attribute. If there is no such attribute, then lang
9453: * returns false. If there is such an attribute, then lang returns
9454: * true if the attribute value is equal to the argument ignoring case,
9455: * or if there is some suffix starting with - such that the attribute
9456: * value is equal to the argument ignoring that suffix of the attribute
9457: * value and ignoring case.
9458: */
9459: void
9460: xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9461: xmlXPathObjectPtr val = NULL;
9462: const xmlChar *theLang = NULL;
9463: const xmlChar *lang;
9464: int ret = 0;
9465: int i;
9466:
9467: CHECK_ARITY(1);
9468: CAST_TO_STRING;
9469: CHECK_TYPE(XPATH_STRING);
9470: val = valuePop(ctxt);
9471: lang = val->stringval;
9472: theLang = xmlNodeGetLang(ctxt->context->node);
9473: if ((theLang != NULL) && (lang != NULL)) {
9474: for (i = 0;lang[i] != 0;i++)
9475: if (toupper(lang[i]) != toupper(theLang[i]))
9476: goto not_equal;
9477: if ((theLang[i] == 0) || (theLang[i] == '-'))
9478: ret = 1;
9479: }
9480: not_equal:
9481: if (theLang != NULL)
9482: xmlFree((void *)theLang);
9483:
9484: xmlXPathReleaseObject(ctxt->context, val);
9485: valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9486: }
9487:
9488: /**
9489: * xmlXPathNumberFunction:
9490: * @ctxt: the XPath Parser context
9491: * @nargs: the number of arguments
9492: *
9493: * Implement the number() XPath function
9494: * number number(object?)
9495: */
9496: void
9497: xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9498: xmlXPathObjectPtr cur;
9499: double res;
9500:
9501: if (ctxt == NULL) return;
9502: if (nargs == 0) {
9503: if (ctxt->context->node == NULL) {
9504: valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9505: } else {
9506: xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9507:
9508: res = xmlXPathStringEvalNumber(content);
9509: valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9510: xmlFree(content);
9511: }
9512: return;
9513: }
9514:
9515: CHECK_ARITY(1);
9516: cur = valuePop(ctxt);
9517: valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9518: }
9519:
9520: /**
9521: * xmlXPathSumFunction:
9522: * @ctxt: the XPath Parser context
9523: * @nargs: the number of arguments
9524: *
9525: * Implement the sum() XPath function
9526: * number sum(node-set)
9527: * The sum function returns the sum of the values of the nodes in
9528: * the argument node-set.
9529: */
9530: void
9531: xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9532: xmlXPathObjectPtr cur;
9533: int i;
9534: double res = 0.0;
9535:
9536: CHECK_ARITY(1);
9537: if ((ctxt->value == NULL) ||
9538: ((ctxt->value->type != XPATH_NODESET) &&
9539: (ctxt->value->type != XPATH_XSLT_TREE)))
9540: XP_ERROR(XPATH_INVALID_TYPE);
9541: cur = valuePop(ctxt);
9542:
9543: if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9544: for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9545: res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9546: }
9547: }
9548: valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9549: xmlXPathReleaseObject(ctxt->context, cur);
9550: }
9551:
9552: /*
9553: * To assure working code on multiple platforms, we want to only depend
9554: * upon the characteristic truncation of converting a floating point value
9555: * to an integer. Unfortunately, because of the different storage sizes
9556: * of our internal floating point value (double) and integer (int), we
9557: * can't directly convert (see bug 301162). This macro is a messy
9558: * 'workaround'
9559: */
9560: #define XTRUNC(f, v) \
9561: f = fmod((v), INT_MAX); \
9562: f = (v) - (f) + (double)((int)(f));
9563:
9564: /**
9565: * xmlXPathFloorFunction:
9566: * @ctxt: the XPath Parser context
9567: * @nargs: the number of arguments
9568: *
9569: * Implement the floor() XPath function
9570: * number floor(number)
9571: * The floor function returns the largest (closest to positive infinity)
9572: * number that is not greater than the argument and that is an integer.
9573: */
9574: void
9575: xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9576: double f;
9577:
9578: CHECK_ARITY(1);
9579: CAST_TO_NUMBER;
9580: CHECK_TYPE(XPATH_NUMBER);
9581:
9582: XTRUNC(f, ctxt->value->floatval);
9583: if (f != ctxt->value->floatval) {
9584: if (ctxt->value->floatval > 0)
9585: ctxt->value->floatval = f;
9586: else
9587: ctxt->value->floatval = f - 1;
9588: }
9589: }
9590:
9591: /**
9592: * xmlXPathCeilingFunction:
9593: * @ctxt: the XPath Parser context
9594: * @nargs: the number of arguments
9595: *
9596: * Implement the ceiling() XPath function
9597: * number ceiling(number)
9598: * The ceiling function returns the smallest (closest to negative infinity)
9599: * number that is not less than the argument and that is an integer.
9600: */
9601: void
9602: xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9603: double f;
9604:
9605: CHECK_ARITY(1);
9606: CAST_TO_NUMBER;
9607: CHECK_TYPE(XPATH_NUMBER);
9608:
9609: #if 0
9610: ctxt->value->floatval = ceil(ctxt->value->floatval);
9611: #else
9612: XTRUNC(f, ctxt->value->floatval);
9613: if (f != ctxt->value->floatval) {
9614: if (ctxt->value->floatval > 0)
9615: ctxt->value->floatval = f + 1;
9616: else {
9617: if (ctxt->value->floatval < 0 && f == 0)
9618: ctxt->value->floatval = xmlXPathNZERO;
9619: else
9620: ctxt->value->floatval = f;
9621: }
9622:
9623: }
9624: #endif
9625: }
9626:
9627: /**
9628: * xmlXPathRoundFunction:
9629: * @ctxt: the XPath Parser context
9630: * @nargs: the number of arguments
9631: *
9632: * Implement the round() XPath function
9633: * number round(number)
9634: * The round function returns the number that is closest to the
9635: * argument and that is an integer. If there are two such numbers,
9636: * then the one that is even is returned.
9637: */
9638: void
9639: xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9640: double f;
9641:
9642: CHECK_ARITY(1);
9643: CAST_TO_NUMBER;
9644: CHECK_TYPE(XPATH_NUMBER);
9645:
9646: if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9647: (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9648: (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
9649: (ctxt->value->floatval == 0.0))
9650: return;
9651:
9652: XTRUNC(f, ctxt->value->floatval);
9653: if (ctxt->value->floatval < 0) {
9654: if (ctxt->value->floatval < f - 0.5)
9655: ctxt->value->floatval = f - 1;
9656: else
9657: ctxt->value->floatval = f;
9658: if (ctxt->value->floatval == 0)
9659: ctxt->value->floatval = xmlXPathNZERO;
9660: } else {
9661: if (ctxt->value->floatval < f + 0.5)
9662: ctxt->value->floatval = f;
9663: else
9664: ctxt->value->floatval = f + 1;
9665: }
9666: }
9667:
9668: /************************************************************************
9669: * *
9670: * The Parser *
9671: * *
9672: ************************************************************************/
9673:
9674: /*
9675: * a few forward declarations since we use a recursive call based
9676: * implementation.
9677: */
9678: static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9679: static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9680: static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9681: static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9682: static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9683: int qualified);
9684:
9685: /**
9686: * xmlXPathCurrentChar:
9687: * @ctxt: the XPath parser context
9688: * @cur: pointer to the beginning of the char
9689: * @len: pointer to the length of the char read
9690: *
9691: * The current char value, if using UTF-8 this may actually span multiple
9692: * bytes in the input buffer.
9693: *
9694: * Returns the current char value and its length
9695: */
9696:
9697: static int
9698: xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9699: unsigned char c;
9700: unsigned int val;
9701: const xmlChar *cur;
9702:
9703: if (ctxt == NULL)
9704: return(0);
9705: cur = ctxt->cur;
9706:
9707: /*
9708: * We are supposed to handle UTF8, check it's valid
9709: * From rfc2044: encoding of the Unicode values on UTF-8:
9710: *
9711: * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9712: * 0000 0000-0000 007F 0xxxxxxx
9713: * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
9714: * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
9715: *
9716: * Check for the 0x110000 limit too
9717: */
9718: c = *cur;
9719: if (c & 0x80) {
9720: if ((cur[1] & 0xc0) != 0x80)
9721: goto encoding_error;
9722: if ((c & 0xe0) == 0xe0) {
9723:
9724: if ((cur[2] & 0xc0) != 0x80)
9725: goto encoding_error;
9726: if ((c & 0xf0) == 0xf0) {
9727: if (((c & 0xf8) != 0xf0) ||
9728: ((cur[3] & 0xc0) != 0x80))
9729: goto encoding_error;
9730: /* 4-byte code */
9731: *len = 4;
9732: val = (cur[0] & 0x7) << 18;
9733: val |= (cur[1] & 0x3f) << 12;
9734: val |= (cur[2] & 0x3f) << 6;
9735: val |= cur[3] & 0x3f;
9736: } else {
9737: /* 3-byte code */
9738: *len = 3;
9739: val = (cur[0] & 0xf) << 12;
9740: val |= (cur[1] & 0x3f) << 6;
9741: val |= cur[2] & 0x3f;
9742: }
9743: } else {
9744: /* 2-byte code */
9745: *len = 2;
9746: val = (cur[0] & 0x1f) << 6;
9747: val |= cur[1] & 0x3f;
9748: }
9749: if (!IS_CHAR(val)) {
9750: XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9751: }
9752: return(val);
9753: } else {
9754: /* 1-byte code */
9755: *len = 1;
9756: return((int) *cur);
9757: }
9758: encoding_error:
9759: /*
9760: * If we detect an UTF8 error that probably means that the
9761: * input encoding didn't get properly advertised in the
9762: * declaration header. Report the error and switch the encoding
9763: * to ISO-Latin-1 (if you don't like this policy, just declare the
9764: * encoding !)
9765: */
9766: *len = 0;
9767: XP_ERROR0(XPATH_ENCODING_ERROR);
9768: }
9769:
9770: /**
9771: * xmlXPathParseNCName:
9772: * @ctxt: the XPath Parser context
9773: *
9774: * parse an XML namespace non qualified name.
9775: *
9776: * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9777: *
9778: * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9779: * CombiningChar | Extender
9780: *
9781: * Returns the namespace name or NULL
9782: */
9783:
9784: xmlChar *
9785: xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9786: const xmlChar *in;
9787: xmlChar *ret;
9788: int count = 0;
9789:
9790: if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9791: /*
9792: * Accelerator for simple ASCII names
9793: */
9794: in = ctxt->cur;
9795: if (((*in >= 0x61) && (*in <= 0x7A)) ||
9796: ((*in >= 0x41) && (*in <= 0x5A)) ||
9797: (*in == '_')) {
9798: in++;
9799: while (((*in >= 0x61) && (*in <= 0x7A)) ||
9800: ((*in >= 0x41) && (*in <= 0x5A)) ||
9801: ((*in >= 0x30) && (*in <= 0x39)) ||
9802: (*in == '_') || (*in == '.') ||
9803: (*in == '-'))
9804: in++;
9805: if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9806: (*in == '[') || (*in == ']') || (*in == ':') ||
9807: (*in == '@') || (*in == '*')) {
9808: count = in - ctxt->cur;
9809: if (count == 0)
9810: return(NULL);
9811: ret = xmlStrndup(ctxt->cur, count);
9812: ctxt->cur = in;
9813: return(ret);
9814: }
9815: }
9816: return(xmlXPathParseNameComplex(ctxt, 0));
9817: }
9818:
9819:
9820: /**
9821: * xmlXPathParseQName:
9822: * @ctxt: the XPath Parser context
9823: * @prefix: a xmlChar **
9824: *
9825: * parse an XML qualified name
9826: *
9827: * [NS 5] QName ::= (Prefix ':')? LocalPart
9828: *
9829: * [NS 6] Prefix ::= NCName
9830: *
9831: * [NS 7] LocalPart ::= NCName
9832: *
9833: * Returns the function returns the local part, and prefix is updated
9834: * to get the Prefix if any.
9835: */
9836:
9837: static xmlChar *
9838: xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9839: xmlChar *ret = NULL;
9840:
9841: *prefix = NULL;
9842: ret = xmlXPathParseNCName(ctxt);
9843: if (ret && CUR == ':') {
9844: *prefix = ret;
9845: NEXT;
9846: ret = xmlXPathParseNCName(ctxt);
9847: }
9848: return(ret);
9849: }
9850:
9851: /**
9852: * xmlXPathParseName:
9853: * @ctxt: the XPath Parser context
9854: *
9855: * parse an XML name
9856: *
9857: * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9858: * CombiningChar | Extender
9859: *
9860: * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9861: *
9862: * Returns the namespace name or NULL
9863: */
9864:
9865: xmlChar *
9866: xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9867: const xmlChar *in;
9868: xmlChar *ret;
9869: int count = 0;
9870:
9871: if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9872: /*
9873: * Accelerator for simple ASCII names
9874: */
9875: in = ctxt->cur;
9876: if (((*in >= 0x61) && (*in <= 0x7A)) ||
9877: ((*in >= 0x41) && (*in <= 0x5A)) ||
9878: (*in == '_') || (*in == ':')) {
9879: in++;
9880: while (((*in >= 0x61) && (*in <= 0x7A)) ||
9881: ((*in >= 0x41) && (*in <= 0x5A)) ||
9882: ((*in >= 0x30) && (*in <= 0x39)) ||
9883: (*in == '_') || (*in == '-') ||
9884: (*in == ':') || (*in == '.'))
9885: in++;
9886: if ((*in > 0) && (*in < 0x80)) {
9887: count = in - ctxt->cur;
9888: ret = xmlStrndup(ctxt->cur, count);
9889: ctxt->cur = in;
9890: return(ret);
9891: }
9892: }
9893: return(xmlXPathParseNameComplex(ctxt, 1));
9894: }
9895:
9896: static xmlChar *
9897: xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9898: xmlChar buf[XML_MAX_NAMELEN + 5];
9899: int len = 0, l;
9900: int c;
9901:
9902: /*
9903: * Handler for more complex cases
9904: */
9905: c = CUR_CHAR(l);
9906: if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9907: (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9908: (c == '*') || /* accelerators */
9909: (!IS_LETTER(c) && (c != '_') &&
9910: ((qualified) && (c != ':')))) {
9911: return(NULL);
9912: }
9913:
9914: while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9915: ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9916: (c == '.') || (c == '-') ||
9917: (c == '_') || ((qualified) && (c == ':')) ||
9918: (IS_COMBINING(c)) ||
9919: (IS_EXTENDER(c)))) {
9920: COPY_BUF(l,buf,len,c);
9921: NEXTL(l);
9922: c = CUR_CHAR(l);
9923: if (len >= XML_MAX_NAMELEN) {
9924: /*
9925: * Okay someone managed to make a huge name, so he's ready to pay
9926: * for the processing speed.
9927: */
9928: xmlChar *buffer;
9929: int max = len * 2;
9930:
9931: buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
9932: if (buffer == NULL) {
9933: XP_ERRORNULL(XPATH_MEMORY_ERROR);
9934: }
9935: memcpy(buffer, buf, len);
9936: while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9937: (c == '.') || (c == '-') ||
9938: (c == '_') || ((qualified) && (c == ':')) ||
9939: (IS_COMBINING(c)) ||
9940: (IS_EXTENDER(c))) {
9941: if (len + 10 > max) {
9942: max *= 2;
9943: buffer = (xmlChar *) xmlRealloc(buffer,
9944: max * sizeof(xmlChar));
9945: if (buffer == NULL) {
9946: XP_ERRORNULL(XPATH_MEMORY_ERROR);
9947: }
9948: }
9949: COPY_BUF(l,buffer,len,c);
9950: NEXTL(l);
9951: c = CUR_CHAR(l);
9952: }
9953: buffer[len] = 0;
9954: return(buffer);
9955: }
9956: }
9957: if (len == 0)
9958: return(NULL);
9959: return(xmlStrndup(buf, len));
9960: }
9961:
9962: #define MAX_FRAC 20
9963:
9964: /*
9965: * These are used as divisors for the fractional part of a number.
9966: * Since the table includes 1.0 (representing '0' fractional digits),
9967: * it must be dimensioned at MAX_FRAC+1 (bug 133921)
9968: */
9969: static double my_pow10[MAX_FRAC+1] = {
9970: 1.0, 10.0, 100.0, 1000.0, 10000.0,
9971: 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
9972: 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
9973: 100000000000000.0,
9974: 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
9975: 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
9976: };
9977:
9978: /**
9979: * xmlXPathStringEvalNumber:
9980: * @str: A string to scan
9981: *
9982: * [30a] Float ::= Number ('e' Digits?)?
9983: *
9984: * [30] Number ::= Digits ('.' Digits?)?
9985: * | '.' Digits
9986: * [31] Digits ::= [0-9]+
9987: *
9988: * Compile a Number in the string
9989: * In complement of the Number expression, this function also handles
9990: * negative values : '-' Number.
9991: *
9992: * Returns the double value.
9993: */
9994: double
9995: xmlXPathStringEvalNumber(const xmlChar *str) {
9996: const xmlChar *cur = str;
9997: double ret;
9998: int ok = 0;
9999: int isneg = 0;
10000: int exponent = 0;
10001: int is_exponent_negative = 0;
10002: #ifdef __GNUC__
10003: unsigned long tmp = 0;
10004: double temp;
10005: #endif
10006: if (cur == NULL) return(0);
10007: while (IS_BLANK_CH(*cur)) cur++;
10008: if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10009: return(xmlXPathNAN);
10010: }
10011: if (*cur == '-') {
10012: isneg = 1;
10013: cur++;
10014: }
10015:
10016: #ifdef __GNUC__
10017: /*
10018: * tmp/temp is a workaround against a gcc compiler bug
10019: * http://veillard.com/gcc.bug
10020: */
10021: ret = 0;
10022: while ((*cur >= '0') && (*cur <= '9')) {
10023: ret = ret * 10;
10024: tmp = (*cur - '0');
10025: ok = 1;
10026: cur++;
10027: temp = (double) tmp;
10028: ret = ret + temp;
10029: }
10030: #else
10031: ret = 0;
10032: while ((*cur >= '0') && (*cur <= '9')) {
10033: ret = ret * 10 + (*cur - '0');
10034: ok = 1;
10035: cur++;
10036: }
10037: #endif
10038:
10039: if (*cur == '.') {
10040: int v, frac = 0;
10041: double fraction = 0;
10042:
10043: cur++;
10044: if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10045: return(xmlXPathNAN);
10046: }
10047: while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
10048: v = (*cur - '0');
10049: fraction = fraction * 10 + v;
10050: frac = frac + 1;
10051: cur++;
10052: }
10053: fraction /= my_pow10[frac];
10054: ret = ret + fraction;
10055: while ((*cur >= '0') && (*cur <= '9'))
10056: cur++;
10057: }
10058: if ((*cur == 'e') || (*cur == 'E')) {
10059: cur++;
10060: if (*cur == '-') {
10061: is_exponent_negative = 1;
10062: cur++;
10063: } else if (*cur == '+') {
10064: cur++;
10065: }
10066: while ((*cur >= '0') && (*cur <= '9')) {
10067: exponent = exponent * 10 + (*cur - '0');
10068: cur++;
10069: }
10070: }
10071: while (IS_BLANK_CH(*cur)) cur++;
10072: if (*cur != 0) return(xmlXPathNAN);
10073: if (isneg) ret = -ret;
10074: if (is_exponent_negative) exponent = -exponent;
10075: ret *= pow(10.0, (double)exponent);
10076: return(ret);
10077: }
10078:
10079: /**
10080: * xmlXPathCompNumber:
10081: * @ctxt: the XPath Parser context
10082: *
10083: * [30] Number ::= Digits ('.' Digits?)?
10084: * | '.' Digits
10085: * [31] Digits ::= [0-9]+
10086: *
10087: * Compile a Number, then push it on the stack
10088: *
10089: */
10090: static void
10091: xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10092: {
10093: double ret = 0.0;
10094: int ok = 0;
10095: int exponent = 0;
10096: int is_exponent_negative = 0;
10097: #ifdef __GNUC__
10098: unsigned long tmp = 0;
10099: double temp;
10100: #endif
10101:
10102: CHECK_ERROR;
10103: if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10104: XP_ERROR(XPATH_NUMBER_ERROR);
10105: }
10106: #ifdef __GNUC__
10107: /*
10108: * tmp/temp is a workaround against a gcc compiler bug
10109: * http://veillard.com/gcc.bug
10110: */
10111: ret = 0;
10112: while ((CUR >= '0') && (CUR <= '9')) {
10113: ret = ret * 10;
10114: tmp = (CUR - '0');
10115: ok = 1;
10116: NEXT;
10117: temp = (double) tmp;
10118: ret = ret + temp;
10119: }
10120: #else
10121: ret = 0;
10122: while ((CUR >= '0') && (CUR <= '9')) {
10123: ret = ret * 10 + (CUR - '0');
10124: ok = 1;
10125: NEXT;
10126: }
10127: #endif
10128: if (CUR == '.') {
10129: int v, frac = 0;
10130: double fraction = 0;
10131:
10132: NEXT;
10133: if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10134: XP_ERROR(XPATH_NUMBER_ERROR);
10135: }
10136: while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) {
10137: v = (CUR - '0');
10138: fraction = fraction * 10 + v;
10139: frac = frac + 1;
10140: NEXT;
10141: }
10142: fraction /= my_pow10[frac];
10143: ret = ret + fraction;
10144: while ((CUR >= '0') && (CUR <= '9'))
10145: NEXT;
10146: }
10147: if ((CUR == 'e') || (CUR == 'E')) {
10148: NEXT;
10149: if (CUR == '-') {
10150: is_exponent_negative = 1;
10151: NEXT;
10152: } else if (CUR == '+') {
10153: NEXT;
10154: }
10155: while ((CUR >= '0') && (CUR <= '9')) {
10156: exponent = exponent * 10 + (CUR - '0');
10157: NEXT;
10158: }
10159: if (is_exponent_negative)
10160: exponent = -exponent;
10161: ret *= pow(10.0, (double) exponent);
10162: }
10163: PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10164: xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10165: }
10166:
10167: /**
10168: * xmlXPathParseLiteral:
10169: * @ctxt: the XPath Parser context
10170: *
10171: * Parse a Literal
10172: *
10173: * [29] Literal ::= '"' [^"]* '"'
10174: * | "'" [^']* "'"
10175: *
10176: * Returns the value found or NULL in case of error
10177: */
10178: static xmlChar *
10179: xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10180: const xmlChar *q;
10181: xmlChar *ret = NULL;
10182:
10183: if (CUR == '"') {
10184: NEXT;
10185: q = CUR_PTR;
10186: while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10187: NEXT;
10188: if (!IS_CHAR_CH(CUR)) {
10189: XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10190: } else {
10191: ret = xmlStrndup(q, CUR_PTR - q);
10192: NEXT;
10193: }
10194: } else 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_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10201: } else {
10202: ret = xmlStrndup(q, CUR_PTR - q);
10203: NEXT;
10204: }
10205: } else {
10206: XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10207: }
10208: return(ret);
10209: }
10210:
10211: /**
10212: * xmlXPathCompLiteral:
10213: * @ctxt: the XPath Parser context
10214: *
10215: * Parse a Literal and push it on the stack.
10216: *
10217: * [29] Literal ::= '"' [^"]* '"'
10218: * | "'" [^']* "'"
10219: *
10220: * TODO: xmlXPathCompLiteral memory allocation could be improved.
10221: */
10222: static void
10223: xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10224: const xmlChar *q;
10225: xmlChar *ret = NULL;
10226:
10227: if (CUR == '"') {
10228: NEXT;
10229: q = CUR_PTR;
10230: while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10231: NEXT;
10232: if (!IS_CHAR_CH(CUR)) {
10233: XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10234: } else {
10235: ret = xmlStrndup(q, CUR_PTR - q);
10236: NEXT;
10237: }
10238: } else if (CUR == '\'') {
10239: NEXT;
10240: q = CUR_PTR;
10241: while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10242: NEXT;
10243: if (!IS_CHAR_CH(CUR)) {
10244: XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10245: } else {
10246: ret = xmlStrndup(q, CUR_PTR - q);
10247: NEXT;
10248: }
10249: } else {
10250: XP_ERROR(XPATH_START_LITERAL_ERROR);
10251: }
10252: if (ret == NULL) return;
10253: PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10254: xmlXPathCacheNewString(ctxt->context, ret), NULL);
10255: xmlFree(ret);
10256: }
10257:
10258: /**
10259: * xmlXPathCompVariableReference:
10260: * @ctxt: the XPath Parser context
10261: *
10262: * Parse a VariableReference, evaluate it and push it on the stack.
10263: *
10264: * The variable bindings consist of a mapping from variable names
10265: * to variable values. The value of a variable is an object, which can be
10266: * of any of the types that are possible for the value of an expression,
10267: * and may also be of additional types not specified here.
10268: *
10269: * Early evaluation is possible since:
10270: * The variable bindings [...] used to evaluate a subexpression are
10271: * always the same as those used to evaluate the containing expression.
10272: *
10273: * [36] VariableReference ::= '$' QName
10274: */
10275: static void
10276: xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10277: xmlChar *name;
10278: xmlChar *prefix;
10279:
10280: SKIP_BLANKS;
10281: if (CUR != '$') {
10282: XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10283: }
10284: NEXT;
10285: name = xmlXPathParseQName(ctxt, &prefix);
10286: if (name == NULL) {
10287: XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10288: }
10289: ctxt->comp->last = -1;
10290: PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10291: name, prefix);
10292: SKIP_BLANKS;
10293: if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10294: XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
10295: }
10296: }
10297:
10298: /**
10299: * xmlXPathIsNodeType:
10300: * @name: a name string
10301: *
10302: * Is the name given a NodeType one.
10303: *
10304: * [38] NodeType ::= 'comment'
10305: * | 'text'
10306: * | 'processing-instruction'
10307: * | 'node'
10308: *
10309: * Returns 1 if true 0 otherwise
10310: */
10311: int
10312: xmlXPathIsNodeType(const xmlChar *name) {
10313: if (name == NULL)
10314: return(0);
10315:
10316: if (xmlStrEqual(name, BAD_CAST "node"))
10317: return(1);
10318: if (xmlStrEqual(name, BAD_CAST "text"))
10319: return(1);
10320: if (xmlStrEqual(name, BAD_CAST "comment"))
10321: return(1);
10322: if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10323: return(1);
10324: return(0);
10325: }
10326:
10327: /**
10328: * xmlXPathCompFunctionCall:
10329: * @ctxt: the XPath Parser context
10330: *
10331: * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10332: * [17] Argument ::= Expr
10333: *
10334: * Compile a function call, the evaluation of all arguments are
10335: * pushed on the stack
10336: */
10337: static void
10338: xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10339: xmlChar *name;
10340: xmlChar *prefix;
10341: int nbargs = 0;
10342: int sort = 1;
10343:
10344: name = xmlXPathParseQName(ctxt, &prefix);
10345: if (name == NULL) {
10346: xmlFree(prefix);
10347: XP_ERROR(XPATH_EXPR_ERROR);
10348: }
10349: SKIP_BLANKS;
10350: #ifdef DEBUG_EXPR
10351: if (prefix == NULL)
10352: xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10353: name);
10354: else
10355: xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10356: prefix, name);
10357: #endif
10358:
10359: if (CUR != '(') {
10360: XP_ERROR(XPATH_EXPR_ERROR);
10361: }
10362: NEXT;
10363: SKIP_BLANKS;
10364:
10365: /*
10366: * Optimization for count(): we don't need the node-set to be sorted.
10367: */
10368: if ((prefix == NULL) && (name[0] == 'c') &&
10369: xmlStrEqual(name, BAD_CAST "count"))
10370: {
10371: sort = 0;
10372: }
10373: ctxt->comp->last = -1;
10374: if (CUR != ')') {
10375: while (CUR != 0) {
10376: int op1 = ctxt->comp->last;
10377: ctxt->comp->last = -1;
10378: xmlXPathCompileExpr(ctxt, sort);
10379: if (ctxt->error != XPATH_EXPRESSION_OK) {
10380: xmlFree(name);
10381: xmlFree(prefix);
10382: return;
10383: }
10384: PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10385: nbargs++;
10386: if (CUR == ')') break;
10387: if (CUR != ',') {
10388: XP_ERROR(XPATH_EXPR_ERROR);
10389: }
10390: NEXT;
10391: SKIP_BLANKS;
10392: }
10393: }
10394: PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10395: name, prefix);
10396: NEXT;
10397: SKIP_BLANKS;
10398: }
10399:
10400: /**
10401: * xmlXPathCompPrimaryExpr:
10402: * @ctxt: the XPath Parser context
10403: *
10404: * [15] PrimaryExpr ::= VariableReference
10405: * | '(' Expr ')'
10406: * | Literal
10407: * | Number
10408: * | FunctionCall
10409: *
10410: * Compile a primary expression.
10411: */
10412: static void
10413: xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10414: SKIP_BLANKS;
10415: if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10416: else if (CUR == '(') {
10417: NEXT;
10418: SKIP_BLANKS;
10419: xmlXPathCompileExpr(ctxt, 1);
10420: CHECK_ERROR;
10421: if (CUR != ')') {
10422: XP_ERROR(XPATH_EXPR_ERROR);
10423: }
10424: NEXT;
10425: SKIP_BLANKS;
10426: } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10427: xmlXPathCompNumber(ctxt);
10428: } else if ((CUR == '\'') || (CUR == '"')) {
10429: xmlXPathCompLiteral(ctxt);
10430: } else {
10431: xmlXPathCompFunctionCall(ctxt);
10432: }
10433: SKIP_BLANKS;
10434: }
10435:
10436: /**
10437: * xmlXPathCompFilterExpr:
10438: * @ctxt: the XPath Parser context
10439: *
10440: * [20] FilterExpr ::= PrimaryExpr
10441: * | FilterExpr Predicate
10442: *
10443: * Compile a filter expression.
10444: * Square brackets are used to filter expressions in the same way that
10445: * they are used in location paths. It is an error if the expression to
10446: * be filtered does not evaluate to a node-set. The context node list
10447: * used for evaluating the expression in square brackets is the node-set
10448: * to be filtered listed in document order.
10449: */
10450:
10451: static void
10452: xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10453: xmlXPathCompPrimaryExpr(ctxt);
10454: CHECK_ERROR;
10455: SKIP_BLANKS;
10456:
10457: while (CUR == '[') {
10458: xmlXPathCompPredicate(ctxt, 1);
10459: SKIP_BLANKS;
10460: }
10461:
10462:
10463: }
10464:
10465: /**
10466: * xmlXPathScanName:
10467: * @ctxt: the XPath Parser context
10468: *
10469: * Trickery: parse an XML name but without consuming the input flow
10470: * Needed to avoid insanity in the parser state.
10471: *
10472: * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10473: * CombiningChar | Extender
10474: *
10475: * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10476: *
10477: * [6] Names ::= Name (S Name)*
10478: *
10479: * Returns the Name parsed or NULL
10480: */
10481:
10482: static xmlChar *
10483: xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10484: int len = 0, l;
10485: int c;
10486: const xmlChar *cur;
10487: xmlChar *ret;
10488:
10489: cur = ctxt->cur;
10490:
10491: c = CUR_CHAR(l);
10492: if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10493: (!IS_LETTER(c) && (c != '_') &&
10494: (c != ':'))) {
10495: return(NULL);
10496: }
10497:
10498: while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10499: ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10500: (c == '.') || (c == '-') ||
10501: (c == '_') || (c == ':') ||
10502: (IS_COMBINING(c)) ||
10503: (IS_EXTENDER(c)))) {
10504: len += l;
10505: NEXTL(l);
10506: c = CUR_CHAR(l);
10507: }
10508: ret = xmlStrndup(cur, ctxt->cur - cur);
10509: ctxt->cur = cur;
10510: return(ret);
10511: }
10512:
10513: /**
10514: * xmlXPathCompPathExpr:
10515: * @ctxt: the XPath Parser context
10516: *
10517: * [19] PathExpr ::= LocationPath
10518: * | FilterExpr
10519: * | FilterExpr '/' RelativeLocationPath
10520: * | FilterExpr '//' RelativeLocationPath
10521: *
10522: * Compile a path expression.
10523: * The / operator and // operators combine an arbitrary expression
10524: * and a relative location path. It is an error if the expression
10525: * does not evaluate to a node-set.
10526: * The / operator does composition in the same way as when / is
10527: * used in a location path. As in location paths, // is short for
10528: * /descendant-or-self::node()/.
10529: */
10530:
10531: static void
10532: xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10533: int lc = 1; /* Should we branch to LocationPath ? */
10534: xmlChar *name = NULL; /* we may have to preparse a name to find out */
10535:
10536: SKIP_BLANKS;
10537: if ((CUR == '$') || (CUR == '(') ||
10538: (IS_ASCII_DIGIT(CUR)) ||
10539: (CUR == '\'') || (CUR == '"') ||
10540: (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10541: lc = 0;
10542: } else if (CUR == '*') {
10543: /* relative or absolute location path */
10544: lc = 1;
10545: } else if (CUR == '/') {
10546: /* relative or absolute location path */
10547: lc = 1;
10548: } else if (CUR == '@') {
10549: /* relative abbreviated attribute location path */
10550: lc = 1;
10551: } else if (CUR == '.') {
10552: /* relative abbreviated attribute location path */
10553: lc = 1;
10554: } else {
10555: /*
10556: * Problem is finding if we have a name here whether it's:
10557: * - a nodetype
10558: * - a function call in which case it's followed by '('
10559: * - an axis in which case it's followed by ':'
10560: * - a element name
10561: * We do an a priori analysis here rather than having to
10562: * maintain parsed token content through the recursive function
10563: * calls. This looks uglier but makes the code easier to
10564: * read/write/debug.
10565: */
10566: SKIP_BLANKS;
10567: name = xmlXPathScanName(ctxt);
10568: if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10569: #ifdef DEBUG_STEP
10570: xmlGenericError(xmlGenericErrorContext,
10571: "PathExpr: Axis\n");
10572: #endif
10573: lc = 1;
10574: xmlFree(name);
10575: } else if (name != NULL) {
10576: int len =xmlStrlen(name);
10577:
10578:
10579: while (NXT(len) != 0) {
10580: if (NXT(len) == '/') {
10581: /* element name */
10582: #ifdef DEBUG_STEP
10583: xmlGenericError(xmlGenericErrorContext,
10584: "PathExpr: AbbrRelLocation\n");
10585: #endif
10586: lc = 1;
10587: break;
10588: } else if (IS_BLANK_CH(NXT(len))) {
10589: /* ignore blanks */
10590: ;
10591: } else if (NXT(len) == ':') {
10592: #ifdef DEBUG_STEP
10593: xmlGenericError(xmlGenericErrorContext,
10594: "PathExpr: AbbrRelLocation\n");
10595: #endif
10596: lc = 1;
10597: break;
10598: } else if ((NXT(len) == '(')) {
10599: /* Note Type or Function */
10600: if (xmlXPathIsNodeType(name)) {
10601: #ifdef DEBUG_STEP
10602: xmlGenericError(xmlGenericErrorContext,
10603: "PathExpr: Type search\n");
10604: #endif
10605: lc = 1;
10606: } else {
10607: #ifdef DEBUG_STEP
10608: xmlGenericError(xmlGenericErrorContext,
10609: "PathExpr: function call\n");
10610: #endif
10611: lc = 0;
10612: }
10613: break;
10614: } else if ((NXT(len) == '[')) {
10615: /* element name */
10616: #ifdef DEBUG_STEP
10617: xmlGenericError(xmlGenericErrorContext,
10618: "PathExpr: AbbrRelLocation\n");
10619: #endif
10620: lc = 1;
10621: break;
10622: } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10623: (NXT(len) == '=')) {
10624: lc = 1;
10625: break;
10626: } else {
10627: lc = 1;
10628: break;
10629: }
10630: len++;
10631: }
10632: if (NXT(len) == 0) {
10633: #ifdef DEBUG_STEP
10634: xmlGenericError(xmlGenericErrorContext,
10635: "PathExpr: AbbrRelLocation\n");
10636: #endif
10637: /* element name */
10638: lc = 1;
10639: }
10640: xmlFree(name);
10641: } else {
10642: /* make sure all cases are covered explicitly */
10643: XP_ERROR(XPATH_EXPR_ERROR);
10644: }
10645: }
10646:
10647: if (lc) {
10648: if (CUR == '/') {
10649: PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10650: } else {
10651: PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10652: }
10653: xmlXPathCompLocationPath(ctxt);
10654: } else {
10655: xmlXPathCompFilterExpr(ctxt);
10656: CHECK_ERROR;
10657: if ((CUR == '/') && (NXT(1) == '/')) {
10658: SKIP(2);
10659: SKIP_BLANKS;
10660:
10661: PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10662: NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10663: PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10664:
10665: xmlXPathCompRelativeLocationPath(ctxt);
10666: } else if (CUR == '/') {
10667: xmlXPathCompRelativeLocationPath(ctxt);
10668: }
10669: }
10670: SKIP_BLANKS;
10671: }
10672:
10673: /**
10674: * xmlXPathCompUnionExpr:
10675: * @ctxt: the XPath Parser context
10676: *
10677: * [18] UnionExpr ::= PathExpr
10678: * | UnionExpr '|' PathExpr
10679: *
10680: * Compile an union expression.
10681: */
10682:
10683: static void
10684: xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10685: xmlXPathCompPathExpr(ctxt);
10686: CHECK_ERROR;
10687: SKIP_BLANKS;
10688: while (CUR == '|') {
10689: int op1 = ctxt->comp->last;
10690: PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10691:
10692: NEXT;
10693: SKIP_BLANKS;
10694: xmlXPathCompPathExpr(ctxt);
10695:
10696: PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10697:
10698: SKIP_BLANKS;
10699: }
10700: }
10701:
10702: /**
10703: * xmlXPathCompUnaryExpr:
10704: * @ctxt: the XPath Parser context
10705: *
10706: * [27] UnaryExpr ::= UnionExpr
10707: * | '-' UnaryExpr
10708: *
10709: * Compile an unary expression.
10710: */
10711:
10712: static void
10713: xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10714: int minus = 0;
10715: int found = 0;
10716:
10717: SKIP_BLANKS;
10718: while (CUR == '-') {
10719: minus = 1 - minus;
10720: found = 1;
10721: NEXT;
10722: SKIP_BLANKS;
10723: }
10724:
10725: xmlXPathCompUnionExpr(ctxt);
10726: CHECK_ERROR;
10727: if (found) {
10728: if (minus)
10729: PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10730: else
10731: PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10732: }
10733: }
10734:
10735: /**
10736: * xmlXPathCompMultiplicativeExpr:
10737: * @ctxt: the XPath Parser context
10738: *
10739: * [26] MultiplicativeExpr ::= UnaryExpr
10740: * | MultiplicativeExpr MultiplyOperator UnaryExpr
10741: * | MultiplicativeExpr 'div' UnaryExpr
10742: * | MultiplicativeExpr 'mod' UnaryExpr
10743: * [34] MultiplyOperator ::= '*'
10744: *
10745: * Compile an Additive expression.
10746: */
10747:
10748: static void
10749: xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10750: xmlXPathCompUnaryExpr(ctxt);
10751: CHECK_ERROR;
10752: SKIP_BLANKS;
10753: while ((CUR == '*') ||
10754: ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10755: ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10756: int op = -1;
10757: int op1 = ctxt->comp->last;
10758:
10759: if (CUR == '*') {
10760: op = 0;
10761: NEXT;
10762: } else if (CUR == 'd') {
10763: op = 1;
10764: SKIP(3);
10765: } else if (CUR == 'm') {
10766: op = 2;
10767: SKIP(3);
10768: }
10769: SKIP_BLANKS;
10770: xmlXPathCompUnaryExpr(ctxt);
10771: CHECK_ERROR;
10772: PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10773: SKIP_BLANKS;
10774: }
10775: }
10776:
10777: /**
10778: * xmlXPathCompAdditiveExpr:
10779: * @ctxt: the XPath Parser context
10780: *
10781: * [25] AdditiveExpr ::= MultiplicativeExpr
10782: * | AdditiveExpr '+' MultiplicativeExpr
10783: * | AdditiveExpr '-' MultiplicativeExpr
10784: *
10785: * Compile an Additive expression.
10786: */
10787:
10788: static void
10789: xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10790:
10791: xmlXPathCompMultiplicativeExpr(ctxt);
10792: CHECK_ERROR;
10793: SKIP_BLANKS;
10794: while ((CUR == '+') || (CUR == '-')) {
10795: int plus;
10796: int op1 = ctxt->comp->last;
10797:
10798: if (CUR == '+') plus = 1;
10799: else plus = 0;
10800: NEXT;
10801: SKIP_BLANKS;
10802: xmlXPathCompMultiplicativeExpr(ctxt);
10803: CHECK_ERROR;
10804: PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10805: SKIP_BLANKS;
10806: }
10807: }
10808:
10809: /**
10810: * xmlXPathCompRelationalExpr:
10811: * @ctxt: the XPath Parser context
10812: *
10813: * [24] RelationalExpr ::= AdditiveExpr
10814: * | RelationalExpr '<' AdditiveExpr
10815: * | RelationalExpr '>' AdditiveExpr
10816: * | RelationalExpr '<=' AdditiveExpr
10817: * | RelationalExpr '>=' AdditiveExpr
10818: *
10819: * A <= B > C is allowed ? Answer from James, yes with
10820: * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10821: * which is basically what got implemented.
10822: *
10823: * Compile a Relational expression, then push the result
10824: * on the stack
10825: */
10826:
10827: static void
10828: xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10829: xmlXPathCompAdditiveExpr(ctxt);
10830: CHECK_ERROR;
10831: SKIP_BLANKS;
10832: while ((CUR == '<') ||
10833: (CUR == '>') ||
10834: ((CUR == '<') && (NXT(1) == '=')) ||
10835: ((CUR == '>') && (NXT(1) == '='))) {
10836: int inf, strict;
10837: int op1 = ctxt->comp->last;
10838:
10839: if (CUR == '<') inf = 1;
10840: else inf = 0;
10841: if (NXT(1) == '=') strict = 0;
10842: else strict = 1;
10843: NEXT;
10844: if (!strict) NEXT;
10845: SKIP_BLANKS;
10846: xmlXPathCompAdditiveExpr(ctxt);
10847: CHECK_ERROR;
10848: PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10849: SKIP_BLANKS;
10850: }
10851: }
10852:
10853: /**
10854: * xmlXPathCompEqualityExpr:
10855: * @ctxt: the XPath Parser context
10856: *
10857: * [23] EqualityExpr ::= RelationalExpr
10858: * | EqualityExpr '=' RelationalExpr
10859: * | EqualityExpr '!=' RelationalExpr
10860: *
10861: * A != B != C is allowed ? Answer from James, yes with
10862: * (RelationalExpr = RelationalExpr) = RelationalExpr
10863: * (RelationalExpr != RelationalExpr) != RelationalExpr
10864: * which is basically what got implemented.
10865: *
10866: * Compile an Equality expression.
10867: *
10868: */
10869: static void
10870: xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10871: xmlXPathCompRelationalExpr(ctxt);
10872: CHECK_ERROR;
10873: SKIP_BLANKS;
10874: while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10875: int eq;
10876: int op1 = ctxt->comp->last;
10877:
10878: if (CUR == '=') eq = 1;
10879: else eq = 0;
10880: NEXT;
10881: if (!eq) NEXT;
10882: SKIP_BLANKS;
10883: xmlXPathCompRelationalExpr(ctxt);
10884: CHECK_ERROR;
10885: PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10886: SKIP_BLANKS;
10887: }
10888: }
10889:
10890: /**
10891: * xmlXPathCompAndExpr:
10892: * @ctxt: the XPath Parser context
10893: *
10894: * [22] AndExpr ::= EqualityExpr
10895: * | AndExpr 'and' EqualityExpr
10896: *
10897: * Compile an AND expression.
10898: *
10899: */
10900: static void
10901: xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10902: xmlXPathCompEqualityExpr(ctxt);
10903: CHECK_ERROR;
10904: SKIP_BLANKS;
10905: while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10906: int op1 = ctxt->comp->last;
10907: SKIP(3);
10908: SKIP_BLANKS;
10909: xmlXPathCompEqualityExpr(ctxt);
10910: CHECK_ERROR;
10911: PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10912: SKIP_BLANKS;
10913: }
10914: }
10915:
10916: /**
10917: * xmlXPathCompileExpr:
10918: * @ctxt: the XPath Parser context
10919: *
10920: * [14] Expr ::= OrExpr
10921: * [21] OrExpr ::= AndExpr
10922: * | OrExpr 'or' AndExpr
10923: *
10924: * Parse and compile an expression
10925: */
10926: static void
10927: xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10928: xmlXPathCompAndExpr(ctxt);
10929: CHECK_ERROR;
10930: SKIP_BLANKS;
10931: while ((CUR == 'o') && (NXT(1) == 'r')) {
10932: int op1 = ctxt->comp->last;
10933: SKIP(2);
10934: SKIP_BLANKS;
10935: xmlXPathCompAndExpr(ctxt);
10936: CHECK_ERROR;
10937: PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10938: SKIP_BLANKS;
10939: }
10940: if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10941: /* more ops could be optimized too */
10942: /*
10943: * This is the main place to eliminate sorting for
10944: * operations which don't require a sorted node-set.
10945: * E.g. count().
10946: */
10947: PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10948: }
10949: }
10950:
10951: /**
10952: * xmlXPathCompPredicate:
10953: * @ctxt: the XPath Parser context
10954: * @filter: act as a filter
10955: *
10956: * [8] Predicate ::= '[' PredicateExpr ']'
10957: * [9] PredicateExpr ::= Expr
10958: *
10959: * Compile a predicate expression
10960: */
10961: static void
10962: xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10963: int op1 = ctxt->comp->last;
10964:
10965: SKIP_BLANKS;
10966: if (CUR != '[') {
10967: XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10968: }
10969: NEXT;
10970: SKIP_BLANKS;
10971:
10972: ctxt->comp->last = -1;
10973: /*
10974: * This call to xmlXPathCompileExpr() will deactivate sorting
10975: * of the predicate result.
10976: * TODO: Sorting is still activated for filters, since I'm not
10977: * sure if needed. Normally sorting should not be needed, since
10978: * a filter can only diminish the number of items in a sequence,
10979: * but won't change its order; so if the initial sequence is sorted,
10980: * subsequent sorting is not needed.
10981: */
10982: if (! filter)
10983: xmlXPathCompileExpr(ctxt, 0);
10984: else
10985: xmlXPathCompileExpr(ctxt, 1);
10986: CHECK_ERROR;
10987:
10988: if (CUR != ']') {
10989: XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10990: }
10991:
10992: if (filter)
10993: PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10994: else
10995: PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
10996:
10997: NEXT;
10998: SKIP_BLANKS;
10999: }
11000:
11001: /**
11002: * xmlXPathCompNodeTest:
11003: * @ctxt: the XPath Parser context
11004: * @test: pointer to a xmlXPathTestVal
11005: * @type: pointer to a xmlXPathTypeVal
11006: * @prefix: placeholder for a possible name prefix
11007: *
11008: * [7] NodeTest ::= NameTest
11009: * | NodeType '(' ')'
11010: * | 'processing-instruction' '(' Literal ')'
11011: *
11012: * [37] NameTest ::= '*'
11013: * | NCName ':' '*'
11014: * | QName
11015: * [38] NodeType ::= 'comment'
11016: * | 'text'
11017: * | 'processing-instruction'
11018: * | 'node'
11019: *
11020: * Returns the name found and updates @test, @type and @prefix appropriately
11021: */
11022: static xmlChar *
11023: xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11024: xmlXPathTypeVal *type, const xmlChar **prefix,
11025: xmlChar *name) {
11026: int blanks;
11027:
11028: if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11029: STRANGE;
11030: return(NULL);
11031: }
11032: *type = (xmlXPathTypeVal) 0;
11033: *test = (xmlXPathTestVal) 0;
11034: *prefix = NULL;
11035: SKIP_BLANKS;
11036:
11037: if ((name == NULL) && (CUR == '*')) {
11038: /*
11039: * All elements
11040: */
11041: NEXT;
11042: *test = NODE_TEST_ALL;
11043: return(NULL);
11044: }
11045:
11046: if (name == NULL)
11047: name = xmlXPathParseNCName(ctxt);
11048: if (name == NULL) {
11049: XP_ERRORNULL(XPATH_EXPR_ERROR);
11050: }
11051:
11052: blanks = IS_BLANK_CH(CUR);
11053: SKIP_BLANKS;
11054: if (CUR == '(') {
11055: NEXT;
11056: /*
11057: * NodeType or PI search
11058: */
11059: if (xmlStrEqual(name, BAD_CAST "comment"))
11060: *type = NODE_TYPE_COMMENT;
11061: else if (xmlStrEqual(name, BAD_CAST "node"))
11062: *type = NODE_TYPE_NODE;
11063: else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11064: *type = NODE_TYPE_PI;
11065: else if (xmlStrEqual(name, BAD_CAST "text"))
11066: *type = NODE_TYPE_TEXT;
11067: else {
11068: if (name != NULL)
11069: xmlFree(name);
11070: XP_ERRORNULL(XPATH_EXPR_ERROR);
11071: }
11072:
11073: *test = NODE_TEST_TYPE;
11074:
11075: SKIP_BLANKS;
11076: if (*type == NODE_TYPE_PI) {
11077: /*
11078: * Specific case: search a PI by name.
11079: */
11080: if (name != NULL)
11081: xmlFree(name);
11082: name = NULL;
11083: if (CUR != ')') {
11084: name = xmlXPathParseLiteral(ctxt);
11085: CHECK_ERROR NULL;
11086: *test = NODE_TEST_PI;
11087: SKIP_BLANKS;
11088: }
11089: }
11090: if (CUR != ')') {
11091: if (name != NULL)
11092: xmlFree(name);
11093: XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11094: }
11095: NEXT;
11096: return(name);
11097: }
11098: *test = NODE_TEST_NAME;
11099: if ((!blanks) && (CUR == ':')) {
11100: NEXT;
11101:
11102: /*
11103: * Since currently the parser context don't have a
11104: * namespace list associated:
11105: * The namespace name for this prefix can be computed
11106: * only at evaluation time. The compilation is done
11107: * outside of any context.
11108: */
11109: #if 0
11110: *prefix = xmlXPathNsLookup(ctxt->context, name);
11111: if (name != NULL)
11112: xmlFree(name);
11113: if (*prefix == NULL) {
11114: XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11115: }
11116: #else
11117: *prefix = name;
11118: #endif
11119:
11120: if (CUR == '*') {
11121: /*
11122: * All elements
11123: */
11124: NEXT;
11125: *test = NODE_TEST_ALL;
11126: return(NULL);
11127: }
11128:
11129: name = xmlXPathParseNCName(ctxt);
11130: if (name == NULL) {
11131: XP_ERRORNULL(XPATH_EXPR_ERROR);
11132: }
11133: }
11134: return(name);
11135: }
11136:
11137: /**
11138: * xmlXPathIsAxisName:
11139: * @name: a preparsed name token
11140: *
11141: * [6] AxisName ::= 'ancestor'
11142: * | 'ancestor-or-self'
11143: * | 'attribute'
11144: * | 'child'
11145: * | 'descendant'
11146: * | 'descendant-or-self'
11147: * | 'following'
11148: * | 'following-sibling'
11149: * | 'namespace'
11150: * | 'parent'
11151: * | 'preceding'
11152: * | 'preceding-sibling'
11153: * | 'self'
11154: *
11155: * Returns the axis or 0
11156: */
11157: static xmlXPathAxisVal
11158: xmlXPathIsAxisName(const xmlChar *name) {
11159: xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11160: switch (name[0]) {
11161: case 'a':
11162: if (xmlStrEqual(name, BAD_CAST "ancestor"))
11163: ret = AXIS_ANCESTOR;
11164: if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11165: ret = AXIS_ANCESTOR_OR_SELF;
11166: if (xmlStrEqual(name, BAD_CAST "attribute"))
11167: ret = AXIS_ATTRIBUTE;
11168: break;
11169: case 'c':
11170: if (xmlStrEqual(name, BAD_CAST "child"))
11171: ret = AXIS_CHILD;
11172: break;
11173: case 'd':
11174: if (xmlStrEqual(name, BAD_CAST "descendant"))
11175: ret = AXIS_DESCENDANT;
11176: if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11177: ret = AXIS_DESCENDANT_OR_SELF;
11178: break;
11179: case 'f':
11180: if (xmlStrEqual(name, BAD_CAST "following"))
11181: ret = AXIS_FOLLOWING;
11182: if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11183: ret = AXIS_FOLLOWING_SIBLING;
11184: break;
11185: case 'n':
11186: if (xmlStrEqual(name, BAD_CAST "namespace"))
11187: ret = AXIS_NAMESPACE;
11188: break;
11189: case 'p':
11190: if (xmlStrEqual(name, BAD_CAST "parent"))
11191: ret = AXIS_PARENT;
11192: if (xmlStrEqual(name, BAD_CAST "preceding"))
11193: ret = AXIS_PRECEDING;
11194: if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11195: ret = AXIS_PRECEDING_SIBLING;
11196: break;
11197: case 's':
11198: if (xmlStrEqual(name, BAD_CAST "self"))
11199: ret = AXIS_SELF;
11200: break;
11201: }
11202: return(ret);
11203: }
11204:
11205: /**
11206: * xmlXPathCompStep:
11207: * @ctxt: the XPath Parser context
11208: *
11209: * [4] Step ::= AxisSpecifier NodeTest Predicate*
11210: * | AbbreviatedStep
11211: *
11212: * [12] AbbreviatedStep ::= '.' | '..'
11213: *
11214: * [5] AxisSpecifier ::= AxisName '::'
11215: * | AbbreviatedAxisSpecifier
11216: *
11217: * [13] AbbreviatedAxisSpecifier ::= '@'?
11218: *
11219: * Modified for XPtr range support as:
11220: *
11221: * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11222: * | AbbreviatedStep
11223: * | 'range-to' '(' Expr ')' Predicate*
11224: *
11225: * Compile one step in a Location Path
11226: * A location step of . is short for self::node(). This is
11227: * particularly useful in conjunction with //. For example, the
11228: * location path .//para is short for
11229: * self::node()/descendant-or-self::node()/child::para
11230: * and so will select all para descendant elements of the context
11231: * node.
11232: * Similarly, a location step of .. is short for parent::node().
11233: * For example, ../title is short for parent::node()/child::title
11234: * and so will select the title children of the parent of the context
11235: * node.
11236: */
11237: static void
11238: xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11239: #ifdef LIBXML_XPTR_ENABLED
11240: int rangeto = 0;
11241: int op2 = -1;
11242: #endif
11243:
11244: SKIP_BLANKS;
11245: if ((CUR == '.') && (NXT(1) == '.')) {
11246: SKIP(2);
11247: SKIP_BLANKS;
11248: PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11249: NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11250: } else if (CUR == '.') {
11251: NEXT;
11252: SKIP_BLANKS;
11253: } else {
11254: xmlChar *name = NULL;
11255: const xmlChar *prefix = NULL;
11256: xmlXPathTestVal test = (xmlXPathTestVal) 0;
11257: xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11258: xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11259: int op1;
11260:
11261: /*
11262: * The modification needed for XPointer change to the production
11263: */
11264: #ifdef LIBXML_XPTR_ENABLED
11265: if (ctxt->xptr) {
11266: name = xmlXPathParseNCName(ctxt);
11267: if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11268: op2 = ctxt->comp->last;
11269: xmlFree(name);
11270: SKIP_BLANKS;
11271: if (CUR != '(') {
11272: XP_ERROR(XPATH_EXPR_ERROR);
11273: }
11274: NEXT;
11275: SKIP_BLANKS;
11276:
11277: xmlXPathCompileExpr(ctxt, 1);
11278: /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11279: CHECK_ERROR;
11280:
11281: SKIP_BLANKS;
11282: if (CUR != ')') {
11283: XP_ERROR(XPATH_EXPR_ERROR);
11284: }
11285: NEXT;
11286: rangeto = 1;
11287: goto eval_predicates;
11288: }
11289: }
11290: #endif
11291: if (CUR == '*') {
11292: axis = AXIS_CHILD;
11293: } else {
11294: if (name == NULL)
11295: name = xmlXPathParseNCName(ctxt);
11296: if (name != NULL) {
11297: axis = xmlXPathIsAxisName(name);
11298: if (axis != 0) {
11299: SKIP_BLANKS;
11300: if ((CUR == ':') && (NXT(1) == ':')) {
11301: SKIP(2);
11302: xmlFree(name);
11303: name = NULL;
11304: } else {
11305: /* an element name can conflict with an axis one :-\ */
11306: axis = AXIS_CHILD;
11307: }
11308: } else {
11309: axis = AXIS_CHILD;
11310: }
11311: } else if (CUR == '@') {
11312: NEXT;
11313: axis = AXIS_ATTRIBUTE;
11314: } else {
11315: axis = AXIS_CHILD;
11316: }
11317: }
11318:
11319: if (ctxt->error != XPATH_EXPRESSION_OK) {
11320: xmlFree(name);
11321: return;
11322: }
11323:
11324: name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11325: if (test == 0)
11326: return;
11327:
11328: if ((prefix != NULL) && (ctxt->context != NULL) &&
11329: (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11330: if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11331: xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11332: }
11333: }
11334: #ifdef DEBUG_STEP
11335: xmlGenericError(xmlGenericErrorContext,
11336: "Basis : computing new set\n");
11337: #endif
11338:
11339: #ifdef DEBUG_STEP
11340: xmlGenericError(xmlGenericErrorContext, "Basis : ");
11341: if (ctxt->value == NULL)
11342: xmlGenericError(xmlGenericErrorContext, "no value\n");
11343: else if (ctxt->value->nodesetval == NULL)
11344: xmlGenericError(xmlGenericErrorContext, "Empty\n");
11345: else
11346: xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11347: #endif
11348:
11349: #ifdef LIBXML_XPTR_ENABLED
11350: eval_predicates:
11351: #endif
11352: op1 = ctxt->comp->last;
11353: ctxt->comp->last = -1;
11354:
11355: SKIP_BLANKS;
11356: while (CUR == '[') {
11357: xmlXPathCompPredicate(ctxt, 0);
11358: }
11359:
11360: #ifdef LIBXML_XPTR_ENABLED
11361: if (rangeto) {
11362: PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11363: } else
11364: #endif
11365: PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11366: test, type, (void *)prefix, (void *)name);
11367:
11368: }
11369: #ifdef DEBUG_STEP
11370: xmlGenericError(xmlGenericErrorContext, "Step : ");
11371: if (ctxt->value == NULL)
11372: xmlGenericError(xmlGenericErrorContext, "no value\n");
11373: else if (ctxt->value->nodesetval == NULL)
11374: xmlGenericError(xmlGenericErrorContext, "Empty\n");
11375: else
11376: xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11377: ctxt->value->nodesetval);
11378: #endif
11379: }
11380:
11381: /**
11382: * xmlXPathCompRelativeLocationPath:
11383: * @ctxt: the XPath Parser context
11384: *
11385: * [3] RelativeLocationPath ::= Step
11386: * | RelativeLocationPath '/' Step
11387: * | AbbreviatedRelativeLocationPath
11388: * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
11389: *
11390: * Compile a relative location path.
11391: */
11392: static void
11393: xmlXPathCompRelativeLocationPath
11394: (xmlXPathParserContextPtr ctxt) {
11395: SKIP_BLANKS;
11396: if ((CUR == '/') && (NXT(1) == '/')) {
11397: SKIP(2);
11398: SKIP_BLANKS;
11399: PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11400: NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11401: } else if (CUR == '/') {
11402: NEXT;
11403: SKIP_BLANKS;
11404: }
11405: xmlXPathCompStep(ctxt);
11406: CHECK_ERROR;
11407: SKIP_BLANKS;
11408: while (CUR == '/') {
11409: if ((CUR == '/') && (NXT(1) == '/')) {
11410: SKIP(2);
11411: SKIP_BLANKS;
11412: PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11413: NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11414: xmlXPathCompStep(ctxt);
11415: } else if (CUR == '/') {
11416: NEXT;
11417: SKIP_BLANKS;
11418: xmlXPathCompStep(ctxt);
11419: }
11420: SKIP_BLANKS;
11421: }
11422: }
11423:
11424: /**
11425: * xmlXPathCompLocationPath:
11426: * @ctxt: the XPath Parser context
11427: *
11428: * [1] LocationPath ::= RelativeLocationPath
11429: * | AbsoluteLocationPath
11430: * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
11431: * | AbbreviatedAbsoluteLocationPath
11432: * [10] AbbreviatedAbsoluteLocationPath ::=
11433: * '//' RelativeLocationPath
11434: *
11435: * Compile a location path
11436: *
11437: * // is short for /descendant-or-self::node()/. For example,
11438: * //para is short for /descendant-or-self::node()/child::para and
11439: * so will select any para element in the document (even a para element
11440: * that is a document element will be selected by //para since the
11441: * document element node is a child of the root node); div//para is
11442: * short for div/descendant-or-self::node()/child::para and so will
11443: * select all para descendants of div children.
11444: */
11445: static void
11446: xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11447: SKIP_BLANKS;
11448: if (CUR != '/') {
11449: xmlXPathCompRelativeLocationPath(ctxt);
11450: } else {
11451: while (CUR == '/') {
11452: if ((CUR == '/') && (NXT(1) == '/')) {
11453: SKIP(2);
11454: SKIP_BLANKS;
11455: PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11456: NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11457: xmlXPathCompRelativeLocationPath(ctxt);
11458: } else if (CUR == '/') {
11459: NEXT;
11460: SKIP_BLANKS;
11461: if ((CUR != 0 ) &&
11462: ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11463: (CUR == '@') || (CUR == '*')))
11464: xmlXPathCompRelativeLocationPath(ctxt);
11465: }
11466: CHECK_ERROR;
11467: }
11468: }
11469: }
11470:
11471: /************************************************************************
11472: * *
11473: * XPath precompiled expression evaluation *
11474: * *
11475: ************************************************************************/
11476:
11477: static int
11478: xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11479:
11480: #ifdef DEBUG_STEP
11481: static void
11482: xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11483: int nbNodes)
11484: {
11485: xmlGenericError(xmlGenericErrorContext, "new step : ");
11486: switch (op->value) {
11487: case AXIS_ANCESTOR:
11488: xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11489: break;
11490: case AXIS_ANCESTOR_OR_SELF:
11491: xmlGenericError(xmlGenericErrorContext,
11492: "axis 'ancestors-or-self' ");
11493: break;
11494: case AXIS_ATTRIBUTE:
11495: xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11496: break;
11497: case AXIS_CHILD:
11498: xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11499: break;
11500: case AXIS_DESCENDANT:
11501: xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11502: break;
11503: case AXIS_DESCENDANT_OR_SELF:
11504: xmlGenericError(xmlGenericErrorContext,
11505: "axis 'descendant-or-self' ");
11506: break;
11507: case AXIS_FOLLOWING:
11508: xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11509: break;
11510: case AXIS_FOLLOWING_SIBLING:
11511: xmlGenericError(xmlGenericErrorContext,
11512: "axis 'following-siblings' ");
11513: break;
11514: case AXIS_NAMESPACE:
11515: xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11516: break;
11517: case AXIS_PARENT:
11518: xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11519: break;
11520: case AXIS_PRECEDING:
11521: xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11522: break;
11523: case AXIS_PRECEDING_SIBLING:
11524: xmlGenericError(xmlGenericErrorContext,
11525: "axis 'preceding-sibling' ");
11526: break;
11527: case AXIS_SELF:
11528: xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11529: break;
11530: }
11531: xmlGenericError(xmlGenericErrorContext,
11532: " context contains %d nodes\n", nbNodes);
11533: switch (op->value2) {
11534: case NODE_TEST_NONE:
11535: xmlGenericError(xmlGenericErrorContext,
11536: " searching for none !!!\n");
11537: break;
11538: case NODE_TEST_TYPE:
11539: xmlGenericError(xmlGenericErrorContext,
11540: " searching for type %d\n", op->value3);
11541: break;
11542: case NODE_TEST_PI:
11543: xmlGenericError(xmlGenericErrorContext,
11544: " searching for PI !!!\n");
11545: break;
11546: case NODE_TEST_ALL:
11547: xmlGenericError(xmlGenericErrorContext,
11548: " searching for *\n");
11549: break;
11550: case NODE_TEST_NS:
11551: xmlGenericError(xmlGenericErrorContext,
11552: " searching for namespace %s\n",
11553: op->value5);
11554: break;
11555: case NODE_TEST_NAME:
11556: xmlGenericError(xmlGenericErrorContext,
11557: " searching for name %s\n", op->value5);
11558: if (op->value4)
11559: xmlGenericError(xmlGenericErrorContext,
11560: " with namespace %s\n", op->value4);
11561: break;
11562: }
11563: xmlGenericError(xmlGenericErrorContext, "Testing : ");
11564: }
11565: #endif /* DEBUG_STEP */
11566:
11567: static int
11568: xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11569: xmlXPathStepOpPtr op,
11570: xmlNodeSetPtr set,
11571: int contextSize,
11572: int hasNsNodes)
11573: {
11574: if (op->ch1 != -1) {
11575: xmlXPathCompExprPtr comp = ctxt->comp;
11576: /*
11577: * Process inner predicates first.
11578: */
11579: if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11580: /*
11581: * TODO: raise an internal error.
11582: */
11583: }
11584: contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11585: &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11586: CHECK_ERROR0;
11587: if (contextSize <= 0)
11588: return(0);
11589: }
11590: if (op->ch2 != -1) {
11591: xmlXPathContextPtr xpctxt = ctxt->context;
11592: xmlNodePtr contextNode, oldContextNode;
11593: xmlDocPtr oldContextDoc;
11594: int i, res, contextPos = 0, newContextSize;
11595: xmlXPathStepOpPtr exprOp;
11596: xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11597:
11598: #ifdef LIBXML_XPTR_ENABLED
11599: /*
11600: * URGENT TODO: Check the following:
11601: * We don't expect location sets if evaluating prediates, right?
11602: * Only filters should expect location sets, right?
11603: */
11604: #endif
11605: /*
11606: * SPEC XPath 1.0:
11607: * "For each node in the node-set to be filtered, the
11608: * PredicateExpr is evaluated with that node as the
11609: * context node, with the number of nodes in the
11610: * node-set as the context size, and with the proximity
11611: * position of the node in the node-set with respect to
11612: * the axis as the context position;"
11613: * @oldset is the node-set" to be filtered.
11614: *
11615: * SPEC XPath 1.0:
11616: * "only predicates change the context position and
11617: * context size (see [2.4 Predicates])."
11618: * Example:
11619: * node-set context pos
11620: * nA 1
11621: * nB 2
11622: * nC 3
11623: * After applying predicate [position() > 1] :
11624: * node-set context pos
11625: * nB 1
11626: * nC 2
11627: */
11628: oldContextNode = xpctxt->node;
11629: oldContextDoc = xpctxt->doc;
11630: /*
11631: * Get the expression of this predicate.
11632: */
11633: exprOp = &ctxt->comp->steps[op->ch2];
11634: newContextSize = 0;
11635: for (i = 0; i < set->nodeNr; i++) {
11636: if (set->nodeTab[i] == NULL)
11637: continue;
11638:
11639: contextNode = set->nodeTab[i];
11640: xpctxt->node = contextNode;
11641: xpctxt->contextSize = contextSize;
11642: xpctxt->proximityPosition = ++contextPos;
11643:
11644: /*
11645: * Also set the xpath document in case things like
11646: * key() are evaluated in the predicate.
11647: */
11648: if ((contextNode->type != XML_NAMESPACE_DECL) &&
11649: (contextNode->doc != NULL))
11650: xpctxt->doc = contextNode->doc;
11651: /*
11652: * Evaluate the predicate expression with 1 context node
11653: * at a time; this node is packaged into a node set; this
11654: * node set is handed over to the evaluation mechanism.
11655: */
11656: if (contextObj == NULL)
11657: contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11658: else
11659: xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11660: contextNode);
11661:
11662: valuePush(ctxt, contextObj);
11663:
11664: res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11665:
11666: if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11667: xmlXPathNodeSetClear(set, hasNsNodes);
11668: newContextSize = 0;
11669: goto evaluation_exit;
11670: }
11671:
11672: if (res != 0) {
11673: newContextSize++;
11674: } else {
11675: /*
11676: * Remove the entry from the initial node set.
11677: */
11678: set->nodeTab[i] = NULL;
11679: if (contextNode->type == XML_NAMESPACE_DECL)
11680: xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11681: }
11682: if (ctxt->value == contextObj) {
11683: /*
11684: * Don't free the temporary XPath object holding the
11685: * context node, in order to avoid massive recreation
11686: * inside this loop.
11687: */
11688: valuePop(ctxt);
11689: xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11690: } else {
11691: /*
11692: * TODO: The object was lost in the evaluation machinery.
11693: * Can this happen? Maybe in internal-error cases.
11694: */
11695: contextObj = NULL;
11696: }
11697: }
11698:
11699: if (contextObj != NULL) {
11700: if (ctxt->value == contextObj)
11701: valuePop(ctxt);
11702: xmlXPathReleaseObject(xpctxt, contextObj);
11703: }
11704: evaluation_exit:
11705: if (exprRes != NULL)
11706: xmlXPathReleaseObject(ctxt->context, exprRes);
11707: /*
11708: * Reset/invalidate the context.
11709: */
11710: xpctxt->node = oldContextNode;
11711: xpctxt->doc = oldContextDoc;
11712: xpctxt->contextSize = -1;
11713: xpctxt->proximityPosition = -1;
11714: return(newContextSize);
11715: }
11716: return(contextSize);
11717: }
11718:
11719: static int
11720: xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11721: xmlXPathStepOpPtr op,
11722: xmlNodeSetPtr set,
11723: int contextSize,
11724: int minPos,
11725: int maxPos,
11726: int hasNsNodes)
11727: {
11728: if (op->ch1 != -1) {
11729: xmlXPathCompExprPtr comp = ctxt->comp;
11730: if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11731: /*
11732: * TODO: raise an internal error.
11733: */
11734: }
11735: contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11736: &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11737: CHECK_ERROR0;
11738: if (contextSize <= 0)
11739: return(0);
11740: }
11741: /*
11742: * Check if the node set contains a sufficient number of nodes for
11743: * the requested range.
11744: */
11745: if (contextSize < minPos) {
11746: xmlXPathNodeSetClear(set, hasNsNodes);
11747: return(0);
11748: }
11749: if (op->ch2 == -1) {
11750: /*
11751: * TODO: Can this ever happen?
11752: */
11753: return (contextSize);
11754: } else {
11755: xmlDocPtr oldContextDoc;
11756: int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11757: xmlXPathStepOpPtr exprOp;
11758: xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11759: xmlNodePtr oldContextNode, contextNode = NULL;
11760: xmlXPathContextPtr xpctxt = ctxt->context;
1.1.1.2 ! misho 11761: int frame;
1.1 misho 11762:
11763: #ifdef LIBXML_XPTR_ENABLED
11764: /*
11765: * URGENT TODO: Check the following:
11766: * We don't expect location sets if evaluating prediates, right?
11767: * Only filters should expect location sets, right?
11768: */
11769: #endif /* LIBXML_XPTR_ENABLED */
11770:
11771: /*
11772: * Save old context.
11773: */
11774: oldContextNode = xpctxt->node;
11775: oldContextDoc = xpctxt->doc;
11776: /*
11777: * Get the expression of this predicate.
11778: */
11779: exprOp = &ctxt->comp->steps[op->ch2];
11780: for (i = 0; i < set->nodeNr; i++) {
1.1.1.2 ! misho 11781: xmlXPathObjectPtr tmp;
! 11782:
1.1 misho 11783: if (set->nodeTab[i] == NULL)
11784: continue;
11785:
11786: contextNode = set->nodeTab[i];
11787: xpctxt->node = contextNode;
11788: xpctxt->contextSize = contextSize;
11789: xpctxt->proximityPosition = ++contextPos;
11790:
11791: /*
11792: * Initialize the new set.
11793: * Also set the xpath document in case things like
11794: * key() evaluation are attempted on the predicate
11795: */
11796: if ((contextNode->type != XML_NAMESPACE_DECL) &&
11797: (contextNode->doc != NULL))
11798: xpctxt->doc = contextNode->doc;
11799: /*
11800: * Evaluate the predicate expression with 1 context node
11801: * at a time; this node is packaged into a node set; this
11802: * node set is handed over to the evaluation mechanism.
11803: */
11804: if (contextObj == NULL)
11805: contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11806: else
11807: xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11808: contextNode);
11809:
1.1.1.2 ! misho 11810: frame = xmlXPathSetFrame(ctxt);
1.1 misho 11811: valuePush(ctxt, contextObj);
11812: res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
1.1.1.2 ! misho 11813: tmp = valuePop(ctxt);
! 11814: xmlXPathPopFrame(ctxt, frame);
1.1 misho 11815:
11816: if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
1.1.1.2 ! misho 11817: while (tmp != contextObj) {
! 11818: /*
! 11819: * Free up the result
! 11820: * then pop off contextObj, which will be freed later
! 11821: */
! 11822: xmlXPathReleaseObject(xpctxt, tmp);
! 11823: tmp = valuePop(ctxt);
! 11824: }
1.1 misho 11825: goto evaluation_error;
11826: }
1.1.1.2 ! misho 11827: /* push the result back onto the stack */
! 11828: valuePush(ctxt, tmp);
1.1 misho 11829:
11830: if (res)
11831: pos++;
11832:
11833: if (res && (pos >= minPos) && (pos <= maxPos)) {
11834: /*
11835: * Fits in the requested range.
11836: */
11837: newContextSize++;
11838: if (minPos == maxPos) {
11839: /*
11840: * Only 1 node was requested.
11841: */
11842: if (contextNode->type == XML_NAMESPACE_DECL) {
11843: /*
11844: * As always: take care of those nasty
11845: * namespace nodes.
11846: */
11847: set->nodeTab[i] = NULL;
11848: }
11849: xmlXPathNodeSetClear(set, hasNsNodes);
11850: set->nodeNr = 1;
11851: set->nodeTab[0] = contextNode;
11852: goto evaluation_exit;
11853: }
11854: if (pos == maxPos) {
11855: /*
11856: * We are done.
11857: */
11858: xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11859: goto evaluation_exit;
11860: }
11861: } else {
11862: /*
11863: * Remove the entry from the initial node set.
11864: */
11865: set->nodeTab[i] = NULL;
11866: if (contextNode->type == XML_NAMESPACE_DECL)
11867: xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11868: }
11869: if (exprRes != NULL) {
11870: xmlXPathReleaseObject(ctxt->context, exprRes);
11871: exprRes = NULL;
11872: }
11873: if (ctxt->value == contextObj) {
11874: /*
11875: * Don't free the temporary XPath object holding the
11876: * context node, in order to avoid massive recreation
11877: * inside this loop.
11878: */
11879: valuePop(ctxt);
11880: xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11881: } else {
11882: /*
11883: * The object was lost in the evaluation machinery.
11884: * Can this happen? Maybe in case of internal-errors.
11885: */
11886: contextObj = NULL;
11887: }
11888: }
11889: goto evaluation_exit;
11890:
11891: evaluation_error:
11892: xmlXPathNodeSetClear(set, hasNsNodes);
11893: newContextSize = 0;
11894:
11895: evaluation_exit:
11896: if (contextObj != NULL) {
11897: if (ctxt->value == contextObj)
11898: valuePop(ctxt);
11899: xmlXPathReleaseObject(xpctxt, contextObj);
11900: }
11901: if (exprRes != NULL)
11902: xmlXPathReleaseObject(ctxt->context, exprRes);
11903: /*
11904: * Reset/invalidate the context.
11905: */
11906: xpctxt->node = oldContextNode;
11907: xpctxt->doc = oldContextDoc;
11908: xpctxt->contextSize = -1;
11909: xpctxt->proximityPosition = -1;
11910: return(newContextSize);
11911: }
11912: return(contextSize);
11913: }
11914:
11915: static int
11916: xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11917: xmlXPathStepOpPtr op,
11918: int *maxPos)
11919: {
11920:
11921: xmlXPathStepOpPtr exprOp;
11922:
11923: /*
11924: * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11925: */
11926:
11927: /*
11928: * If not -1, then ch1 will point to:
11929: * 1) For predicates (XPATH_OP_PREDICATE):
11930: * - an inner predicate operator
11931: * 2) For filters (XPATH_OP_FILTER):
11932: * - an inner filter operater OR
11933: * - an expression selecting the node set.
11934: * E.g. "key('a', 'b')" or "(//foo | //bar)".
11935: */
11936: if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11937: return(0);
11938:
11939: if (op->ch2 != -1) {
11940: exprOp = &ctxt->comp->steps[op->ch2];
11941: } else
11942: return(0);
11943:
11944: if ((exprOp != NULL) &&
11945: (exprOp->op == XPATH_OP_VALUE) &&
11946: (exprOp->value4 != NULL) &&
11947: (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11948: {
11949: /*
11950: * We have a "[n]" predicate here.
11951: * TODO: Unfortunately this simplistic test here is not
11952: * able to detect a position() predicate in compound
11953: * expressions like "[@attr = 'a" and position() = 1],
11954: * and even not the usage of position() in
11955: * "[position() = 1]"; thus - obviously - a position-range,
11956: * like it "[position() < 5]", is also not detected.
11957: * Maybe we could rewrite the AST to ease the optimization.
11958: */
11959: *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11960:
11961: if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
11962: (float) *maxPos)
11963: {
11964: return(1);
11965: }
11966: }
11967: return(0);
11968: }
11969:
11970: static int
11971: xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11972: xmlXPathStepOpPtr op,
11973: xmlNodePtr * first, xmlNodePtr * last,
11974: int toBool)
11975: {
11976:
11977: #define XP_TEST_HIT \
11978: if (hasAxisRange != 0) { \
11979: if (++pos == maxPos) { \
11980: addNode(seq, cur); \
11981: goto axis_range_end; } \
11982: } else { \
11983: addNode(seq, cur); \
11984: if (breakOnFirstHit) goto first_hit; }
11985:
11986: #define XP_TEST_HIT_NS \
11987: if (hasAxisRange != 0) { \
11988: if (++pos == maxPos) { \
11989: hasNsNodes = 1; \
11990: xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
11991: goto axis_range_end; } \
11992: } else { \
11993: hasNsNodes = 1; \
11994: xmlXPathNodeSetAddNs(seq, \
11995: xpctxt->node, (xmlNsPtr) cur); \
11996: if (breakOnFirstHit) goto first_hit; }
11997:
11998: xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11999: xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12000: xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12001: const xmlChar *prefix = op->value4;
12002: const xmlChar *name = op->value5;
12003: const xmlChar *URI = NULL;
12004:
12005: #ifdef DEBUG_STEP
12006: int nbMatches = 0, prevMatches = 0;
12007: #endif
12008: int total = 0, hasNsNodes = 0;
12009: /* The popped object holding the context nodes */
12010: xmlXPathObjectPtr obj;
12011: /* The set of context nodes for the node tests */
12012: xmlNodeSetPtr contextSeq;
12013: int contextIdx;
12014: xmlNodePtr contextNode;
12015: /* The context node for a compound traversal */
12016: xmlNodePtr outerContextNode;
12017: /* The final resulting node set wrt to all context nodes */
12018: xmlNodeSetPtr outSeq;
12019: /*
12020: * The temporary resulting node set wrt 1 context node.
12021: * Used to feed predicate evaluation.
12022: */
12023: xmlNodeSetPtr seq;
12024: xmlNodePtr cur;
12025: /* First predicate operator */
12026: xmlXPathStepOpPtr predOp;
12027: int maxPos; /* The requested position() (when a "[n]" predicate) */
12028: int hasPredicateRange, hasAxisRange, pos, size, newSize;
12029: int breakOnFirstHit;
12030:
12031: xmlXPathTraversalFunction next = NULL;
12032: /* compound axis traversal */
12033: xmlXPathTraversalFunctionExt outerNext = NULL;
12034: void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12035: xmlXPathNodeSetMergeFunction mergeAndClear;
12036: xmlNodePtr oldContextNode;
12037: xmlXPathContextPtr xpctxt = ctxt->context;
12038:
12039:
12040: CHECK_TYPE0(XPATH_NODESET);
12041: obj = valuePop(ctxt);
12042: /*
12043: * Setup namespaces.
12044: */
12045: if (prefix != NULL) {
12046: URI = xmlXPathNsLookup(xpctxt, prefix);
12047: if (URI == NULL) {
12048: xmlXPathReleaseObject(xpctxt, obj);
12049: XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12050: }
12051: }
12052: /*
12053: * Setup axis.
12054: *
12055: * MAYBE FUTURE TODO: merging optimizations:
12056: * - If the nodes to be traversed wrt to the initial nodes and
12057: * the current axis cannot overlap, then we could avoid searching
12058: * for duplicates during the merge.
12059: * But the question is how/when to evaluate if they cannot overlap.
12060: * Example: if we know that for two initial nodes, the one is
12061: * not in the ancestor-or-self axis of the other, then we could safely
12062: * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12063: * the descendant-or-self axis.
12064: */
12065: mergeAndClear = xmlXPathNodeSetMergeAndClear;
12066: switch (axis) {
12067: case AXIS_ANCESTOR:
12068: first = NULL;
12069: next = xmlXPathNextAncestor;
12070: break;
12071: case AXIS_ANCESTOR_OR_SELF:
12072: first = NULL;
12073: next = xmlXPathNextAncestorOrSelf;
12074: break;
12075: case AXIS_ATTRIBUTE:
12076: first = NULL;
12077: last = NULL;
12078: next = xmlXPathNextAttribute;
12079: mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12080: break;
12081: case AXIS_CHILD:
12082: last = NULL;
12083: if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
12084: /*
12085: * This iterator will give us only nodes which can
12086: * hold element nodes.
12087: */
12088: outerNext = xmlXPathNextDescendantOrSelfElemParent;
12089: }
12090: if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12091: (type == NODE_TYPE_NODE))
12092: {
12093: /*
12094: * Optimization if an element node type is 'element'.
12095: */
12096: next = xmlXPathNextChildElement;
12097: } else
12098: next = xmlXPathNextChild;
12099: mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12100: break;
12101: case AXIS_DESCENDANT:
12102: last = NULL;
12103: next = xmlXPathNextDescendant;
12104: break;
12105: case AXIS_DESCENDANT_OR_SELF:
12106: last = NULL;
12107: next = xmlXPathNextDescendantOrSelf;
12108: break;
12109: case AXIS_FOLLOWING:
12110: last = NULL;
12111: next = xmlXPathNextFollowing;
12112: break;
12113: case AXIS_FOLLOWING_SIBLING:
12114: last = NULL;
12115: next = xmlXPathNextFollowingSibling;
12116: break;
12117: case AXIS_NAMESPACE:
12118: first = NULL;
12119: last = NULL;
12120: next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12121: mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12122: break;
12123: case AXIS_PARENT:
12124: first = NULL;
12125: next = xmlXPathNextParent;
12126: break;
12127: case AXIS_PRECEDING:
12128: first = NULL;
12129: next = xmlXPathNextPrecedingInternal;
12130: break;
12131: case AXIS_PRECEDING_SIBLING:
12132: first = NULL;
12133: next = xmlXPathNextPrecedingSibling;
12134: break;
12135: case AXIS_SELF:
12136: first = NULL;
12137: last = NULL;
12138: next = xmlXPathNextSelf;
12139: mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12140: break;
12141: }
12142:
12143: #ifdef DEBUG_STEP
12144: xmlXPathDebugDumpStepAxis(op,
12145: (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12146: #endif
12147:
12148: if (next == NULL) {
12149: xmlXPathReleaseObject(xpctxt, obj);
12150: return(0);
12151: }
12152: contextSeq = obj->nodesetval;
12153: if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12154: xmlXPathReleaseObject(xpctxt, obj);
12155: valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12156: return(0);
12157: }
12158: /*
12159: * Predicate optimization ---------------------------------------------
12160: * If this step has a last predicate, which contains a position(),
12161: * then we'll optimize (although not exactly "position()", but only
12162: * the short-hand form, i.e., "[n]".
12163: *
12164: * Example - expression "/foo[parent::bar][1]":
12165: *
12166: * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12167: * ROOT -- op->ch1
12168: * PREDICATE -- op->ch2 (predOp)
12169: * PREDICATE -- predOp->ch1 = [parent::bar]
12170: * SORT
12171: * COLLECT 'parent' 'name' 'node' bar
12172: * NODE
12173: * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12174: *
12175: */
12176: maxPos = 0;
12177: predOp = NULL;
12178: hasPredicateRange = 0;
12179: hasAxisRange = 0;
12180: if (op->ch2 != -1) {
12181: /*
12182: * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12183: */
12184: predOp = &ctxt->comp->steps[op->ch2];
12185: if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12186: if (predOp->ch1 != -1) {
12187: /*
12188: * Use the next inner predicate operator.
12189: */
12190: predOp = &ctxt->comp->steps[predOp->ch1];
12191: hasPredicateRange = 1;
12192: } else {
12193: /*
12194: * There's no other predicate than the [n] predicate.
12195: */
12196: predOp = NULL;
12197: hasAxisRange = 1;
12198: }
12199: }
12200: }
12201: breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12202: /*
12203: * Axis traversal -----------------------------------------------------
12204: */
12205: /*
12206: * 2.3 Node Tests
12207: * - For the attribute axis, the principal node type is attribute.
12208: * - For the namespace axis, the principal node type is namespace.
12209: * - For other axes, the principal node type is element.
12210: *
12211: * A node test * is true for any node of the
12212: * principal node type. For example, child::* will
12213: * select all element children of the context node
12214: */
12215: oldContextNode = xpctxt->node;
12216: addNode = xmlXPathNodeSetAddUnique;
12217: outSeq = NULL;
12218: seq = NULL;
12219: outerContextNode = NULL;
12220: contextNode = NULL;
12221: contextIdx = 0;
12222:
12223:
12224: while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
12225: if (outerNext != NULL) {
12226: /*
12227: * This is a compound traversal.
12228: */
12229: if (contextNode == NULL) {
12230: /*
12231: * Set the context for the outer traversal.
12232: */
12233: outerContextNode = contextSeq->nodeTab[contextIdx++];
12234: contextNode = outerNext(NULL, outerContextNode);
12235: } else
12236: contextNode = outerNext(contextNode, outerContextNode);
12237: if (contextNode == NULL)
12238: continue;
12239: /*
12240: * Set the context for the main traversal.
12241: */
12242: xpctxt->node = contextNode;
12243: } else
12244: xpctxt->node = contextSeq->nodeTab[contextIdx++];
12245:
12246: if (seq == NULL) {
12247: seq = xmlXPathNodeSetCreate(NULL);
12248: if (seq == NULL) {
12249: total = 0;
12250: goto error;
12251: }
12252: }
12253: /*
12254: * Traverse the axis and test the nodes.
12255: */
12256: pos = 0;
12257: cur = NULL;
12258: hasNsNodes = 0;
12259: do {
12260: cur = next(ctxt, cur);
12261: if (cur == NULL)
12262: break;
12263:
12264: /*
12265: * QUESTION TODO: What does the "first" and "last" stuff do?
12266: */
12267: if ((first != NULL) && (*first != NULL)) {
12268: if (*first == cur)
12269: break;
12270: if (((total % 256) == 0) &&
12271: #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12272: (xmlXPathCmpNodesExt(*first, cur) >= 0))
12273: #else
12274: (xmlXPathCmpNodes(*first, cur) >= 0))
12275: #endif
12276: {
12277: break;
12278: }
12279: }
12280: if ((last != NULL) && (*last != NULL)) {
12281: if (*last == cur)
12282: break;
12283: if (((total % 256) == 0) &&
12284: #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12285: (xmlXPathCmpNodesExt(cur, *last) >= 0))
12286: #else
12287: (xmlXPathCmpNodes(cur, *last) >= 0))
12288: #endif
12289: {
12290: break;
12291: }
12292: }
12293:
12294: total++;
12295:
12296: #ifdef DEBUG_STEP
12297: xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12298: #endif
12299:
12300: switch (test) {
12301: case NODE_TEST_NONE:
12302: total = 0;
12303: STRANGE
12304: goto error;
12305: case NODE_TEST_TYPE:
12306: /*
12307: * TODO: Don't we need to use
12308: * xmlXPathNodeSetAddNs() for namespace nodes here?
12309: * Surprisingly, some c14n tests fail, if we do this.
12310: */
12311: if (type == NODE_TYPE_NODE) {
12312: switch (cur->type) {
12313: case XML_DOCUMENT_NODE:
12314: case XML_HTML_DOCUMENT_NODE:
12315: #ifdef LIBXML_DOCB_ENABLED
12316: case XML_DOCB_DOCUMENT_NODE:
12317: #endif
12318: case XML_ELEMENT_NODE:
12319: case XML_ATTRIBUTE_NODE:
12320: case XML_PI_NODE:
12321: case XML_COMMENT_NODE:
12322: case XML_CDATA_SECTION_NODE:
12323: case XML_TEXT_NODE:
12324: case XML_NAMESPACE_DECL:
12325: XP_TEST_HIT
12326: break;
12327: default:
12328: break;
12329: }
12330: } else if (cur->type == type) {
12331: if (type == XML_NAMESPACE_DECL)
12332: XP_TEST_HIT_NS
12333: else
12334: XP_TEST_HIT
12335: } else if ((type == NODE_TYPE_TEXT) &&
12336: (cur->type == XML_CDATA_SECTION_NODE))
12337: {
12338: XP_TEST_HIT
12339: }
12340: break;
12341: case NODE_TEST_PI:
12342: if ((cur->type == XML_PI_NODE) &&
12343: ((name == NULL) || xmlStrEqual(name, cur->name)))
12344: {
12345: XP_TEST_HIT
12346: }
12347: break;
12348: case NODE_TEST_ALL:
12349: if (axis == AXIS_ATTRIBUTE) {
12350: if (cur->type == XML_ATTRIBUTE_NODE)
12351: {
12352: XP_TEST_HIT
12353: }
12354: } else if (axis == AXIS_NAMESPACE) {
12355: if (cur->type == XML_NAMESPACE_DECL)
12356: {
12357: XP_TEST_HIT_NS
12358: }
12359: } else {
12360: if (cur->type == XML_ELEMENT_NODE) {
12361: if (prefix == NULL)
12362: {
12363: XP_TEST_HIT
12364:
12365: } else if ((cur->ns != NULL) &&
12366: (xmlStrEqual(URI, cur->ns->href)))
12367: {
12368: XP_TEST_HIT
12369: }
12370: }
12371: }
12372: break;
12373: case NODE_TEST_NS:{
12374: TODO;
12375: break;
12376: }
12377: case NODE_TEST_NAME:
12378: if (axis == AXIS_ATTRIBUTE) {
12379: if (cur->type != XML_ATTRIBUTE_NODE)
12380: break;
12381: } else if (axis == AXIS_NAMESPACE) {
12382: if (cur->type != XML_NAMESPACE_DECL)
12383: break;
12384: } else {
12385: if (cur->type != XML_ELEMENT_NODE)
12386: break;
12387: }
12388: switch (cur->type) {
12389: case XML_ELEMENT_NODE:
12390: if (xmlStrEqual(name, cur->name)) {
12391: if (prefix == NULL) {
12392: if (cur->ns == NULL)
12393: {
12394: XP_TEST_HIT
12395: }
12396: } else {
12397: if ((cur->ns != NULL) &&
12398: (xmlStrEqual(URI, cur->ns->href)))
12399: {
12400: XP_TEST_HIT
12401: }
12402: }
12403: }
12404: break;
12405: case XML_ATTRIBUTE_NODE:{
12406: xmlAttrPtr attr = (xmlAttrPtr) cur;
12407:
12408: if (xmlStrEqual(name, attr->name)) {
12409: if (prefix == NULL) {
12410: if ((attr->ns == NULL) ||
12411: (attr->ns->prefix == NULL))
12412: {
12413: XP_TEST_HIT
12414: }
12415: } else {
12416: if ((attr->ns != NULL) &&
12417: (xmlStrEqual(URI,
12418: attr->ns->href)))
12419: {
12420: XP_TEST_HIT
12421: }
12422: }
12423: }
12424: break;
12425: }
12426: case XML_NAMESPACE_DECL:
12427: if (cur->type == XML_NAMESPACE_DECL) {
12428: xmlNsPtr ns = (xmlNsPtr) cur;
12429:
12430: if ((ns->prefix != NULL) && (name != NULL)
12431: && (xmlStrEqual(ns->prefix, name)))
12432: {
12433: XP_TEST_HIT_NS
12434: }
12435: }
12436: break;
12437: default:
12438: break;
12439: }
12440: break;
12441: } /* switch(test) */
12442: } while (cur != NULL);
12443:
12444: goto apply_predicates;
12445:
12446: axis_range_end: /* ----------------------------------------------------- */
12447: /*
12448: * We have a "/foo[n]", and position() = n was reached.
12449: * Note that we can have as well "/foo/::parent::foo[1]", so
12450: * a duplicate-aware merge is still needed.
12451: * Merge with the result.
12452: */
12453: if (outSeq == NULL) {
12454: outSeq = seq;
12455: seq = NULL;
12456: } else
12457: outSeq = mergeAndClear(outSeq, seq, 0);
12458: /*
12459: * Break if only a true/false result was requested.
12460: */
12461: if (toBool)
12462: break;
12463: continue;
12464:
12465: first_hit: /* ---------------------------------------------------------- */
12466: /*
12467: * Break if only a true/false result was requested and
12468: * no predicates existed and a node test succeeded.
12469: */
12470: if (outSeq == NULL) {
12471: outSeq = seq;
12472: seq = NULL;
12473: } else
12474: outSeq = mergeAndClear(outSeq, seq, 0);
12475: break;
12476:
12477: #ifdef DEBUG_STEP
12478: if (seq != NULL)
12479: nbMatches += seq->nodeNr;
12480: #endif
12481:
12482: apply_predicates: /* --------------------------------------------------- */
12483: /*
12484: * Apply predicates.
12485: */
12486: if ((predOp != NULL) && (seq->nodeNr > 0)) {
12487: /*
12488: * E.g. when we have a "/foo[some expression][n]".
12489: */
12490: /*
12491: * QUESTION TODO: The old predicate evaluation took into
12492: * account location-sets.
12493: * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12494: * Do we expect such a set here?
12495: * All what I learned now from the evaluation semantics
12496: * does not indicate that a location-set will be processed
12497: * here, so this looks OK.
12498: */
12499: /*
12500: * Iterate over all predicates, starting with the outermost
12501: * predicate.
12502: * TODO: Problem: we cannot execute the inner predicates first
12503: * since we cannot go back *up* the operator tree!
12504: * Options we have:
12505: * 1) Use of recursive functions (like is it currently done
12506: * via xmlXPathCompOpEval())
12507: * 2) Add a predicate evaluation information stack to the
12508: * context struct
12509: * 3) Change the way the operators are linked; we need a
12510: * "parent" field on xmlXPathStepOp
12511: *
12512: * For the moment, I'll try to solve this with a recursive
12513: * function: xmlXPathCompOpEvalPredicate().
12514: */
12515: size = seq->nodeNr;
12516: if (hasPredicateRange != 0)
12517: newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12518: predOp, seq, size, maxPos, maxPos, hasNsNodes);
12519: else
12520: newSize = xmlXPathCompOpEvalPredicate(ctxt,
12521: predOp, seq, size, hasNsNodes);
12522:
12523: if (ctxt->error != XPATH_EXPRESSION_OK) {
12524: total = 0;
12525: goto error;
12526: }
12527: /*
12528: * Add the filtered set of nodes to the result node set.
12529: */
12530: if (newSize == 0) {
12531: /*
12532: * The predicates filtered all nodes out.
12533: */
12534: xmlXPathNodeSetClear(seq, hasNsNodes);
12535: } else if (seq->nodeNr > 0) {
12536: /*
12537: * Add to result set.
12538: */
12539: if (outSeq == NULL) {
12540: if (size != newSize) {
12541: /*
12542: * We need to merge and clear here, since
12543: * the sequence will contained NULLed entries.
12544: */
12545: outSeq = mergeAndClear(NULL, seq, 1);
12546: } else {
12547: outSeq = seq;
12548: seq = NULL;
12549: }
12550: } else
12551: outSeq = mergeAndClear(outSeq, seq,
12552: (size != newSize) ? 1: 0);
12553: /*
12554: * Break if only a true/false result was requested.
12555: */
12556: if (toBool)
12557: break;
12558: }
12559: } else if (seq->nodeNr > 0) {
12560: /*
12561: * Add to result set.
12562: */
12563: if (outSeq == NULL) {
12564: outSeq = seq;
12565: seq = NULL;
12566: } else {
12567: outSeq = mergeAndClear(outSeq, seq, 0);
12568: }
12569: }
12570: }
12571:
12572: error:
12573: if ((obj->boolval) && (obj->user != NULL)) {
12574: /*
12575: * QUESTION TODO: What does this do and why?
12576: * TODO: Do we have to do this also for the "error"
12577: * cleanup further down?
12578: */
12579: ctxt->value->boolval = 1;
12580: ctxt->value->user = obj->user;
12581: obj->user = NULL;
12582: obj->boolval = 0;
12583: }
12584: xmlXPathReleaseObject(xpctxt, obj);
12585:
12586: /*
12587: * Ensure we return at least an emtpy set.
12588: */
12589: if (outSeq == NULL) {
12590: if ((seq != NULL) && (seq->nodeNr == 0))
12591: outSeq = seq;
12592: else
12593: outSeq = xmlXPathNodeSetCreate(NULL);
12594: /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12595: }
12596: if ((seq != NULL) && (seq != outSeq)) {
12597: xmlXPathFreeNodeSet(seq);
12598: }
12599: /*
12600: * Hand over the result. Better to push the set also in
12601: * case of errors.
12602: */
12603: valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12604: /*
12605: * Reset the context node.
12606: */
12607: xpctxt->node = oldContextNode;
12608:
12609: #ifdef DEBUG_STEP
12610: xmlGenericError(xmlGenericErrorContext,
12611: "\nExamined %d nodes, found %d nodes at that step\n",
12612: total, nbMatches);
12613: #endif
12614:
12615: return(total);
12616: }
12617:
12618: static int
12619: xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12620: xmlXPathStepOpPtr op, xmlNodePtr * first);
12621:
12622: /**
12623: * xmlXPathCompOpEvalFirst:
12624: * @ctxt: the XPath parser context with the compiled expression
12625: * @op: an XPath compiled operation
12626: * @first: the first elem found so far
12627: *
12628: * Evaluate the Precompiled XPath operation searching only the first
12629: * element in document order
12630: *
12631: * Returns the number of examined objects.
12632: */
12633: static int
12634: xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12635: xmlXPathStepOpPtr op, xmlNodePtr * first)
12636: {
12637: int total = 0, cur;
12638: xmlXPathCompExprPtr comp;
12639: xmlXPathObjectPtr arg1, arg2;
12640:
12641: CHECK_ERROR0;
12642: comp = ctxt->comp;
12643: switch (op->op) {
12644: case XPATH_OP_END:
12645: return (0);
12646: case XPATH_OP_UNION:
12647: total =
12648: xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12649: first);
12650: CHECK_ERROR0;
12651: if ((ctxt->value != NULL)
12652: && (ctxt->value->type == XPATH_NODESET)
12653: && (ctxt->value->nodesetval != NULL)
12654: && (ctxt->value->nodesetval->nodeNr >= 1)) {
12655: /*
12656: * limit tree traversing to first node in the result
12657: */
12658: /*
12659: * OPTIMIZE TODO: This implicitely sorts
12660: * the result, even if not needed. E.g. if the argument
12661: * of the count() function, no sorting is needed.
12662: * OPTIMIZE TODO: How do we know if the node-list wasn't
12663: * aready sorted?
12664: */
12665: if (ctxt->value->nodesetval->nodeNr > 1)
12666: xmlXPathNodeSetSort(ctxt->value->nodesetval);
12667: *first = ctxt->value->nodesetval->nodeTab[0];
12668: }
12669: cur =
12670: xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12671: first);
12672: CHECK_ERROR0;
12673: CHECK_TYPE0(XPATH_NODESET);
12674: arg2 = valuePop(ctxt);
12675:
12676: CHECK_TYPE0(XPATH_NODESET);
12677: arg1 = valuePop(ctxt);
12678:
12679: arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12680: arg2->nodesetval);
12681: valuePush(ctxt, arg1);
12682: xmlXPathReleaseObject(ctxt->context, arg2);
12683: /* optimizer */
12684: if (total > cur)
12685: xmlXPathCompSwap(op);
12686: return (total + cur);
12687: case XPATH_OP_ROOT:
12688: xmlXPathRoot(ctxt);
12689: return (0);
12690: case XPATH_OP_NODE:
12691: if (op->ch1 != -1)
12692: total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12693: CHECK_ERROR0;
12694: if (op->ch2 != -1)
12695: total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12696: CHECK_ERROR0;
12697: valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12698: ctxt->context->node));
12699: return (total);
12700: case XPATH_OP_RESET:
12701: if (op->ch1 != -1)
12702: total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12703: CHECK_ERROR0;
12704: if (op->ch2 != -1)
12705: total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12706: CHECK_ERROR0;
12707: ctxt->context->node = NULL;
12708: return (total);
12709: case XPATH_OP_COLLECT:{
12710: if (op->ch1 == -1)
12711: return (total);
12712:
12713: total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12714: CHECK_ERROR0;
12715:
12716: total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12717: return (total);
12718: }
12719: case XPATH_OP_VALUE:
12720: valuePush(ctxt,
12721: xmlXPathCacheObjectCopy(ctxt->context,
12722: (xmlXPathObjectPtr) op->value4));
12723: return (0);
12724: case XPATH_OP_SORT:
12725: if (op->ch1 != -1)
12726: total +=
12727: xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12728: first);
12729: CHECK_ERROR0;
12730: if ((ctxt->value != NULL)
12731: && (ctxt->value->type == XPATH_NODESET)
12732: && (ctxt->value->nodesetval != NULL)
12733: && (ctxt->value->nodesetval->nodeNr > 1))
12734: xmlXPathNodeSetSort(ctxt->value->nodesetval);
12735: return (total);
12736: #ifdef XP_OPTIMIZED_FILTER_FIRST
12737: case XPATH_OP_FILTER:
12738: total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12739: return (total);
12740: #endif
12741: default:
12742: return (xmlXPathCompOpEval(ctxt, op));
12743: }
12744: }
12745:
12746: /**
12747: * xmlXPathCompOpEvalLast:
12748: * @ctxt: the XPath parser context with the compiled expression
12749: * @op: an XPath compiled operation
12750: * @last: the last elem found so far
12751: *
12752: * Evaluate the Precompiled XPath operation searching only the last
12753: * element in document order
12754: *
12755: * Returns the number of nodes traversed
12756: */
12757: static int
12758: xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12759: xmlNodePtr * last)
12760: {
12761: int total = 0, cur;
12762: xmlXPathCompExprPtr comp;
12763: xmlXPathObjectPtr arg1, arg2;
12764: xmlNodePtr bak;
12765: xmlDocPtr bakd;
12766: int pp;
12767: int cs;
12768:
12769: CHECK_ERROR0;
12770: comp = ctxt->comp;
12771: switch (op->op) {
12772: case XPATH_OP_END:
12773: return (0);
12774: case XPATH_OP_UNION:
12775: bakd = ctxt->context->doc;
12776: bak = ctxt->context->node;
12777: pp = ctxt->context->proximityPosition;
12778: cs = ctxt->context->contextSize;
12779: total =
12780: xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12781: CHECK_ERROR0;
12782: if ((ctxt->value != NULL)
12783: && (ctxt->value->type == XPATH_NODESET)
12784: && (ctxt->value->nodesetval != NULL)
12785: && (ctxt->value->nodesetval->nodeNr >= 1)) {
12786: /*
12787: * limit tree traversing to first node in the result
12788: */
12789: if (ctxt->value->nodesetval->nodeNr > 1)
12790: xmlXPathNodeSetSort(ctxt->value->nodesetval);
12791: *last =
12792: ctxt->value->nodesetval->nodeTab[ctxt->value->
12793: nodesetval->nodeNr -
12794: 1];
12795: }
12796: ctxt->context->doc = bakd;
12797: ctxt->context->node = bak;
12798: ctxt->context->proximityPosition = pp;
12799: ctxt->context->contextSize = cs;
12800: cur =
12801: xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12802: CHECK_ERROR0;
12803: if ((ctxt->value != NULL)
12804: && (ctxt->value->type == XPATH_NODESET)
12805: && (ctxt->value->nodesetval != NULL)
12806: && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12807: }
12808: CHECK_TYPE0(XPATH_NODESET);
12809: arg2 = valuePop(ctxt);
12810:
12811: CHECK_TYPE0(XPATH_NODESET);
12812: arg1 = valuePop(ctxt);
12813:
12814: arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12815: arg2->nodesetval);
12816: valuePush(ctxt, arg1);
12817: xmlXPathReleaseObject(ctxt->context, arg2);
12818: /* optimizer */
12819: if (total > cur)
12820: xmlXPathCompSwap(op);
12821: return (total + cur);
12822: case XPATH_OP_ROOT:
12823: xmlXPathRoot(ctxt);
12824: return (0);
12825: case XPATH_OP_NODE:
12826: if (op->ch1 != -1)
12827: total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12828: CHECK_ERROR0;
12829: if (op->ch2 != -1)
12830: total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12831: CHECK_ERROR0;
12832: valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12833: ctxt->context->node));
12834: return (total);
12835: case XPATH_OP_RESET:
12836: if (op->ch1 != -1)
12837: total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12838: CHECK_ERROR0;
12839: if (op->ch2 != -1)
12840: total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12841: CHECK_ERROR0;
12842: ctxt->context->node = NULL;
12843: return (total);
12844: case XPATH_OP_COLLECT:{
12845: if (op->ch1 == -1)
12846: return (0);
12847:
12848: total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12849: CHECK_ERROR0;
12850:
12851: total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12852: return (total);
12853: }
12854: case XPATH_OP_VALUE:
12855: valuePush(ctxt,
12856: xmlXPathCacheObjectCopy(ctxt->context,
12857: (xmlXPathObjectPtr) op->value4));
12858: return (0);
12859: case XPATH_OP_SORT:
12860: if (op->ch1 != -1)
12861: total +=
12862: xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12863: last);
12864: CHECK_ERROR0;
12865: if ((ctxt->value != NULL)
12866: && (ctxt->value->type == XPATH_NODESET)
12867: && (ctxt->value->nodesetval != NULL)
12868: && (ctxt->value->nodesetval->nodeNr > 1))
12869: xmlXPathNodeSetSort(ctxt->value->nodesetval);
12870: return (total);
12871: default:
12872: return (xmlXPathCompOpEval(ctxt, op));
12873: }
12874: }
12875:
12876: #ifdef XP_OPTIMIZED_FILTER_FIRST
12877: static int
12878: xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12879: xmlXPathStepOpPtr op, xmlNodePtr * first)
12880: {
12881: int total = 0;
12882: xmlXPathCompExprPtr comp;
12883: xmlXPathObjectPtr res;
12884: xmlXPathObjectPtr obj;
12885: xmlNodeSetPtr oldset;
12886: xmlNodePtr oldnode;
12887: xmlDocPtr oldDoc;
12888: int i;
12889:
12890: CHECK_ERROR0;
12891: comp = ctxt->comp;
12892: /*
12893: * Optimization for ()[last()] selection i.e. the last elem
12894: */
12895: if ((op->ch1 != -1) && (op->ch2 != -1) &&
12896: (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12897: (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12898: int f = comp->steps[op->ch2].ch1;
12899:
12900: if ((f != -1) &&
12901: (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12902: (comp->steps[f].value5 == NULL) &&
12903: (comp->steps[f].value == 0) &&
12904: (comp->steps[f].value4 != NULL) &&
12905: (xmlStrEqual
12906: (comp->steps[f].value4, BAD_CAST "last"))) {
12907: xmlNodePtr last = NULL;
12908:
12909: total +=
12910: xmlXPathCompOpEvalLast(ctxt,
12911: &comp->steps[op->ch1],
12912: &last);
12913: CHECK_ERROR0;
12914: /*
12915: * The nodeset should be in document order,
12916: * Keep only the last value
12917: */
12918: if ((ctxt->value != NULL) &&
12919: (ctxt->value->type == XPATH_NODESET) &&
12920: (ctxt->value->nodesetval != NULL) &&
12921: (ctxt->value->nodesetval->nodeTab != NULL) &&
12922: (ctxt->value->nodesetval->nodeNr > 1)) {
12923: ctxt->value->nodesetval->nodeTab[0] =
12924: ctxt->value->nodesetval->nodeTab[ctxt->
12925: value->
12926: nodesetval->
12927: nodeNr -
12928: 1];
12929: ctxt->value->nodesetval->nodeNr = 1;
12930: *first = *(ctxt->value->nodesetval->nodeTab);
12931: }
12932: return (total);
12933: }
12934: }
12935:
12936: if (op->ch1 != -1)
12937: total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12938: CHECK_ERROR0;
12939: if (op->ch2 == -1)
12940: return (total);
12941: if (ctxt->value == NULL)
12942: return (total);
12943:
12944: #ifdef LIBXML_XPTR_ENABLED
12945: oldnode = ctxt->context->node;
12946: /*
12947: * Hum are we filtering the result of an XPointer expression
12948: */
12949: if (ctxt->value->type == XPATH_LOCATIONSET) {
12950: xmlXPathObjectPtr tmp = NULL;
12951: xmlLocationSetPtr newlocset = NULL;
12952: xmlLocationSetPtr oldlocset;
12953:
12954: /*
12955: * Extract the old locset, and then evaluate the result of the
12956: * expression for all the element in the locset. use it to grow
12957: * up a new locset.
12958: */
12959: CHECK_TYPE0(XPATH_LOCATIONSET);
12960: obj = valuePop(ctxt);
12961: oldlocset = obj->user;
12962: ctxt->context->node = NULL;
12963:
12964: if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12965: ctxt->context->contextSize = 0;
12966: ctxt->context->proximityPosition = 0;
12967: if (op->ch2 != -1)
12968: total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12969: res = valuePop(ctxt);
12970: if (res != NULL) {
12971: xmlXPathReleaseObject(ctxt->context, res);
12972: }
12973: valuePush(ctxt, obj);
12974: CHECK_ERROR0;
12975: return (total);
12976: }
12977: newlocset = xmlXPtrLocationSetCreate(NULL);
12978:
12979: for (i = 0; i < oldlocset->locNr; i++) {
12980: /*
12981: * Run the evaluation with a node list made of a
12982: * single item in the nodelocset.
12983: */
12984: ctxt->context->node = oldlocset->locTab[i]->user;
12985: ctxt->context->contextSize = oldlocset->locNr;
12986: ctxt->context->proximityPosition = i + 1;
12987: if (tmp == NULL) {
12988: tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12989: ctxt->context->node);
12990: } else {
12991: xmlXPathNodeSetAddUnique(tmp->nodesetval,
12992: ctxt->context->node);
12993: }
12994: valuePush(ctxt, tmp);
12995: if (op->ch2 != -1)
12996: total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12997: if (ctxt->error != XPATH_EXPRESSION_OK) {
12998: xmlXPathFreeObject(obj);
12999: return(0);
13000: }
13001: /*
13002: * The result of the evaluation need to be tested to
13003: * decided whether the filter succeeded or not
13004: */
13005: res = valuePop(ctxt);
13006: if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13007: xmlXPtrLocationSetAdd(newlocset,
13008: xmlXPathCacheObjectCopy(ctxt->context,
13009: oldlocset->locTab[i]));
13010: }
13011: /*
13012: * Cleanup
13013: */
13014: if (res != NULL) {
13015: xmlXPathReleaseObject(ctxt->context, res);
13016: }
13017: if (ctxt->value == tmp) {
13018: valuePop(ctxt);
13019: xmlXPathNodeSetClear(tmp->nodesetval, 1);
13020: /*
13021: * REVISIT TODO: Don't create a temporary nodeset
13022: * for everly iteration.
13023: */
13024: /* OLD: xmlXPathFreeObject(res); */
13025: } else
13026: tmp = NULL;
13027: ctxt->context->node = NULL;
13028: /*
13029: * Only put the first node in the result, then leave.
13030: */
13031: if (newlocset->locNr > 0) {
13032: *first = (xmlNodePtr) oldlocset->locTab[i]->user;
13033: break;
13034: }
13035: }
13036: if (tmp != NULL) {
13037: xmlXPathReleaseObject(ctxt->context, tmp);
13038: }
13039: /*
13040: * The result is used as the new evaluation locset.
13041: */
13042: xmlXPathReleaseObject(ctxt->context, obj);
13043: ctxt->context->node = NULL;
13044: ctxt->context->contextSize = -1;
13045: ctxt->context->proximityPosition = -1;
13046: valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13047: ctxt->context->node = oldnode;
13048: return (total);
13049: }
13050: #endif /* LIBXML_XPTR_ENABLED */
13051:
13052: /*
13053: * Extract the old set, and then evaluate the result of the
13054: * expression for all the element in the set. use it to grow
13055: * up a new set.
13056: */
13057: CHECK_TYPE0(XPATH_NODESET);
13058: obj = valuePop(ctxt);
13059: oldset = obj->nodesetval;
13060:
13061: oldnode = ctxt->context->node;
13062: oldDoc = ctxt->context->doc;
13063: ctxt->context->node = NULL;
13064:
13065: if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13066: ctxt->context->contextSize = 0;
13067: ctxt->context->proximityPosition = 0;
13068: /* QUESTION TODO: Why was this code commented out?
13069: if (op->ch2 != -1)
13070: total +=
13071: xmlXPathCompOpEval(ctxt,
13072: &comp->steps[op->ch2]);
13073: CHECK_ERROR0;
13074: res = valuePop(ctxt);
13075: if (res != NULL)
13076: xmlXPathFreeObject(res);
13077: */
13078: valuePush(ctxt, obj);
13079: ctxt->context->node = oldnode;
13080: CHECK_ERROR0;
13081: } else {
13082: xmlNodeSetPtr newset;
13083: xmlXPathObjectPtr tmp = NULL;
13084: /*
13085: * Initialize the new set.
13086: * Also set the xpath document in case things like
13087: * key() evaluation are attempted on the predicate
13088: */
13089: newset = xmlXPathNodeSetCreate(NULL);
13090: /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13091:
13092: for (i = 0; i < oldset->nodeNr; i++) {
13093: /*
13094: * Run the evaluation with a node list made of
13095: * a single item in the nodeset.
13096: */
13097: ctxt->context->node = oldset->nodeTab[i];
13098: if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13099: (oldset->nodeTab[i]->doc != NULL))
13100: ctxt->context->doc = oldset->nodeTab[i]->doc;
13101: if (tmp == NULL) {
13102: tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13103: ctxt->context->node);
13104: } else {
13105: xmlXPathNodeSetAddUnique(tmp->nodesetval,
13106: ctxt->context->node);
13107: }
13108: valuePush(ctxt, tmp);
13109: ctxt->context->contextSize = oldset->nodeNr;
13110: ctxt->context->proximityPosition = i + 1;
13111: if (op->ch2 != -1)
13112: total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13113: if (ctxt->error != XPATH_EXPRESSION_OK) {
13114: xmlXPathFreeNodeSet(newset);
13115: xmlXPathFreeObject(obj);
13116: return(0);
13117: }
13118: /*
13119: * The result of the evaluation needs to be tested to
13120: * decide whether the filter succeeded or not
13121: */
13122: res = valuePop(ctxt);
13123: if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13124: xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13125: }
13126: /*
13127: * Cleanup
13128: */
13129: if (res != NULL) {
13130: xmlXPathReleaseObject(ctxt->context, res);
13131: }
13132: if (ctxt->value == tmp) {
13133: valuePop(ctxt);
13134: /*
13135: * Don't free the temporary nodeset
13136: * in order to avoid massive recreation inside this
13137: * loop.
13138: */
13139: xmlXPathNodeSetClear(tmp->nodesetval, 1);
13140: } else
13141: tmp = NULL;
13142: ctxt->context->node = NULL;
13143: /*
13144: * Only put the first node in the result, then leave.
13145: */
13146: if (newset->nodeNr > 0) {
13147: *first = *(newset->nodeTab);
13148: break;
13149: }
13150: }
13151: if (tmp != NULL) {
13152: xmlXPathReleaseObject(ctxt->context, tmp);
13153: }
13154: /*
13155: * The result is used as the new evaluation set.
13156: */
13157: xmlXPathReleaseObject(ctxt->context, obj);
13158: ctxt->context->node = NULL;
13159: ctxt->context->contextSize = -1;
13160: ctxt->context->proximityPosition = -1;
13161: /* may want to move this past the '}' later */
13162: ctxt->context->doc = oldDoc;
13163: valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13164: }
13165: ctxt->context->node = oldnode;
13166: return(total);
13167: }
13168: #endif /* XP_OPTIMIZED_FILTER_FIRST */
13169:
13170: /**
13171: * xmlXPathCompOpEval:
13172: * @ctxt: the XPath parser context with the compiled expression
13173: * @op: an XPath compiled operation
13174: *
13175: * Evaluate the Precompiled XPath operation
13176: * Returns the number of nodes traversed
13177: */
13178: static int
13179: xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13180: {
13181: int total = 0;
13182: int equal, ret;
13183: xmlXPathCompExprPtr comp;
13184: xmlXPathObjectPtr arg1, arg2;
13185: xmlNodePtr bak;
13186: xmlDocPtr bakd;
13187: int pp;
13188: int cs;
13189:
13190: CHECK_ERROR0;
13191: comp = ctxt->comp;
13192: switch (op->op) {
13193: case XPATH_OP_END:
13194: return (0);
13195: case XPATH_OP_AND:
13196: bakd = ctxt->context->doc;
13197: bak = ctxt->context->node;
13198: pp = ctxt->context->proximityPosition;
13199: cs = ctxt->context->contextSize;
13200: total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13201: CHECK_ERROR0;
13202: xmlXPathBooleanFunction(ctxt, 1);
13203: if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13204: return (total);
13205: arg2 = valuePop(ctxt);
13206: ctxt->context->doc = bakd;
13207: ctxt->context->node = bak;
13208: ctxt->context->proximityPosition = pp;
13209: ctxt->context->contextSize = cs;
13210: total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13211: if (ctxt->error) {
13212: xmlXPathFreeObject(arg2);
13213: return(0);
13214: }
13215: xmlXPathBooleanFunction(ctxt, 1);
13216: arg1 = valuePop(ctxt);
13217: arg1->boolval &= arg2->boolval;
13218: valuePush(ctxt, arg1);
13219: xmlXPathReleaseObject(ctxt->context, arg2);
13220: return (total);
13221: case XPATH_OP_OR:
13222: bakd = ctxt->context->doc;
13223: bak = ctxt->context->node;
13224: pp = ctxt->context->proximityPosition;
13225: cs = ctxt->context->contextSize;
13226: total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13227: CHECK_ERROR0;
13228: xmlXPathBooleanFunction(ctxt, 1);
13229: if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13230: return (total);
13231: arg2 = valuePop(ctxt);
13232: ctxt->context->doc = bakd;
13233: ctxt->context->node = bak;
13234: ctxt->context->proximityPosition = pp;
13235: ctxt->context->contextSize = cs;
13236: total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13237: if (ctxt->error) {
13238: xmlXPathFreeObject(arg2);
13239: return(0);
13240: }
13241: xmlXPathBooleanFunction(ctxt, 1);
13242: arg1 = valuePop(ctxt);
13243: arg1->boolval |= arg2->boolval;
13244: valuePush(ctxt, arg1);
13245: xmlXPathReleaseObject(ctxt->context, arg2);
13246: return (total);
13247: case XPATH_OP_EQUAL:
13248: bakd = ctxt->context->doc;
13249: bak = ctxt->context->node;
13250: pp = ctxt->context->proximityPosition;
13251: cs = ctxt->context->contextSize;
13252: total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13253: CHECK_ERROR0;
13254: ctxt->context->doc = bakd;
13255: ctxt->context->node = bak;
13256: ctxt->context->proximityPosition = pp;
13257: ctxt->context->contextSize = cs;
13258: total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13259: CHECK_ERROR0;
13260: if (op->value)
13261: equal = xmlXPathEqualValues(ctxt);
13262: else
13263: equal = xmlXPathNotEqualValues(ctxt);
13264: valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13265: return (total);
13266: case XPATH_OP_CMP:
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: ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13280: valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13281: return (total);
13282: case XPATH_OP_PLUS:
13283: bakd = ctxt->context->doc;
13284: bak = ctxt->context->node;
13285: pp = ctxt->context->proximityPosition;
13286: cs = ctxt->context->contextSize;
13287: total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13288: CHECK_ERROR0;
13289: if (op->ch2 != -1) {
13290: ctxt->context->doc = bakd;
13291: ctxt->context->node = bak;
13292: ctxt->context->proximityPosition = pp;
13293: ctxt->context->contextSize = cs;
13294: total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13295: }
13296: CHECK_ERROR0;
13297: if (op->value == 0)
13298: xmlXPathSubValues(ctxt);
13299: else if (op->value == 1)
13300: xmlXPathAddValues(ctxt);
13301: else if (op->value == 2)
13302: xmlXPathValueFlipSign(ctxt);
13303: else if (op->value == 3) {
13304: CAST_TO_NUMBER;
13305: CHECK_TYPE0(XPATH_NUMBER);
13306: }
13307: return (total);
13308: case XPATH_OP_MULT:
13309: bakd = ctxt->context->doc;
13310: bak = ctxt->context->node;
13311: pp = ctxt->context->proximityPosition;
13312: cs = ctxt->context->contextSize;
13313: total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13314: CHECK_ERROR0;
13315: ctxt->context->doc = bakd;
13316: ctxt->context->node = bak;
13317: ctxt->context->proximityPosition = pp;
13318: ctxt->context->contextSize = cs;
13319: total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13320: CHECK_ERROR0;
13321: if (op->value == 0)
13322: xmlXPathMultValues(ctxt);
13323: else if (op->value == 1)
13324: xmlXPathDivValues(ctxt);
13325: else if (op->value == 2)
13326: xmlXPathModValues(ctxt);
13327: return (total);
13328: case XPATH_OP_UNION:
13329: bakd = ctxt->context->doc;
13330: bak = ctxt->context->node;
13331: pp = ctxt->context->proximityPosition;
13332: cs = ctxt->context->contextSize;
13333: total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13334: CHECK_ERROR0;
13335: ctxt->context->doc = bakd;
13336: ctxt->context->node = bak;
13337: ctxt->context->proximityPosition = pp;
13338: ctxt->context->contextSize = cs;
13339: total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13340: CHECK_ERROR0;
13341: CHECK_TYPE0(XPATH_NODESET);
13342: arg2 = valuePop(ctxt);
13343:
13344: CHECK_TYPE0(XPATH_NODESET);
13345: arg1 = valuePop(ctxt);
13346:
13347: if ((arg1->nodesetval == NULL) ||
13348: ((arg2->nodesetval != NULL) &&
13349: (arg2->nodesetval->nodeNr != 0)))
13350: {
13351: arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13352: arg2->nodesetval);
13353: }
13354:
13355: valuePush(ctxt, arg1);
13356: xmlXPathReleaseObject(ctxt->context, arg2);
13357: return (total);
13358: case XPATH_OP_ROOT:
13359: xmlXPathRoot(ctxt);
13360: return (total);
13361: case XPATH_OP_NODE:
13362: if (op->ch1 != -1)
13363: total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13364: CHECK_ERROR0;
13365: if (op->ch2 != -1)
13366: total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13367: CHECK_ERROR0;
13368: valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13369: ctxt->context->node));
13370: return (total);
13371: case XPATH_OP_RESET:
13372: if (op->ch1 != -1)
13373: total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13374: CHECK_ERROR0;
13375: if (op->ch2 != -1)
13376: total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13377: CHECK_ERROR0;
13378: ctxt->context->node = NULL;
13379: return (total);
13380: case XPATH_OP_COLLECT:{
13381: if (op->ch1 == -1)
13382: return (total);
13383:
13384: total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13385: CHECK_ERROR0;
13386:
13387: total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13388: return (total);
13389: }
13390: case XPATH_OP_VALUE:
13391: valuePush(ctxt,
13392: xmlXPathCacheObjectCopy(ctxt->context,
13393: (xmlXPathObjectPtr) op->value4));
13394: return (total);
13395: case XPATH_OP_VARIABLE:{
13396: xmlXPathObjectPtr val;
13397:
13398: if (op->ch1 != -1)
13399: total +=
13400: xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13401: if (op->value5 == NULL) {
13402: val = xmlXPathVariableLookup(ctxt->context, op->value4);
13403: if (val == NULL) {
13404: ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13405: return(0);
13406: }
13407: valuePush(ctxt, val);
13408: } else {
13409: const xmlChar *URI;
13410:
13411: URI = xmlXPathNsLookup(ctxt->context, op->value5);
13412: if (URI == NULL) {
13413: xmlGenericError(xmlGenericErrorContext,
13414: "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13415: (char *) op->value4, (char *)op->value5);
1.1.1.2 ! misho 13416: ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
1.1 misho 13417: return (total);
13418: }
13419: val = xmlXPathVariableLookupNS(ctxt->context,
13420: op->value4, URI);
13421: if (val == NULL) {
13422: ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13423: return(0);
13424: }
13425: valuePush(ctxt, val);
13426: }
13427: return (total);
13428: }
13429: case XPATH_OP_FUNCTION:{
13430: xmlXPathFunction func;
13431: const xmlChar *oldFunc, *oldFuncURI;
13432: int i;
1.1.1.2 ! misho 13433: int frame;
1.1 misho 13434:
1.1.1.2 ! misho 13435: frame = xmlXPathSetFrame(ctxt);
1.1 misho 13436: if (op->ch1 != -1)
13437: total +=
13438: xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13439: if (ctxt->valueNr < op->value) {
13440: xmlGenericError(xmlGenericErrorContext,
13441: "xmlXPathCompOpEval: parameter error\n");
13442: ctxt->error = XPATH_INVALID_OPERAND;
1.1.1.2 ! misho 13443: xmlXPathPopFrame(ctxt, frame);
1.1 misho 13444: return (total);
13445: }
1.1.1.2 ! misho 13446: for (i = 0; i < op->value; i++) {
1.1 misho 13447: if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13448: xmlGenericError(xmlGenericErrorContext,
13449: "xmlXPathCompOpEval: parameter error\n");
13450: ctxt->error = XPATH_INVALID_OPERAND;
1.1.1.2 ! misho 13451: xmlXPathPopFrame(ctxt, frame);
1.1 misho 13452: return (total);
13453: }
1.1.1.2 ! misho 13454: }
1.1 misho 13455: if (op->cache != NULL)
13456: XML_CAST_FPTR(func) = op->cache;
13457: else {
13458: const xmlChar *URI = NULL;
13459:
13460: if (op->value5 == NULL)
13461: func =
13462: xmlXPathFunctionLookup(ctxt->context,
13463: op->value4);
13464: else {
13465: URI = xmlXPathNsLookup(ctxt->context, op->value5);
13466: if (URI == NULL) {
13467: xmlGenericError(xmlGenericErrorContext,
13468: "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13469: (char *)op->value4, (char *)op->value5);
1.1.1.2 ! misho 13470: xmlXPathPopFrame(ctxt, frame);
! 13471: ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
1.1 misho 13472: return (total);
13473: }
13474: func = xmlXPathFunctionLookupNS(ctxt->context,
13475: op->value4, URI);
13476: }
13477: if (func == NULL) {
13478: xmlGenericError(xmlGenericErrorContext,
13479: "xmlXPathCompOpEval: function %s not found\n",
13480: (char *)op->value4);
13481: XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13482: }
13483: op->cache = XML_CAST_FPTR(func);
13484: op->cacheURI = (void *) URI;
13485: }
13486: oldFunc = ctxt->context->function;
13487: oldFuncURI = ctxt->context->functionURI;
13488: ctxt->context->function = op->value4;
13489: ctxt->context->functionURI = op->cacheURI;
13490: func(ctxt, op->value);
13491: ctxt->context->function = oldFunc;
13492: ctxt->context->functionURI = oldFuncURI;
1.1.1.2 ! misho 13493: xmlXPathPopFrame(ctxt, frame);
1.1 misho 13494: return (total);
13495: }
13496: case XPATH_OP_ARG:
13497: bakd = ctxt->context->doc;
13498: bak = ctxt->context->node;
13499: pp = ctxt->context->proximityPosition;
13500: cs = ctxt->context->contextSize;
13501: if (op->ch1 != -1)
13502: total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13503: ctxt->context->contextSize = cs;
13504: ctxt->context->proximityPosition = pp;
13505: ctxt->context->node = bak;
13506: ctxt->context->doc = bakd;
13507: CHECK_ERROR0;
13508: if (op->ch2 != -1) {
13509: total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13510: ctxt->context->doc = bakd;
13511: ctxt->context->node = bak;
13512: CHECK_ERROR0;
13513: }
13514: return (total);
13515: case XPATH_OP_PREDICATE:
13516: case XPATH_OP_FILTER:{
13517: xmlXPathObjectPtr res;
13518: xmlXPathObjectPtr obj, tmp;
13519: xmlNodeSetPtr newset = NULL;
13520: xmlNodeSetPtr oldset;
13521: xmlNodePtr oldnode;
13522: xmlDocPtr oldDoc;
13523: int i;
13524:
13525: /*
13526: * Optimization for ()[1] selection i.e. the first elem
13527: */
13528: if ((op->ch1 != -1) && (op->ch2 != -1) &&
13529: #ifdef XP_OPTIMIZED_FILTER_FIRST
13530: /*
13531: * FILTER TODO: Can we assume that the inner processing
13532: * will result in an ordered list if we have an
13533: * XPATH_OP_FILTER?
13534: * What about an additional field or flag on
13535: * xmlXPathObject like @sorted ? This way we wouln'd need
13536: * to assume anything, so it would be more robust and
13537: * easier to optimize.
13538: */
13539: ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13540: (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13541: #else
13542: (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13543: #endif
13544: (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13545: xmlXPathObjectPtr val;
13546:
13547: val = comp->steps[op->ch2].value4;
13548: if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13549: (val->floatval == 1.0)) {
13550: xmlNodePtr first = NULL;
13551:
13552: total +=
13553: xmlXPathCompOpEvalFirst(ctxt,
13554: &comp->steps[op->ch1],
13555: &first);
13556: CHECK_ERROR0;
13557: /*
13558: * The nodeset should be in document order,
13559: * Keep only the first value
13560: */
13561: if ((ctxt->value != NULL) &&
13562: (ctxt->value->type == XPATH_NODESET) &&
13563: (ctxt->value->nodesetval != NULL) &&
13564: (ctxt->value->nodesetval->nodeNr > 1))
13565: ctxt->value->nodesetval->nodeNr = 1;
13566: return (total);
13567: }
13568: }
13569: /*
13570: * Optimization for ()[last()] selection i.e. the last elem
13571: */
13572: if ((op->ch1 != -1) && (op->ch2 != -1) &&
13573: (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13574: (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13575: int f = comp->steps[op->ch2].ch1;
13576:
13577: if ((f != -1) &&
13578: (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13579: (comp->steps[f].value5 == NULL) &&
13580: (comp->steps[f].value == 0) &&
13581: (comp->steps[f].value4 != NULL) &&
13582: (xmlStrEqual
13583: (comp->steps[f].value4, BAD_CAST "last"))) {
13584: xmlNodePtr last = NULL;
13585:
13586: total +=
13587: xmlXPathCompOpEvalLast(ctxt,
13588: &comp->steps[op->ch1],
13589: &last);
13590: CHECK_ERROR0;
13591: /*
13592: * The nodeset should be in document order,
13593: * Keep only the last value
13594: */
13595: if ((ctxt->value != NULL) &&
13596: (ctxt->value->type == XPATH_NODESET) &&
13597: (ctxt->value->nodesetval != NULL) &&
13598: (ctxt->value->nodesetval->nodeTab != NULL) &&
13599: (ctxt->value->nodesetval->nodeNr > 1)) {
13600: ctxt->value->nodesetval->nodeTab[0] =
13601: ctxt->value->nodesetval->nodeTab[ctxt->
13602: value->
13603: nodesetval->
13604: nodeNr -
13605: 1];
13606: ctxt->value->nodesetval->nodeNr = 1;
13607: }
13608: return (total);
13609: }
13610: }
13611: /*
13612: * Process inner predicates first.
13613: * Example "index[parent::book][1]":
13614: * ...
13615: * PREDICATE <-- we are here "[1]"
13616: * PREDICATE <-- process "[parent::book]" first
13617: * SORT
13618: * COLLECT 'parent' 'name' 'node' book
13619: * NODE
13620: * ELEM Object is a number : 1
13621: */
13622: if (op->ch1 != -1)
13623: total +=
13624: xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13625: CHECK_ERROR0;
13626: if (op->ch2 == -1)
13627: return (total);
13628: if (ctxt->value == NULL)
13629: return (total);
13630:
13631: oldnode = ctxt->context->node;
13632:
13633: #ifdef LIBXML_XPTR_ENABLED
13634: /*
13635: * Hum are we filtering the result of an XPointer expression
13636: */
13637: if (ctxt->value->type == XPATH_LOCATIONSET) {
13638: xmlLocationSetPtr newlocset = NULL;
13639: xmlLocationSetPtr oldlocset;
13640:
13641: /*
13642: * Extract the old locset, and then evaluate the result of the
13643: * expression for all the element in the locset. use it to grow
13644: * up a new locset.
13645: */
13646: CHECK_TYPE0(XPATH_LOCATIONSET);
13647: obj = valuePop(ctxt);
13648: oldlocset = obj->user;
13649: ctxt->context->node = NULL;
13650:
13651: if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13652: ctxt->context->contextSize = 0;
13653: ctxt->context->proximityPosition = 0;
13654: if (op->ch2 != -1)
13655: total +=
13656: xmlXPathCompOpEval(ctxt,
13657: &comp->steps[op->ch2]);
13658: res = valuePop(ctxt);
13659: if (res != NULL) {
13660: xmlXPathReleaseObject(ctxt->context, res);
13661: }
13662: valuePush(ctxt, obj);
13663: CHECK_ERROR0;
13664: return (total);
13665: }
13666: newlocset = xmlXPtrLocationSetCreate(NULL);
13667:
13668: for (i = 0; i < oldlocset->locNr; i++) {
13669: /*
13670: * Run the evaluation with a node list made of a
13671: * single item in the nodelocset.
13672: */
13673: ctxt->context->node = oldlocset->locTab[i]->user;
13674: ctxt->context->contextSize = oldlocset->locNr;
13675: ctxt->context->proximityPosition = i + 1;
13676: tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13677: ctxt->context->node);
13678: valuePush(ctxt, tmp);
13679:
13680: if (op->ch2 != -1)
13681: total +=
13682: xmlXPathCompOpEval(ctxt,
13683: &comp->steps[op->ch2]);
13684: if (ctxt->error != XPATH_EXPRESSION_OK) {
13685: xmlXPathFreeObject(obj);
13686: return(0);
13687: }
13688:
13689: /*
13690: * The result of the evaluation need to be tested to
13691: * decided whether the filter succeeded or not
13692: */
13693: res = valuePop(ctxt);
13694: if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13695: xmlXPtrLocationSetAdd(newlocset,
13696: xmlXPathObjectCopy
13697: (oldlocset->locTab[i]));
13698: }
13699:
13700: /*
13701: * Cleanup
13702: */
13703: if (res != NULL) {
13704: xmlXPathReleaseObject(ctxt->context, res);
13705: }
13706: if (ctxt->value == tmp) {
13707: res = valuePop(ctxt);
13708: xmlXPathReleaseObject(ctxt->context, res);
13709: }
13710:
13711: ctxt->context->node = NULL;
13712: }
13713:
13714: /*
13715: * The result is used as the new evaluation locset.
13716: */
13717: xmlXPathReleaseObject(ctxt->context, obj);
13718: ctxt->context->node = NULL;
13719: ctxt->context->contextSize = -1;
13720: ctxt->context->proximityPosition = -1;
13721: valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13722: ctxt->context->node = oldnode;
13723: return (total);
13724: }
13725: #endif /* LIBXML_XPTR_ENABLED */
13726:
13727: /*
13728: * Extract the old set, and then evaluate the result of the
13729: * expression for all the element in the set. use it to grow
13730: * up a new set.
13731: */
13732: CHECK_TYPE0(XPATH_NODESET);
13733: obj = valuePop(ctxt);
13734: oldset = obj->nodesetval;
13735:
13736: oldnode = ctxt->context->node;
13737: oldDoc = ctxt->context->doc;
13738: ctxt->context->node = NULL;
13739:
13740: if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13741: ctxt->context->contextSize = 0;
13742: ctxt->context->proximityPosition = 0;
13743: /*
13744: if (op->ch2 != -1)
13745: total +=
13746: xmlXPathCompOpEval(ctxt,
13747: &comp->steps[op->ch2]);
13748: CHECK_ERROR0;
13749: res = valuePop(ctxt);
13750: if (res != NULL)
13751: xmlXPathFreeObject(res);
13752: */
13753: valuePush(ctxt, obj);
13754: ctxt->context->node = oldnode;
13755: CHECK_ERROR0;
13756: } else {
13757: tmp = NULL;
13758: /*
13759: * Initialize the new set.
13760: * Also set the xpath document in case things like
13761: * key() evaluation are attempted on the predicate
13762: */
13763: newset = xmlXPathNodeSetCreate(NULL);
13764: /*
13765: * SPEC XPath 1.0:
13766: * "For each node in the node-set to be filtered, the
13767: * PredicateExpr is evaluated with that node as the
13768: * context node, with the number of nodes in the
13769: * node-set as the context size, and with the proximity
13770: * position of the node in the node-set with respect to
13771: * the axis as the context position;"
13772: * @oldset is the node-set" to be filtered.
13773: *
13774: * SPEC XPath 1.0:
13775: * "only predicates change the context position and
13776: * context size (see [2.4 Predicates])."
13777: * Example:
13778: * node-set context pos
13779: * nA 1
13780: * nB 2
13781: * nC 3
13782: * After applying predicate [position() > 1] :
13783: * node-set context pos
13784: * nB 1
13785: * nC 2
13786: *
13787: * removed the first node in the node-set, then
13788: * the context position of the
13789: */
13790: for (i = 0; i < oldset->nodeNr; i++) {
13791: /*
13792: * Run the evaluation with a node list made of
13793: * a single item in the nodeset.
13794: */
13795: ctxt->context->node = oldset->nodeTab[i];
13796: if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13797: (oldset->nodeTab[i]->doc != NULL))
13798: ctxt->context->doc = oldset->nodeTab[i]->doc;
13799: if (tmp == NULL) {
13800: tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13801: ctxt->context->node);
13802: } else {
13803: xmlXPathNodeSetAddUnique(tmp->nodesetval,
13804: ctxt->context->node);
13805: }
13806: valuePush(ctxt, tmp);
13807: ctxt->context->contextSize = oldset->nodeNr;
13808: ctxt->context->proximityPosition = i + 1;
13809: /*
13810: * Evaluate the predicate against the context node.
13811: * Can/should we optimize position() predicates
13812: * here (e.g. "[1]")?
13813: */
13814: if (op->ch2 != -1)
13815: total +=
13816: xmlXPathCompOpEval(ctxt,
13817: &comp->steps[op->ch2]);
13818: if (ctxt->error != XPATH_EXPRESSION_OK) {
13819: xmlXPathFreeNodeSet(newset);
13820: xmlXPathFreeObject(obj);
13821: return(0);
13822: }
13823:
13824: /*
13825: * The result of the evaluation needs to be tested to
13826: * decide whether the filter succeeded or not
13827: */
13828: /*
13829: * OPTIMIZE TODO: Can we use
13830: * xmlXPathNodeSetAdd*Unique()* instead?
13831: */
13832: res = valuePop(ctxt);
13833: if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13834: xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13835: }
13836:
13837: /*
13838: * Cleanup
13839: */
13840: if (res != NULL) {
13841: xmlXPathReleaseObject(ctxt->context, res);
13842: }
13843: if (ctxt->value == tmp) {
13844: valuePop(ctxt);
13845: xmlXPathNodeSetClear(tmp->nodesetval, 1);
13846: /*
13847: * Don't free the temporary nodeset
13848: * in order to avoid massive recreation inside this
13849: * loop.
13850: */
13851: } else
13852: tmp = NULL;
13853: ctxt->context->node = NULL;
13854: }
13855: if (tmp != NULL)
13856: xmlXPathReleaseObject(ctxt->context, tmp);
13857: /*
13858: * The result is used as the new evaluation set.
13859: */
13860: xmlXPathReleaseObject(ctxt->context, obj);
13861: ctxt->context->node = NULL;
13862: ctxt->context->contextSize = -1;
13863: ctxt->context->proximityPosition = -1;
13864: /* may want to move this past the '}' later */
13865: ctxt->context->doc = oldDoc;
13866: valuePush(ctxt,
13867: xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13868: }
13869: ctxt->context->node = oldnode;
13870: return (total);
13871: }
13872: case XPATH_OP_SORT:
13873: if (op->ch1 != -1)
13874: total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13875: CHECK_ERROR0;
13876: if ((ctxt->value != NULL) &&
13877: (ctxt->value->type == XPATH_NODESET) &&
13878: (ctxt->value->nodesetval != NULL) &&
13879: (ctxt->value->nodesetval->nodeNr > 1))
13880: {
13881: xmlXPathNodeSetSort(ctxt->value->nodesetval);
13882: }
13883: return (total);
13884: #ifdef LIBXML_XPTR_ENABLED
13885: case XPATH_OP_RANGETO:{
13886: xmlXPathObjectPtr range;
13887: xmlXPathObjectPtr res, obj;
13888: xmlXPathObjectPtr tmp;
13889: xmlLocationSetPtr newlocset = NULL;
13890: xmlLocationSetPtr oldlocset;
13891: xmlNodeSetPtr oldset;
13892: int i, j;
13893:
13894: if (op->ch1 != -1)
13895: total +=
13896: xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13897: if (op->ch2 == -1)
13898: return (total);
13899:
13900: if (ctxt->value->type == XPATH_LOCATIONSET) {
13901: /*
13902: * Extract the old locset, and then evaluate the result of the
13903: * expression for all the element in the locset. use it to grow
13904: * up a new locset.
13905: */
13906: CHECK_TYPE0(XPATH_LOCATIONSET);
13907: obj = valuePop(ctxt);
13908: oldlocset = obj->user;
13909:
13910: if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13911: ctxt->context->node = NULL;
13912: ctxt->context->contextSize = 0;
13913: ctxt->context->proximityPosition = 0;
13914: total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13915: res = valuePop(ctxt);
13916: if (res != NULL) {
13917: xmlXPathReleaseObject(ctxt->context, res);
13918: }
13919: valuePush(ctxt, obj);
13920: CHECK_ERROR0;
13921: return (total);
13922: }
13923: newlocset = xmlXPtrLocationSetCreate(NULL);
13924:
13925: for (i = 0; i < oldlocset->locNr; i++) {
13926: /*
13927: * Run the evaluation with a node list made of a
13928: * single item in the nodelocset.
13929: */
13930: ctxt->context->node = oldlocset->locTab[i]->user;
13931: ctxt->context->contextSize = oldlocset->locNr;
13932: ctxt->context->proximityPosition = i + 1;
13933: tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13934: ctxt->context->node);
13935: valuePush(ctxt, tmp);
13936:
13937: if (op->ch2 != -1)
13938: total +=
13939: xmlXPathCompOpEval(ctxt,
13940: &comp->steps[op->ch2]);
13941: if (ctxt->error != XPATH_EXPRESSION_OK) {
13942: xmlXPathFreeObject(obj);
13943: return(0);
13944: }
13945:
13946: res = valuePop(ctxt);
13947: if (res->type == XPATH_LOCATIONSET) {
13948: xmlLocationSetPtr rloc =
13949: (xmlLocationSetPtr)res->user;
13950: for (j=0; j<rloc->locNr; j++) {
13951: range = xmlXPtrNewRange(
13952: oldlocset->locTab[i]->user,
13953: oldlocset->locTab[i]->index,
13954: rloc->locTab[j]->user2,
13955: rloc->locTab[j]->index2);
13956: if (range != NULL) {
13957: xmlXPtrLocationSetAdd(newlocset, range);
13958: }
13959: }
13960: } else {
13961: range = xmlXPtrNewRangeNodeObject(
13962: (xmlNodePtr)oldlocset->locTab[i]->user, res);
13963: if (range != NULL) {
13964: xmlXPtrLocationSetAdd(newlocset,range);
13965: }
13966: }
13967:
13968: /*
13969: * Cleanup
13970: */
13971: if (res != NULL) {
13972: xmlXPathReleaseObject(ctxt->context, res);
13973: }
13974: if (ctxt->value == tmp) {
13975: res = valuePop(ctxt);
13976: xmlXPathReleaseObject(ctxt->context, res);
13977: }
13978:
13979: ctxt->context->node = NULL;
13980: }
13981: } else { /* Not a location set */
13982: CHECK_TYPE0(XPATH_NODESET);
13983: obj = valuePop(ctxt);
13984: oldset = obj->nodesetval;
13985: ctxt->context->node = NULL;
13986:
13987: newlocset = xmlXPtrLocationSetCreate(NULL);
13988:
13989: if (oldset != NULL) {
13990: for (i = 0; i < oldset->nodeNr; i++) {
13991: /*
13992: * Run the evaluation with a node list made of a single item
13993: * in the nodeset.
13994: */
13995: ctxt->context->node = oldset->nodeTab[i];
13996: /*
13997: * OPTIMIZE TODO: Avoid recreation for every iteration.
13998: */
13999: tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14000: ctxt->context->node);
14001: valuePush(ctxt, tmp);
14002:
14003: if (op->ch2 != -1)
14004: total +=
14005: xmlXPathCompOpEval(ctxt,
14006: &comp->steps[op->ch2]);
14007: if (ctxt->error != XPATH_EXPRESSION_OK) {
14008: xmlXPathFreeObject(obj);
14009: return(0);
14010: }
14011:
14012: res = valuePop(ctxt);
14013: range =
14014: xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
14015: res);
14016: if (range != NULL) {
14017: xmlXPtrLocationSetAdd(newlocset, range);
14018: }
14019:
14020: /*
14021: * Cleanup
14022: */
14023: if (res != NULL) {
14024: xmlXPathReleaseObject(ctxt->context, res);
14025: }
14026: if (ctxt->value == tmp) {
14027: res = valuePop(ctxt);
14028: xmlXPathReleaseObject(ctxt->context, res);
14029: }
14030:
14031: ctxt->context->node = NULL;
14032: }
14033: }
14034: }
14035:
14036: /*
14037: * The result is used as the new evaluation set.
14038: */
14039: xmlXPathReleaseObject(ctxt->context, obj);
14040: ctxt->context->node = NULL;
14041: ctxt->context->contextSize = -1;
14042: ctxt->context->proximityPosition = -1;
14043: valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
14044: return (total);
14045: }
14046: #endif /* LIBXML_XPTR_ENABLED */
14047: }
14048: xmlGenericError(xmlGenericErrorContext,
14049: "XPath: unknown precompiled operation %d\n", op->op);
1.1.1.2 ! misho 14050: ctxt->error = XPATH_INVALID_OPERAND;
1.1 misho 14051: return (total);
14052: }
14053:
14054: /**
14055: * xmlXPathCompOpEvalToBoolean:
14056: * @ctxt: the XPath parser context
14057: *
14058: * Evaluates if the expression evaluates to true.
14059: *
14060: * Returns 1 if true, 0 if false and -1 on API or internal errors.
14061: */
14062: static int
14063: xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
14064: xmlXPathStepOpPtr op,
14065: int isPredicate)
14066: {
14067: xmlXPathObjectPtr resObj = NULL;
14068:
14069: start:
14070: /* comp = ctxt->comp; */
14071: switch (op->op) {
14072: case XPATH_OP_END:
14073: return (0);
14074: case XPATH_OP_VALUE:
14075: resObj = (xmlXPathObjectPtr) op->value4;
14076: if (isPredicate)
14077: return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14078: return(xmlXPathCastToBoolean(resObj));
14079: case XPATH_OP_SORT:
14080: /*
14081: * We don't need sorting for boolean results. Skip this one.
14082: */
14083: if (op->ch1 != -1) {
14084: op = &ctxt->comp->steps[op->ch1];
14085: goto start;
14086: }
14087: return(0);
14088: case XPATH_OP_COLLECT:
14089: if (op->ch1 == -1)
14090: return(0);
14091:
14092: xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14093: if (ctxt->error != XPATH_EXPRESSION_OK)
14094: return(-1);
14095:
14096: xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14097: if (ctxt->error != XPATH_EXPRESSION_OK)
14098: return(-1);
14099:
14100: resObj = valuePop(ctxt);
14101: if (resObj == NULL)
14102: return(-1);
14103: break;
14104: default:
14105: /*
14106: * Fallback to call xmlXPathCompOpEval().
14107: */
14108: xmlXPathCompOpEval(ctxt, op);
14109: if (ctxt->error != XPATH_EXPRESSION_OK)
14110: return(-1);
14111:
14112: resObj = valuePop(ctxt);
14113: if (resObj == NULL)
14114: return(-1);
14115: break;
14116: }
14117:
14118: if (resObj) {
14119: int res;
14120:
14121: if (resObj->type == XPATH_BOOLEAN) {
14122: res = resObj->boolval;
14123: } else if (isPredicate) {
14124: /*
14125: * For predicates a result of type "number" is handled
14126: * differently:
14127: * SPEC XPath 1.0:
14128: * "If the result is a number, the result will be converted
14129: * to true if the number is equal to the context position
14130: * and will be converted to false otherwise;"
14131: */
14132: res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14133: } else {
14134: res = xmlXPathCastToBoolean(resObj);
14135: }
14136: xmlXPathReleaseObject(ctxt->context, resObj);
14137: return(res);
14138: }
14139:
14140: return(0);
14141: }
14142:
14143: #ifdef XPATH_STREAMING
14144: /**
14145: * xmlXPathRunStreamEval:
14146: * @ctxt: the XPath parser context with the compiled expression
14147: *
14148: * Evaluate the Precompiled Streamable XPath expression in the given context.
14149: */
14150: static int
14151: xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14152: xmlXPathObjectPtr *resultSeq, int toBool)
14153: {
14154: int max_depth, min_depth;
14155: int from_root;
14156: int ret, depth;
14157: int eval_all_nodes;
14158: xmlNodePtr cur = NULL, limit = NULL;
14159: xmlStreamCtxtPtr patstream = NULL;
14160:
14161: int nb_nodes = 0;
14162:
14163: if ((ctxt == NULL) || (comp == NULL))
14164: return(-1);
14165: max_depth = xmlPatternMaxDepth(comp);
14166: if (max_depth == -1)
14167: return(-1);
14168: if (max_depth == -2)
14169: max_depth = 10000;
14170: min_depth = xmlPatternMinDepth(comp);
14171: if (min_depth == -1)
14172: return(-1);
14173: from_root = xmlPatternFromRoot(comp);
14174: if (from_root < 0)
14175: return(-1);
14176: #if 0
14177: printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14178: #endif
14179:
14180: if (! toBool) {
14181: if (resultSeq == NULL)
14182: return(-1);
14183: *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14184: if (*resultSeq == NULL)
14185: return(-1);
14186: }
14187:
14188: /*
14189: * handle the special cases of "/" amd "." being matched
14190: */
14191: if (min_depth == 0) {
14192: if (from_root) {
14193: /* Select "/" */
14194: if (toBool)
14195: return(1);
14196: xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14197: (xmlNodePtr) ctxt->doc);
14198: } else {
14199: /* Select "self::node()" */
14200: if (toBool)
14201: return(1);
14202: xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14203: }
14204: }
14205: if (max_depth == 0) {
14206: return(0);
14207: }
14208:
14209: if (from_root) {
14210: cur = (xmlNodePtr)ctxt->doc;
14211: } else if (ctxt->node != NULL) {
14212: switch (ctxt->node->type) {
14213: case XML_ELEMENT_NODE:
14214: case XML_DOCUMENT_NODE:
14215: case XML_DOCUMENT_FRAG_NODE:
14216: case XML_HTML_DOCUMENT_NODE:
14217: #ifdef LIBXML_DOCB_ENABLED
14218: case XML_DOCB_DOCUMENT_NODE:
14219: #endif
14220: cur = ctxt->node;
14221: break;
14222: case XML_ATTRIBUTE_NODE:
14223: case XML_TEXT_NODE:
14224: case XML_CDATA_SECTION_NODE:
14225: case XML_ENTITY_REF_NODE:
14226: case XML_ENTITY_NODE:
14227: case XML_PI_NODE:
14228: case XML_COMMENT_NODE:
14229: case XML_NOTATION_NODE:
14230: case XML_DTD_NODE:
14231: case XML_DOCUMENT_TYPE_NODE:
14232: case XML_ELEMENT_DECL:
14233: case XML_ATTRIBUTE_DECL:
14234: case XML_ENTITY_DECL:
14235: case XML_NAMESPACE_DECL:
14236: case XML_XINCLUDE_START:
14237: case XML_XINCLUDE_END:
14238: break;
14239: }
14240: limit = cur;
14241: }
14242: if (cur == NULL) {
14243: return(0);
14244: }
14245:
14246: patstream = xmlPatternGetStreamCtxt(comp);
14247: if (patstream == NULL) {
14248: /*
14249: * QUESTION TODO: Is this an error?
14250: */
14251: return(0);
14252: }
14253:
14254: eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14255:
14256: if (from_root) {
14257: ret = xmlStreamPush(patstream, NULL, NULL);
14258: if (ret < 0) {
14259: } else if (ret == 1) {
14260: if (toBool)
14261: goto return_1;
14262: xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14263: }
14264: }
14265: depth = 0;
14266: goto scan_children;
14267: next_node:
14268: do {
14269: nb_nodes++;
14270:
14271: switch (cur->type) {
14272: case XML_ELEMENT_NODE:
14273: case XML_TEXT_NODE:
14274: case XML_CDATA_SECTION_NODE:
14275: case XML_COMMENT_NODE:
14276: case XML_PI_NODE:
14277: if (cur->type == XML_ELEMENT_NODE) {
14278: ret = xmlStreamPush(patstream, cur->name,
14279: (cur->ns ? cur->ns->href : NULL));
14280: } else if (eval_all_nodes)
14281: ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14282: else
14283: break;
14284:
14285: if (ret < 0) {
14286: /* NOP. */
14287: } else if (ret == 1) {
14288: if (toBool)
14289: goto return_1;
14290: xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14291: }
14292: if ((cur->children == NULL) || (depth >= max_depth)) {
14293: ret = xmlStreamPop(patstream);
14294: while (cur->next != NULL) {
14295: cur = cur->next;
14296: if ((cur->type != XML_ENTITY_DECL) &&
14297: (cur->type != XML_DTD_NODE))
14298: goto next_node;
14299: }
14300: }
14301: default:
14302: break;
14303: }
14304:
14305: scan_children:
14306: if ((cur->children != NULL) && (depth < max_depth)) {
14307: /*
14308: * Do not descend on entities declarations
14309: */
14310: if (cur->children->type != XML_ENTITY_DECL) {
14311: cur = cur->children;
14312: depth++;
14313: /*
14314: * Skip DTDs
14315: */
14316: if (cur->type != XML_DTD_NODE)
14317: continue;
14318: }
14319: }
14320:
14321: if (cur == limit)
14322: break;
14323:
14324: while (cur->next != NULL) {
14325: cur = cur->next;
14326: if ((cur->type != XML_ENTITY_DECL) &&
14327: (cur->type != XML_DTD_NODE))
14328: goto next_node;
14329: }
14330:
14331: do {
14332: cur = cur->parent;
14333: depth--;
14334: if ((cur == NULL) || (cur == limit))
14335: goto done;
14336: if (cur->type == XML_ELEMENT_NODE) {
14337: ret = xmlStreamPop(patstream);
14338: } else if ((eval_all_nodes) &&
14339: ((cur->type == XML_TEXT_NODE) ||
14340: (cur->type == XML_CDATA_SECTION_NODE) ||
14341: (cur->type == XML_COMMENT_NODE) ||
14342: (cur->type == XML_PI_NODE)))
14343: {
14344: ret = xmlStreamPop(patstream);
14345: }
14346: if (cur->next != NULL) {
14347: cur = cur->next;
14348: break;
14349: }
14350: } while (cur != NULL);
14351:
14352: } while ((cur != NULL) && (depth >= 0));
14353:
14354: done:
14355:
14356: #if 0
14357: printf("stream eval: checked %d nodes selected %d\n",
14358: nb_nodes, retObj->nodesetval->nodeNr);
14359: #endif
14360:
14361: if (patstream)
14362: xmlFreeStreamCtxt(patstream);
14363: return(0);
14364:
14365: return_1:
14366: if (patstream)
14367: xmlFreeStreamCtxt(patstream);
14368: return(1);
14369: }
14370: #endif /* XPATH_STREAMING */
14371:
14372: /**
14373: * xmlXPathRunEval:
14374: * @ctxt: the XPath parser context with the compiled expression
14375: * @toBool: evaluate to a boolean result
14376: *
14377: * Evaluate the Precompiled XPath expression in the given context.
14378: */
14379: static int
14380: xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14381: {
14382: xmlXPathCompExprPtr comp;
14383:
14384: if ((ctxt == NULL) || (ctxt->comp == NULL))
14385: return(-1);
14386:
14387: if (ctxt->valueTab == NULL) {
14388: /* Allocate the value stack */
14389: ctxt->valueTab = (xmlXPathObjectPtr *)
14390: xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14391: if (ctxt->valueTab == NULL) {
14392: xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14393: xmlFree(ctxt);
14394: }
14395: ctxt->valueNr = 0;
14396: ctxt->valueMax = 10;
14397: ctxt->value = NULL;
1.1.1.2 ! misho 14398: ctxt->valueFrame = 0;
1.1 misho 14399: }
14400: #ifdef XPATH_STREAMING
14401: if (ctxt->comp->stream) {
14402: int res;
14403:
14404: if (toBool) {
14405: /*
14406: * Evaluation to boolean result.
14407: */
14408: res = xmlXPathRunStreamEval(ctxt->context,
14409: ctxt->comp->stream, NULL, 1);
14410: if (res != -1)
14411: return(res);
14412: } else {
14413: xmlXPathObjectPtr resObj = NULL;
14414:
14415: /*
14416: * Evaluation to a sequence.
14417: */
14418: res = xmlXPathRunStreamEval(ctxt->context,
14419: ctxt->comp->stream, &resObj, 0);
14420:
14421: if ((res != -1) && (resObj != NULL)) {
14422: valuePush(ctxt, resObj);
14423: return(0);
14424: }
14425: if (resObj != NULL)
14426: xmlXPathReleaseObject(ctxt->context, resObj);
14427: }
14428: /*
14429: * QUESTION TODO: This falls back to normal XPath evaluation
14430: * if res == -1. Is this intended?
14431: */
14432: }
14433: #endif
14434: comp = ctxt->comp;
14435: if (comp->last < 0) {
14436: xmlGenericError(xmlGenericErrorContext,
14437: "xmlXPathRunEval: last is less than zero\n");
14438: return(-1);
14439: }
14440: if (toBool)
14441: return(xmlXPathCompOpEvalToBoolean(ctxt,
14442: &comp->steps[comp->last], 0));
14443: else
14444: xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14445:
14446: return(0);
14447: }
14448:
14449: /************************************************************************
14450: * *
14451: * Public interfaces *
14452: * *
14453: ************************************************************************/
14454:
14455: /**
14456: * xmlXPathEvalPredicate:
14457: * @ctxt: the XPath context
14458: * @res: the Predicate Expression evaluation result
14459: *
14460: * Evaluate a predicate result for the current node.
14461: * A PredicateExpr is evaluated by evaluating the Expr and converting
14462: * the result to a boolean. If the result is a number, the result will
14463: * be converted to true if the number is equal to the position of the
14464: * context node in the context node list (as returned by the position
14465: * function) and will be converted to false otherwise; if the result
14466: * is not a number, then the result will be converted as if by a call
14467: * to the boolean function.
14468: *
14469: * Returns 1 if predicate is true, 0 otherwise
14470: */
14471: int
14472: xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14473: if ((ctxt == NULL) || (res == NULL)) return(0);
14474: switch (res->type) {
14475: case XPATH_BOOLEAN:
14476: return(res->boolval);
14477: case XPATH_NUMBER:
14478: return(res->floatval == ctxt->proximityPosition);
14479: case XPATH_NODESET:
14480: case XPATH_XSLT_TREE:
14481: if (res->nodesetval == NULL)
14482: return(0);
14483: return(res->nodesetval->nodeNr != 0);
14484: case XPATH_STRING:
14485: return((res->stringval != NULL) &&
14486: (xmlStrlen(res->stringval) != 0));
14487: default:
14488: STRANGE
14489: }
14490: return(0);
14491: }
14492:
14493: /**
14494: * xmlXPathEvaluatePredicateResult:
14495: * @ctxt: the XPath Parser context
14496: * @res: the Predicate Expression evaluation result
14497: *
14498: * Evaluate a predicate result for the current node.
14499: * A PredicateExpr is evaluated by evaluating the Expr and converting
14500: * the result to a boolean. If the result is a number, the result will
14501: * be converted to true if the number is equal to the position of the
14502: * context node in the context node list (as returned by the position
14503: * function) and will be converted to false otherwise; if the result
14504: * is not a number, then the result will be converted as if by a call
14505: * to the boolean function.
14506: *
14507: * Returns 1 if predicate is true, 0 otherwise
14508: */
14509: int
14510: xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14511: xmlXPathObjectPtr res) {
14512: if ((ctxt == NULL) || (res == NULL)) return(0);
14513: switch (res->type) {
14514: case XPATH_BOOLEAN:
14515: return(res->boolval);
14516: case XPATH_NUMBER:
14517: #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14518: return((res->floatval == ctxt->context->proximityPosition) &&
14519: (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14520: #else
14521: return(res->floatval == ctxt->context->proximityPosition);
14522: #endif
14523: case XPATH_NODESET:
14524: case XPATH_XSLT_TREE:
14525: if (res->nodesetval == NULL)
14526: return(0);
14527: return(res->nodesetval->nodeNr != 0);
14528: case XPATH_STRING:
14529: return((res->stringval != NULL) && (res->stringval[0] != 0));
14530: #ifdef LIBXML_XPTR_ENABLED
14531: case XPATH_LOCATIONSET:{
14532: xmlLocationSetPtr ptr = res->user;
14533: if (ptr == NULL)
14534: return(0);
14535: return (ptr->locNr != 0);
14536: }
14537: #endif
14538: default:
14539: STRANGE
14540: }
14541: return(0);
14542: }
14543:
14544: #ifdef XPATH_STREAMING
14545: /**
14546: * xmlXPathTryStreamCompile:
14547: * @ctxt: an XPath context
14548: * @str: the XPath expression
14549: *
14550: * Try to compile the XPath expression as a streamable subset.
14551: *
14552: * Returns the compiled expression or NULL if failed to compile.
14553: */
14554: static xmlXPathCompExprPtr
14555: xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14556: /*
14557: * Optimization: use streaming patterns when the XPath expression can
14558: * be compiled to a stream lookup
14559: */
14560: xmlPatternPtr stream;
14561: xmlXPathCompExprPtr comp;
14562: xmlDictPtr dict = NULL;
14563: const xmlChar **namespaces = NULL;
14564: xmlNsPtr ns;
14565: int i, j;
14566:
14567: if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14568: (!xmlStrchr(str, '@'))) {
14569: const xmlChar *tmp;
14570:
14571: /*
14572: * We don't try to handle expressions using the verbose axis
14573: * specifiers ("::"), just the simplied form at this point.
14574: * Additionally, if there is no list of namespaces available and
14575: * there's a ":" in the expression, indicating a prefixed QName,
14576: * then we won't try to compile either. xmlPatterncompile() needs
14577: * to have a list of namespaces at compilation time in order to
14578: * compile prefixed name tests.
14579: */
14580: tmp = xmlStrchr(str, ':');
14581: if ((tmp != NULL) &&
14582: ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14583: return(NULL);
14584:
14585: if (ctxt != NULL) {
14586: dict = ctxt->dict;
14587: if (ctxt->nsNr > 0) {
14588: namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14589: if (namespaces == NULL) {
14590: xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14591: return(NULL);
14592: }
14593: for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14594: ns = ctxt->namespaces[j];
14595: namespaces[i++] = ns->href;
14596: namespaces[i++] = ns->prefix;
14597: }
14598: namespaces[i++] = NULL;
14599: namespaces[i] = NULL;
14600: }
14601: }
14602:
14603: stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14604: &namespaces[0]);
14605: if (namespaces != NULL) {
14606: xmlFree((xmlChar **)namespaces);
14607: }
14608: if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14609: comp = xmlXPathNewCompExpr();
14610: if (comp == NULL) {
14611: xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14612: return(NULL);
14613: }
14614: comp->stream = stream;
14615: comp->dict = dict;
14616: if (comp->dict)
14617: xmlDictReference(comp->dict);
14618: return(comp);
14619: }
14620: xmlFreePattern(stream);
14621: }
14622: return(NULL);
14623: }
14624: #endif /* XPATH_STREAMING */
14625:
14626: static int
14627: xmlXPathCanRewriteDosExpression(xmlChar *expr)
14628: {
14629: if (expr == NULL)
14630: return(0);
14631: do {
14632: if ((*expr == '/') && (*(++expr) == '/'))
14633: return(1);
14634: } while (*expr++);
14635: return(0);
14636: }
14637: static void
14638: xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14639: {
14640: /*
14641: * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14642: * internal representation.
14643: */
14644: if (op->ch1 != -1) {
14645: if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14646: ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
14647: ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14648: ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14649: {
14650: /*
14651: * This is a "child::foo"
14652: */
14653: xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14654:
14655: if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14656: (prevop->ch1 != -1) &&
14657: ((xmlXPathAxisVal) prevop->value ==
14658: AXIS_DESCENDANT_OR_SELF) &&
14659: (prevop->ch2 == -1) &&
14660: ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14661: ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
14662: (comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
14663: {
14664: /*
14665: * This is a "/descendant-or-self::node()" without predicates.
14666: * Eliminate it.
14667: */
14668: op->ch1 = prevop->ch1;
14669: op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
14670: }
14671: }
14672: if (op->ch1 != -1)
14673: xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14674: }
14675: if (op->ch2 != -1)
14676: xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14677: }
14678:
14679: /**
14680: * xmlXPathCtxtCompile:
14681: * @ctxt: an XPath context
14682: * @str: the XPath expression
14683: *
14684: * Compile an XPath expression
14685: *
14686: * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14687: * the caller has to free the object.
14688: */
14689: xmlXPathCompExprPtr
14690: xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14691: xmlXPathParserContextPtr pctxt;
14692: xmlXPathCompExprPtr comp;
14693:
14694: #ifdef XPATH_STREAMING
14695: comp = xmlXPathTryStreamCompile(ctxt, str);
14696: if (comp != NULL)
14697: return(comp);
14698: #endif
14699:
14700: xmlXPathInit();
14701:
14702: pctxt = xmlXPathNewParserContext(str, ctxt);
14703: if (pctxt == NULL)
14704: return NULL;
14705: xmlXPathCompileExpr(pctxt, 1);
14706:
14707: if( pctxt->error != XPATH_EXPRESSION_OK )
14708: {
14709: xmlXPathFreeParserContext(pctxt);
14710: return(NULL);
14711: }
14712:
14713: if (*pctxt->cur != 0) {
14714: /*
14715: * aleksey: in some cases this line prints *second* error message
14716: * (see bug #78858) and probably this should be fixed.
14717: * However, we are not sure that all error messages are printed
14718: * out in other places. It's not critical so we leave it as-is for now
14719: */
14720: xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14721: comp = NULL;
14722: } else {
14723: comp = pctxt->comp;
14724: pctxt->comp = NULL;
14725: }
14726: xmlXPathFreeParserContext(pctxt);
14727:
14728: if (comp != NULL) {
14729: comp->expr = xmlStrdup(str);
14730: #ifdef DEBUG_EVAL_COUNTS
14731: comp->string = xmlStrdup(str);
14732: comp->nb = 0;
14733: #endif
14734: if ((comp->expr != NULL) &&
14735: (comp->nbStep > 2) &&
14736: (comp->last >= 0) &&
14737: (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14738: {
14739: xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
14740: }
14741: }
14742: return(comp);
14743: }
14744:
14745: /**
14746: * xmlXPathCompile:
14747: * @str: the XPath expression
14748: *
14749: * Compile an XPath expression
14750: *
14751: * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14752: * the caller has to free the object.
14753: */
14754: xmlXPathCompExprPtr
14755: xmlXPathCompile(const xmlChar *str) {
14756: return(xmlXPathCtxtCompile(NULL, str));
14757: }
14758:
14759: /**
14760: * xmlXPathCompiledEvalInternal:
14761: * @comp: the compiled XPath expression
14762: * @ctxt: the XPath context
14763: * @resObj: the resulting XPath object or NULL
14764: * @toBool: 1 if only a boolean result is requested
14765: *
14766: * Evaluate the Precompiled XPath expression in the given context.
14767: * The caller has to free @resObj.
14768: *
14769: * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14770: * the caller has to free the object.
14771: */
14772: static int
14773: xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14774: xmlXPathContextPtr ctxt,
14775: xmlXPathObjectPtr *resObj,
14776: int toBool)
14777: {
14778: xmlXPathParserContextPtr pctxt;
14779: #ifndef LIBXML_THREAD_ENABLED
14780: static int reentance = 0;
14781: #endif
14782: int res;
14783:
14784: CHECK_CTXT_NEG(ctxt)
14785:
14786: if (comp == NULL)
14787: return(-1);
14788: xmlXPathInit();
14789:
14790: #ifndef LIBXML_THREAD_ENABLED
14791: reentance++;
14792: if (reentance > 1)
14793: xmlXPathDisableOptimizer = 1;
14794: #endif
14795:
14796: #ifdef DEBUG_EVAL_COUNTS
14797: comp->nb++;
14798: if ((comp->string != NULL) && (comp->nb > 100)) {
14799: fprintf(stderr, "100 x %s\n", comp->string);
14800: comp->nb = 0;
14801: }
14802: #endif
14803: pctxt = xmlXPathCompParserContext(comp, ctxt);
14804: res = xmlXPathRunEval(pctxt, toBool);
14805:
14806: if (resObj) {
14807: if (pctxt->value == NULL) {
14808: xmlGenericError(xmlGenericErrorContext,
14809: "xmlXPathCompiledEval: evaluation failed\n");
14810: *resObj = NULL;
14811: } else {
14812: *resObj = valuePop(pctxt);
14813: }
14814: }
14815:
14816: /*
14817: * Pop all remaining objects from the stack.
14818: */
14819: if (pctxt->valueNr > 0) {
14820: xmlXPathObjectPtr tmp;
14821: int stack = 0;
14822:
14823: do {
14824: tmp = valuePop(pctxt);
14825: if (tmp != NULL) {
14826: stack++;
14827: xmlXPathReleaseObject(ctxt, tmp);
14828: }
14829: } while (tmp != NULL);
14830: if ((stack != 0) &&
14831: ((toBool) || ((resObj) && (*resObj))))
14832: {
14833: xmlGenericError(xmlGenericErrorContext,
14834: "xmlXPathCompiledEval: %d objects left on the stack.\n",
14835: stack);
14836: }
14837: }
14838:
14839: if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14840: xmlXPathFreeObject(*resObj);
14841: *resObj = NULL;
14842: }
14843: pctxt->comp = NULL;
14844: xmlXPathFreeParserContext(pctxt);
14845: #ifndef LIBXML_THREAD_ENABLED
14846: reentance--;
14847: #endif
14848:
14849: return(res);
14850: }
14851:
14852: /**
14853: * xmlXPathCompiledEval:
14854: * @comp: the compiled XPath expression
14855: * @ctx: the XPath context
14856: *
14857: * Evaluate the Precompiled XPath expression in the given context.
14858: *
14859: * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14860: * the caller has to free the object.
14861: */
14862: xmlXPathObjectPtr
14863: xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14864: {
14865: xmlXPathObjectPtr res = NULL;
14866:
14867: xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14868: return(res);
14869: }
14870:
14871: /**
14872: * xmlXPathCompiledEvalToBoolean:
14873: * @comp: the compiled XPath expression
14874: * @ctxt: the XPath context
14875: *
14876: * Applies the XPath boolean() function on the result of the given
14877: * compiled expression.
14878: *
14879: * Returns 1 if the expression evaluated to true, 0 if to false and
14880: * -1 in API and internal errors.
14881: */
14882: int
14883: xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14884: xmlXPathContextPtr ctxt)
14885: {
14886: return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14887: }
14888:
14889: /**
14890: * xmlXPathEvalExpr:
14891: * @ctxt: the XPath Parser context
14892: *
14893: * Parse and evaluate an XPath expression in the given context,
14894: * then push the result on the context stack
14895: */
14896: void
14897: xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14898: #ifdef XPATH_STREAMING
14899: xmlXPathCompExprPtr comp;
14900: #endif
14901:
14902: if (ctxt == NULL) return;
14903:
14904: #ifdef XPATH_STREAMING
14905: comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14906: if (comp != NULL) {
14907: if (ctxt->comp != NULL)
14908: xmlXPathFreeCompExpr(ctxt->comp);
14909: ctxt->comp = comp;
14910: if (ctxt->cur != NULL)
14911: while (*ctxt->cur != 0) ctxt->cur++;
14912: } else
14913: #endif
14914: {
14915: xmlXPathCompileExpr(ctxt, 1);
14916: /*
14917: * In this scenario the expression string will sit in ctxt->base.
14918: */
14919: if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14920: (ctxt->comp != NULL) &&
14921: (ctxt->base != NULL) &&
14922: (ctxt->comp->nbStep > 2) &&
14923: (ctxt->comp->last >= 0) &&
14924: (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
14925: {
14926: xmlXPathRewriteDOSExpression(ctxt->comp,
14927: &ctxt->comp->steps[ctxt->comp->last]);
14928: }
14929: }
14930: CHECK_ERROR;
14931: xmlXPathRunEval(ctxt, 0);
14932: }
14933:
14934: /**
14935: * xmlXPathEval:
14936: * @str: the XPath expression
14937: * @ctx: the XPath context
14938: *
14939: * Evaluate the XPath Location Path in the given context.
14940: *
14941: * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14942: * the caller has to free the object.
14943: */
14944: xmlXPathObjectPtr
14945: xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14946: xmlXPathParserContextPtr ctxt;
14947: xmlXPathObjectPtr res, tmp, init = NULL;
14948: int stack = 0;
14949:
14950: CHECK_CTXT(ctx)
14951:
14952: xmlXPathInit();
14953:
14954: ctxt = xmlXPathNewParserContext(str, ctx);
14955: if (ctxt == NULL)
14956: return NULL;
14957: xmlXPathEvalExpr(ctxt);
14958:
14959: if (ctxt->value == NULL) {
14960: xmlGenericError(xmlGenericErrorContext,
14961: "xmlXPathEval: evaluation failed\n");
14962: res = NULL;
14963: } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
14964: #ifdef XPATH_STREAMING
14965: && (ctxt->comp->stream == NULL)
14966: #endif
14967: ) {
14968: xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14969: res = NULL;
14970: } else {
14971: res = valuePop(ctxt);
14972: }
14973:
14974: do {
14975: tmp = valuePop(ctxt);
14976: if (tmp != NULL) {
14977: if (tmp != init)
14978: stack++;
14979: xmlXPathReleaseObject(ctx, tmp);
14980: }
14981: } while (tmp != NULL);
14982: if ((stack != 0) && (res != NULL)) {
14983: xmlGenericError(xmlGenericErrorContext,
14984: "xmlXPathEval: %d object left on the stack\n",
14985: stack);
14986: }
14987: if (ctxt->error != XPATH_EXPRESSION_OK) {
14988: xmlXPathFreeObject(res);
14989: res = NULL;
14990: }
14991:
14992: xmlXPathFreeParserContext(ctxt);
14993: return(res);
14994: }
14995:
14996: /**
14997: * xmlXPathEvalExpression:
14998: * @str: the XPath expression
14999: * @ctxt: the XPath context
15000: *
15001: * Evaluate the XPath expression in the given context.
15002: *
15003: * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15004: * the caller has to free the object.
15005: */
15006: xmlXPathObjectPtr
15007: xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
15008: xmlXPathParserContextPtr pctxt;
15009: xmlXPathObjectPtr res, tmp;
15010: int stack = 0;
15011:
15012: CHECK_CTXT(ctxt)
15013:
15014: xmlXPathInit();
15015:
15016: pctxt = xmlXPathNewParserContext(str, ctxt);
15017: if (pctxt == NULL)
15018: return NULL;
15019: xmlXPathEvalExpr(pctxt);
15020:
15021: if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
15022: xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
15023: res = NULL;
15024: } else {
15025: res = valuePop(pctxt);
15026: }
15027: do {
15028: tmp = valuePop(pctxt);
15029: if (tmp != NULL) {
15030: xmlXPathReleaseObject(ctxt, tmp);
15031: stack++;
15032: }
15033: } while (tmp != NULL);
15034: if ((stack != 0) && (res != NULL)) {
15035: xmlGenericError(xmlGenericErrorContext,
15036: "xmlXPathEvalExpression: %d object left on the stack\n",
15037: stack);
15038: }
15039: xmlXPathFreeParserContext(pctxt);
15040: return(res);
15041: }
15042:
15043: /************************************************************************
15044: * *
15045: * Extra functions not pertaining to the XPath spec *
15046: * *
15047: ************************************************************************/
15048: /**
15049: * xmlXPathEscapeUriFunction:
15050: * @ctxt: the XPath Parser context
15051: * @nargs: the number of arguments
15052: *
15053: * Implement the escape-uri() XPath function
15054: * string escape-uri(string $str, bool $escape-reserved)
15055: *
15056: * This function applies the URI escaping rules defined in section 2 of [RFC
15057: * 2396] to the string supplied as $uri-part, which typically represents all
15058: * or part of a URI. The effect of the function is to replace any special
15059: * character in the string by an escape sequence of the form %xx%yy...,
15060: * where xxyy... is the hexadecimal representation of the octets used to
15061: * represent the character in UTF-8.
15062: *
15063: * The set of characters that are escaped depends on the setting of the
15064: * boolean argument $escape-reserved.
15065: *
15066: * If $escape-reserved is true, all characters are escaped other than lower
15067: * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15068: * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15069: * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15070: * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15071: * A-F).
15072: *
15073: * If $escape-reserved is false, the behavior differs in that characters
15074: * referred to in [RFC 2396] as reserved characters are not escaped. These
15075: * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
15076: *
15077: * [RFC 2396] does not define whether escaped URIs should use lower case or
15078: * upper case for hexadecimal digits. To ensure that escaped URIs can be
15079: * compared using string comparison functions, this function must always use
15080: * the upper-case letters A-F.
15081: *
15082: * Generally, $escape-reserved should be set to true when escaping a string
15083: * that is to form a single part of a URI, and to false when escaping an
15084: * entire URI or URI reference.
15085: *
15086: * In the case of non-ascii characters, the string is encoded according to
15087: * utf-8 and then converted according to RFC 2396.
15088: *
15089: * Examples
15090: * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
15091: * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15092: * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15093: * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15094: *
15095: */
15096: static void
15097: xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15098: xmlXPathObjectPtr str;
15099: int escape_reserved;
15100: xmlBufferPtr target;
15101: xmlChar *cptr;
15102: xmlChar escape[4];
15103:
15104: CHECK_ARITY(2);
15105:
15106: escape_reserved = xmlXPathPopBoolean(ctxt);
15107:
15108: CAST_TO_STRING;
15109: str = valuePop(ctxt);
15110:
15111: target = xmlBufferCreate();
15112:
15113: escape[0] = '%';
15114: escape[3] = 0;
15115:
15116: if (target) {
15117: for (cptr = str->stringval; *cptr; cptr++) {
15118: if ((*cptr >= 'A' && *cptr <= 'Z') ||
15119: (*cptr >= 'a' && *cptr <= 'z') ||
15120: (*cptr >= '0' && *cptr <= '9') ||
15121: *cptr == '-' || *cptr == '_' || *cptr == '.' ||
15122: *cptr == '!' || *cptr == '~' || *cptr == '*' ||
15123: *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
15124: (*cptr == '%' &&
15125: ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15126: (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15127: (cptr[1] >= '0' && cptr[1] <= '9')) &&
15128: ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15129: (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15130: (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15131: (!escape_reserved &&
15132: (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15133: *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15134: *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15135: *cptr == ','))) {
15136: xmlBufferAdd(target, cptr, 1);
15137: } else {
15138: if ((*cptr >> 4) < 10)
15139: escape[1] = '0' + (*cptr >> 4);
15140: else
15141: escape[1] = 'A' - 10 + (*cptr >> 4);
15142: if ((*cptr & 0xF) < 10)
15143: escape[2] = '0' + (*cptr & 0xF);
15144: else
15145: escape[2] = 'A' - 10 + (*cptr & 0xF);
15146:
15147: xmlBufferAdd(target, &escape[0], 3);
15148: }
15149: }
15150: }
15151: valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15152: xmlBufferContent(target)));
15153: xmlBufferFree(target);
15154: xmlXPathReleaseObject(ctxt->context, str);
15155: }
15156:
15157: /**
15158: * xmlXPathRegisterAllFunctions:
15159: * @ctxt: the XPath context
15160: *
15161: * Registers all default XPath functions in this context
15162: */
15163: void
15164: xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15165: {
15166: xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15167: xmlXPathBooleanFunction);
15168: xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15169: xmlXPathCeilingFunction);
15170: xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15171: xmlXPathCountFunction);
15172: xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15173: xmlXPathConcatFunction);
15174: xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15175: xmlXPathContainsFunction);
15176: xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15177: xmlXPathIdFunction);
15178: xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15179: xmlXPathFalseFunction);
15180: xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15181: xmlXPathFloorFunction);
15182: xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15183: xmlXPathLastFunction);
15184: xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15185: xmlXPathLangFunction);
15186: xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15187: xmlXPathLocalNameFunction);
15188: xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15189: xmlXPathNotFunction);
15190: xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15191: xmlXPathNameFunction);
15192: xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15193: xmlXPathNamespaceURIFunction);
15194: xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15195: xmlXPathNormalizeFunction);
15196: xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15197: xmlXPathNumberFunction);
15198: xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15199: xmlXPathPositionFunction);
15200: xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15201: xmlXPathRoundFunction);
15202: xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15203: xmlXPathStringFunction);
15204: xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15205: xmlXPathStringLengthFunction);
15206: xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15207: xmlXPathStartsWithFunction);
15208: xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15209: xmlXPathSubstringFunction);
15210: xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15211: xmlXPathSubstringBeforeFunction);
15212: xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15213: xmlXPathSubstringAfterFunction);
15214: xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15215: xmlXPathSumFunction);
15216: xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15217: xmlXPathTrueFunction);
15218: xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15219: xmlXPathTranslateFunction);
15220:
15221: xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15222: (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15223: xmlXPathEscapeUriFunction);
15224: }
15225:
15226: #endif /* LIBXML_XPATH_ENABLED */
15227: #define bottom_xpath
15228: #include "elfgcchack.h"
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>