blob: ce46c499473933de5f5452ae0d807889aba9f163 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
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
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005 *f
Owen Taylor3473f882001-02-23 17:55:21 +00006 * 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 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011 * See Copyright for the status of this software
Owen Taylor3473f882001-02-23 17:55:21 +000012 *
Daniel Veillardc5d64342001-06-24 12:13:24 +000013 * Author: daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000014 *
Owen Taylor3473f882001-02-23 17:55:21 +000015 */
16
Daniel Veillard34ce8be2002-03-18 19:37:11 +000017#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000018#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000019
Owen Taylor3473f882001-02-23 17:55:21 +000020#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
Owen Taylor3473f882001-02-23 17:55:21 +000031#ifdef HAVE_CTYPE_H
32#include <ctype.h>
33#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000034#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000035#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000036#endif
Owen Taylor3473f882001-02-23 17:55:21 +000037
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>
Daniel Veillard81463942001-10-16 12:34:39 +000052#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000053#include <libxml/globals.h>
Daniel Veillard56de87e2005-02-16 00:22:29 +000054#ifdef LIBXML_PATTERN_ENABLED
55#include <libxml/pattern.h>
56#endif
57
58#ifdef LIBXML_PATTERN_ENABLED
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000059#define XPATH_STREAMING
Daniel Veillard56de87e2005-02-16 00:22:29 +000060#endif
Owen Taylor3473f882001-02-23 17:55:21 +000061
Daniel Veillardd96f6d32003-10-07 21:25:12 +000062#define TODO \
63 xmlGenericError(xmlGenericErrorContext, \
64 "Unimplemented block at %s:%d\n", \
65 __FILE__, __LINE__);
66
William M. Brackd1757ab2004-10-02 22:07:48 +000067/*
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000068* XP_PATTERN_TO_ANY_NODE_ENABLED: when an XPath expression can be
69* evaluated using the streaming mode (pattern.c) then this is used to
70* enable resolution to nodes of type text-node, cdata-section-node,
71* comment-node and pi-node. The only known scenario where this is
72* needed is an expression like "foo//.", "//.", etc.; i.e. an expression
73* where the final node to be selected can be of any type.
74* Disabling this #define will result in an incorrect evaluation to
75* only element-nodes and the document node.
76*/
77#define XP_PATTERN_TO_ANY_NODE_ENABLED
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +000078
79/*
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000080* XP_OPTIMIZED_NON_ELEM_COMPARISON:
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +000081* If defined, this will use xmlXPathCmpNodesExt() instead of
82* xmlXPathCmpNodes(). The new function is optimized comparison of
83* non-element nodes; actually it will speed up comparison only if
84* xmlXPathOrderDocElems() was called in order to index the elements of
85* a tree in document order; Libxslt does such an indexing, thus it will
86* benefit from this optimization.
87*/
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000088#define XP_OPTIMIZED_NON_ELEM_COMPARISON
89
90/*
91* XP_OPTIMIZED_FILTER_FIRST:
92* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
93* in a way, that it stop evaluation at the first node.
94*/
95#define XP_OPTIMIZED_FILTER_FIRST
96
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000097/*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000098* XP_DEBUG_OBJ_USAGE:
99* Internal flag to enable tracking of how much XPath objects have been
100* created.
101*/
102/* #define XP_DEBUG_OBJ_USAGE */
103
104/*
William M. Brackd1757ab2004-10-02 22:07:48 +0000105 * TODO:
106 * There are a few spots where some tests are done which depend upon ascii
107 * data. These should be enhanced for full UTF8 support (see particularly
108 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
109 */
Kasimier T. Buchcik97258712006-01-05 12:30:43 +0000110
William M. Brack21e4ef22005-01-02 09:53:13 +0000111#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000112/************************************************************************
113 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000114 * Forward declarations *
115 * *
116 ************************************************************************/
117static void
118xmlXPathFreeValueTree(xmlNodeSetPtr obj);
119static void
120xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
121
122/************************************************************************
123 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000124 * Floating point stuff *
125 * *
126 ************************************************************************/
127
Daniel Veillardc0631a62001-09-20 13:56:06 +0000128#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +0000129#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +0000130#endif
Daniel Veillardcda96922001-08-21 10:56:31 +0000131#include "trionan.c"
132
Owen Taylor3473f882001-02-23 17:55:21 +0000133/*
Owen Taylor3473f882001-02-23 17:55:21 +0000134 * The lack of portability of this section of the libc is annoying !
135 */
136double xmlXPathNAN = 0;
137double xmlXPathPINF = 1;
138double xmlXPathNINF = -1;
Daniel Veillard24505b02005-07-28 23:49:35 +0000139static double xmlXPathNZERO = 0; /* not exported from headers */
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000140static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000141
Owen Taylor3473f882001-02-23 17:55:21 +0000142/**
143 * xmlXPathInit:
144 *
145 * Initialize the XPath environment
146 */
147void
148xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000149 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +0000150
Bjorn Reese45029602001-08-21 09:23:53 +0000151 xmlXPathPINF = trio_pinf();
152 xmlXPathNINF = trio_ninf();
153 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000154 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +0000155
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000156 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000157}
158
Daniel Veillardcda96922001-08-21 10:56:31 +0000159/**
160 * xmlXPathIsNaN:
161 * @val: a double value
162 *
163 * Provides a portable isnan() function to detect whether a double
164 * is a NotaNumber. Based on trio code
165 * http://sourceforge.net/projects/ctrio/
166 *
167 * Returns 1 if the value is a NaN, 0 otherwise
168 */
169int
170xmlXPathIsNaN(double val) {
171 return(trio_isnan(val));
172}
173
174/**
175 * xmlXPathIsInf:
176 * @val: a double value
177 *
178 * Provides a portable isinf() function to detect whether a double
179 * is a +Infinite or -Infinite. Based on trio code
180 * http://sourceforge.net/projects/ctrio/
181 *
182 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
183 */
184int
185xmlXPathIsInf(double val) {
186 return(trio_isinf(val));
187}
188
Daniel Veillard4432df22003-09-28 18:58:27 +0000189#endif /* SCHEMAS or XPATH */
190#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000191/**
192 * xmlXPathGetSign:
193 * @val: a double value
194 *
195 * Provides a portable function to detect the sign of a double
196 * Modified from trio code
197 * http://sourceforge.net/projects/ctrio/
198 *
199 * Returns 1 if the value is Negative, 0 if positive
200 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000201static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000202xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000203 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000204}
205
206
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000207/*
208 * TODO: when compatibility allows remove all "fake node libxslt" strings
209 * the test should just be name[0] = ' '
210 */
211/* #define DEBUG */
212/* #define DEBUG_STEP */
213/* #define DEBUG_STEP_NTH */
214/* #define DEBUG_EXPR */
215/* #define DEBUG_EVAL_COUNTS */
216
217static xmlNs xmlXPathXMLNamespaceStruct = {
218 NULL,
219 XML_NAMESPACE_DECL,
220 XML_XML_NAMESPACE,
221 BAD_CAST "xml",
222 NULL
223};
224static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
225#ifndef LIBXML_THREAD_ENABLED
226/*
227 * Optimizer is disabled only when threaded apps are detected while
228 * the library ain't compiled for thread safety.
229 */
230static int xmlXPathDisableOptimizer = 0;
231#endif
232
Owen Taylor3473f882001-02-23 17:55:21 +0000233/************************************************************************
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000234 * *
235 * Error handling routines *
236 * *
237 ************************************************************************/
238
Daniel Veillard24505b02005-07-28 23:49:35 +0000239/**
240 * XP_ERRORNULL:
241 * @X: the error code
242 *
243 * Macro to raise an XPath error and return NULL.
244 */
245#define XP_ERRORNULL(X) \
246 { xmlXPathErr(ctxt, X); return(NULL); }
247
William M. Brack08171912003-12-29 02:52:11 +0000248/*
249 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
250 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000251static const char *xmlXPathErrorMessages[] = {
252 "Ok\n",
253 "Number encoding\n",
254 "Unfinished literal\n",
255 "Start of literal\n",
256 "Expected $ for variable reference\n",
257 "Undefined variable\n",
258 "Invalid predicate\n",
259 "Invalid expression\n",
260 "Missing closing curly brace\n",
261 "Unregistered function\n",
262 "Invalid operand\n",
263 "Invalid type\n",
264 "Invalid number of arguments\n",
265 "Invalid context size\n",
266 "Invalid context position\n",
267 "Memory allocation error\n",
268 "Syntax error\n",
269 "Resource error\n",
270 "Sub resource error\n",
271 "Undefined namespace prefix\n",
272 "Encoding error\n",
Daniel Veillard57b25162004-11-06 14:50:18 +0000273 "Char out of XML range\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000274 "Invalid or incomplete context\n",
275 "?? Unknown error ??\n" /* Must be last in the list! */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000276};
William M. Brackcd65bc92005-01-06 09:39:18 +0000277#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
278 sizeof(xmlXPathErrorMessages[0])) - 1)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000279/**
280 * xmlXPathErrMemory:
281 * @ctxt: an XPath context
282 * @extra: extra informations
283 *
284 * Handle a redefinition of attribute error
285 */
286static void
287xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
288{
289 if (ctxt != NULL) {
290 if (extra) {
291 xmlChar buf[200];
292
293 xmlStrPrintf(buf, 200,
294 BAD_CAST "Memory allocation failed : %s\n",
295 extra);
296 ctxt->lastError.message = (char *) xmlStrdup(buf);
297 } else {
298 ctxt->lastError.message = (char *)
299 xmlStrdup(BAD_CAST "Memory allocation failed\n");
300 }
301 ctxt->lastError.domain = XML_FROM_XPATH;
302 ctxt->lastError.code = XML_ERR_NO_MEMORY;
303 if (ctxt->error != NULL)
304 ctxt->error(ctxt->userData, &ctxt->lastError);
305 } else {
306 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000307 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000308 NULL, NULL, XML_FROM_XPATH,
309 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
310 extra, NULL, NULL, 0, 0,
311 "Memory allocation failed : %s\n", extra);
312 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000313 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000314 NULL, NULL, XML_FROM_XPATH,
315 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
316 NULL, NULL, NULL, 0, 0,
317 "Memory allocation failed\n");
318 }
319}
320
321/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000322 * xmlXPathPErrMemory:
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000323 * @ctxt: an XPath parser context
324 * @extra: extra informations
325 *
326 * Handle a redefinition of attribute error
327 */
328static void
329xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
330{
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000331 if (ctxt == NULL)
332 xmlXPathErrMemory(NULL, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000333 else {
334 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000335 xmlXPathErrMemory(ctxt->context, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000336 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000337}
338
339/**
340 * xmlXPathErr:
341 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000342 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000343 *
William M. Brackcd65bc92005-01-06 09:39:18 +0000344 * Handle an XPath error
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000345 */
346void
347xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
348{
William M. Brackcd65bc92005-01-06 09:39:18 +0000349 if ((error < 0) || (error > MAXERRNO))
350 error = MAXERRNO;
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000351 if (ctxt == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000352 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000353 NULL, NULL, XML_FROM_XPATH,
354 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
355 XML_ERR_ERROR, NULL, 0,
356 NULL, NULL, NULL, 0, 0,
357 xmlXPathErrorMessages[error]);
358 return;
359 }
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000360 ctxt->error = error;
361 if (ctxt->context == NULL) {
362 __xmlRaiseError(NULL, NULL, NULL,
363 NULL, NULL, XML_FROM_XPATH,
364 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
365 XML_ERR_ERROR, NULL, 0,
366 (const char *) ctxt->base, NULL, NULL,
367 ctxt->cur - ctxt->base, 0,
368 xmlXPathErrorMessages[error]);
369 return;
370 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +0000371
372 /* cleanup current last error */
373 xmlResetError(&ctxt->context->lastError);
374
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000375 ctxt->context->lastError.domain = XML_FROM_XPATH;
376 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
377 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000378 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000379 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
380 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
381 ctxt->context->lastError.node = ctxt->context->debugNode;
382 if (ctxt->context->error != NULL) {
383 ctxt->context->error(ctxt->context->userData,
384 &ctxt->context->lastError);
385 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000386 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000387 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
388 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
389 XML_ERR_ERROR, NULL, 0,
390 (const char *) ctxt->base, NULL, NULL,
391 ctxt->cur - ctxt->base, 0,
392 xmlXPathErrorMessages[error]);
393 }
394
395}
396
397/**
398 * xmlXPatherror:
399 * @ctxt: the XPath Parser context
400 * @file: the file name
401 * @line: the line number
402 * @no: the error number
403 *
404 * Formats an error message.
405 */
406void
407xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
408 int line ATTRIBUTE_UNUSED, int no) {
409 xmlXPathErr(ctxt, no);
410}
411
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000412/************************************************************************
413 * *
414 * Utilities *
415 * *
416 ************************************************************************/
417
418/**
419 * xsltPointerList:
420 *
421 * Pointer-list for various purposes.
422 */
423typedef struct _xmlPointerList xmlPointerList;
424typedef xmlPointerList *xmlPointerListPtr;
425struct _xmlPointerList {
426 void **items;
427 int number;
428 int size;
429};
430/*
431* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
432* and here, we should make the functions public.
433*/
434static int
435xmlPointerListAddSize(xmlPointerListPtr list,
436 void *item,
437 int initialSize)
438{
439 if (list->items == NULL) {
440 if (initialSize <= 0)
441 initialSize = 1;
442 list->items = (void **) xmlMalloc(
443 initialSize * sizeof(void *));
444 if (list->items == NULL) {
445 xmlXPathErrMemory(NULL,
446 "xmlPointerListCreate: allocating item\n");
447 return(-1);
448 }
449 list->number = 0;
450 list->size = initialSize;
451 } else if (list->size <= list->number) {
452 list->size *= 2;
453 list->items = (void **) xmlRealloc(list->items,
454 list->size * sizeof(void *));
455 if (list->items == NULL) {
456 xmlXPathErrMemory(NULL,
457 "xmlPointerListCreate: re-allocating item\n");
458 list->size = 0;
459 return(-1);
460 }
461 }
462 list->items[list->number++] = item;
463 return(0);
464}
465
466/**
467 * xsltPointerListCreate:
468 *
469 * Creates an xsltPointerList structure.
470 *
471 * Returns a xsltPointerList structure or NULL in case of an error.
472 */
473static xmlPointerListPtr
474xmlPointerListCreate(int initialSize)
475{
476 xmlPointerListPtr ret;
477
478 ret = xmlMalloc(sizeof(xmlPointerList));
479 if (ret == NULL) {
480 xmlXPathErrMemory(NULL,
481 "xmlPointerListCreate: allocating item\n");
482 return (NULL);
483 }
484 memset(ret, 0, sizeof(xmlPointerList));
485 if (initialSize > 0) {
486 xmlPointerListAddSize(ret, NULL, initialSize);
487 ret->number = 0;
488 }
489 return (ret);
490}
491
492/**
493 * xsltPointerListFree:
494 *
495 * Frees the xsltPointerList structure. This does not free
496 * the content of the list.
497 */
498static void
499xmlPointerListFree(xmlPointerListPtr list)
500{
501 if (list == NULL)
502 return;
503 if (list->items != NULL)
504 xmlFree(list->items);
505 xmlFree(list);
506}
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000507
508/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000509 * *
510 * Parser Types *
511 * *
512 ************************************************************************/
513
514/*
515 * Types are private:
516 */
517
518typedef enum {
519 XPATH_OP_END=0,
520 XPATH_OP_AND,
521 XPATH_OP_OR,
522 XPATH_OP_EQUAL,
523 XPATH_OP_CMP,
524 XPATH_OP_PLUS,
525 XPATH_OP_MULT,
526 XPATH_OP_UNION,
527 XPATH_OP_ROOT,
528 XPATH_OP_NODE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000529 XPATH_OP_RESET, /* 10 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000530 XPATH_OP_COLLECT,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000531 XPATH_OP_VALUE, /* 12 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000532 XPATH_OP_VARIABLE,
533 XPATH_OP_FUNCTION,
534 XPATH_OP_ARG,
535 XPATH_OP_PREDICATE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000536 XPATH_OP_FILTER, /* 17 */
537 XPATH_OP_SORT /* 18 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000538#ifdef LIBXML_XPTR_ENABLED
539 ,XPATH_OP_RANGETO
540#endif
541} xmlXPathOp;
542
543typedef enum {
544 AXIS_ANCESTOR = 1,
545 AXIS_ANCESTOR_OR_SELF,
546 AXIS_ATTRIBUTE,
547 AXIS_CHILD,
548 AXIS_DESCENDANT,
549 AXIS_DESCENDANT_OR_SELF,
550 AXIS_FOLLOWING,
551 AXIS_FOLLOWING_SIBLING,
552 AXIS_NAMESPACE,
553 AXIS_PARENT,
554 AXIS_PRECEDING,
555 AXIS_PRECEDING_SIBLING,
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +0000556 AXIS_SELF
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000557} xmlXPathAxisVal;
558
559typedef enum {
560 NODE_TEST_NONE = 0,
561 NODE_TEST_TYPE = 1,
562 NODE_TEST_PI = 2,
563 NODE_TEST_ALL = 3,
564 NODE_TEST_NS = 4,
565 NODE_TEST_NAME = 5
566} xmlXPathTestVal;
567
568typedef enum {
569 NODE_TYPE_NODE = 0,
570 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
571 NODE_TYPE_TEXT = XML_TEXT_NODE,
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +0000572 NODE_TYPE_PI = XML_PI_NODE
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000573} xmlXPathTypeVal;
574
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +0000575#define XP_REWRITE_DOS_CHILD_ELEM 1
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000576
577typedef struct _xmlXPathStepOp xmlXPathStepOp;
578typedef xmlXPathStepOp *xmlXPathStepOpPtr;
579struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000580 xmlXPathOp op; /* The identifier of the operation */
581 int ch1; /* First child */
582 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000583 int value;
584 int value2;
585 int value3;
586 void *value4;
587 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000588 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000589 void *cacheURI;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +0000590 int rewriteType;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000591};
592
593struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000594 int nbStep; /* Number of steps in this expression */
595 int maxStep; /* Maximum number of steps allocated */
596 xmlXPathStepOp *steps; /* ops for computation of this expression */
597 int last; /* index of last step in expression */
598 xmlChar *expr; /* the expression being computed */
Daniel Veillard4773df22004-01-23 13:15:13 +0000599 xmlDictPtr dict; /* the dictionnary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000600#ifdef DEBUG_EVAL_COUNTS
601 int nb;
602 xmlChar *string;
603#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000604#ifdef XPATH_STREAMING
605 xmlPatternPtr stream;
606#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000607};
608
609/************************************************************************
610 * *
611 * Parser Type functions *
612 * *
613 ************************************************************************/
614
615/**
616 * xmlXPathNewCompExpr:
617 *
618 * Create a new Xpath component
619 *
620 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
621 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000622static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000623xmlXPathNewCompExpr(void) {
624 xmlXPathCompExprPtr cur;
625
626 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
627 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000628 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000629 return(NULL);
630 }
631 memset(cur, 0, sizeof(xmlXPathCompExpr));
632 cur->maxStep = 10;
633 cur->nbStep = 0;
634 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
635 sizeof(xmlXPathStepOp));
636 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000637 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000638 xmlFree(cur);
639 return(NULL);
640 }
641 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
642 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000643#ifdef DEBUG_EVAL_COUNTS
644 cur->nb = 0;
645#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000646 return(cur);
647}
648
649/**
650 * xmlXPathFreeCompExpr:
651 * @comp: an XPATH comp
652 *
653 * Free up the memory allocated by @comp
654 */
655void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000656xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
657{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000658 xmlXPathStepOpPtr op;
659 int i;
660
661 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000662 return;
Daniel Veillard4773df22004-01-23 13:15:13 +0000663 if (comp->dict == NULL) {
664 for (i = 0; i < comp->nbStep; i++) {
665 op = &comp->steps[i];
666 if (op->value4 != NULL) {
667 if (op->op == XPATH_OP_VALUE)
668 xmlXPathFreeObject(op->value4);
669 else
670 xmlFree(op->value4);
671 }
672 if (op->value5 != NULL)
673 xmlFree(op->value5);
674 }
675 } else {
676 for (i = 0; i < comp->nbStep; i++) {
677 op = &comp->steps[i];
678 if (op->value4 != NULL) {
679 if (op->op == XPATH_OP_VALUE)
680 xmlXPathFreeObject(op->value4);
681 }
682 }
683 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000684 }
685 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000686 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000687 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000688#ifdef DEBUG_EVAL_COUNTS
689 if (comp->string != NULL) {
690 xmlFree(comp->string);
691 }
692#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000693#ifdef XPATH_STREAMING
694 if (comp->stream != NULL) {
695 xmlFreePatternList(comp->stream);
696 }
697#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000698 if (comp->expr != NULL) {
699 xmlFree(comp->expr);
700 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000701
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000702 xmlFree(comp);
703}
704
705/**
706 * xmlXPathCompExprAdd:
707 * @comp: the compiled expression
708 * @ch1: first child index
709 * @ch2: second child index
710 * @op: an op
711 * @value: the first int value
712 * @value2: the second int value
713 * @value3: the third int value
714 * @value4: the first string value
715 * @value5: the second string value
716 *
William M. Brack08171912003-12-29 02:52:11 +0000717 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000718 *
719 * Returns -1 in case of failure, the index otherwise
720 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000721static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000722xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
723 xmlXPathOp op, int value,
724 int value2, int value3, void *value4, void *value5) {
725 if (comp->nbStep >= comp->maxStep) {
726 xmlXPathStepOp *real;
727
728 comp->maxStep *= 2;
729 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
730 comp->maxStep * sizeof(xmlXPathStepOp));
731 if (real == NULL) {
732 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000733 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000734 return(-1);
735 }
736 comp->steps = real;
737 }
738 comp->last = comp->nbStep;
Kasimier T. Buchcik6422d912006-06-26 14:31:53 +0000739 comp->steps[comp->nbStep].rewriteType = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000740 comp->steps[comp->nbStep].ch1 = ch1;
741 comp->steps[comp->nbStep].ch2 = ch2;
742 comp->steps[comp->nbStep].op = op;
743 comp->steps[comp->nbStep].value = value;
744 comp->steps[comp->nbStep].value2 = value2;
745 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +0000746 if ((comp->dict != NULL) &&
747 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
748 (op == XPATH_OP_COLLECT))) {
749 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000750 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000751 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000752 xmlFree(value4);
753 } else
754 comp->steps[comp->nbStep].value4 = NULL;
755 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000756 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000757 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000758 xmlFree(value5);
759 } else
760 comp->steps[comp->nbStep].value5 = NULL;
761 } else {
762 comp->steps[comp->nbStep].value4 = value4;
763 comp->steps[comp->nbStep].value5 = value5;
764 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000765 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000766 return(comp->nbStep++);
767}
768
Daniel Veillardf06307e2001-07-03 10:35:50 +0000769/**
770 * xmlXPathCompSwap:
771 * @comp: the compiled expression
772 * @op: operation index
773 *
774 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000775 */
776static void
777xmlXPathCompSwap(xmlXPathStepOpPtr op) {
778 int tmp;
779
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000780#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000781 /*
782 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +0000783 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +0000784 * application
785 */
786 if (xmlXPathDisableOptimizer)
787 return;
788#endif
789
Daniel Veillardf06307e2001-07-03 10:35:50 +0000790 tmp = op->ch1;
791 op->ch1 = op->ch2;
792 op->ch2 = tmp;
793}
794
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000795#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
796 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
797 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000798#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
799 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
800 (op), (val), (val2), (val3), (val4), (val5))
801
802#define PUSH_LEAVE_EXPR(op, val, val2) \
803xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
804
805#define PUSH_UNARY_EXPR(op, ch, val, val2) \
806xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
807
808#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +0000809xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
810 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000811
812/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000813 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000814 * XPath object cache structures *
815 * *
816 ************************************************************************/
817
818/* #define XP_DEFAULT_CACHE_ON */
819
Kasimier T. Buchcik58694692006-05-31 12:37:28 +0000820#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000821
Kasimier T. Buchcik58694692006-05-31 12:37:28 +0000822typedef struct _xmlXPathContextCache xmlXPathContextCache;
823typedef xmlXPathContextCache *xmlXPathContextCachePtr;
824struct _xmlXPathContextCache {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +0000825 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
826 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
827 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
828 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
829 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000830 int maxNodeset;
831 int maxString;
832 int maxBoolean;
833 int maxNumber;
834 int maxMisc;
835#ifdef XP_DEBUG_OBJ_USAGE
836 int dbgCachedAll;
837 int dbgCachedNodeset;
838 int dbgCachedString;
839 int dbgCachedBool;
840 int dbgCachedNumber;
841 int dbgCachedPoint;
842 int dbgCachedRange;
843 int dbgCachedLocset;
844 int dbgCachedUsers;
845 int dbgCachedXSLTTree;
846 int dbgCachedUndefined;
847
848
849 int dbgReusedAll;
850 int dbgReusedNodeset;
851 int dbgReusedString;
852 int dbgReusedBool;
853 int dbgReusedNumber;
854 int dbgReusedPoint;
855 int dbgReusedRange;
856 int dbgReusedLocset;
857 int dbgReusedUsers;
858 int dbgReusedXSLTTree;
859 int dbgReusedUndefined;
860
861#endif
862};
863
864/************************************************************************
865 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000866 * Debugging related functions *
867 * *
868 ************************************************************************/
869
Owen Taylor3473f882001-02-23 17:55:21 +0000870#define STRANGE \
871 xmlGenericError(xmlGenericErrorContext, \
872 "Internal error at %s:%d\n", \
873 __FILE__, __LINE__);
874
875#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000876static void
877xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000878 int i;
879 char shift[100];
880
881 for (i = 0;((i < depth) && (i < 25));i++)
882 shift[2 * i] = shift[2 * i + 1] = ' ';
883 shift[2 * i] = shift[2 * i + 1] = 0;
884 if (cur == NULL) {
885 fprintf(output, shift);
886 fprintf(output, "Node is NULL !\n");
887 return;
888
889 }
890
891 if ((cur->type == XML_DOCUMENT_NODE) ||
892 (cur->type == XML_HTML_DOCUMENT_NODE)) {
893 fprintf(output, shift);
894 fprintf(output, " /\n");
895 } else if (cur->type == XML_ATTRIBUTE_NODE)
896 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
897 else
898 xmlDebugDumpOneNode(output, cur, depth);
899}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000900static void
901xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000902 xmlNodePtr tmp;
903 int i;
904 char shift[100];
905
906 for (i = 0;((i < depth) && (i < 25));i++)
907 shift[2 * i] = shift[2 * i + 1] = ' ';
908 shift[2 * i] = shift[2 * i + 1] = 0;
909 if (cur == NULL) {
910 fprintf(output, shift);
911 fprintf(output, "Node is NULL !\n");
912 return;
913
914 }
915
916 while (cur != NULL) {
917 tmp = cur;
918 cur = cur->next;
919 xmlDebugDumpOneNode(output, tmp, depth);
920 }
921}
Owen Taylor3473f882001-02-23 17:55:21 +0000922
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000923static void
924xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000925 int i;
926 char shift[100];
927
928 for (i = 0;((i < depth) && (i < 25));i++)
929 shift[2 * i] = shift[2 * i + 1] = ' ';
930 shift[2 * i] = shift[2 * i + 1] = 0;
931
932 if (cur == NULL) {
933 fprintf(output, shift);
934 fprintf(output, "NodeSet is NULL !\n");
935 return;
936
937 }
938
Daniel Veillard911f49a2001-04-07 15:39:35 +0000939 if (cur != NULL) {
940 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
941 for (i = 0;i < cur->nodeNr;i++) {
942 fprintf(output, shift);
943 fprintf(output, "%d", i + 1);
944 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
945 }
Owen Taylor3473f882001-02-23 17:55:21 +0000946 }
947}
948
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000949static void
950xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000951 int i;
952 char shift[100];
953
954 for (i = 0;((i < depth) && (i < 25));i++)
955 shift[2 * i] = shift[2 * i + 1] = ' ';
956 shift[2 * i] = shift[2 * i + 1] = 0;
957
958 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
959 fprintf(output, shift);
960 fprintf(output, "Value Tree is NULL !\n");
961 return;
962
963 }
964
965 fprintf(output, shift);
966 fprintf(output, "%d", i + 1);
967 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
968}
Owen Taylor3473f882001-02-23 17:55:21 +0000969#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000970static void
971xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000972 int i;
973 char shift[100];
974
975 for (i = 0;((i < depth) && (i < 25));i++)
976 shift[2 * i] = shift[2 * i + 1] = ' ';
977 shift[2 * i] = shift[2 * i + 1] = 0;
978
979 if (cur == NULL) {
980 fprintf(output, shift);
981 fprintf(output, "LocationSet is NULL !\n");
982 return;
983
984 }
985
986 for (i = 0;i < cur->locNr;i++) {
987 fprintf(output, shift);
988 fprintf(output, "%d : ", i + 1);
989 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
990 }
991}
Daniel Veillard017b1082001-06-21 11:20:21 +0000992#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000993
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000994/**
995 * xmlXPathDebugDumpObject:
996 * @output: the FILE * to dump the output
997 * @cur: the object to inspect
998 * @depth: indentation level
999 *
1000 * Dump the content of the object for debugging purposes
1001 */
1002void
1003xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001004 int i;
1005 char shift[100];
1006
Daniel Veillarda82b1822004-11-08 16:24:57 +00001007 if (output == NULL) return;
1008
Owen Taylor3473f882001-02-23 17:55:21 +00001009 for (i = 0;((i < depth) && (i < 25));i++)
1010 shift[2 * i] = shift[2 * i + 1] = ' ';
1011 shift[2 * i] = shift[2 * i + 1] = 0;
1012
Kasimier T. Buchcik97258712006-01-05 12:30:43 +00001013
1014 fprintf(output, shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001015
1016 if (cur == NULL) {
1017 fprintf(output, "Object is empty (NULL)\n");
1018 return;
1019 }
1020 switch(cur->type) {
1021 case XPATH_UNDEFINED:
1022 fprintf(output, "Object is uninitialized\n");
1023 break;
1024 case XPATH_NODESET:
1025 fprintf(output, "Object is a Node Set :\n");
1026 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1027 break;
1028 case XPATH_XSLT_TREE:
1029 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001030 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +00001031 break;
1032 case XPATH_BOOLEAN:
1033 fprintf(output, "Object is a Boolean : ");
1034 if (cur->boolval) fprintf(output, "true\n");
1035 else fprintf(output, "false\n");
1036 break;
1037 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +00001038 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001039 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001040 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001041 break;
1042 case -1:
1043 fprintf(output, "Object is a number : -Infinity\n");
1044 break;
1045 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001046 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001047 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001048 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1049 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001050 } else {
1051 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1052 }
1053 }
Owen Taylor3473f882001-02-23 17:55:21 +00001054 break;
1055 case XPATH_STRING:
1056 fprintf(output, "Object is a string : ");
1057 xmlDebugDumpString(output, cur->stringval);
1058 fprintf(output, "\n");
1059 break;
1060 case XPATH_POINT:
1061 fprintf(output, "Object is a point : index %d in node", cur->index);
1062 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1063 fprintf(output, "\n");
1064 break;
1065 case XPATH_RANGE:
1066 if ((cur->user2 == NULL) ||
1067 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1068 fprintf(output, "Object is a collapsed range :\n");
1069 fprintf(output, shift);
1070 if (cur->index >= 0)
1071 fprintf(output, "index %d in ", cur->index);
1072 fprintf(output, "node\n");
1073 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1074 depth + 1);
1075 } else {
1076 fprintf(output, "Object is a range :\n");
1077 fprintf(output, shift);
1078 fprintf(output, "From ");
1079 if (cur->index >= 0)
1080 fprintf(output, "index %d in ", cur->index);
1081 fprintf(output, "node\n");
1082 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1083 depth + 1);
1084 fprintf(output, shift);
1085 fprintf(output, "To ");
1086 if (cur->index2 >= 0)
1087 fprintf(output, "index %d in ", cur->index2);
1088 fprintf(output, "node\n");
1089 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1090 depth + 1);
1091 fprintf(output, "\n");
1092 }
1093 break;
1094 case XPATH_LOCATIONSET:
1095#if defined(LIBXML_XPTR_ENABLED)
1096 fprintf(output, "Object is a Location Set:\n");
1097 xmlXPathDebugDumpLocationSet(output,
1098 (xmlLocationSetPtr) cur->user, depth);
1099#endif
1100 break;
1101 case XPATH_USERS:
1102 fprintf(output, "Object is user defined\n");
1103 break;
1104 }
1105}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001106
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001107static void
1108xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001109 xmlXPathStepOpPtr op, int depth) {
1110 int i;
1111 char shift[100];
1112
1113 for (i = 0;((i < depth) && (i < 25));i++)
1114 shift[2 * i] = shift[2 * i + 1] = ' ';
1115 shift[2 * i] = shift[2 * i + 1] = 0;
1116
1117 fprintf(output, shift);
1118 if (op == NULL) {
1119 fprintf(output, "Step is NULL\n");
1120 return;
1121 }
1122 switch (op->op) {
1123 case XPATH_OP_END:
1124 fprintf(output, "END"); break;
1125 case XPATH_OP_AND:
1126 fprintf(output, "AND"); break;
1127 case XPATH_OP_OR:
1128 fprintf(output, "OR"); break;
1129 case XPATH_OP_EQUAL:
1130 if (op->value)
1131 fprintf(output, "EQUAL =");
1132 else
1133 fprintf(output, "EQUAL !=");
1134 break;
1135 case XPATH_OP_CMP:
1136 if (op->value)
1137 fprintf(output, "CMP <");
1138 else
1139 fprintf(output, "CMP >");
1140 if (!op->value2)
1141 fprintf(output, "=");
1142 break;
1143 case XPATH_OP_PLUS:
1144 if (op->value == 0)
1145 fprintf(output, "PLUS -");
1146 else if (op->value == 1)
1147 fprintf(output, "PLUS +");
1148 else if (op->value == 2)
1149 fprintf(output, "PLUS unary -");
1150 else if (op->value == 3)
1151 fprintf(output, "PLUS unary - -");
1152 break;
1153 case XPATH_OP_MULT:
1154 if (op->value == 0)
1155 fprintf(output, "MULT *");
1156 else if (op->value == 1)
1157 fprintf(output, "MULT div");
1158 else
1159 fprintf(output, "MULT mod");
1160 break;
1161 case XPATH_OP_UNION:
1162 fprintf(output, "UNION"); break;
1163 case XPATH_OP_ROOT:
1164 fprintf(output, "ROOT"); break;
1165 case XPATH_OP_NODE:
1166 fprintf(output, "NODE"); break;
1167 case XPATH_OP_RESET:
1168 fprintf(output, "RESET"); break;
1169 case XPATH_OP_SORT:
1170 fprintf(output, "SORT"); break;
1171 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +00001172 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1173 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1174 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001175 const xmlChar *prefix = op->value4;
1176 const xmlChar *name = op->value5;
1177
1178 fprintf(output, "COLLECT ");
1179 switch (axis) {
1180 case AXIS_ANCESTOR:
1181 fprintf(output, " 'ancestors' "); break;
1182 case AXIS_ANCESTOR_OR_SELF:
1183 fprintf(output, " 'ancestors-or-self' "); break;
1184 case AXIS_ATTRIBUTE:
1185 fprintf(output, " 'attributes' "); break;
1186 case AXIS_CHILD:
1187 fprintf(output, " 'child' "); break;
1188 case AXIS_DESCENDANT:
1189 fprintf(output, " 'descendant' "); break;
1190 case AXIS_DESCENDANT_OR_SELF:
1191 fprintf(output, " 'descendant-or-self' "); break;
1192 case AXIS_FOLLOWING:
1193 fprintf(output, " 'following' "); break;
1194 case AXIS_FOLLOWING_SIBLING:
1195 fprintf(output, " 'following-siblings' "); break;
1196 case AXIS_NAMESPACE:
1197 fprintf(output, " 'namespace' "); break;
1198 case AXIS_PARENT:
1199 fprintf(output, " 'parent' "); break;
1200 case AXIS_PRECEDING:
1201 fprintf(output, " 'preceding' "); break;
1202 case AXIS_PRECEDING_SIBLING:
1203 fprintf(output, " 'preceding-sibling' "); break;
1204 case AXIS_SELF:
1205 fprintf(output, " 'self' "); break;
1206 }
1207 switch (test) {
1208 case NODE_TEST_NONE:
1209 fprintf(output, "'none' "); break;
1210 case NODE_TEST_TYPE:
1211 fprintf(output, "'type' "); break;
1212 case NODE_TEST_PI:
1213 fprintf(output, "'PI' "); break;
1214 case NODE_TEST_ALL:
1215 fprintf(output, "'all' "); break;
1216 case NODE_TEST_NS:
1217 fprintf(output, "'namespace' "); break;
1218 case NODE_TEST_NAME:
1219 fprintf(output, "'name' "); break;
1220 }
1221 switch (type) {
1222 case NODE_TYPE_NODE:
1223 fprintf(output, "'node' "); break;
1224 case NODE_TYPE_COMMENT:
1225 fprintf(output, "'comment' "); break;
1226 case NODE_TYPE_TEXT:
1227 fprintf(output, "'text' "); break;
1228 case NODE_TYPE_PI:
1229 fprintf(output, "'PI' "); break;
1230 }
1231 if (prefix != NULL)
1232 fprintf(output, "%s:", prefix);
1233 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001234 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001235 break;
1236
1237 }
1238 case XPATH_OP_VALUE: {
1239 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1240
1241 fprintf(output, "ELEM ");
1242 xmlXPathDebugDumpObject(output, object, 0);
1243 goto finish;
1244 }
1245 case XPATH_OP_VARIABLE: {
1246 const xmlChar *prefix = op->value5;
1247 const xmlChar *name = op->value4;
1248
1249 if (prefix != NULL)
1250 fprintf(output, "VARIABLE %s:%s", prefix, name);
1251 else
1252 fprintf(output, "VARIABLE %s", name);
1253 break;
1254 }
1255 case XPATH_OP_FUNCTION: {
1256 int nbargs = op->value;
1257 const xmlChar *prefix = op->value5;
1258 const xmlChar *name = op->value4;
1259
1260 if (prefix != NULL)
1261 fprintf(output, "FUNCTION %s:%s(%d args)",
1262 prefix, name, nbargs);
1263 else
1264 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1265 break;
1266 }
1267 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1268 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001269 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001270#ifdef LIBXML_XPTR_ENABLED
1271 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1272#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001273 default:
1274 fprintf(output, "UNKNOWN %d\n", op->op); return;
1275 }
1276 fprintf(output, "\n");
1277finish:
1278 if (op->ch1 >= 0)
1279 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1280 if (op->ch2 >= 0)
1281 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1282}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001283
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001284/**
1285 * xmlXPathDebugDumpCompExpr:
1286 * @output: the FILE * for the output
1287 * @comp: the precompiled XPath expression
1288 * @depth: the indentation level.
1289 *
1290 * Dumps the tree of the compiled XPath expression.
1291 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001292void
1293xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1294 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001295 int i;
1296 char shift[100];
1297
Daniel Veillarda82b1822004-11-08 16:24:57 +00001298 if ((output == NULL) || (comp == NULL)) return;
1299
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001300 for (i = 0;((i < depth) && (i < 25));i++)
1301 shift[2 * i] = shift[2 * i + 1] = ' ';
1302 shift[2 * i] = shift[2 * i + 1] = 0;
1303
1304 fprintf(output, shift);
1305
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001306 fprintf(output, "Compiled Expression : %d elements\n",
1307 comp->nbStep);
1308 i = comp->last;
1309 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1310}
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001311
1312#ifdef XP_DEBUG_OBJ_USAGE
1313
1314/*
1315* XPath object usage related debugging variables.
1316*/
1317static int xmlXPathDebugObjCounterUndefined = 0;
1318static int xmlXPathDebugObjCounterNodeset = 0;
1319static int xmlXPathDebugObjCounterBool = 0;
1320static int xmlXPathDebugObjCounterNumber = 0;
1321static int xmlXPathDebugObjCounterString = 0;
1322static int xmlXPathDebugObjCounterPoint = 0;
1323static int xmlXPathDebugObjCounterRange = 0;
1324static int xmlXPathDebugObjCounterLocset = 0;
1325static int xmlXPathDebugObjCounterUsers = 0;
1326static int xmlXPathDebugObjCounterXSLTTree = 0;
1327static int xmlXPathDebugObjCounterAll = 0;
1328
1329static int xmlXPathDebugObjTotalUndefined = 0;
1330static int xmlXPathDebugObjTotalNodeset = 0;
1331static int xmlXPathDebugObjTotalBool = 0;
1332static int xmlXPathDebugObjTotalNumber = 0;
1333static int xmlXPathDebugObjTotalString = 0;
1334static int xmlXPathDebugObjTotalPoint = 0;
1335static int xmlXPathDebugObjTotalRange = 0;
1336static int xmlXPathDebugObjTotalLocset = 0;
1337static int xmlXPathDebugObjTotalUsers = 0;
1338static int xmlXPathDebugObjTotalXSLTTree = 0;
1339static int xmlXPathDebugObjTotalAll = 0;
1340
1341static int xmlXPathDebugObjMaxUndefined = 0;
1342static int xmlXPathDebugObjMaxNodeset = 0;
1343static int xmlXPathDebugObjMaxBool = 0;
1344static int xmlXPathDebugObjMaxNumber = 0;
1345static int xmlXPathDebugObjMaxString = 0;
1346static int xmlXPathDebugObjMaxPoint = 0;
1347static int xmlXPathDebugObjMaxRange = 0;
1348static int xmlXPathDebugObjMaxLocset = 0;
1349static int xmlXPathDebugObjMaxUsers = 0;
1350static int xmlXPathDebugObjMaxXSLTTree = 0;
1351static int xmlXPathDebugObjMaxAll = 0;
1352
1353/* REVISIT TODO: Make this static when committing */
1354static void
1355xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1356{
1357 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001358 if (ctxt->cache != NULL) {
1359 xmlXPathContextCachePtr cache =
1360 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001361
1362 cache->dbgCachedAll = 0;
1363 cache->dbgCachedNodeset = 0;
1364 cache->dbgCachedString = 0;
1365 cache->dbgCachedBool = 0;
1366 cache->dbgCachedNumber = 0;
1367 cache->dbgCachedPoint = 0;
1368 cache->dbgCachedRange = 0;
1369 cache->dbgCachedLocset = 0;
1370 cache->dbgCachedUsers = 0;
1371 cache->dbgCachedXSLTTree = 0;
1372 cache->dbgCachedUndefined = 0;
1373
1374 cache->dbgReusedAll = 0;
1375 cache->dbgReusedNodeset = 0;
1376 cache->dbgReusedString = 0;
1377 cache->dbgReusedBool = 0;
1378 cache->dbgReusedNumber = 0;
1379 cache->dbgReusedPoint = 0;
1380 cache->dbgReusedRange = 0;
1381 cache->dbgReusedLocset = 0;
1382 cache->dbgReusedUsers = 0;
1383 cache->dbgReusedXSLTTree = 0;
1384 cache->dbgReusedUndefined = 0;
1385 }
1386 }
1387
1388 xmlXPathDebugObjCounterUndefined = 0;
1389 xmlXPathDebugObjCounterNodeset = 0;
1390 xmlXPathDebugObjCounterBool = 0;
1391 xmlXPathDebugObjCounterNumber = 0;
1392 xmlXPathDebugObjCounterString = 0;
1393 xmlXPathDebugObjCounterPoint = 0;
1394 xmlXPathDebugObjCounterRange = 0;
1395 xmlXPathDebugObjCounterLocset = 0;
1396 xmlXPathDebugObjCounterUsers = 0;
1397 xmlXPathDebugObjCounterXSLTTree = 0;
1398 xmlXPathDebugObjCounterAll = 0;
1399
1400 xmlXPathDebugObjTotalUndefined = 0;
1401 xmlXPathDebugObjTotalNodeset = 0;
1402 xmlXPathDebugObjTotalBool = 0;
1403 xmlXPathDebugObjTotalNumber = 0;
1404 xmlXPathDebugObjTotalString = 0;
1405 xmlXPathDebugObjTotalPoint = 0;
1406 xmlXPathDebugObjTotalRange = 0;
1407 xmlXPathDebugObjTotalLocset = 0;
1408 xmlXPathDebugObjTotalUsers = 0;
1409 xmlXPathDebugObjTotalXSLTTree = 0;
1410 xmlXPathDebugObjTotalAll = 0;
1411
1412 xmlXPathDebugObjMaxUndefined = 0;
1413 xmlXPathDebugObjMaxNodeset = 0;
1414 xmlXPathDebugObjMaxBool = 0;
1415 xmlXPathDebugObjMaxNumber = 0;
1416 xmlXPathDebugObjMaxString = 0;
1417 xmlXPathDebugObjMaxPoint = 0;
1418 xmlXPathDebugObjMaxRange = 0;
1419 xmlXPathDebugObjMaxLocset = 0;
1420 xmlXPathDebugObjMaxUsers = 0;
1421 xmlXPathDebugObjMaxXSLTTree = 0;
1422 xmlXPathDebugObjMaxAll = 0;
1423
1424}
1425
1426static void
1427xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1428 xmlXPathObjectType objType)
1429{
1430 int isCached = 0;
1431
1432 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001433 if (ctxt->cache != NULL) {
1434 xmlXPathContextCachePtr cache =
1435 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001436
1437 isCached = 1;
1438
1439 cache->dbgReusedAll++;
1440 switch (objType) {
1441 case XPATH_UNDEFINED:
1442 cache->dbgReusedUndefined++;
1443 break;
1444 case XPATH_NODESET:
1445 cache->dbgReusedNodeset++;
1446 break;
1447 case XPATH_BOOLEAN:
1448 cache->dbgReusedBool++;
1449 break;
1450 case XPATH_NUMBER:
1451 cache->dbgReusedNumber++;
1452 break;
1453 case XPATH_STRING:
1454 cache->dbgReusedString++;
1455 break;
1456 case XPATH_POINT:
1457 cache->dbgReusedPoint++;
1458 break;
1459 case XPATH_RANGE:
1460 cache->dbgReusedRange++;
1461 break;
1462 case XPATH_LOCATIONSET:
1463 cache->dbgReusedLocset++;
1464 break;
1465 case XPATH_USERS:
1466 cache->dbgReusedUsers++;
1467 break;
1468 case XPATH_XSLT_TREE:
1469 cache->dbgReusedXSLTTree++;
1470 break;
1471 default:
1472 break;
1473 }
1474 }
1475 }
1476
1477 switch (objType) {
1478 case XPATH_UNDEFINED:
1479 if (! isCached)
1480 xmlXPathDebugObjTotalUndefined++;
1481 xmlXPathDebugObjCounterUndefined++;
1482 if (xmlXPathDebugObjCounterUndefined >
1483 xmlXPathDebugObjMaxUndefined)
1484 xmlXPathDebugObjMaxUndefined =
1485 xmlXPathDebugObjCounterUndefined;
1486 break;
1487 case XPATH_NODESET:
1488 if (! isCached)
1489 xmlXPathDebugObjTotalNodeset++;
1490 xmlXPathDebugObjCounterNodeset++;
1491 if (xmlXPathDebugObjCounterNodeset >
1492 xmlXPathDebugObjMaxNodeset)
1493 xmlXPathDebugObjMaxNodeset =
1494 xmlXPathDebugObjCounterNodeset;
1495 break;
1496 case XPATH_BOOLEAN:
1497 if (! isCached)
1498 xmlXPathDebugObjTotalBool++;
1499 xmlXPathDebugObjCounterBool++;
1500 if (xmlXPathDebugObjCounterBool >
1501 xmlXPathDebugObjMaxBool)
1502 xmlXPathDebugObjMaxBool =
1503 xmlXPathDebugObjCounterBool;
1504 break;
1505 case XPATH_NUMBER:
1506 if (! isCached)
1507 xmlXPathDebugObjTotalNumber++;
1508 xmlXPathDebugObjCounterNumber++;
1509 if (xmlXPathDebugObjCounterNumber >
1510 xmlXPathDebugObjMaxNumber)
1511 xmlXPathDebugObjMaxNumber =
1512 xmlXPathDebugObjCounterNumber;
1513 break;
1514 case XPATH_STRING:
1515 if (! isCached)
1516 xmlXPathDebugObjTotalString++;
1517 xmlXPathDebugObjCounterString++;
1518 if (xmlXPathDebugObjCounterString >
1519 xmlXPathDebugObjMaxString)
1520 xmlXPathDebugObjMaxString =
1521 xmlXPathDebugObjCounterString;
1522 break;
1523 case XPATH_POINT:
1524 if (! isCached)
1525 xmlXPathDebugObjTotalPoint++;
1526 xmlXPathDebugObjCounterPoint++;
1527 if (xmlXPathDebugObjCounterPoint >
1528 xmlXPathDebugObjMaxPoint)
1529 xmlXPathDebugObjMaxPoint =
1530 xmlXPathDebugObjCounterPoint;
1531 break;
1532 case XPATH_RANGE:
1533 if (! isCached)
1534 xmlXPathDebugObjTotalRange++;
1535 xmlXPathDebugObjCounterRange++;
1536 if (xmlXPathDebugObjCounterRange >
1537 xmlXPathDebugObjMaxRange)
1538 xmlXPathDebugObjMaxRange =
1539 xmlXPathDebugObjCounterRange;
1540 break;
1541 case XPATH_LOCATIONSET:
1542 if (! isCached)
1543 xmlXPathDebugObjTotalLocset++;
1544 xmlXPathDebugObjCounterLocset++;
1545 if (xmlXPathDebugObjCounterLocset >
1546 xmlXPathDebugObjMaxLocset)
1547 xmlXPathDebugObjMaxLocset =
1548 xmlXPathDebugObjCounterLocset;
1549 break;
1550 case XPATH_USERS:
1551 if (! isCached)
1552 xmlXPathDebugObjTotalUsers++;
1553 xmlXPathDebugObjCounterUsers++;
1554 if (xmlXPathDebugObjCounterUsers >
1555 xmlXPathDebugObjMaxUsers)
1556 xmlXPathDebugObjMaxUsers =
1557 xmlXPathDebugObjCounterUsers;
1558 break;
1559 case XPATH_XSLT_TREE:
1560 if (! isCached)
1561 xmlXPathDebugObjTotalXSLTTree++;
1562 xmlXPathDebugObjCounterXSLTTree++;
1563 if (xmlXPathDebugObjCounterXSLTTree >
1564 xmlXPathDebugObjMaxXSLTTree)
1565 xmlXPathDebugObjMaxXSLTTree =
1566 xmlXPathDebugObjCounterXSLTTree;
1567 break;
1568 default:
1569 break;
1570 }
1571 if (! isCached)
1572 xmlXPathDebugObjTotalAll++;
1573 xmlXPathDebugObjCounterAll++;
1574 if (xmlXPathDebugObjCounterAll >
1575 xmlXPathDebugObjMaxAll)
1576 xmlXPathDebugObjMaxAll =
1577 xmlXPathDebugObjCounterAll;
1578}
1579
1580static void
1581xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1582 xmlXPathObjectType objType)
1583{
1584 int isCached = 0;
1585
1586 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001587 if (ctxt->cache != NULL) {
1588 xmlXPathContextCachePtr cache =
1589 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001590
1591 isCached = 1;
1592
1593 cache->dbgCachedAll++;
1594 switch (objType) {
1595 case XPATH_UNDEFINED:
1596 cache->dbgCachedUndefined++;
1597 break;
1598 case XPATH_NODESET:
1599 cache->dbgCachedNodeset++;
1600 break;
1601 case XPATH_BOOLEAN:
1602 cache->dbgCachedBool++;
1603 break;
1604 case XPATH_NUMBER:
1605 cache->dbgCachedNumber++;
1606 break;
1607 case XPATH_STRING:
1608 cache->dbgCachedString++;
1609 break;
1610 case XPATH_POINT:
1611 cache->dbgCachedPoint++;
1612 break;
1613 case XPATH_RANGE:
1614 cache->dbgCachedRange++;
1615 break;
1616 case XPATH_LOCATIONSET:
1617 cache->dbgCachedLocset++;
1618 break;
1619 case XPATH_USERS:
1620 cache->dbgCachedUsers++;
1621 break;
1622 case XPATH_XSLT_TREE:
1623 cache->dbgCachedXSLTTree++;
1624 break;
1625 default:
1626 break;
1627 }
1628
1629 }
1630 }
1631 switch (objType) {
1632 case XPATH_UNDEFINED:
1633 xmlXPathDebugObjCounterUndefined--;
1634 break;
1635 case XPATH_NODESET:
1636 xmlXPathDebugObjCounterNodeset--;
1637 break;
1638 case XPATH_BOOLEAN:
1639 xmlXPathDebugObjCounterBool--;
1640 break;
1641 case XPATH_NUMBER:
1642 xmlXPathDebugObjCounterNumber--;
1643 break;
1644 case XPATH_STRING:
1645 xmlXPathDebugObjCounterString--;
1646 break;
1647 case XPATH_POINT:
1648 xmlXPathDebugObjCounterPoint--;
1649 break;
1650 case XPATH_RANGE:
1651 xmlXPathDebugObjCounterRange--;
1652 break;
1653 case XPATH_LOCATIONSET:
1654 xmlXPathDebugObjCounterLocset--;
1655 break;
1656 case XPATH_USERS:
1657 xmlXPathDebugObjCounterUsers--;
1658 break;
1659 case XPATH_XSLT_TREE:
1660 xmlXPathDebugObjCounterXSLTTree--;
1661 break;
1662 default:
1663 break;
1664 }
1665 xmlXPathDebugObjCounterAll--;
1666}
1667
1668/* REVISIT TODO: Make this static when committing */
1669static void
1670xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
1671{
1672 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
1673 reqXSLTTree, reqUndefined;
1674 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
1675 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
1676 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
1677 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
1678 int leftObjs = xmlXPathDebugObjCounterAll;
1679
1680 reqAll = xmlXPathDebugObjTotalAll;
1681 reqNodeset = xmlXPathDebugObjTotalNodeset;
1682 reqString = xmlXPathDebugObjTotalString;
1683 reqBool = xmlXPathDebugObjTotalBool;
1684 reqNumber = xmlXPathDebugObjTotalNumber;
1685 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
1686 reqUndefined = xmlXPathDebugObjTotalUndefined;
1687
1688 printf("# XPath object usage:\n");
1689
1690 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001691 if (ctxt->cache != NULL) {
1692 xmlXPathContextCachePtr cache =
1693 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001694
1695 reAll = cache->dbgReusedAll;
1696 reqAll += reAll;
1697 reNodeset = cache->dbgReusedNodeset;
1698 reqNodeset += reNodeset;
1699 reString = cache->dbgReusedString;
1700 reqString += reString;
1701 reBool = cache->dbgReusedBool;
1702 reqBool += reBool;
1703 reNumber = cache->dbgReusedNumber;
1704 reqNumber += reNumber;
1705 reXSLTTree = cache->dbgReusedXSLTTree;
1706 reqXSLTTree += reXSLTTree;
1707 reUndefined = cache->dbgReusedUndefined;
1708 reqUndefined += reUndefined;
1709
1710 caAll = cache->dbgCachedAll;
1711 caBool = cache->dbgCachedBool;
1712 caNodeset = cache->dbgCachedNodeset;
1713 caString = cache->dbgCachedString;
1714 caNumber = cache->dbgCachedNumber;
1715 caXSLTTree = cache->dbgCachedXSLTTree;
1716 caUndefined = cache->dbgCachedUndefined;
1717
1718 if (cache->nodesetObjs)
1719 leftObjs -= cache->nodesetObjs->number;
1720 if (cache->stringObjs)
1721 leftObjs -= cache->stringObjs->number;
1722 if (cache->booleanObjs)
1723 leftObjs -= cache->booleanObjs->number;
1724 if (cache->numberObjs)
1725 leftObjs -= cache->numberObjs->number;
1726 if (cache->miscObjs)
1727 leftObjs -= cache->miscObjs->number;
1728 }
1729 }
1730
1731 printf("# all\n");
1732 printf("# total : %d\n", reqAll);
1733 printf("# left : %d\n", leftObjs);
1734 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
1735 printf("# reused : %d\n", reAll);
1736 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
1737
1738 printf("# node-sets\n");
1739 printf("# total : %d\n", reqNodeset);
1740 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
1741 printf("# reused : %d\n", reNodeset);
1742 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
1743
1744 printf("# strings\n");
1745 printf("# total : %d\n", reqString);
1746 printf("# created: %d\n", xmlXPathDebugObjTotalString);
1747 printf("# reused : %d\n", reString);
1748 printf("# max : %d\n", xmlXPathDebugObjMaxString);
1749
1750 printf("# booleans\n");
1751 printf("# total : %d\n", reqBool);
1752 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
1753 printf("# reused : %d\n", reBool);
1754 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
1755
1756 printf("# numbers\n");
1757 printf("# total : %d\n", reqNumber);
1758 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
1759 printf("# reused : %d\n", reNumber);
1760 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
1761
1762 printf("# XSLT result tree fragments\n");
1763 printf("# total : %d\n", reqXSLTTree);
1764 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
1765 printf("# reused : %d\n", reXSLTTree);
1766 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
1767
1768 printf("# undefined\n");
1769 printf("# total : %d\n", reqUndefined);
1770 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
1771 printf("# reused : %d\n", reUndefined);
1772 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
1773
1774}
1775
1776#endif /* XP_DEBUG_OBJ_USAGE */
1777
Daniel Veillard017b1082001-06-21 11:20:21 +00001778#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001779
1780/************************************************************************
1781 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001782 * XPath object caching *
1783 * *
1784 ************************************************************************/
1785
1786/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001787 * xmlXPathNewCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001788 *
1789 * Create a new object cache
1790 *
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001791 * Returns the xmlXPathCache just allocated.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001792 */
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001793static xmlXPathContextCachePtr
1794xmlXPathNewCache(void)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001795{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001796 xmlXPathContextCachePtr ret;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001797
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001798 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001799 if (ret == NULL) {
1800 xmlXPathErrMemory(NULL, "creating object cache\n");
1801 return(NULL);
1802 }
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001803 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001804 ret->maxNodeset = 100;
1805 ret->maxString = 100;
1806 ret->maxBoolean = 100;
1807 ret->maxNumber = 100;
1808 ret->maxMisc = 100;
1809 return(ret);
1810}
1811
1812static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001813xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001814{
1815 int i;
1816 xmlXPathObjectPtr obj;
1817
1818 if (list == NULL)
1819 return;
1820
1821 for (i = 0; i < list->number; i++) {
1822 obj = list->items[i];
1823 /*
1824 * Note that it is already assured that we don't need to
1825 * look out for namespace nodes in the node-set.
1826 */
1827 if (obj->nodesetval != NULL) {
1828 if (obj->nodesetval->nodeTab != NULL)
1829 xmlFree(obj->nodesetval->nodeTab);
1830 xmlFree(obj->nodesetval);
1831 }
1832 xmlFree(obj);
1833#ifdef XP_DEBUG_OBJ_USAGE
1834 xmlXPathDebugObjCounterAll--;
1835#endif
1836 }
1837 xmlPointerListFree(list);
1838}
1839
1840static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001841xmlXPathFreeCache(xmlXPathContextCachePtr cache)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001842{
1843 if (cache == NULL)
1844 return;
1845 if (cache->nodesetObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001846 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001847 if (cache->stringObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001848 xmlXPathCacheFreeObjectList(cache->stringObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001849 if (cache->booleanObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001850 xmlXPathCacheFreeObjectList(cache->booleanObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001851 if (cache->numberObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001852 xmlXPathCacheFreeObjectList(cache->numberObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001853 if (cache->miscObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001854 xmlXPathCacheFreeObjectList(cache->miscObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001855 xmlFree(cache);
1856}
1857
1858/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001859 * xmlXPathContextSetCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001860 *
1861 * @ctxt: the XPath context
1862 * @active: enables/disables (creates/frees) the cache
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001863 * @value: a value with semantics dependant on @options
1864 * @options: options (currently only the value 0 is used)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001865 *
1866 * Creates/frees an object cache on the XPath context.
1867 * If activates XPath objects (xmlXPathObject) will be cached internally
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001868 * to be reused.
1869 * @options:
1870 * 0: This will set the XPath object caching:
1871 * @value:
1872 * This will set the maximum number of XPath objects
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001873 * to be cached per slot
1874 * There are 5 slots for: node-set, string, number, boolean, and
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001875 * misc objects. Use <0 for the default number (100).
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001876 * Other values for @options have currently no effect.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001877 *
1878 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1879 */
1880int
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001881xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1882 int active,
1883 int value,
1884 int options)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001885{
1886 if (ctxt == NULL)
1887 return(-1);
1888 if (active) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001889 xmlXPathContextCachePtr cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001890
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001891 if (ctxt->cache == NULL) {
1892 ctxt->cache = xmlXPathNewCache();
1893 if (ctxt->cache == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001894 return(-1);
1895 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001896 cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001897 if (options == 0) {
1898 if (value < 0)
1899 value = 100;
1900 cache->maxNodeset = value;
1901 cache->maxString = value;
1902 cache->maxNumber = value;
1903 cache->maxBoolean = value;
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001904 cache->maxMisc = value;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001905 }
1906 } else if (ctxt->cache != NULL) {
1907 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1908 ctxt->cache = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001909 }
1910 return(0);
1911}
1912
1913/**
1914 * xmlXPathCacheWrapNodeSet:
1915 * @ctxt: the XPath context
1916 * @val: the NodePtr value
1917 *
1918 * This is the cached version of xmlXPathWrapNodeSet().
1919 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1920 *
1921 * Returns the created or reused object.
1922 */
1923static xmlXPathObjectPtr
1924xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
1925{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001926 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1927 xmlXPathContextCachePtr cache =
1928 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001929
1930 if ((cache->miscObjs != NULL) &&
1931 (cache->miscObjs->number != 0))
1932 {
1933 xmlXPathObjectPtr ret;
1934
1935 ret = (xmlXPathObjectPtr)
1936 cache->miscObjs->items[--cache->miscObjs->number];
1937 ret->type = XPATH_NODESET;
1938 ret->nodesetval = val;
1939#ifdef XP_DEBUG_OBJ_USAGE
1940 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
1941#endif
1942 return(ret);
1943 }
1944 }
1945
1946 return(xmlXPathWrapNodeSet(val));
1947
1948}
1949
1950/**
1951 * xmlXPathCacheWrapString:
1952 * @ctxt: the XPath context
1953 * @val: the xmlChar * value
1954 *
1955 * This is the cached version of xmlXPathWrapString().
1956 * Wraps the @val string into an XPath object.
1957 *
1958 * Returns the created or reused object.
1959 */
1960static xmlXPathObjectPtr
1961xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
1962{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001963 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1964 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001965
1966 if ((cache->stringObjs != NULL) &&
1967 (cache->stringObjs->number != 0))
1968 {
1969
1970 xmlXPathObjectPtr ret;
1971
1972 ret = (xmlXPathObjectPtr)
1973 cache->stringObjs->items[--cache->stringObjs->number];
1974 ret->type = XPATH_STRING;
1975 ret->stringval = val;
1976#ifdef XP_DEBUG_OBJ_USAGE
1977 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1978#endif
1979 return(ret);
1980 } else if ((cache->miscObjs != NULL) &&
1981 (cache->miscObjs->number != 0))
1982 {
1983 xmlXPathObjectPtr ret;
1984 /*
1985 * Fallback to misc-cache.
1986 */
1987 ret = (xmlXPathObjectPtr)
1988 cache->miscObjs->items[--cache->miscObjs->number];
1989
1990 ret->type = XPATH_STRING;
1991 ret->stringval = val;
1992#ifdef XP_DEBUG_OBJ_USAGE
1993 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1994#endif
1995 return(ret);
1996 }
1997 }
1998 return(xmlXPathWrapString(val));
1999}
2000
2001/**
2002 * xmlXPathCacheNewNodeSet:
2003 * @ctxt: the XPath context
2004 * @val: the NodePtr value
2005 *
2006 * This is the cached version of xmlXPathNewNodeSet().
2007 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2008 * it with the single Node @val
2009 *
2010 * Returns the created or reused object.
2011 */
2012static xmlXPathObjectPtr
2013xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2014{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002015 if ((ctxt != NULL) && (ctxt->cache)) {
2016 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002017
2018 if ((cache->nodesetObjs != NULL) &&
2019 (cache->nodesetObjs->number != 0))
2020 {
2021 xmlXPathObjectPtr ret;
2022 /*
2023 * Use the nodset-cache.
2024 */
2025 ret = (xmlXPathObjectPtr)
2026 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2027 ret->type = XPATH_NODESET;
2028 ret->boolval = 0;
2029 if (val) {
2030 if ((ret->nodesetval->nodeMax == 0) ||
2031 (val->type == XML_NAMESPACE_DECL))
2032 {
2033 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2034 } else {
2035 ret->nodesetval->nodeTab[0] = val;
2036 ret->nodesetval->nodeNr = 1;
2037 }
2038 }
2039#ifdef XP_DEBUG_OBJ_USAGE
2040 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2041#endif
2042 return(ret);
2043 } else if ((cache->miscObjs != NULL) &&
2044 (cache->miscObjs->number != 0))
2045 {
2046 xmlXPathObjectPtr ret;
2047 /*
2048 * Fallback to misc-cache.
2049 */
2050
2051 ret = (xmlXPathObjectPtr)
2052 cache->miscObjs->items[--cache->miscObjs->number];
2053
2054 ret->type = XPATH_NODESET;
2055 ret->boolval = 0;
2056 ret->nodesetval = xmlXPathNodeSetCreate(val);
2057#ifdef XP_DEBUG_OBJ_USAGE
2058 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2059#endif
2060 return(ret);
2061 }
2062 }
2063 return(xmlXPathNewNodeSet(val));
2064}
2065
2066/**
2067 * xmlXPathCacheNewCString:
2068 * @ctxt: the XPath context
2069 * @val: the char * value
2070 *
2071 * This is the cached version of xmlXPathNewCString().
2072 * Acquire an xmlXPathObjectPtr of type string and of value @val
2073 *
2074 * Returns the created or reused object.
2075 */
2076static xmlXPathObjectPtr
2077xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2078{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002079 if ((ctxt != NULL) && (ctxt->cache)) {
2080 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002081
2082 if ((cache->stringObjs != NULL) &&
2083 (cache->stringObjs->number != 0))
2084 {
2085 xmlXPathObjectPtr ret;
2086
2087 ret = (xmlXPathObjectPtr)
2088 cache->stringObjs->items[--cache->stringObjs->number];
2089
2090 ret->type = XPATH_STRING;
2091 ret->stringval = xmlStrdup(BAD_CAST val);
2092#ifdef XP_DEBUG_OBJ_USAGE
2093 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2094#endif
2095 return(ret);
2096 } else if ((cache->miscObjs != NULL) &&
2097 (cache->miscObjs->number != 0))
2098 {
2099 xmlXPathObjectPtr ret;
2100
2101 ret = (xmlXPathObjectPtr)
2102 cache->miscObjs->items[--cache->miscObjs->number];
2103
2104 ret->type = XPATH_STRING;
2105 ret->stringval = xmlStrdup(BAD_CAST val);
2106#ifdef XP_DEBUG_OBJ_USAGE
2107 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2108#endif
2109 return(ret);
2110 }
2111 }
2112 return(xmlXPathNewCString(val));
2113}
2114
2115/**
2116 * xmlXPathCacheNewString:
2117 * @ctxt: the XPath context
2118 * @val: the xmlChar * value
2119 *
2120 * This is the cached version of xmlXPathNewString().
2121 * Acquire an xmlXPathObjectPtr of type string and of value @val
2122 *
2123 * Returns the created or reused object.
2124 */
2125static xmlXPathObjectPtr
2126xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2127{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002128 if ((ctxt != NULL) && (ctxt->cache)) {
2129 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002130
2131 if ((cache->stringObjs != NULL) &&
2132 (cache->stringObjs->number != 0))
2133 {
2134 xmlXPathObjectPtr ret;
2135
2136 ret = (xmlXPathObjectPtr)
2137 cache->stringObjs->items[--cache->stringObjs->number];
2138 ret->type = XPATH_STRING;
2139 if (val != NULL)
2140 ret->stringval = xmlStrdup(val);
2141 else
2142 ret->stringval = xmlStrdup((const xmlChar *)"");
2143#ifdef XP_DEBUG_OBJ_USAGE
2144 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2145#endif
2146 return(ret);
2147 } else if ((cache->miscObjs != NULL) &&
2148 (cache->miscObjs->number != 0))
2149 {
2150 xmlXPathObjectPtr ret;
2151
2152 ret = (xmlXPathObjectPtr)
2153 cache->miscObjs->items[--cache->miscObjs->number];
2154
2155 ret->type = XPATH_STRING;
2156 if (val != NULL)
2157 ret->stringval = xmlStrdup(val);
2158 else
2159 ret->stringval = xmlStrdup((const xmlChar *)"");
2160#ifdef XP_DEBUG_OBJ_USAGE
2161 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2162#endif
2163 return(ret);
2164 }
2165 }
2166 return(xmlXPathNewString(val));
2167}
2168
2169/**
2170 * xmlXPathCacheNewBoolean:
2171 * @ctxt: the XPath context
2172 * @val: the boolean value
2173 *
2174 * This is the cached version of xmlXPathNewBoolean().
2175 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2176 *
2177 * Returns the created or reused object.
2178 */
2179static xmlXPathObjectPtr
2180xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2181{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002182 if ((ctxt != NULL) && (ctxt->cache)) {
2183 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002184
2185 if ((cache->booleanObjs != NULL) &&
2186 (cache->booleanObjs->number != 0))
2187 {
2188 xmlXPathObjectPtr ret;
2189
2190 ret = (xmlXPathObjectPtr)
2191 cache->booleanObjs->items[--cache->booleanObjs->number];
2192 ret->type = XPATH_BOOLEAN;
2193 ret->boolval = (val != 0);
2194#ifdef XP_DEBUG_OBJ_USAGE
2195 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2196#endif
2197 return(ret);
2198 } else if ((cache->miscObjs != NULL) &&
2199 (cache->miscObjs->number != 0))
2200 {
2201 xmlXPathObjectPtr ret;
2202
2203 ret = (xmlXPathObjectPtr)
2204 cache->miscObjs->items[--cache->miscObjs->number];
2205
2206 ret->type = XPATH_BOOLEAN;
2207 ret->boolval = (val != 0);
2208#ifdef XP_DEBUG_OBJ_USAGE
2209 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2210#endif
2211 return(ret);
2212 }
2213 }
2214 return(xmlXPathNewBoolean(val));
2215}
2216
2217/**
2218 * xmlXPathCacheNewFloat:
2219 * @ctxt: the XPath context
2220 * @val: the double value
2221 *
2222 * This is the cached version of xmlXPathNewFloat().
2223 * Acquires an xmlXPathObjectPtr of type double and of value @val
2224 *
2225 * Returns the created or reused object.
2226 */
2227static xmlXPathObjectPtr
2228xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2229{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002230 if ((ctxt != NULL) && (ctxt->cache)) {
2231 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002232
2233 if ((cache->numberObjs != NULL) &&
2234 (cache->numberObjs->number != 0))
2235 {
2236 xmlXPathObjectPtr ret;
2237
2238 ret = (xmlXPathObjectPtr)
2239 cache->numberObjs->items[--cache->numberObjs->number];
2240 ret->type = XPATH_NUMBER;
2241 ret->floatval = val;
2242#ifdef XP_DEBUG_OBJ_USAGE
2243 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2244#endif
2245 return(ret);
2246 } else if ((cache->miscObjs != NULL) &&
2247 (cache->miscObjs->number != 0))
2248 {
2249 xmlXPathObjectPtr ret;
2250
2251 ret = (xmlXPathObjectPtr)
2252 cache->miscObjs->items[--cache->miscObjs->number];
2253
2254 ret->type = XPATH_NUMBER;
2255 ret->floatval = val;
2256#ifdef XP_DEBUG_OBJ_USAGE
2257 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2258#endif
2259 return(ret);
2260 }
2261 }
2262 return(xmlXPathNewFloat(val));
2263}
2264
2265/**
2266 * xmlXPathCacheConvertString:
2267 * @ctxt: the XPath context
2268 * @val: an XPath object
2269 *
2270 * This is the cached version of xmlXPathConvertString().
2271 * Converts an existing object to its string() equivalent
2272 *
2273 * Returns a created or reused object, the old one is freed (cached)
2274 * (or the operation is done directly on @val)
2275 */
2276
2277static xmlXPathObjectPtr
2278xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2279 xmlChar *res = NULL;
2280
2281 if (val == NULL)
2282 return(xmlXPathCacheNewCString(ctxt, ""));
2283
2284 switch (val->type) {
2285 case XPATH_UNDEFINED:
2286#ifdef DEBUG_EXPR
2287 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2288#endif
2289 break;
2290 case XPATH_NODESET:
2291 case XPATH_XSLT_TREE:
2292 res = xmlXPathCastNodeSetToString(val->nodesetval);
2293 break;
2294 case XPATH_STRING:
2295 return(val);
2296 case XPATH_BOOLEAN:
2297 res = xmlXPathCastBooleanToString(val->boolval);
2298 break;
2299 case XPATH_NUMBER:
2300 res = xmlXPathCastNumberToString(val->floatval);
2301 break;
2302 case XPATH_USERS:
2303 case XPATH_POINT:
2304 case XPATH_RANGE:
2305 case XPATH_LOCATIONSET:
2306 TODO;
2307 break;
2308 }
2309 xmlXPathReleaseObject(ctxt, val);
2310 if (res == NULL)
2311 return(xmlXPathCacheNewCString(ctxt, ""));
2312 return(xmlXPathCacheWrapString(ctxt, res));
2313}
2314
2315/**
2316 * xmlXPathCacheObjectCopy:
2317 * @ctxt: the XPath context
2318 * @val: the original object
2319 *
2320 * This is the cached version of xmlXPathObjectCopy().
2321 * Acquire a copy of a given object
2322 *
2323 * Returns a created or reused created object.
2324 */
2325static xmlXPathObjectPtr
2326xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2327{
2328 if (val == NULL)
2329 return(NULL);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002330
2331 switch (val->type) {
2332 case XPATH_NODESET:
2333 if (XP_HAS_CACHE(ctxt))
2334 return(xmlXPathCacheWrapNodeSet(ctxt,
2335 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2336 case XPATH_STRING:
2337 if (XP_HAS_CACHE(ctxt))
2338 return(xmlXPathCacheNewString(ctxt, val->stringval));
2339 case XPATH_BOOLEAN:
2340 if (XP_HAS_CACHE(ctxt))
2341 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2342 case XPATH_NUMBER:
2343 if (XP_HAS_CACHE(ctxt))
2344 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2345 default:
2346 break;
2347 }
2348 return(xmlXPathObjectCopy(val));
2349}
2350
2351/**
2352 * xmlXPathCacheConvertBoolean:
2353 * @ctxt: the XPath context
2354 * @val: an XPath object
2355 *
2356 * This is the cached version of xmlXPathConvertBoolean().
2357 * Converts an existing object to its boolean() equivalent
2358 *
2359 * Returns a created or reused object, the old one is freed (or the operation
2360 * is done directly on @val)
2361 */
2362static xmlXPathObjectPtr
2363xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2364 xmlXPathObjectPtr ret;
2365
2366 if (val == NULL)
2367 return(xmlXPathCacheNewBoolean(ctxt, 0));
2368 if (val->type == XPATH_BOOLEAN)
2369 return(val);
2370 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2371 xmlXPathReleaseObject(ctxt, val);
2372 return(ret);
2373}
2374
2375/**
2376 * xmlXPathCacheConvertNumber:
2377 * @ctxt: the XPath context
2378 * @val: an XPath object
2379 *
2380 * This is the cached version of xmlXPathConvertNumber().
2381 * Converts an existing object to its number() equivalent
2382 *
2383 * Returns a created or reused object, the old one is freed (or the operation
2384 * is done directly on @val)
2385 */
2386static xmlXPathObjectPtr
2387xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2388 xmlXPathObjectPtr ret;
2389
2390 if (val == NULL)
2391 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2392 if (val->type == XPATH_NUMBER)
2393 return(val);
2394 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2395 xmlXPathReleaseObject(ctxt, val);
2396 return(ret);
2397}
2398
2399/************************************************************************
2400 * *
Owen Taylor3473f882001-02-23 17:55:21 +00002401 * Parser stacks related functions and macros *
2402 * *
2403 ************************************************************************/
2404
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002405/**
2406 * valuePop:
2407 * @ctxt: an XPath evaluation context
2408 *
2409 * Pops the top XPath object from the value stack
2410 *
2411 * Returns the XPath object just removed
2412 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002413xmlXPathObjectPtr
Daniel Veillard1c732d22002-11-30 11:22:59 +00002414valuePop(xmlXPathParserContextPtr ctxt)
2415{
2416 xmlXPathObjectPtr ret;
2417
Daniel Veillarda82b1822004-11-08 16:24:57 +00002418 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard24505b02005-07-28 23:49:35 +00002419 return (NULL);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002420 ctxt->valueNr--;
2421 if (ctxt->valueNr > 0)
2422 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2423 else
2424 ctxt->value = NULL;
2425 ret = ctxt->valueTab[ctxt->valueNr];
Daniel Veillard24505b02005-07-28 23:49:35 +00002426 ctxt->valueTab[ctxt->valueNr] = NULL;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002427 return (ret);
2428}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002429/**
2430 * valuePush:
2431 * @ctxt: an XPath evaluation context
2432 * @value: the XPath object
2433 *
2434 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002435 *
2436 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002437 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002438int
Daniel Veillard1c732d22002-11-30 11:22:59 +00002439valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2440{
Daniel Veillarda82b1822004-11-08 16:24:57 +00002441 if ((ctxt == NULL) || (value == NULL)) return(-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002442 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002443 xmlXPathObjectPtr *tmp;
2444
2445 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2446 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00002447 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002448 if (tmp == NULL) {
Daniel Veillard1c732d22002-11-30 11:22:59 +00002449 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
2450 return (0);
2451 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002452 ctxt->valueMax *= 2;
2453 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002454 }
2455 ctxt->valueTab[ctxt->valueNr] = value;
2456 ctxt->value = value;
2457 return (ctxt->valueNr++);
2458}
Owen Taylor3473f882001-02-23 17:55:21 +00002459
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002460/**
2461 * xmlXPathPopBoolean:
2462 * @ctxt: an XPath parser context
2463 *
2464 * Pops a boolean from the stack, handling conversion if needed.
2465 * Check error with #xmlXPathCheckError.
2466 *
2467 * Returns the boolean
2468 */
2469int
2470xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2471 xmlXPathObjectPtr obj;
2472 int ret;
2473
2474 obj = valuePop(ctxt);
2475 if (obj == NULL) {
2476 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2477 return(0);
2478 }
William M. Brack08171912003-12-29 02:52:11 +00002479 if (obj->type != XPATH_BOOLEAN)
2480 ret = xmlXPathCastToBoolean(obj);
2481 else
2482 ret = obj->boolval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002483 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002484 return(ret);
2485}
2486
2487/**
2488 * xmlXPathPopNumber:
2489 * @ctxt: an XPath parser context
2490 *
2491 * Pops a number from the stack, handling conversion if needed.
2492 * Check error with #xmlXPathCheckError.
2493 *
2494 * Returns the number
2495 */
2496double
2497xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2498 xmlXPathObjectPtr obj;
2499 double ret;
2500
2501 obj = valuePop(ctxt);
2502 if (obj == NULL) {
2503 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2504 return(0);
2505 }
William M. Brack08171912003-12-29 02:52:11 +00002506 if (obj->type != XPATH_NUMBER)
2507 ret = xmlXPathCastToNumber(obj);
2508 else
2509 ret = obj->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002510 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002511 return(ret);
2512}
2513
2514/**
2515 * xmlXPathPopString:
2516 * @ctxt: an XPath parser context
2517 *
2518 * Pops a string from the stack, handling conversion if needed.
2519 * Check error with #xmlXPathCheckError.
2520 *
2521 * Returns the string
2522 */
2523xmlChar *
2524xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2525 xmlXPathObjectPtr obj;
2526 xmlChar * ret;
2527
2528 obj = valuePop(ctxt);
2529 if (obj == NULL) {
2530 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2531 return(NULL);
2532 }
William M. Brack08171912003-12-29 02:52:11 +00002533 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002534 /* TODO: needs refactoring somewhere else */
2535 if (obj->stringval == ret)
2536 obj->stringval = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002537 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002538 return(ret);
2539}
2540
2541/**
2542 * xmlXPathPopNodeSet:
2543 * @ctxt: an XPath parser context
2544 *
2545 * Pops a node-set from the stack, handling conversion if needed.
2546 * Check error with #xmlXPathCheckError.
2547 *
2548 * Returns the node-set
2549 */
2550xmlNodeSetPtr
2551xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2552 xmlXPathObjectPtr obj;
2553 xmlNodeSetPtr ret;
2554
Daniel Veillardf2a36f92004-11-08 17:55:01 +00002555 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002556 if (ctxt->value == NULL) {
2557 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2558 return(NULL);
2559 }
2560 if (!xmlXPathStackIsNodeSet(ctxt)) {
2561 xmlXPathSetTypeError(ctxt);
2562 return(NULL);
2563 }
2564 obj = valuePop(ctxt);
2565 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00002566#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00002567 /* to fix memory leak of not clearing obj->user */
2568 if (obj->boolval && obj->user != NULL)
2569 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00002570#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002571 obj->nodesetval = NULL;
2572 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002573 return(ret);
2574}
2575
2576/**
2577 * xmlXPathPopExternal:
2578 * @ctxt: an XPath parser context
2579 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002580 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002581 * Check error with #xmlXPathCheckError.
2582 *
2583 * Returns the object
2584 */
2585void *
2586xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2587 xmlXPathObjectPtr obj;
2588 void * ret;
2589
Daniel Veillarda82b1822004-11-08 16:24:57 +00002590 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002591 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2592 return(NULL);
2593 }
2594 if (ctxt->value->type != XPATH_USERS) {
2595 xmlXPathSetTypeError(ctxt);
2596 return(NULL);
2597 }
2598 obj = valuePop(ctxt);
2599 ret = obj->user;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002600 obj->user = NULL;
2601 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002602 return(ret);
2603}
2604
Owen Taylor3473f882001-02-23 17:55:21 +00002605/*
2606 * Macros for accessing the content. Those should be used only by the parser,
2607 * and not exported.
2608 *
2609 * Dirty macros, i.e. one need to make assumption on the context to use them
2610 *
2611 * CUR_PTR return the current pointer to the xmlChar to be parsed.
2612 * CUR returns the current xmlChar value, i.e. a 8 bit value
2613 * in ISO-Latin or UTF-8.
2614 * This should be used internally by the parser
2615 * only to compare to ASCII values otherwise it would break when
2616 * running with UTF-8 encoding.
2617 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
2618 * to compare on ASCII based substring.
2619 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2620 * strings within the parser.
2621 * CURRENT Returns the current char value, with the full decoding of
2622 * UTF-8 if we are using this mode. It returns an int.
2623 * NEXT Skip to the next character, this does the proper decoding
2624 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
2625 * It returns the pointer to the current xmlChar.
2626 */
2627
2628#define CUR (*ctxt->cur)
2629#define SKIP(val) ctxt->cur += (val)
2630#define NXT(val) ctxt->cur[(val)]
2631#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00002632#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2633
2634#define COPY_BUF(l,b,i,v) \
2635 if (l == 1) b[i++] = (xmlChar) v; \
2636 else i += xmlCopyChar(l,&b[i],v)
2637
2638#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00002639
2640#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00002641 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00002642
2643#define CURRENT (*ctxt->cur)
2644#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
2645
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002646
2647#ifndef DBL_DIG
2648#define DBL_DIG 16
2649#endif
2650#ifndef DBL_EPSILON
2651#define DBL_EPSILON 1E-9
2652#endif
2653
2654#define UPPER_DOUBLE 1E9
2655#define LOWER_DOUBLE 1E-5
2656
2657#define INTEGER_DIGITS DBL_DIG
2658#define FRACTION_DIGITS (DBL_DIG + 1)
2659#define EXPONENT_DIGITS (3 + 2)
2660
2661/**
2662 * xmlXPathFormatNumber:
2663 * @number: number to format
2664 * @buffer: output buffer
2665 * @buffersize: size of output buffer
2666 *
2667 * Convert the number into a string representation.
2668 */
2669static void
2670xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2671{
Daniel Veillardcda96922001-08-21 10:56:31 +00002672 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002673 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00002674 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002675 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002676 break;
2677 case -1:
2678 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002679 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002680 break;
2681 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00002682 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002683 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002684 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00002685 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002686 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002687 } else if (number == ((int) number)) {
2688 char work[30];
2689 char *ptr, *cur;
Daniel Veillardb3d14912005-09-04 20:47:39 +00002690 int value = (int) number;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002691
2692 ptr = &buffer[0];
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002693 if (value == 0) {
2694 *ptr++ = '0';
2695 } else {
Daniel Veillardb3d14912005-09-04 20:47:39 +00002696 snprintf(work, 29, "%d", value);
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002697 cur = &work[0];
Daniel Veillardb3d14912005-09-04 20:47:39 +00002698 while ((*cur) && (ptr - buffer < buffersize)) {
2699 *ptr++ = *cur++;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002700 }
2701 }
2702 if (ptr - buffer < buffersize) {
2703 *ptr = 0;
2704 } else if (buffersize > 0) {
2705 ptr--;
2706 *ptr = 0;
2707 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002708 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002709 /* 3 is sign, decimal point, and terminating zero */
2710 char work[DBL_DIG + EXPONENT_DIGITS + 3];
2711 int integer_place, fraction_place;
2712 char *ptr;
2713 char *after_fraction;
2714 double absolute_value;
2715 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002716
Bjorn Reese70a9da52001-04-21 16:57:29 +00002717 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002718
Bjorn Reese70a9da52001-04-21 16:57:29 +00002719 /*
2720 * First choose format - scientific or regular floating point.
2721 * In either case, result is in work, and after_fraction points
2722 * just past the fractional part.
2723 */
2724 if ( ((absolute_value > UPPER_DOUBLE) ||
2725 (absolute_value < LOWER_DOUBLE)) &&
2726 (absolute_value != 0.0) ) {
2727 /* Use scientific notation */
2728 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2729 fraction_place = DBL_DIG - 1;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002730 size = snprintf(work, sizeof(work),"%*.*e",
Bjorn Reese70a9da52001-04-21 16:57:29 +00002731 integer_place, fraction_place, number);
Daniel Veillard11ce4002006-03-10 00:36:23 +00002732 while ((size > 0) && (work[size] != 'e')) size--;
2733 after_fraction = work + size;
2734
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002735 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002736 else {
2737 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00002738 if (absolute_value > 0.0)
2739 integer_place = 1 + (int)log10(absolute_value);
2740 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00002741 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002742 fraction_place = (integer_place > 0)
2743 ? DBL_DIG - integer_place
2744 : DBL_DIG;
2745 size = snprintf(work, sizeof(work), "%0.*f",
2746 fraction_place, number);
2747 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002748 }
2749
Bjorn Reese70a9da52001-04-21 16:57:29 +00002750 /* Remove fractional trailing zeroes */
2751 ptr = after_fraction;
2752 while (*(--ptr) == '0')
2753 ;
2754 if (*ptr != '.')
2755 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002756 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002757
2758 /* Finally copy result back to caller */
2759 size = strlen(work) + 1;
2760 if (size > buffersize) {
2761 work[buffersize - 1] = 0;
2762 size = buffersize;
2763 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002764 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002765 }
2766 break;
2767 }
2768}
2769
Owen Taylor3473f882001-02-23 17:55:21 +00002770
2771/************************************************************************
2772 * *
2773 * Routines to handle NodeSets *
2774 * *
2775 ************************************************************************/
2776
2777/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002778 * xmlXPathOrderDocElems:
2779 * @doc: an input document
2780 *
2781 * Call this routine to speed up XPath computation on static documents.
2782 * This stamps all the element nodes with the document order
2783 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00002784 * field, the value stored is actually - the node number (starting at -1)
2785 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002786 *
William M. Brack08171912003-12-29 02:52:11 +00002787 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002788 * of error.
2789 */
2790long
2791xmlXPathOrderDocElems(xmlDocPtr doc) {
2792 long count = 0;
2793 xmlNodePtr cur;
2794
2795 if (doc == NULL)
2796 return(-1);
2797 cur = doc->children;
2798 while (cur != NULL) {
2799 if (cur->type == XML_ELEMENT_NODE) {
2800 cur->content = (void *) (-(++count));
2801 if (cur->children != NULL) {
2802 cur = cur->children;
2803 continue;
2804 }
2805 }
2806 if (cur->next != NULL) {
2807 cur = cur->next;
2808 continue;
2809 }
2810 do {
2811 cur = cur->parent;
2812 if (cur == NULL)
2813 break;
2814 if (cur == (xmlNodePtr) doc) {
2815 cur = NULL;
2816 break;
2817 }
2818 if (cur->next != NULL) {
2819 cur = cur->next;
2820 break;
2821 }
2822 } while (cur != NULL);
2823 }
2824 return(count);
2825}
2826
2827/**
Owen Taylor3473f882001-02-23 17:55:21 +00002828 * xmlXPathCmpNodes:
2829 * @node1: the first node
2830 * @node2: the second node
2831 *
2832 * Compare two nodes w.r.t document order
2833 *
2834 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00002835 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00002836 */
2837int
2838xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2839 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002840 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002841 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002842 xmlNodePtr cur, root;
2843
2844 if ((node1 == NULL) || (node2 == NULL))
2845 return(-2);
2846 /*
2847 * a couple of optimizations which will avoid computations in most cases
2848 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00002849 if (node1->type == XML_ATTRIBUTE_NODE) {
2850 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002851 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002852 node1 = node1->parent;
2853 }
2854 if (node2->type == XML_ATTRIBUTE_NODE) {
2855 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002856 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002857 node2 = node2->parent;
2858 }
2859 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00002860 if (attr1 == attr2) {
2861 /* not required, but we keep attributes in order */
2862 if (attr1 != 0) {
2863 cur = attrNode2->prev;
2864 while (cur != NULL) {
2865 if (cur == attrNode1)
2866 return (1);
2867 cur = cur->prev;
2868 }
2869 return (-1);
2870 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00002871 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00002872 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00002873 if (attr2 == 1)
2874 return(1);
2875 return(-1);
2876 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002877 if ((node1->type == XML_NAMESPACE_DECL) ||
2878 (node2->type == XML_NAMESPACE_DECL))
2879 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00002880 if (node1 == node2->prev)
2881 return(1);
2882 if (node1 == node2->next)
2883 return(-1);
2884
2885 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002886 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002887 */
2888 if ((node1->type == XML_ELEMENT_NODE) &&
2889 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002890 (0 > (long) node1->content) &&
2891 (0 > (long) node2->content) &&
2892 (node1->doc == node2->doc)) {
2893 long l1, l2;
2894
2895 l1 = -((long) node1->content);
2896 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002897 if (l1 < l2)
2898 return(1);
2899 if (l1 > l2)
2900 return(-1);
2901 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002902
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002903 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002904 * compute depth to root
2905 */
2906 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2907 if (cur == node1)
2908 return(1);
2909 depth2++;
2910 }
2911 root = cur;
2912 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2913 if (cur == node2)
2914 return(-1);
2915 depth1++;
2916 }
2917 /*
2918 * Distinct document (or distinct entities :-( ) case.
2919 */
2920 if (root != cur) {
2921 return(-2);
2922 }
2923 /*
2924 * get the nearest common ancestor.
2925 */
2926 while (depth1 > depth2) {
2927 depth1--;
2928 node1 = node1->parent;
2929 }
2930 while (depth2 > depth1) {
2931 depth2--;
2932 node2 = node2->parent;
2933 }
2934 while (node1->parent != node2->parent) {
2935 node1 = node1->parent;
2936 node2 = node2->parent;
2937 /* should not happen but just in case ... */
2938 if ((node1 == NULL) || (node2 == NULL))
2939 return(-2);
2940 }
2941 /*
2942 * Find who's first.
2943 */
Daniel Veillardf49be472004-02-17 11:48:18 +00002944 if (node1 == node2->prev)
2945 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00002946 if (node1 == node2->next)
2947 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00002948 /*
2949 * Speedup using document order if availble.
2950 */
2951 if ((node1->type == XML_ELEMENT_NODE) &&
2952 (node2->type == XML_ELEMENT_NODE) &&
2953 (0 > (long) node1->content) &&
2954 (0 > (long) node2->content) &&
2955 (node1->doc == node2->doc)) {
2956 long l1, l2;
2957
2958 l1 = -((long) node1->content);
2959 l2 = -((long) node2->content);
2960 if (l1 < l2)
2961 return(1);
2962 if (l1 > l2)
2963 return(-1);
2964 }
2965
Owen Taylor3473f882001-02-23 17:55:21 +00002966 for (cur = node1->next;cur != NULL;cur = cur->next)
2967 if (cur == node2)
2968 return(1);
2969 return(-1); /* assume there is no sibling list corruption */
2970}
2971
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00002972#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002973/**
2974 * xmlXPathCmpNodesExt:
2975 * @node1: the first node
2976 * @node2: the second node
2977 *
2978 * Compare two nodes w.r.t document order.
2979 * This one is optimized for handling of non-element nodes.
2980 *
2981 * Returns -2 in case of error 1 if first point < second point, 0 if
2982 * it's the same node, -1 otherwise
2983 */
2984static int
2985xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
2986 int depth1, depth2;
2987 int misc = 0, precedence1 = 0, precedence2 = 0;
2988 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
2989 xmlNodePtr cur, root;
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00002990 long l1, l2;
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002991
2992 if ((node1 == NULL) || (node2 == NULL))
2993 return(-2);
2994
2995 if (node1 == node2)
2996 return(0);
2997
2998 /*
2999 * a couple of optimizations which will avoid computations in most cases
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003000 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003001 switch (node1->type) {
3002 case XML_ELEMENT_NODE:
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003003 if (node2->type == XML_ELEMENT_NODE) {
3004 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
3005 (0 > (long) node2->content) &&
3006 (node1->doc == node2->doc))
3007 {
3008 l1 = -((long) node1->content);
3009 l2 = -((long) node2->content);
3010 if (l1 < l2)
3011 return(1);
3012 if (l1 > l2)
3013 return(-1);
3014 } else
3015 goto turtle_comparison;
3016 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003017 break;
3018 case XML_ATTRIBUTE_NODE:
3019 precedence1 = 1; /* element is owner */
3020 miscNode1 = node1;
3021 node1 = node1->parent;
3022 misc = 1;
3023 break;
3024 case XML_TEXT_NODE:
3025 case XML_CDATA_SECTION_NODE:
3026 case XML_COMMENT_NODE:
3027 case XML_PI_NODE: {
3028 miscNode1 = node1;
3029 /*
3030 * Find nearest element node.
3031 */
3032 if (node1->prev != NULL) {
3033 do {
3034 node1 = node1->prev;
3035 if (node1->type == XML_ELEMENT_NODE) {
3036 precedence1 = 3; /* element in prev-sibl axis */
3037 break;
3038 }
3039 if (node1->prev == NULL) {
3040 precedence1 = 2; /* element is parent */
3041 /*
3042 * URGENT TODO: Are there any cases, where the
3043 * parent of such a node is not an element node?
3044 */
3045 node1 = node1->parent;
3046 break;
3047 }
3048 } while (1);
3049 } else {
3050 precedence1 = 2; /* element is parent */
3051 node1 = node1->parent;
3052 }
3053 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE)) {
3054 /*
3055 * Fallback for whatever case.
3056 */
3057 node1 = miscNode1;
3058 precedence1 = 0;
3059 } else
3060 misc = 1;
3061 }
3062 break;
3063 case XML_NAMESPACE_DECL:
3064 /*
3065 * TODO: why do we return 1 for namespace nodes?
3066 */
3067 return(1);
3068 default:
3069 break;
3070 }
3071 switch (node2->type) {
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003072 case XML_ELEMENT_NODE:
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003073 break;
3074 case XML_ATTRIBUTE_NODE:
3075 precedence2 = 1; /* element is owner */
3076 miscNode2 = node2;
3077 node2 = node2->parent;
3078 misc = 1;
3079 break;
3080 case XML_TEXT_NODE:
3081 case XML_CDATA_SECTION_NODE:
3082 case XML_COMMENT_NODE:
3083 case XML_PI_NODE: {
3084 miscNode2 = node2;
3085 if (node2->prev != NULL) {
3086 do {
3087 node2 = node2->prev;
3088 if (node2->type == XML_ELEMENT_NODE) {
3089 precedence2 = 3; /* element in prev-sibl axis */
3090 break;
3091 }
3092 if (node2->prev == NULL) {
3093 precedence2 = 2; /* element is parent */
3094 node2 = node2->parent;
3095 break;
3096 }
3097 } while (1);
3098 } else {
3099 precedence2 = 2; /* element is parent */
3100 node2 = node2->parent;
3101 }
3102 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3103 (0 <= (long) node1->content))
3104 {
3105 node2 = miscNode2;
3106 precedence2 = 0;
3107 } else
3108 misc = 1;
3109 }
3110 break;
3111 case XML_NAMESPACE_DECL:
3112 return(1);
3113 default:
3114 break;
3115 }
3116 if (misc) {
3117 if (node1 == node2) {
3118 if (precedence1 == precedence2) {
3119 /*
3120 * The ugly case; but normally there aren't many
3121 * adjacent non-element nodes around.
3122 */
3123 cur = miscNode2->prev;
3124 while (cur != NULL) {
3125 if (cur == miscNode1)
3126 return(1);
3127 if (cur->type == XML_ELEMENT_NODE)
3128 return(-1);
3129 cur = cur->prev;
3130 }
3131 return (-1);
3132 } else {
3133 /*
3134 * Evaluate based on higher precedence wrt to the element.
3135 * TODO: This assumes attributes are sorted before content.
3136 * Is this 100% correct?
3137 */
3138 if (precedence1 < precedence2)
3139 return(1);
3140 else
3141 return(-1);
3142 }
3143 }
3144 /*
3145 * Special case: One of the helper-elements is contained by the other.
3146 * <foo>
3147 * <node2>
3148 * <node1>Text-1(precedence1 == 2)</node1>
3149 * </node2>
3150 * Text-6(precedence2 == 3)
3151 * </foo>
3152 */
3153 if ((precedence2 == 3) && (precedence1 > 1)) {
3154 cur = node1->parent;
3155 while (cur) {
3156 if (cur == node2)
3157 return(1);
3158 cur = cur->parent;
3159 }
3160 }
3161 if ((precedence1 == 3) && (precedence2 > 1)) {
3162 cur = node2->parent;
3163 while (cur) {
3164 if (cur == node1)
3165 return(-1);
3166 cur = cur->parent;
3167 }
3168 }
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003169 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003170
3171 /*
3172 * Speedup using document order if availble.
3173 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003174 if ((node1->type == XML_ELEMENT_NODE) &&
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003175 (node2->type == XML_ELEMENT_NODE) &&
3176 (0 > (long) node1->content) &&
3177 (0 > (long) node2->content) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003178 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003179
3180 l1 = -((long) node1->content);
3181 l2 = -((long) node2->content);
3182 if (l1 < l2)
3183 return(1);
3184 if (l1 > l2)
3185 return(-1);
3186 }
3187
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003188turtle_comparison:
3189
3190 if (node1 == node2->prev)
3191 return(1);
3192 if (node1 == node2->next)
3193 return(-1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003194 /*
3195 * compute depth to root
3196 */
3197 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3198 if (cur == node1)
3199 return(1);
3200 depth2++;
3201 }
3202 root = cur;
3203 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3204 if (cur == node2)
3205 return(-1);
3206 depth1++;
3207 }
3208 /*
3209 * Distinct document (or distinct entities :-( ) case.
3210 */
3211 if (root != cur) {
3212 return(-2);
3213 }
3214 /*
3215 * get the nearest common ancestor.
3216 */
3217 while (depth1 > depth2) {
3218 depth1--;
3219 node1 = node1->parent;
3220 }
3221 while (depth2 > depth1) {
3222 depth2--;
3223 node2 = node2->parent;
3224 }
3225 while (node1->parent != node2->parent) {
3226 node1 = node1->parent;
3227 node2 = node2->parent;
3228 /* should not happen but just in case ... */
3229 if ((node1 == NULL) || (node2 == NULL))
3230 return(-2);
3231 }
3232 /*
3233 * Find who's first.
3234 */
3235 if (node1 == node2->prev)
3236 return(1);
3237 if (node1 == node2->next)
3238 return(-1);
3239 /*
3240 * Speedup using document order if availble.
3241 */
3242 if ((node1->type == XML_ELEMENT_NODE) &&
3243 (node2->type == XML_ELEMENT_NODE) &&
3244 (0 > (long) node1->content) &&
3245 (0 > (long) node2->content) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003246 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003247
3248 l1 = -((long) node1->content);
3249 l2 = -((long) node2->content);
3250 if (l1 < l2)
3251 return(1);
3252 if (l1 > l2)
3253 return(-1);
3254 }
3255
3256 for (cur = node1->next;cur != NULL;cur = cur->next)
3257 if (cur == node2)
3258 return(1);
3259 return(-1); /* assume there is no sibling list corruption */
3260}
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003261#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003262
Owen Taylor3473f882001-02-23 17:55:21 +00003263/**
3264 * xmlXPathNodeSetSort:
3265 * @set: the node set
3266 *
3267 * Sort the node set in document order
3268 */
3269void
3270xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003271 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003272 xmlNodePtr tmp;
3273
3274 if (set == NULL)
3275 return;
3276
3277 /* Use Shell's sort to sort the node-set */
3278 len = set->nodeNr;
3279 for (incr = len / 2; incr > 0; incr /= 2) {
3280 for (i = incr; i < len; i++) {
3281 j = i - incr;
3282 while (j >= 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003283#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003284 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3285 set->nodeTab[j + incr]) == -1)
3286#else
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003287 if (xmlXPathCmpNodes(set->nodeTab[j],
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003288 set->nodeTab[j + incr]) == -1)
3289#endif
3290 {
Owen Taylor3473f882001-02-23 17:55:21 +00003291 tmp = set->nodeTab[j];
3292 set->nodeTab[j] = set->nodeTab[j + incr];
3293 set->nodeTab[j + incr] = tmp;
3294 j -= incr;
3295 } else
3296 break;
3297 }
3298 }
3299 }
3300}
3301
3302#define XML_NODESET_DEFAULT 10
3303/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003304 * xmlXPathNodeSetDupNs:
3305 * @node: the parent node of the namespace XPath node
3306 * @ns: the libxml namespace declaration node.
3307 *
3308 * Namespace node in libxml don't match the XPath semantic. In a node set
3309 * the namespace nodes are duplicated and the next pointer is set to the
3310 * parent node in the XPath semantic.
3311 *
3312 * Returns the newly created object.
3313 */
3314static xmlNodePtr
3315xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3316 xmlNsPtr cur;
3317
3318 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3319 return(NULL);
3320 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3321 return((xmlNodePtr) ns);
3322
3323 /*
3324 * Allocate a new Namespace and fill the fields.
3325 */
3326 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3327 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003328 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003329 return(NULL);
3330 }
3331 memset(cur, 0, sizeof(xmlNs));
3332 cur->type = XML_NAMESPACE_DECL;
3333 if (ns->href != NULL)
3334 cur->href = xmlStrdup(ns->href);
3335 if (ns->prefix != NULL)
3336 cur->prefix = xmlStrdup(ns->prefix);
3337 cur->next = (xmlNsPtr) node;
3338 return((xmlNodePtr) cur);
3339}
3340
3341/**
3342 * xmlXPathNodeSetFreeNs:
3343 * @ns: the XPath namespace node found in a nodeset.
3344 *
William M. Brack08171912003-12-29 02:52:11 +00003345 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003346 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00003347 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003348 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00003349void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003350xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3351 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3352 return;
3353
3354 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3355 if (ns->href != NULL)
3356 xmlFree((xmlChar *)ns->href);
3357 if (ns->prefix != NULL)
3358 xmlFree((xmlChar *)ns->prefix);
3359 xmlFree(ns);
3360 }
3361}
3362
3363/**
Owen Taylor3473f882001-02-23 17:55:21 +00003364 * xmlXPathNodeSetCreate:
3365 * @val: an initial xmlNodePtr, or NULL
3366 *
3367 * Create a new xmlNodeSetPtr of type double and of value @val
3368 *
3369 * Returns the newly created object.
3370 */
3371xmlNodeSetPtr
3372xmlXPathNodeSetCreate(xmlNodePtr val) {
3373 xmlNodeSetPtr ret;
3374
3375 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3376 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003377 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003378 return(NULL);
3379 }
3380 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3381 if (val != NULL) {
3382 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3383 sizeof(xmlNodePtr));
3384 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003385 xmlXPathErrMemory(NULL, "creating nodeset\n");
3386 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003387 return(NULL);
3388 }
3389 memset(ret->nodeTab, 0 ,
3390 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3391 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003392 if (val->type == XML_NAMESPACE_DECL) {
3393 xmlNsPtr ns = (xmlNsPtr) val;
3394
3395 ret->nodeTab[ret->nodeNr++] =
3396 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3397 } else
3398 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003399 }
3400 return(ret);
3401}
3402
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003403/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003404 * xmlXPathNodeSetCreateSize:
3405 * @size: the initial size of the set
3406 *
3407 * Create a new xmlNodeSetPtr of type double and of value @val
3408 *
3409 * Returns the newly created object.
3410 */
3411static xmlNodeSetPtr
3412xmlXPathNodeSetCreateSize(int size) {
3413 xmlNodeSetPtr ret;
3414
3415 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3416 if (ret == NULL) {
3417 xmlXPathErrMemory(NULL, "creating nodeset\n");
3418 return(NULL);
3419 }
3420 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3421 if (size < XML_NODESET_DEFAULT)
3422 size = XML_NODESET_DEFAULT;
3423 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3424 if (ret->nodeTab == NULL) {
3425 xmlXPathErrMemory(NULL, "creating nodeset\n");
3426 xmlFree(ret);
3427 return(NULL);
3428 }
3429 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3430 ret->nodeMax = size;
3431 return(ret);
3432}
3433
3434/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003435 * xmlXPathNodeSetContains:
3436 * @cur: the node-set
3437 * @val: the node
3438 *
3439 * checks whether @cur contains @val
3440 *
3441 * Returns true (1) if @cur contains @val, false (0) otherwise
3442 */
3443int
3444xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3445 int i;
3446
Daniel Veillarda82b1822004-11-08 16:24:57 +00003447 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003448 if (val->type == XML_NAMESPACE_DECL) {
3449 for (i = 0; i < cur->nodeNr; i++) {
3450 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3451 xmlNsPtr ns1, ns2;
3452
3453 ns1 = (xmlNsPtr) val;
3454 ns2 = (xmlNsPtr) cur->nodeTab[i];
3455 if (ns1 == ns2)
3456 return(1);
3457 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3458 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3459 return(1);
3460 }
3461 }
3462 } else {
3463 for (i = 0; i < cur->nodeNr; i++) {
3464 if (cur->nodeTab[i] == val)
3465 return(1);
3466 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003467 }
3468 return(0);
3469}
3470
3471/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003472 * xmlXPathNodeSetAddNs:
3473 * @cur: the initial node set
3474 * @node: the hosting node
3475 * @ns: a the namespace node
3476 *
3477 * add a new namespace node to an existing NodeSet
3478 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00003479void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003480xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3481 int i;
3482
Daniel Veillarda82b1822004-11-08 16:24:57 +00003483
3484 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3485 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003486 (node->type != XML_ELEMENT_NODE))
3487 return;
3488
William M. Brack08171912003-12-29 02:52:11 +00003489 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003490 /*
William M. Brack08171912003-12-29 02:52:11 +00003491 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003492 */
3493 for (i = 0;i < cur->nodeNr;i++) {
3494 if ((cur->nodeTab[i] != NULL) &&
3495 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00003496 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003497 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3498 return;
3499 }
3500
3501 /*
3502 * grow the nodeTab if needed
3503 */
3504 if (cur->nodeMax == 0) {
3505 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3506 sizeof(xmlNodePtr));
3507 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003508 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003509 return;
3510 }
3511 memset(cur->nodeTab, 0 ,
3512 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3513 cur->nodeMax = XML_NODESET_DEFAULT;
3514 } else if (cur->nodeNr == cur->nodeMax) {
3515 xmlNodePtr *temp;
3516
3517 cur->nodeMax *= 2;
3518 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3519 sizeof(xmlNodePtr));
3520 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003521 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003522 return;
3523 }
3524 cur->nodeTab = temp;
3525 }
3526 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3527}
3528
3529/**
Owen Taylor3473f882001-02-23 17:55:21 +00003530 * xmlXPathNodeSetAdd:
3531 * @cur: the initial node set
3532 * @val: a new xmlNodePtr
3533 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003534 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00003535 */
3536void
3537xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3538 int i;
3539
Daniel Veillarda82b1822004-11-08 16:24:57 +00003540 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003541
Daniel Veillardef0b4502003-03-24 13:57:34 +00003542#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00003543 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3544 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00003545#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00003546
William M. Brack08171912003-12-29 02:52:11 +00003547 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003548 /*
William M. Brack08171912003-12-29 02:52:11 +00003549 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00003550 */
3551 for (i = 0;i < cur->nodeNr;i++)
3552 if (cur->nodeTab[i] == val) return;
3553
3554 /*
3555 * grow the nodeTab if needed
3556 */
3557 if (cur->nodeMax == 0) {
3558 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3559 sizeof(xmlNodePtr));
3560 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003561 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003562 return;
3563 }
3564 memset(cur->nodeTab, 0 ,
3565 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3566 cur->nodeMax = XML_NODESET_DEFAULT;
3567 } else if (cur->nodeNr == cur->nodeMax) {
3568 xmlNodePtr *temp;
3569
3570 cur->nodeMax *= 2;
3571 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3572 sizeof(xmlNodePtr));
3573 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003574 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003575 return;
3576 }
3577 cur->nodeTab = temp;
3578 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003579 if (val->type == XML_NAMESPACE_DECL) {
3580 xmlNsPtr ns = (xmlNsPtr) val;
3581
3582 cur->nodeTab[cur->nodeNr++] =
3583 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3584 } else
3585 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003586}
3587
3588/**
3589 * xmlXPathNodeSetAddUnique:
3590 * @cur: the initial node set
3591 * @val: a new xmlNodePtr
3592 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003593 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00003594 * when we are sure the node is not already in the set.
3595 */
3596void
3597xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00003598 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003599
Daniel Veillardef0b4502003-03-24 13:57:34 +00003600#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00003601 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3602 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00003603#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00003604
William M. Brack08171912003-12-29 02:52:11 +00003605 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003606 /*
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) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003613 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003614 return;
3615 }
3616 memset(cur->nodeTab, 0 ,
3617 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3618 cur->nodeMax = XML_NODESET_DEFAULT;
3619 } else if (cur->nodeNr == cur->nodeMax) {
3620 xmlNodePtr *temp;
3621
3622 cur->nodeMax *= 2;
3623 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3624 sizeof(xmlNodePtr));
3625 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003626 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003627 return;
3628 }
3629 cur->nodeTab = temp;
3630 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003631 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;
Owen Taylor3473f882001-02-23 17:55:21 +00003638}
3639
3640/**
3641 * xmlXPathNodeSetMerge:
3642 * @val1: the first NodeSet or NULL
3643 * @val2: the second NodeSet
3644 *
3645 * Merges two nodesets, all nodes from @val2 are added to @val1
3646 * if @val1 is NULL, a new set is created and copied from @val2
3647 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003648 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003649 */
3650xmlNodeSetPtr
3651xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003652 int i, j, initNr, skip;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003653 xmlNodePtr n1, n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003654
3655 if (val2 == NULL) return(val1);
3656 if (val1 == NULL) {
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003657 val1 = xmlXPathNodeSetCreate(NULL);
3658#if 0
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003659 /*
3660 * TODO: The optimization won't work in every case, since
3661 * those nasty namespace nodes need to be added with
3662 * xmlXPathNodeSetDupNs() to the set; thus a pure
3663 * memcpy is not possible.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00003664 * If there was a flag on the nodesetval, indicating that
3665 * some temporary nodes are in, that would be helpfull.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003666 */
3667 /*
3668 * Optimization: Create an equally sized node-set
3669 * and memcpy the content.
3670 */
3671 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3672 if (val1 == NULL)
3673 return(NULL);
3674 if (val2->nodeNr != 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003675 if (val2->nodeNr == 1)
3676 *(val1->nodeTab) = *(val2->nodeTab);
3677 else {
3678 memcpy(val1->nodeTab, val2->nodeTab,
3679 val2->nodeNr * sizeof(xmlNodePtr));
3680 }
3681 val1->nodeNr = val2->nodeNr;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003682 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003683 return(val1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003684#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003685 }
3686
William M. Brack08171912003-12-29 02:52:11 +00003687 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003688 initNr = val1->nodeNr;
3689
3690 for (i = 0;i < val2->nodeNr;i++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003691 n2 = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00003692 /*
William M. Brack08171912003-12-29 02:52:11 +00003693 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003694 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003695 skip = 0;
3696 for (j = 0; j < initNr; j++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003697 n1 = val1->nodeTab[j];
3698 if (n1 == n2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003699 skip = 1;
3700 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003701 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3702 (n2->type == XML_NAMESPACE_DECL)) {
3703 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3704 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3705 ((xmlNsPtr) n2)->prefix)))
3706 {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003707 skip = 1;
3708 break;
3709 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003710 }
3711 }
3712 if (skip)
3713 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00003714
3715 /*
3716 * grow the nodeTab if needed
3717 */
3718 if (val1->nodeMax == 0) {
3719 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3720 sizeof(xmlNodePtr));
3721 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003722 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003723 return(NULL);
3724 }
3725 memset(val1->nodeTab, 0 ,
3726 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3727 val1->nodeMax = XML_NODESET_DEFAULT;
3728 } else if (val1->nodeNr == val1->nodeMax) {
3729 xmlNodePtr *temp;
3730
3731 val1->nodeMax *= 2;
3732 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3733 sizeof(xmlNodePtr));
3734 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003735 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003736 return(NULL);
3737 }
3738 val1->nodeTab = temp;
3739 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003740 if (n2->type == XML_NAMESPACE_DECL) {
3741 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003742
3743 val1->nodeTab[val1->nodeNr++] =
3744 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3745 } else
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003746 val1->nodeTab[val1->nodeNr++] = n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003747 }
3748
3749 return(val1);
3750}
3751
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003752#if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
Owen Taylor3473f882001-02-23 17:55:21 +00003753/**
Daniel Veillard75be0132002-03-13 10:03:35 +00003754 * xmlXPathNodeSetMergeUnique:
3755 * @val1: the first NodeSet or NULL
3756 * @val2: the second NodeSet
3757 *
3758 * Merges two nodesets, all nodes from @val2 are added to @val1
3759 * if @val1 is NULL, a new set is created and copied from @val2
3760 *
3761 * Returns @val1 once extended or NULL in case of error.
3762 */
3763static xmlNodeSetPtr
3764xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00003765 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00003766
3767 if (val2 == NULL) return(val1);
3768 if (val1 == NULL) {
3769 val1 = xmlXPathNodeSetCreate(NULL);
3770 }
3771
William M. Brack08171912003-12-29 02:52:11 +00003772 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00003773
3774 for (i = 0;i < val2->nodeNr;i++) {
3775 /*
3776 * grow the nodeTab if needed
3777 */
3778 if (val1->nodeMax == 0) {
3779 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3780 sizeof(xmlNodePtr));
3781 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003782 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00003783 return(NULL);
3784 }
3785 memset(val1->nodeTab, 0 ,
3786 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3787 val1->nodeMax = XML_NODESET_DEFAULT;
3788 } else if (val1->nodeNr == val1->nodeMax) {
3789 xmlNodePtr *temp;
3790
3791 val1->nodeMax *= 2;
3792 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3793 sizeof(xmlNodePtr));
3794 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003795 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00003796 return(NULL);
3797 }
3798 val1->nodeTab = temp;
3799 }
3800 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3801 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
3802
3803 val1->nodeTab[val1->nodeNr++] =
3804 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3805 } else
3806 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
3807 }
3808
3809 return(val1);
3810}
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003811#endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3812
3813/**
3814 * xmlXPathNodeSetMergeAndClear:
3815 * @set1: the first NodeSet or NULL
3816 * @set2: the second NodeSet
3817 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3818 *
3819 * Merges two nodesets, all nodes from @set2 are added to @set1
3820 * if @set1 is NULL, a new set is created and copied from @set2.
3821 * Checks for duplicate nodes. Clears set2.
3822 *
3823 * Returns @set1 once extended or NULL in case of error.
3824 */
3825static xmlNodeSetPtr
3826xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3827 int hasNullEntries)
3828{
3829 if ((set1 == NULL) && (hasNullEntries == 0)) {
3830 /*
3831 * Note that doing a memcpy of the list, namespace nodes are
3832 * just assigned to set1, since set2 is cleared anyway.
3833 */
3834 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3835 if (set1 == NULL)
3836 return(NULL);
3837 if (set2->nodeNr != 0) {
3838 memcpy(set1->nodeTab, set2->nodeTab,
3839 set2->nodeNr * sizeof(xmlNodePtr));
3840 set1->nodeNr = set2->nodeNr;
3841 }
3842 } else {
3843 int i, j, initNbSet1;
3844 xmlNodePtr n1, n2;
3845
3846 if (set1 == NULL)
3847 set1 = xmlXPathNodeSetCreate(NULL);
3848
3849 initNbSet1 = set1->nodeNr;
3850 for (i = 0;i < set2->nodeNr;i++) {
3851 n2 = set2->nodeTab[i];
3852 /*
3853 * Skip NULLed entries.
3854 */
3855 if (n2 == NULL)
3856 continue;
3857 /*
3858 * Skip duplicates.
3859 */
3860 for (j = 0; j < initNbSet1; j++) {
3861 n1 = set1->nodeTab[j];
3862 if (n1 == n2) {
3863 goto skip_node;
3864 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3865 (n2->type == XML_NAMESPACE_DECL))
3866 {
3867 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3868 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3869 ((xmlNsPtr) n2)->prefix)))
3870 {
3871 /*
3872 * Free the namespace node.
3873 */
3874 set2->nodeTab[i] = NULL;
3875 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3876 goto skip_node;
3877 }
3878 }
3879 }
3880 /*
3881 * grow the nodeTab if needed
3882 */
3883 if (set1->nodeMax == 0) {
3884 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3885 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3886 if (set1->nodeTab == NULL) {
3887 xmlXPathErrMemory(NULL, "merging nodeset\n");
3888 return(NULL);
3889 }
3890 memset(set1->nodeTab, 0,
3891 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3892 set1->nodeMax = XML_NODESET_DEFAULT;
3893 } else if (set1->nodeNr >= set1->nodeMax) {
3894 xmlNodePtr *temp;
3895
3896 set1->nodeMax *= 2;
3897 temp = (xmlNodePtr *) xmlRealloc(
3898 set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3899 if (temp == NULL) {
3900 xmlXPathErrMemory(NULL, "merging nodeset\n");
3901 return(NULL);
3902 }
3903 set1->nodeTab = temp;
3904 }
3905 if (n2->type == XML_NAMESPACE_DECL) {
3906 xmlNsPtr ns = (xmlNsPtr) n2;
3907
3908 set1->nodeTab[set1->nodeNr++] =
3909 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3910 } else
3911 set1->nodeTab[set1->nodeNr++] = n2;
3912skip_node:
3913 {}
3914 }
3915 }
3916 set2->nodeNr = 0;
3917 return(set1);
3918}
3919
3920/**
3921 * xmlXPathNodeSetMergeAndClearNoDupls:
3922 * @set1: the first NodeSet or NULL
3923 * @set2: the second NodeSet
3924 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3925 *
3926 * Merges two nodesets, all nodes from @set2 are added to @set1
3927 * if @set1 is NULL, a new set is created and copied from @set2.
3928 * Doesn't chack for duplicate nodes. Clears set2.
3929 *
3930 * Returns @set1 once extended or NULL in case of error.
3931 */
3932static xmlNodeSetPtr
3933xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3934 int hasNullEntries)
3935{
3936 if (set2 == NULL)
3937 return(set1);
3938 if ((set1 == NULL) && (hasNullEntries == 0)) {
3939 /*
3940 * Note that doing a memcpy of the list, namespace nodes are
3941 * just assigned to set1, since set2 is cleared anyway.
3942 */
3943 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3944 if (set1 == NULL)
3945 return(NULL);
3946 if (set2->nodeNr != 0) {
3947 memcpy(set1->nodeTab, set2->nodeTab,
3948 set2->nodeNr * sizeof(xmlNodePtr));
3949 set1->nodeNr = set2->nodeNr;
3950 }
3951 } else {
3952 int i;
3953 xmlNodePtr n2;
3954
3955 if (set1 == NULL)
3956 set1 = xmlXPathNodeSetCreate(NULL);
3957
3958 for (i = 0;i < set2->nodeNr;i++) {
3959 n2 = set2->nodeTab[i];
3960 /*
3961 * Skip NULLed entries.
3962 */
3963 if (n2 == NULL)
3964 continue;
3965 if (set1->nodeMax == 0) {
3966 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3967 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3968 if (set1->nodeTab == NULL) {
3969 xmlXPathErrMemory(NULL, "merging nodeset\n");
3970 return(NULL);
3971 }
3972 memset(set1->nodeTab, 0,
3973 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3974 set1->nodeMax = XML_NODESET_DEFAULT;
3975 } else if (set1->nodeNr >= set1->nodeMax) {
3976 xmlNodePtr *temp;
3977
3978 set1->nodeMax *= 2;
3979 temp = (xmlNodePtr *) xmlRealloc(
3980 set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3981 if (temp == NULL) {
3982 xmlXPathErrMemory(NULL, "merging nodeset\n");
3983 return(NULL);
3984 }
3985 set1->nodeTab = temp;
3986 }
3987 set1->nodeTab[set1->nodeNr++] = n2;
3988 }
3989 }
3990 set2->nodeNr = 0;
3991 return(set1);
3992}
Daniel Veillard75be0132002-03-13 10:03:35 +00003993
3994/**
Owen Taylor3473f882001-02-23 17:55:21 +00003995 * xmlXPathNodeSetDel:
3996 * @cur: the initial node set
3997 * @val: an xmlNodePtr
3998 *
3999 * Removes an xmlNodePtr from an existing NodeSet
4000 */
4001void
4002xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4003 int i;
4004
4005 if (cur == NULL) return;
4006 if (val == NULL) return;
4007
4008 /*
William M. Brack08171912003-12-29 02:52:11 +00004009 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00004010 */
4011 for (i = 0;i < cur->nodeNr;i++)
4012 if (cur->nodeTab[i] == val) break;
4013
William M. Brack08171912003-12-29 02:52:11 +00004014 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00004015#ifdef DEBUG
4016 xmlGenericError(xmlGenericErrorContext,
4017 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4018 val->name);
4019#endif
4020 return;
4021 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004022 if ((cur->nodeTab[i] != NULL) &&
4023 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4024 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004025 cur->nodeNr--;
4026 for (;i < cur->nodeNr;i++)
4027 cur->nodeTab[i] = cur->nodeTab[i + 1];
4028 cur->nodeTab[cur->nodeNr] = NULL;
4029}
4030
4031/**
4032 * xmlXPathNodeSetRemove:
4033 * @cur: the initial node set
4034 * @val: the index to remove
4035 *
4036 * Removes an entry from an existing NodeSet list.
4037 */
4038void
4039xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4040 if (cur == NULL) return;
4041 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004042 if ((cur->nodeTab[val] != NULL) &&
4043 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4044 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00004045 cur->nodeNr--;
4046 for (;val < cur->nodeNr;val++)
4047 cur->nodeTab[val] = cur->nodeTab[val + 1];
4048 cur->nodeTab[cur->nodeNr] = NULL;
4049}
4050
4051/**
4052 * xmlXPathFreeNodeSet:
4053 * @obj: the xmlNodeSetPtr to free
4054 *
4055 * Free the NodeSet compound (not the actual nodes !).
4056 */
4057void
4058xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4059 if (obj == NULL) return;
4060 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004061 int i;
4062
William M. Brack08171912003-12-29 02:52:11 +00004063 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004064 for (i = 0;i < obj->nodeNr;i++)
4065 if ((obj->nodeTab[i] != NULL) &&
4066 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4067 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004068 xmlFree(obj->nodeTab);
4069 }
Owen Taylor3473f882001-02-23 17:55:21 +00004070 xmlFree(obj);
4071}
4072
4073/**
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004074 * xmlXPathNodeSetClear:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004075 * @set: the node set to clear
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004076 *
4077 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4078 * are feed), but does *not* free the list itself. Sets the length of the
4079 * list to 0.
4080 */
4081static void
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004082xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4083{
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004084 if ((set == NULL) || (set->nodeNr <= 0))
4085 return;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004086 else if (hasNsNodes) {
4087 int i;
4088 xmlNodePtr node;
4089
4090 for (i = 0; i < set->nodeNr; i++) {
4091 node = set->nodeTab[i];
4092 if ((node != NULL) &&
4093 (node->type == XML_NAMESPACE_DECL))
4094 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4095 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004096 }
4097 set->nodeNr = 0;
4098}
4099
4100/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004101 * xmlXPathNodeSetClearFromPos:
4102 * @set: the node set to be cleared
4103 * @pos: the start position to clear from
4104 *
4105 * Clears the list from temporary XPath objects (e.g. namespace nodes
4106 * are feed) starting with the entry at @pos, but does *not* free the list
4107 * itself. Sets the length of the list to @pos.
4108 */
4109static void
4110xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4111{
4112 if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4113 return;
4114 else if ((hasNsNodes)) {
4115 int i;
4116 xmlNodePtr node;
4117
4118 for (i = pos; i < set->nodeNr; i++) {
4119 node = set->nodeTab[i];
4120 if ((node != NULL) &&
4121 (node->type == XML_NAMESPACE_DECL))
4122 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4123 }
4124 }
4125 set->nodeNr = pos;
4126}
4127
4128/**
Owen Taylor3473f882001-02-23 17:55:21 +00004129 * xmlXPathFreeValueTree:
4130 * @obj: the xmlNodeSetPtr to free
4131 *
4132 * Free the NodeSet compound and the actual tree, this is different
4133 * from xmlXPathFreeNodeSet()
4134 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004135static void
Owen Taylor3473f882001-02-23 17:55:21 +00004136xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4137 int i;
4138
4139 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00004140
4141 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004142 for (i = 0;i < obj->nodeNr;i++) {
4143 if (obj->nodeTab[i] != NULL) {
4144 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4145 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4146 } else {
4147 xmlFreeNodeList(obj->nodeTab[i]);
4148 }
4149 }
4150 }
Owen Taylor3473f882001-02-23 17:55:21 +00004151 xmlFree(obj->nodeTab);
4152 }
Owen Taylor3473f882001-02-23 17:55:21 +00004153 xmlFree(obj);
4154}
4155
4156#if defined(DEBUG) || defined(DEBUG_STEP)
4157/**
4158 * xmlGenericErrorContextNodeSet:
4159 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00004160 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00004161 *
4162 * Quick display of a NodeSet
4163 */
4164void
4165xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4166 int i;
4167
4168 if (output == NULL) output = xmlGenericErrorContext;
4169 if (obj == NULL) {
4170 fprintf(output, "NodeSet == NULL !\n");
4171 return;
4172 }
4173 if (obj->nodeNr == 0) {
4174 fprintf(output, "NodeSet is empty\n");
4175 return;
4176 }
4177 if (obj->nodeTab == NULL) {
4178 fprintf(output, " nodeTab == NULL !\n");
4179 return;
4180 }
4181 for (i = 0; i < obj->nodeNr; i++) {
4182 if (obj->nodeTab[i] == NULL) {
4183 fprintf(output, " NULL !\n");
4184 return;
4185 }
4186 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4187 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4188 fprintf(output, " /");
4189 else if (obj->nodeTab[i]->name == NULL)
4190 fprintf(output, " noname!");
4191 else fprintf(output, " %s", obj->nodeTab[i]->name);
4192 }
4193 fprintf(output, "\n");
4194}
4195#endif
4196
4197/**
4198 * xmlXPathNewNodeSet:
4199 * @val: the NodePtr value
4200 *
4201 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4202 * it with the single Node @val
4203 *
4204 * Returns the newly created object.
4205 */
4206xmlXPathObjectPtr
4207xmlXPathNewNodeSet(xmlNodePtr val) {
4208 xmlXPathObjectPtr ret;
4209
4210 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4211 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004212 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004213 return(NULL);
4214 }
4215 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4216 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00004217 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004218 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00004219 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004220#ifdef XP_DEBUG_OBJ_USAGE
4221 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4222#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004223 return(ret);
4224}
4225
4226/**
4227 * xmlXPathNewValueTree:
4228 * @val: the NodePtr value
4229 *
4230 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4231 * it with the tree root @val
4232 *
4233 * Returns the newly created object.
4234 */
4235xmlXPathObjectPtr
4236xmlXPathNewValueTree(xmlNodePtr val) {
4237 xmlXPathObjectPtr ret;
4238
4239 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4240 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004241 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004242 return(NULL);
4243 }
4244 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4245 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00004246 ret->boolval = 1;
4247 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00004248 ret->nodesetval = xmlXPathNodeSetCreate(val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004249#ifdef XP_DEBUG_OBJ_USAGE
4250 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4251#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004252 return(ret);
4253}
4254
4255/**
4256 * xmlXPathNewNodeSetList:
4257 * @val: an existing NodeSet
4258 *
4259 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4260 * it with the Nodeset @val
4261 *
4262 * Returns the newly created object.
4263 */
4264xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004265xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4266{
Owen Taylor3473f882001-02-23 17:55:21 +00004267 xmlXPathObjectPtr ret;
4268 int i;
4269
4270 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004271 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00004272 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004273 ret = xmlXPathNewNodeSet(NULL);
4274 else {
4275 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4276 for (i = 1; i < val->nodeNr; ++i)
4277 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
4278 }
Owen Taylor3473f882001-02-23 17:55:21 +00004279
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004280 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004281}
4282
4283/**
4284 * xmlXPathWrapNodeSet:
4285 * @val: the NodePtr value
4286 *
4287 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4288 *
4289 * Returns the newly created object.
4290 */
4291xmlXPathObjectPtr
4292xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4293 xmlXPathObjectPtr ret;
4294
4295 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4296 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004297 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004298 return(NULL);
4299 }
4300 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4301 ret->type = XPATH_NODESET;
4302 ret->nodesetval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004303#ifdef XP_DEBUG_OBJ_USAGE
4304 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4305#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004306 return(ret);
4307}
4308
4309/**
4310 * xmlXPathFreeNodeSetList:
4311 * @obj: an existing NodeSetList object
4312 *
4313 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4314 * the list contrary to xmlXPathFreeObject().
4315 */
4316void
4317xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4318 if (obj == NULL) return;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004319#ifdef XP_DEBUG_OBJ_USAGE
4320 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4321#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004322 xmlFree(obj);
4323}
4324
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004325/**
4326 * xmlXPathDifference:
4327 * @nodes1: a node-set
4328 * @nodes2: a node-set
4329 *
4330 * Implements the EXSLT - Sets difference() function:
4331 * node-set set:difference (node-set, node-set)
4332 *
4333 * Returns the difference between the two node sets, or nodes1 if
4334 * nodes2 is empty
4335 */
4336xmlNodeSetPtr
4337xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4338 xmlNodeSetPtr ret;
4339 int i, l1;
4340 xmlNodePtr cur;
4341
4342 if (xmlXPathNodeSetIsEmpty(nodes2))
4343 return(nodes1);
4344
4345 ret = xmlXPathNodeSetCreate(NULL);
4346 if (xmlXPathNodeSetIsEmpty(nodes1))
4347 return(ret);
4348
4349 l1 = xmlXPathNodeSetGetLength(nodes1);
4350
4351 for (i = 0; i < l1; i++) {
4352 cur = xmlXPathNodeSetItem(nodes1, i);
4353 if (!xmlXPathNodeSetContains(nodes2, cur))
4354 xmlXPathNodeSetAddUnique(ret, cur);
4355 }
4356 return(ret);
4357}
4358
4359/**
4360 * xmlXPathIntersection:
4361 * @nodes1: a node-set
4362 * @nodes2: a node-set
4363 *
4364 * Implements the EXSLT - Sets intersection() function:
4365 * node-set set:intersection (node-set, node-set)
4366 *
4367 * Returns a node set comprising the nodes that are within both the
4368 * node sets passed as arguments
4369 */
4370xmlNodeSetPtr
4371xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4372 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4373 int i, l1;
4374 xmlNodePtr cur;
4375
4376 if (xmlXPathNodeSetIsEmpty(nodes1))
4377 return(ret);
4378 if (xmlXPathNodeSetIsEmpty(nodes2))
4379 return(ret);
4380
4381 l1 = xmlXPathNodeSetGetLength(nodes1);
4382
4383 for (i = 0; i < l1; i++) {
4384 cur = xmlXPathNodeSetItem(nodes1, i);
4385 if (xmlXPathNodeSetContains(nodes2, cur))
4386 xmlXPathNodeSetAddUnique(ret, cur);
4387 }
4388 return(ret);
4389}
4390
4391/**
4392 * xmlXPathDistinctSorted:
4393 * @nodes: a node-set, sorted by document order
4394 *
4395 * Implements the EXSLT - Sets distinct() function:
4396 * node-set set:distinct (node-set)
4397 *
4398 * Returns a subset of the nodes contained in @nodes, or @nodes if
4399 * it is empty
4400 */
4401xmlNodeSetPtr
4402xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4403 xmlNodeSetPtr ret;
4404 xmlHashTablePtr hash;
4405 int i, l;
4406 xmlChar * strval;
4407 xmlNodePtr cur;
4408
4409 if (xmlXPathNodeSetIsEmpty(nodes))
4410 return(nodes);
4411
4412 ret = xmlXPathNodeSetCreate(NULL);
4413 l = xmlXPathNodeSetGetLength(nodes);
4414 hash = xmlHashCreate (l);
4415 for (i = 0; i < l; i++) {
4416 cur = xmlXPathNodeSetItem(nodes, i);
4417 strval = xmlXPathCastNodeToString(cur);
4418 if (xmlHashLookup(hash, strval) == NULL) {
4419 xmlHashAddEntry(hash, strval, strval);
4420 xmlXPathNodeSetAddUnique(ret, cur);
4421 } else {
4422 xmlFree(strval);
4423 }
4424 }
4425 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4426 return(ret);
4427}
4428
4429/**
4430 * xmlXPathDistinct:
4431 * @nodes: a node-set
4432 *
4433 * Implements the EXSLT - Sets distinct() function:
4434 * node-set set:distinct (node-set)
4435 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4436 * is called with the sorted node-set
4437 *
4438 * Returns a subset of the nodes contained in @nodes, or @nodes if
4439 * it is empty
4440 */
4441xmlNodeSetPtr
4442xmlXPathDistinct (xmlNodeSetPtr nodes) {
4443 if (xmlXPathNodeSetIsEmpty(nodes))
4444 return(nodes);
4445
4446 xmlXPathNodeSetSort(nodes);
4447 return(xmlXPathDistinctSorted(nodes));
4448}
4449
4450/**
4451 * xmlXPathHasSameNodes:
4452 * @nodes1: a node-set
4453 * @nodes2: a node-set
4454 *
4455 * Implements the EXSLT - Sets has-same-nodes function:
4456 * boolean set:has-same-node(node-set, node-set)
4457 *
4458 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4459 * otherwise
4460 */
4461int
4462xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4463 int i, l;
4464 xmlNodePtr cur;
4465
4466 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4467 xmlXPathNodeSetIsEmpty(nodes2))
4468 return(0);
4469
4470 l = xmlXPathNodeSetGetLength(nodes1);
4471 for (i = 0; i < l; i++) {
4472 cur = xmlXPathNodeSetItem(nodes1, i);
4473 if (xmlXPathNodeSetContains(nodes2, cur))
4474 return(1);
4475 }
4476 return(0);
4477}
4478
4479/**
4480 * xmlXPathNodeLeadingSorted:
4481 * @nodes: a node-set, sorted by document order
4482 * @node: a node
4483 *
4484 * Implements the EXSLT - Sets leading() function:
4485 * node-set set:leading (node-set, node-set)
4486 *
4487 * Returns the nodes in @nodes that precede @node in document order,
4488 * @nodes if @node is NULL or an empty node-set if @nodes
4489 * doesn't contain @node
4490 */
4491xmlNodeSetPtr
4492xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4493 int i, l;
4494 xmlNodePtr cur;
4495 xmlNodeSetPtr ret;
4496
4497 if (node == NULL)
4498 return(nodes);
4499
4500 ret = xmlXPathNodeSetCreate(NULL);
4501 if (xmlXPathNodeSetIsEmpty(nodes) ||
4502 (!xmlXPathNodeSetContains(nodes, node)))
4503 return(ret);
4504
4505 l = xmlXPathNodeSetGetLength(nodes);
4506 for (i = 0; i < l; i++) {
4507 cur = xmlXPathNodeSetItem(nodes, i);
4508 if (cur == node)
4509 break;
4510 xmlXPathNodeSetAddUnique(ret, cur);
4511 }
4512 return(ret);
4513}
4514
4515/**
4516 * xmlXPathNodeLeading:
4517 * @nodes: a node-set
4518 * @node: a node
4519 *
4520 * Implements the EXSLT - Sets leading() function:
4521 * node-set set:leading (node-set, node-set)
4522 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4523 * is called.
4524 *
4525 * Returns the nodes in @nodes that precede @node in document order,
4526 * @nodes if @node is NULL or an empty node-set if @nodes
4527 * doesn't contain @node
4528 */
4529xmlNodeSetPtr
4530xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4531 xmlXPathNodeSetSort(nodes);
4532 return(xmlXPathNodeLeadingSorted(nodes, node));
4533}
4534
4535/**
4536 * xmlXPathLeadingSorted:
4537 * @nodes1: a node-set, sorted by document order
4538 * @nodes2: a node-set, sorted by document order
4539 *
4540 * Implements the EXSLT - Sets leading() function:
4541 * node-set set:leading (node-set, node-set)
4542 *
4543 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4544 * in document order, @nodes1 if @nodes2 is NULL or empty or
4545 * an empty node-set if @nodes1 doesn't contain @nodes2
4546 */
4547xmlNodeSetPtr
4548xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4549 if (xmlXPathNodeSetIsEmpty(nodes2))
4550 return(nodes1);
4551 return(xmlXPathNodeLeadingSorted(nodes1,
4552 xmlXPathNodeSetItem(nodes2, 1)));
4553}
4554
4555/**
4556 * xmlXPathLeading:
4557 * @nodes1: a node-set
4558 * @nodes2: a node-set
4559 *
4560 * Implements the EXSLT - Sets leading() function:
4561 * node-set set:leading (node-set, node-set)
4562 * @nodes1 and @nodes2 are sorted by document order, then
4563 * #exslSetsLeadingSorted is called.
4564 *
4565 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4566 * in document order, @nodes1 if @nodes2 is NULL or empty or
4567 * an empty node-set if @nodes1 doesn't contain @nodes2
4568 */
4569xmlNodeSetPtr
4570xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4571 if (xmlXPathNodeSetIsEmpty(nodes2))
4572 return(nodes1);
4573 if (xmlXPathNodeSetIsEmpty(nodes1))
4574 return(xmlXPathNodeSetCreate(NULL));
4575 xmlXPathNodeSetSort(nodes1);
4576 xmlXPathNodeSetSort(nodes2);
4577 return(xmlXPathNodeLeadingSorted(nodes1,
4578 xmlXPathNodeSetItem(nodes2, 1)));
4579}
4580
4581/**
4582 * xmlXPathNodeTrailingSorted:
4583 * @nodes: a node-set, sorted by document order
4584 * @node: a node
4585 *
4586 * Implements the EXSLT - Sets trailing() function:
4587 * node-set set:trailing (node-set, node-set)
4588 *
4589 * Returns the nodes in @nodes that follow @node in document order,
4590 * @nodes if @node is NULL or an empty node-set if @nodes
4591 * doesn't contain @node
4592 */
4593xmlNodeSetPtr
4594xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4595 int i, l;
4596 xmlNodePtr cur;
4597 xmlNodeSetPtr ret;
4598
4599 if (node == NULL)
4600 return(nodes);
4601
4602 ret = xmlXPathNodeSetCreate(NULL);
4603 if (xmlXPathNodeSetIsEmpty(nodes) ||
4604 (!xmlXPathNodeSetContains(nodes, node)))
4605 return(ret);
4606
4607 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00004608 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004609 cur = xmlXPathNodeSetItem(nodes, i);
4610 if (cur == node)
4611 break;
4612 xmlXPathNodeSetAddUnique(ret, cur);
4613 }
4614 return(ret);
4615}
4616
4617/**
4618 * xmlXPathNodeTrailing:
4619 * @nodes: a node-set
4620 * @node: a node
4621 *
4622 * Implements the EXSLT - Sets trailing() function:
4623 * node-set set:trailing (node-set, node-set)
4624 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4625 * is called.
4626 *
4627 * Returns the nodes in @nodes that follow @node in document order,
4628 * @nodes if @node is NULL or an empty node-set if @nodes
4629 * doesn't contain @node
4630 */
4631xmlNodeSetPtr
4632xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4633 xmlXPathNodeSetSort(nodes);
4634 return(xmlXPathNodeTrailingSorted(nodes, node));
4635}
4636
4637/**
4638 * xmlXPathTrailingSorted:
4639 * @nodes1: a node-set, sorted by document order
4640 * @nodes2: a node-set, sorted by document order
4641 *
4642 * Implements the EXSLT - Sets trailing() function:
4643 * node-set set:trailing (node-set, node-set)
4644 *
4645 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4646 * in document order, @nodes1 if @nodes2 is NULL or empty or
4647 * an empty node-set if @nodes1 doesn't contain @nodes2
4648 */
4649xmlNodeSetPtr
4650xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4651 if (xmlXPathNodeSetIsEmpty(nodes2))
4652 return(nodes1);
4653 return(xmlXPathNodeTrailingSorted(nodes1,
4654 xmlXPathNodeSetItem(nodes2, 0)));
4655}
4656
4657/**
4658 * xmlXPathTrailing:
4659 * @nodes1: a node-set
4660 * @nodes2: a node-set
4661 *
4662 * Implements the EXSLT - Sets trailing() function:
4663 * node-set set:trailing (node-set, node-set)
4664 * @nodes1 and @nodes2 are sorted by document order, then
4665 * #xmlXPathTrailingSorted is called.
4666 *
4667 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4668 * in document order, @nodes1 if @nodes2 is NULL or empty or
4669 * an empty node-set if @nodes1 doesn't contain @nodes2
4670 */
4671xmlNodeSetPtr
4672xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4673 if (xmlXPathNodeSetIsEmpty(nodes2))
4674 return(nodes1);
4675 if (xmlXPathNodeSetIsEmpty(nodes1))
4676 return(xmlXPathNodeSetCreate(NULL));
4677 xmlXPathNodeSetSort(nodes1);
4678 xmlXPathNodeSetSort(nodes2);
4679 return(xmlXPathNodeTrailingSorted(nodes1,
4680 xmlXPathNodeSetItem(nodes2, 0)));
4681}
4682
Owen Taylor3473f882001-02-23 17:55:21 +00004683/************************************************************************
4684 * *
4685 * Routines to handle extra functions *
4686 * *
4687 ************************************************************************/
4688
4689/**
4690 * xmlXPathRegisterFunc:
4691 * @ctxt: the XPath context
4692 * @name: the function name
4693 * @f: the function implementation or NULL
4694 *
4695 * Register a new function. If @f is NULL it unregisters the function
4696 *
4697 * Returns 0 in case of success, -1 in case of error
4698 */
4699int
4700xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4701 xmlXPathFunction f) {
4702 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4703}
4704
4705/**
4706 * xmlXPathRegisterFuncNS:
4707 * @ctxt: the XPath context
4708 * @name: the function name
4709 * @ns_uri: the function namespace URI
4710 * @f: the function implementation or NULL
4711 *
4712 * Register a new function. If @f is NULL it unregisters the function
4713 *
4714 * Returns 0 in case of success, -1 in case of error
4715 */
4716int
4717xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4718 const xmlChar *ns_uri, xmlXPathFunction f) {
4719 if (ctxt == NULL)
4720 return(-1);
4721 if (name == NULL)
4722 return(-1);
4723
4724 if (ctxt->funcHash == NULL)
4725 ctxt->funcHash = xmlHashCreate(0);
4726 if (ctxt->funcHash == NULL)
4727 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004728 if (f == NULL)
4729 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
William M. Brackad0e67c2004-12-01 14:35:10 +00004730 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
Owen Taylor3473f882001-02-23 17:55:21 +00004731}
4732
4733/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00004734 * xmlXPathRegisterFuncLookup:
4735 * @ctxt: the XPath context
4736 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004737 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00004738 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004739 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00004740 */
4741void
4742xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4743 xmlXPathFuncLookupFunc f,
4744 void *funcCtxt) {
4745 if (ctxt == NULL)
4746 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004747 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004748 ctxt->funcLookupData = funcCtxt;
4749}
4750
4751/**
Owen Taylor3473f882001-02-23 17:55:21 +00004752 * xmlXPathFunctionLookup:
4753 * @ctxt: the XPath context
4754 * @name: the function name
4755 *
4756 * Search in the Function array of the context for the given
4757 * function.
4758 *
4759 * Returns the xmlXPathFunction or NULL if not found
4760 */
4761xmlXPathFunction
4762xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00004763 if (ctxt == NULL)
4764 return (NULL);
4765
4766 if (ctxt->funcLookupFunc != NULL) {
4767 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004768 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004769
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004770 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004771 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004772 if (ret != NULL)
4773 return(ret);
4774 }
Owen Taylor3473f882001-02-23 17:55:21 +00004775 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4776}
4777
4778/**
4779 * xmlXPathFunctionLookupNS:
4780 * @ctxt: the XPath context
4781 * @name: the function name
4782 * @ns_uri: the function namespace URI
4783 *
4784 * Search in the Function array of the context for the given
4785 * function.
4786 *
4787 * Returns the xmlXPathFunction or NULL if not found
4788 */
4789xmlXPathFunction
4790xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4791 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00004792 xmlXPathFunction ret;
4793
Owen Taylor3473f882001-02-23 17:55:21 +00004794 if (ctxt == NULL)
4795 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004796 if (name == NULL)
4797 return(NULL);
4798
Thomas Broyerba4ad322001-07-26 16:55:21 +00004799 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004800 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004801
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004802 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004803 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004804 if (ret != NULL)
4805 return(ret);
4806 }
4807
4808 if (ctxt->funcHash == NULL)
4809 return(NULL);
4810
William M. Brackad0e67c2004-12-01 14:35:10 +00004811 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4812 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004813}
4814
4815/**
4816 * xmlXPathRegisteredFuncsCleanup:
4817 * @ctxt: the XPath context
4818 *
4819 * Cleanup the XPath context data associated to registered functions
4820 */
4821void
4822xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4823 if (ctxt == NULL)
4824 return;
4825
4826 xmlHashFree(ctxt->funcHash, NULL);
4827 ctxt->funcHash = NULL;
4828}
4829
4830/************************************************************************
4831 * *
William M. Brack08171912003-12-29 02:52:11 +00004832 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00004833 * *
4834 ************************************************************************/
4835
4836/**
4837 * xmlXPathRegisterVariable:
4838 * @ctxt: the XPath context
4839 * @name: the variable name
4840 * @value: the variable value or NULL
4841 *
4842 * Register a new variable value. If @value is NULL it unregisters
4843 * the variable
4844 *
4845 * Returns 0 in case of success, -1 in case of error
4846 */
4847int
4848xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4849 xmlXPathObjectPtr value) {
4850 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4851}
4852
4853/**
4854 * xmlXPathRegisterVariableNS:
4855 * @ctxt: the XPath context
4856 * @name: the variable name
4857 * @ns_uri: the variable namespace URI
4858 * @value: the variable value or NULL
4859 *
4860 * Register a new variable value. If @value is NULL it unregisters
4861 * the variable
4862 *
4863 * Returns 0 in case of success, -1 in case of error
4864 */
4865int
4866xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4867 const xmlChar *ns_uri,
4868 xmlXPathObjectPtr value) {
4869 if (ctxt == NULL)
4870 return(-1);
4871 if (name == NULL)
4872 return(-1);
4873
4874 if (ctxt->varHash == NULL)
4875 ctxt->varHash = xmlHashCreate(0);
4876 if (ctxt->varHash == NULL)
4877 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004878 if (value == NULL)
4879 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4880 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00004881 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4882 (void *) value,
4883 (xmlHashDeallocator)xmlXPathFreeObject));
4884}
4885
4886/**
4887 * xmlXPathRegisterVariableLookup:
4888 * @ctxt: the XPath context
4889 * @f: the lookup function
4890 * @data: the lookup data
4891 *
4892 * register an external mechanism to do variable lookup
4893 */
4894void
4895xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4896 xmlXPathVariableLookupFunc f, void *data) {
4897 if (ctxt == NULL)
4898 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004899 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00004900 ctxt->varLookupData = data;
4901}
4902
4903/**
4904 * xmlXPathVariableLookup:
4905 * @ctxt: the XPath context
4906 * @name: the variable name
4907 *
4908 * Search in the Variable array of the context for the given
4909 * variable value.
4910 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00004911 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00004912 */
4913xmlXPathObjectPtr
4914xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4915 if (ctxt == NULL)
4916 return(NULL);
4917
4918 if (ctxt->varLookupFunc != NULL) {
4919 xmlXPathObjectPtr ret;
4920
4921 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4922 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00004923 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004924 }
4925 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4926}
4927
4928/**
4929 * xmlXPathVariableLookupNS:
4930 * @ctxt: the XPath context
4931 * @name: the variable name
4932 * @ns_uri: the variable namespace URI
4933 *
4934 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00004935 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00004936 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00004937 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00004938 */
4939xmlXPathObjectPtr
4940xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4941 const xmlChar *ns_uri) {
4942 if (ctxt == NULL)
4943 return(NULL);
4944
4945 if (ctxt->varLookupFunc != NULL) {
4946 xmlXPathObjectPtr ret;
4947
4948 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4949 (ctxt->varLookupData, name, ns_uri);
4950 if (ret != NULL) return(ret);
4951 }
4952
4953 if (ctxt->varHash == NULL)
4954 return(NULL);
4955 if (name == NULL)
4956 return(NULL);
4957
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004958 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
Daniel Veillard8c357d52001-07-03 23:43:33 +00004959 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00004960}
4961
4962/**
4963 * xmlXPathRegisteredVariablesCleanup:
4964 * @ctxt: the XPath context
4965 *
4966 * Cleanup the XPath context data associated to registered variables
4967 */
4968void
4969xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4970 if (ctxt == NULL)
4971 return;
4972
Daniel Veillard76d66f42001-05-16 21:05:17 +00004973 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00004974 ctxt->varHash = NULL;
4975}
4976
4977/**
4978 * xmlXPathRegisterNs:
4979 * @ctxt: the XPath context
4980 * @prefix: the namespace prefix
4981 * @ns_uri: the namespace name
4982 *
4983 * Register a new namespace. If @ns_uri is NULL it unregisters
4984 * the namespace
4985 *
4986 * Returns 0 in case of success, -1 in case of error
4987 */
4988int
4989xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
4990 const xmlChar *ns_uri) {
4991 if (ctxt == NULL)
4992 return(-1);
4993 if (prefix == NULL)
4994 return(-1);
4995
4996 if (ctxt->nsHash == NULL)
4997 ctxt->nsHash = xmlHashCreate(10);
4998 if (ctxt->nsHash == NULL)
4999 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00005000 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00005001 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00005002 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00005003 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00005004 (xmlHashDeallocator)xmlFree));
5005}
5006
5007/**
5008 * xmlXPathNsLookup:
5009 * @ctxt: the XPath context
5010 * @prefix: the namespace prefix value
5011 *
5012 * Search in the namespace declaration array of the context for the given
5013 * namespace name associated to the given prefix
5014 *
5015 * Returns the value or NULL if not found
5016 */
5017const xmlChar *
5018xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5019 if (ctxt == NULL)
5020 return(NULL);
5021 if (prefix == NULL)
5022 return(NULL);
5023
5024#ifdef XML_XML_NAMESPACE
5025 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5026 return(XML_XML_NAMESPACE);
5027#endif
5028
Daniel Veillardc8f620b2001-04-30 20:31:33 +00005029 if (ctxt->namespaces != NULL) {
5030 int i;
5031
5032 for (i = 0;i < ctxt->nsNr;i++) {
5033 if ((ctxt->namespaces[i] != NULL) &&
5034 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5035 return(ctxt->namespaces[i]->href);
5036 }
5037 }
Owen Taylor3473f882001-02-23 17:55:21 +00005038
5039 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5040}
5041
5042/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005043 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00005044 * @ctxt: the XPath context
5045 *
5046 * Cleanup the XPath context data associated to registered variables
5047 */
5048void
5049xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5050 if (ctxt == NULL)
5051 return;
5052
Daniel Veillard42766c02002-08-22 20:52:17 +00005053 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00005054 ctxt->nsHash = NULL;
5055}
5056
5057/************************************************************************
5058 * *
5059 * Routines to handle Values *
5060 * *
5061 ************************************************************************/
5062
William M. Brack08171912003-12-29 02:52:11 +00005063/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005064
5065/**
5066 * xmlXPathNewFloat:
5067 * @val: the double value
5068 *
5069 * Create a new xmlXPathObjectPtr of type double and of value @val
5070 *
5071 * Returns the newly created object.
5072 */
5073xmlXPathObjectPtr
5074xmlXPathNewFloat(double val) {
5075 xmlXPathObjectPtr ret;
5076
5077 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5078 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005079 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005080 return(NULL);
5081 }
5082 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5083 ret->type = XPATH_NUMBER;
5084 ret->floatval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005085#ifdef XP_DEBUG_OBJ_USAGE
5086 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5087#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005088 return(ret);
5089}
5090
5091/**
5092 * xmlXPathNewBoolean:
5093 * @val: the boolean value
5094 *
5095 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5096 *
5097 * Returns the newly created object.
5098 */
5099xmlXPathObjectPtr
5100xmlXPathNewBoolean(int val) {
5101 xmlXPathObjectPtr ret;
5102
5103 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5104 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005105 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005106 return(NULL);
5107 }
5108 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5109 ret->type = XPATH_BOOLEAN;
5110 ret->boolval = (val != 0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005111#ifdef XP_DEBUG_OBJ_USAGE
5112 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5113#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005114 return(ret);
5115}
5116
5117/**
5118 * xmlXPathNewString:
5119 * @val: the xmlChar * value
5120 *
5121 * Create a new xmlXPathObjectPtr of type string and of value @val
5122 *
5123 * Returns the newly created object.
5124 */
5125xmlXPathObjectPtr
5126xmlXPathNewString(const xmlChar *val) {
5127 xmlXPathObjectPtr ret;
5128
5129 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5130 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005131 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005132 return(NULL);
5133 }
5134 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5135 ret->type = XPATH_STRING;
5136 if (val != NULL)
5137 ret->stringval = xmlStrdup(val);
5138 else
5139 ret->stringval = xmlStrdup((const xmlChar *)"");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005140#ifdef XP_DEBUG_OBJ_USAGE
5141 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5142#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005143 return(ret);
5144}
5145
5146/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005147 * xmlXPathWrapString:
5148 * @val: the xmlChar * value
5149 *
5150 * Wraps the @val string into an XPath object.
5151 *
5152 * Returns the newly created object.
5153 */
5154xmlXPathObjectPtr
5155xmlXPathWrapString (xmlChar *val) {
5156 xmlXPathObjectPtr ret;
5157
5158 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5159 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005160 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005161 return(NULL);
5162 }
5163 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5164 ret->type = XPATH_STRING;
5165 ret->stringval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005166#ifdef XP_DEBUG_OBJ_USAGE
5167 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5168#endif
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005169 return(ret);
5170}
5171
5172/**
Owen Taylor3473f882001-02-23 17:55:21 +00005173 * xmlXPathNewCString:
5174 * @val: the char * value
5175 *
5176 * Create a new xmlXPathObjectPtr of type string and of value @val
5177 *
5178 * Returns the newly created object.
5179 */
5180xmlXPathObjectPtr
5181xmlXPathNewCString(const char *val) {
5182 xmlXPathObjectPtr ret;
5183
5184 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5185 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005186 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005187 return(NULL);
5188 }
5189 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5190 ret->type = XPATH_STRING;
5191 ret->stringval = xmlStrdup(BAD_CAST val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005192#ifdef XP_DEBUG_OBJ_USAGE
5193 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5194#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005195 return(ret);
5196}
5197
5198/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005199 * xmlXPathWrapCString:
5200 * @val: the char * value
5201 *
5202 * Wraps a string into an XPath object.
5203 *
5204 * Returns the newly created object.
5205 */
5206xmlXPathObjectPtr
5207xmlXPathWrapCString (char * val) {
5208 return(xmlXPathWrapString((xmlChar *)(val)));
5209}
5210
5211/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005212 * xmlXPathWrapExternal:
5213 * @val: the user data
5214 *
5215 * Wraps the @val data into an XPath object.
5216 *
5217 * Returns the newly created object.
5218 */
5219xmlXPathObjectPtr
5220xmlXPathWrapExternal (void *val) {
5221 xmlXPathObjectPtr ret;
5222
5223 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5224 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005225 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005226 return(NULL);
5227 }
5228 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5229 ret->type = XPATH_USERS;
5230 ret->user = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005231#ifdef XP_DEBUG_OBJ_USAGE
5232 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5233#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005234 return(ret);
5235}
5236
5237/**
Owen Taylor3473f882001-02-23 17:55:21 +00005238 * xmlXPathObjectCopy:
5239 * @val: the original object
5240 *
5241 * allocate a new copy of a given object
5242 *
5243 * Returns the newly created object.
5244 */
5245xmlXPathObjectPtr
5246xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5247 xmlXPathObjectPtr ret;
5248
5249 if (val == NULL)
5250 return(NULL);
5251
5252 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5253 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005254 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005255 return(NULL);
5256 }
5257 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005258#ifdef XP_DEBUG_OBJ_USAGE
5259 xmlXPathDebugObjUsageRequested(NULL, val->type);
5260#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005261 switch (val->type) {
5262 case XPATH_BOOLEAN:
5263 case XPATH_NUMBER:
5264 case XPATH_POINT:
5265 case XPATH_RANGE:
5266 break;
5267 case XPATH_STRING:
5268 ret->stringval = xmlStrdup(val->stringval);
5269 break;
5270 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00005271#if 0
5272/*
5273 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5274 this previous handling is no longer correct, and can cause some serious
5275 problems (ref. bug 145547)
5276*/
Owen Taylor3473f882001-02-23 17:55:21 +00005277 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005278 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005279 xmlNodePtr cur, tmp;
5280 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005281
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005282 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005283 top = xmlNewDoc(NULL);
5284 top->name = (char *)
5285 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005286 ret->user = top;
5287 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005288 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005289 cur = val->nodesetval->nodeTab[0]->children;
5290 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005291 tmp = xmlDocCopyNode(cur, top, 1);
5292 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005293 cur = cur->next;
5294 }
5295 }
William M. Bracke9449c52004-07-11 14:41:20 +00005296
Daniel Veillard9adc0462003-03-24 18:39:54 +00005297 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005298 } else
Owen Taylor3473f882001-02-23 17:55:21 +00005299 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005300 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00005301 break;
William M. Bracke9449c52004-07-11 14:41:20 +00005302#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005303 case XPATH_NODESET:
5304 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005305 /* Do not deallocate the copied tree value */
5306 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005307 break;
5308 case XPATH_LOCATIONSET:
5309#ifdef LIBXML_XPTR_ENABLED
5310 {
5311 xmlLocationSetPtr loc = val->user;
5312 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5313 break;
5314 }
5315#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00005316 case XPATH_USERS:
5317 ret->user = val->user;
5318 break;
5319 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00005320 xmlGenericError(xmlGenericErrorContext,
5321 "xmlXPathObjectCopy: unsupported type %d\n",
5322 val->type);
5323 break;
5324 }
5325 return(ret);
5326}
5327
5328/**
5329 * xmlXPathFreeObject:
5330 * @obj: the object to free
5331 *
5332 * Free up an xmlXPathObjectPtr object.
5333 */
5334void
5335xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5336 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005337 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00005338 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00005339#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005340 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005341 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00005342 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00005343 } else
5344#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005345 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
William M. Bracke9449c52004-07-11 14:41:20 +00005346 if (obj->nodesetval != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005347 xmlXPathFreeValueTree(obj->nodesetval);
Daniel Veillard77851712001-02-27 21:54:07 +00005348 } else {
5349 if (obj->nodesetval != NULL)
5350 xmlXPathFreeNodeSet(obj->nodesetval);
5351 }
Owen Taylor3473f882001-02-23 17:55:21 +00005352#ifdef LIBXML_XPTR_ENABLED
5353 } else if (obj->type == XPATH_LOCATIONSET) {
5354 if (obj->user != NULL)
5355 xmlXPtrFreeLocationSet(obj->user);
5356#endif
5357 } else if (obj->type == XPATH_STRING) {
5358 if (obj->stringval != NULL)
5359 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005360 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005361#ifdef XP_DEBUG_OBJ_USAGE
5362 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5363#endif
5364 xmlFree(obj);
5365}
Owen Taylor3473f882001-02-23 17:55:21 +00005366
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005367/**
5368 * xmlXPathReleaseObject:
5369 * @obj: the xmlXPathObjectPtr to free or to cache
5370 *
5371 * Depending on the state of the cache this frees the given
5372 * XPath object or stores it in the cache.
5373 */
5374static void
5375xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5376{
5377#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5378 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5379 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5380
5381#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5382
5383 if (obj == NULL)
5384 return;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005385 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005386 xmlXPathFreeObject(obj);
5387 } else {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005388 xmlXPathContextCachePtr cache =
5389 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005390
5391 switch (obj->type) {
5392 case XPATH_NODESET:
5393 case XPATH_XSLT_TREE:
5394 if (obj->nodesetval != NULL) {
5395 if (obj->boolval) {
5396 /*
5397 * It looks like the @boolval is used for
5398 * evaluation if this an XSLT Result Tree Fragment.
5399 * TODO: Check if this assumption is correct.
5400 */
5401 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5402 xmlXPathFreeValueTree(obj->nodesetval);
5403 obj->nodesetval = NULL;
5404 } else if ((obj->nodesetval->nodeMax <= 40) &&
5405 (XP_CACHE_WANTS(cache->nodesetObjs,
5406 cache->maxNodeset)))
5407 {
5408 XP_CACHE_ADD(cache->nodesetObjs, obj);
5409 goto obj_cached;
5410 } else {
5411 xmlXPathFreeNodeSet(obj->nodesetval);
5412 obj->nodesetval = NULL;
5413 }
5414 }
5415 break;
5416 case XPATH_STRING:
5417 if (obj->stringval != NULL)
5418 xmlFree(obj->stringval);
5419
5420 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5421 XP_CACHE_ADD(cache->stringObjs, obj);
5422 goto obj_cached;
5423 }
5424 break;
5425 case XPATH_BOOLEAN:
5426 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5427 XP_CACHE_ADD(cache->booleanObjs, obj);
5428 goto obj_cached;
5429 }
5430 break;
5431 case XPATH_NUMBER:
5432 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5433 XP_CACHE_ADD(cache->numberObjs, obj);
5434 goto obj_cached;
5435 }
5436 break;
5437#ifdef LIBXML_XPTR_ENABLED
5438 case XPATH_LOCATIONSET:
5439 if (obj->user != NULL) {
5440 xmlXPtrFreeLocationSet(obj->user);
5441 }
5442 goto free_obj;
5443#endif
5444 default:
5445 goto free_obj;
5446 }
5447
5448 /*
5449 * Fallback to adding to the misc-objects slot.
5450 */
5451 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5452 XP_CACHE_ADD(cache->miscObjs, obj);
5453 } else
5454 goto free_obj;
5455
5456obj_cached:
5457
5458#ifdef XP_DEBUG_OBJ_USAGE
5459 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5460#endif
5461
5462 if (obj->nodesetval != NULL) {
5463 xmlNodeSetPtr tmpset = obj->nodesetval;
5464
5465 /*
5466 * TODO: Due to those nasty ns-nodes, we need to traverse
5467 * the list and free the ns-nodes.
5468 * URGENT TODO: Check if it's actually slowing things down.
5469 * Maybe we shouldn't try to preserve the list.
5470 */
5471 if (tmpset->nodeNr > 1) {
5472 int i;
5473 xmlNodePtr node;
5474
5475 for (i = 0; i < tmpset->nodeNr; i++) {
5476 node = tmpset->nodeTab[i];
5477 if ((node != NULL) &&
5478 (node->type == XML_NAMESPACE_DECL))
5479 {
5480 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5481 }
5482 }
5483 } else if (tmpset->nodeNr == 1) {
5484 if ((tmpset->nodeTab[0] != NULL) &&
5485 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5486 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5487 }
5488 tmpset->nodeNr = 0;
5489 memset(obj, 0, sizeof(xmlXPathObject));
5490 obj->nodesetval = tmpset;
5491 } else
5492 memset(obj, 0, sizeof(xmlXPathObject));
5493
5494 return;
5495
5496free_obj:
5497 /*
5498 * Cache is full; free the object.
5499 */
5500 if (obj->nodesetval != NULL)
5501 xmlXPathFreeNodeSet(obj->nodesetval);
5502#ifdef XP_DEBUG_OBJ_USAGE
5503 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5504#endif
5505 xmlFree(obj);
5506 }
5507 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005508}
5509
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005510
5511/************************************************************************
5512 * *
5513 * Type Casting Routines *
5514 * *
5515 ************************************************************************/
5516
5517/**
5518 * xmlXPathCastBooleanToString:
5519 * @val: a boolean
5520 *
5521 * Converts a boolean to its string value.
5522 *
5523 * Returns a newly allocated string.
5524 */
5525xmlChar *
5526xmlXPathCastBooleanToString (int val) {
5527 xmlChar *ret;
5528 if (val)
5529 ret = xmlStrdup((const xmlChar *) "true");
5530 else
5531 ret = xmlStrdup((const xmlChar *) "false");
5532 return(ret);
5533}
5534
5535/**
5536 * xmlXPathCastNumberToString:
5537 * @val: a number
5538 *
5539 * Converts a number to its string value.
5540 *
5541 * Returns a newly allocated string.
5542 */
5543xmlChar *
5544xmlXPathCastNumberToString (double val) {
5545 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00005546 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005547 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005548 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005549 break;
5550 case -1:
5551 ret = xmlStrdup((const xmlChar *) "-Infinity");
5552 break;
5553 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00005554 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005555 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005556 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5557 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005558 } else {
5559 /* could be improved */
5560 char buf[100];
Daniel Veillard11ce4002006-03-10 00:36:23 +00005561 xmlXPathFormatNumber(val, buf, 99);
5562 buf[99] = 0;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005563 ret = xmlStrdup((const xmlChar *) buf);
5564 }
5565 }
5566 return(ret);
5567}
5568
5569/**
5570 * xmlXPathCastNodeToString:
5571 * @node: a node
5572 *
5573 * Converts a node to its string value.
5574 *
5575 * Returns a newly allocated string.
5576 */
5577xmlChar *
5578xmlXPathCastNodeToString (xmlNodePtr node) {
5579 return(xmlNodeGetContent(node));
5580}
5581
5582/**
5583 * xmlXPathCastNodeSetToString:
5584 * @ns: a node-set
5585 *
5586 * Converts a node-set to its string value.
5587 *
5588 * Returns a newly allocated string.
5589 */
5590xmlChar *
5591xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5592 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5593 return(xmlStrdup((const xmlChar *) ""));
5594
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00005595 if (ns->nodeNr > 1)
5596 xmlXPathNodeSetSort(ns);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005597 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5598}
5599
5600/**
5601 * xmlXPathCastToString:
5602 * @val: an XPath object
5603 *
5604 * Converts an existing object to its string() equivalent
5605 *
5606 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005607 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005608 * string object).
5609 */
5610xmlChar *
5611xmlXPathCastToString(xmlXPathObjectPtr val) {
5612 xmlChar *ret = NULL;
5613
5614 if (val == NULL)
5615 return(xmlStrdup((const xmlChar *) ""));
5616 switch (val->type) {
5617 case XPATH_UNDEFINED:
5618#ifdef DEBUG_EXPR
5619 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5620#endif
5621 ret = xmlStrdup((const xmlChar *) "");
5622 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005623 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005624 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005625 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5626 break;
5627 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00005628 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005629 case XPATH_BOOLEAN:
5630 ret = xmlXPathCastBooleanToString(val->boolval);
5631 break;
5632 case XPATH_NUMBER: {
5633 ret = xmlXPathCastNumberToString(val->floatval);
5634 break;
5635 }
5636 case XPATH_USERS:
5637 case XPATH_POINT:
5638 case XPATH_RANGE:
5639 case XPATH_LOCATIONSET:
5640 TODO
5641 ret = xmlStrdup((const xmlChar *) "");
5642 break;
5643 }
5644 return(ret);
5645}
5646
5647/**
5648 * xmlXPathConvertString:
5649 * @val: an XPath object
5650 *
5651 * Converts an existing object to its string() equivalent
5652 *
5653 * Returns the new object, the old one is freed (or the operation
5654 * is done directly on @val)
5655 */
5656xmlXPathObjectPtr
5657xmlXPathConvertString(xmlXPathObjectPtr val) {
5658 xmlChar *res = NULL;
5659
5660 if (val == NULL)
5661 return(xmlXPathNewCString(""));
5662
5663 switch (val->type) {
5664 case XPATH_UNDEFINED:
5665#ifdef DEBUG_EXPR
5666 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5667#endif
5668 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005669 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005670 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005671 res = xmlXPathCastNodeSetToString(val->nodesetval);
5672 break;
5673 case XPATH_STRING:
5674 return(val);
5675 case XPATH_BOOLEAN:
5676 res = xmlXPathCastBooleanToString(val->boolval);
5677 break;
5678 case XPATH_NUMBER:
5679 res = xmlXPathCastNumberToString(val->floatval);
5680 break;
5681 case XPATH_USERS:
5682 case XPATH_POINT:
5683 case XPATH_RANGE:
5684 case XPATH_LOCATIONSET:
5685 TODO;
5686 break;
5687 }
5688 xmlXPathFreeObject(val);
5689 if (res == NULL)
5690 return(xmlXPathNewCString(""));
5691 return(xmlXPathWrapString(res));
5692}
5693
5694/**
5695 * xmlXPathCastBooleanToNumber:
5696 * @val: a boolean
5697 *
5698 * Converts a boolean to its number value
5699 *
5700 * Returns the number value
5701 */
5702double
5703xmlXPathCastBooleanToNumber(int val) {
5704 if (val)
5705 return(1.0);
5706 return(0.0);
5707}
5708
5709/**
5710 * xmlXPathCastStringToNumber:
5711 * @val: a string
5712 *
5713 * Converts a string to its number value
5714 *
5715 * Returns the number value
5716 */
5717double
5718xmlXPathCastStringToNumber(const xmlChar * val) {
5719 return(xmlXPathStringEvalNumber(val));
5720}
5721
5722/**
5723 * xmlXPathCastNodeToNumber:
5724 * @node: a node
5725 *
5726 * Converts a node to its number value
5727 *
5728 * Returns the number value
5729 */
5730double
5731xmlXPathCastNodeToNumber (xmlNodePtr node) {
5732 xmlChar *strval;
5733 double ret;
5734
5735 if (node == NULL)
5736 return(xmlXPathNAN);
5737 strval = xmlXPathCastNodeToString(node);
5738 if (strval == NULL)
5739 return(xmlXPathNAN);
5740 ret = xmlXPathCastStringToNumber(strval);
5741 xmlFree(strval);
5742
5743 return(ret);
5744}
5745
5746/**
5747 * xmlXPathCastNodeSetToNumber:
5748 * @ns: a node-set
5749 *
5750 * Converts a node-set to its number value
5751 *
5752 * Returns the number value
5753 */
5754double
5755xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5756 xmlChar *str;
5757 double ret;
5758
5759 if (ns == NULL)
5760 return(xmlXPathNAN);
5761 str = xmlXPathCastNodeSetToString(ns);
5762 ret = xmlXPathCastStringToNumber(str);
5763 xmlFree(str);
5764 return(ret);
5765}
5766
5767/**
5768 * xmlXPathCastToNumber:
5769 * @val: an XPath object
5770 *
5771 * Converts an XPath object to its number value
5772 *
5773 * Returns the number value
5774 */
5775double
5776xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5777 double ret = 0.0;
5778
5779 if (val == NULL)
5780 return(xmlXPathNAN);
5781 switch (val->type) {
5782 case XPATH_UNDEFINED:
5783#ifdef DEGUB_EXPR
5784 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5785#endif
5786 ret = xmlXPathNAN;
5787 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005788 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005789 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005790 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5791 break;
5792 case XPATH_STRING:
5793 ret = xmlXPathCastStringToNumber(val->stringval);
5794 break;
5795 case XPATH_NUMBER:
5796 ret = val->floatval;
5797 break;
5798 case XPATH_BOOLEAN:
5799 ret = xmlXPathCastBooleanToNumber(val->boolval);
5800 break;
5801 case XPATH_USERS:
5802 case XPATH_POINT:
5803 case XPATH_RANGE:
5804 case XPATH_LOCATIONSET:
5805 TODO;
5806 ret = xmlXPathNAN;
5807 break;
5808 }
5809 return(ret);
5810}
5811
5812/**
5813 * xmlXPathConvertNumber:
5814 * @val: an XPath object
5815 *
5816 * Converts an existing object to its number() equivalent
5817 *
5818 * Returns the new object, the old one is freed (or the operation
5819 * is done directly on @val)
5820 */
5821xmlXPathObjectPtr
5822xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5823 xmlXPathObjectPtr ret;
5824
5825 if (val == NULL)
5826 return(xmlXPathNewFloat(0.0));
5827 if (val->type == XPATH_NUMBER)
5828 return(val);
5829 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5830 xmlXPathFreeObject(val);
5831 return(ret);
5832}
5833
5834/**
5835 * xmlXPathCastNumberToBoolean:
5836 * @val: a number
5837 *
5838 * Converts a number to its boolean value
5839 *
5840 * Returns the boolean value
5841 */
5842int
5843xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00005844 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005845 return(0);
5846 return(1);
5847}
5848
5849/**
5850 * xmlXPathCastStringToBoolean:
5851 * @val: a string
5852 *
5853 * Converts a string to its boolean value
5854 *
5855 * Returns the boolean value
5856 */
5857int
5858xmlXPathCastStringToBoolean (const xmlChar *val) {
5859 if ((val == NULL) || (xmlStrlen(val) == 0))
5860 return(0);
5861 return(1);
5862}
5863
5864/**
5865 * xmlXPathCastNodeSetToBoolean:
5866 * @ns: a node-set
5867 *
5868 * Converts a node-set to its boolean value
5869 *
5870 * Returns the boolean value
5871 */
5872int
5873xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5874 if ((ns == NULL) || (ns->nodeNr == 0))
5875 return(0);
5876 return(1);
5877}
5878
5879/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005880 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005881 * @val: an XPath object
5882 *
5883 * Converts an XPath object to its boolean value
5884 *
5885 * Returns the boolean value
5886 */
5887int
5888xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5889 int ret = 0;
5890
5891 if (val == NULL)
5892 return(0);
5893 switch (val->type) {
5894 case XPATH_UNDEFINED:
5895#ifdef DEBUG_EXPR
5896 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
5897#endif
5898 ret = 0;
5899 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005900 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005901 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005902 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5903 break;
5904 case XPATH_STRING:
5905 ret = xmlXPathCastStringToBoolean(val->stringval);
5906 break;
5907 case XPATH_NUMBER:
5908 ret = xmlXPathCastNumberToBoolean(val->floatval);
5909 break;
5910 case XPATH_BOOLEAN:
5911 ret = val->boolval;
5912 break;
5913 case XPATH_USERS:
5914 case XPATH_POINT:
5915 case XPATH_RANGE:
5916 case XPATH_LOCATIONSET:
5917 TODO;
5918 ret = 0;
5919 break;
5920 }
5921 return(ret);
5922}
5923
5924
5925/**
5926 * xmlXPathConvertBoolean:
5927 * @val: an XPath object
5928 *
5929 * Converts an existing object to its boolean() equivalent
5930 *
5931 * Returns the new object, the old one is freed (or the operation
5932 * is done directly on @val)
5933 */
5934xmlXPathObjectPtr
5935xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
5936 xmlXPathObjectPtr ret;
5937
5938 if (val == NULL)
5939 return(xmlXPathNewBoolean(0));
5940 if (val->type == XPATH_BOOLEAN)
5941 return(val);
5942 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
5943 xmlXPathFreeObject(val);
5944 return(ret);
5945}
5946
Owen Taylor3473f882001-02-23 17:55:21 +00005947/************************************************************************
5948 * *
5949 * Routines to handle XPath contexts *
5950 * *
5951 ************************************************************************/
5952
5953/**
5954 * xmlXPathNewContext:
5955 * @doc: the XML document
5956 *
5957 * Create a new xmlXPathContext
5958 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00005959 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00005960 */
5961xmlXPathContextPtr
5962xmlXPathNewContext(xmlDocPtr doc) {
5963 xmlXPathContextPtr ret;
5964
5965 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
5966 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005967 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005968 return(NULL);
5969 }
5970 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
5971 ret->doc = doc;
5972 ret->node = NULL;
5973
5974 ret->varHash = NULL;
5975
5976 ret->nb_types = 0;
5977 ret->max_types = 0;
5978 ret->types = NULL;
5979
5980 ret->funcHash = xmlHashCreate(0);
5981
5982 ret->nb_axis = 0;
5983 ret->max_axis = 0;
5984 ret->axis = NULL;
5985
5986 ret->nsHash = NULL;
5987 ret->user = NULL;
5988
5989 ret->contextSize = -1;
5990 ret->proximityPosition = -1;
5991
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005992#ifdef XP_DEFAULT_CACHE_ON
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005993 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005994 xmlXPathFreeContext(ret);
5995 return(NULL);
5996 }
5997#endif
5998
5999 xmlXPathRegisterAllFunctions(ret);
6000
Owen Taylor3473f882001-02-23 17:55:21 +00006001 return(ret);
6002}
6003
6004/**
6005 * xmlXPathFreeContext:
6006 * @ctxt: the context to free
6007 *
6008 * Free up an xmlXPathContext
6009 */
6010void
6011xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006012 if (ctxt == NULL) return;
6013
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006014 if (ctxt->cache != NULL)
6015 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
Owen Taylor3473f882001-02-23 17:55:21 +00006016 xmlXPathRegisteredNsCleanup(ctxt);
6017 xmlXPathRegisteredFuncsCleanup(ctxt);
6018 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006019 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00006020 xmlFree(ctxt);
6021}
6022
6023/************************************************************************
6024 * *
6025 * Routines to handle XPath parser contexts *
6026 * *
6027 ************************************************************************/
6028
6029#define CHECK_CTXT(ctxt) \
6030 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00006031 __xmlRaiseError(NULL, NULL, NULL, \
6032 NULL, NULL, XML_FROM_XPATH, \
6033 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6034 __FILE__, __LINE__, \
6035 NULL, NULL, NULL, 0, 0, \
6036 "NULL context pointer\n"); \
6037 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00006038 } \
6039
6040
6041#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00006042 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
6043 (ctxt->doc->children == NULL)) { \
6044 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00006045 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00006046 }
Owen Taylor3473f882001-02-23 17:55:21 +00006047
6048
6049/**
6050 * xmlXPathNewParserContext:
6051 * @str: the XPath expression
6052 * @ctxt: the XPath context
6053 *
6054 * Create a new xmlXPathParserContext
6055 *
6056 * Returns the xmlXPathParserContext just allocated.
6057 */
6058xmlXPathParserContextPtr
6059xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6060 xmlXPathParserContextPtr ret;
6061
6062 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6063 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006064 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006065 return(NULL);
6066 }
6067 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6068 ret->cur = ret->base = str;
6069 ret->context = ctxt;
6070
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006071 ret->comp = xmlXPathNewCompExpr();
6072 if (ret->comp == NULL) {
6073 xmlFree(ret->valueTab);
6074 xmlFree(ret);
6075 return(NULL);
6076 }
Daniel Veillard4773df22004-01-23 13:15:13 +00006077 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6078 ret->comp->dict = ctxt->dict;
6079 xmlDictReference(ret->comp->dict);
6080 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006081
6082 return(ret);
6083}
6084
6085/**
6086 * xmlXPathCompParserContext:
6087 * @comp: the XPath compiled expression
6088 * @ctxt: the XPath context
6089 *
6090 * Create a new xmlXPathParserContext when processing a compiled expression
6091 *
6092 * Returns the xmlXPathParserContext just allocated.
6093 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006094static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006095xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6096 xmlXPathParserContextPtr ret;
6097
6098 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6099 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006100 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006101 return(NULL);
6102 }
6103 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6104
Owen Taylor3473f882001-02-23 17:55:21 +00006105 /* Allocate the value stack */
6106 ret->valueTab = (xmlXPathObjectPtr *)
6107 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006108 if (ret->valueTab == NULL) {
6109 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006110 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006111 return(NULL);
6112 }
Owen Taylor3473f882001-02-23 17:55:21 +00006113 ret->valueNr = 0;
6114 ret->valueMax = 10;
6115 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006116
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006117 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006118 ret->comp = comp;
6119
Owen Taylor3473f882001-02-23 17:55:21 +00006120 return(ret);
6121}
6122
6123/**
6124 * xmlXPathFreeParserContext:
6125 * @ctxt: the context to free
6126 *
6127 * Free up an xmlXPathParserContext
6128 */
6129void
6130xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6131 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006132 xmlFree(ctxt->valueTab);
6133 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00006134 if (ctxt->comp != NULL) {
6135#ifdef XPATH_STREAMING
6136 if (ctxt->comp->stream != NULL) {
6137 xmlFreePatternList(ctxt->comp->stream);
6138 ctxt->comp->stream = NULL;
6139 }
6140#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006141 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00006142 }
Owen Taylor3473f882001-02-23 17:55:21 +00006143 xmlFree(ctxt);
6144}
6145
6146/************************************************************************
6147 * *
6148 * The implicit core function library *
6149 * *
6150 ************************************************************************/
6151
Owen Taylor3473f882001-02-23 17:55:21 +00006152/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006153 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00006154 * @node: a node pointer
6155 *
6156 * Function computing the beginning of the string value of the node,
6157 * used to speed up comparisons
6158 *
6159 * Returns an int usable as a hash
6160 */
6161static unsigned int
6162xmlXPathNodeValHash(xmlNodePtr node) {
6163 int len = 2;
6164 const xmlChar * string = NULL;
6165 xmlNodePtr tmp = NULL;
6166 unsigned int ret = 0;
6167
6168 if (node == NULL)
6169 return(0);
6170
Daniel Veillard9adc0462003-03-24 18:39:54 +00006171 if (node->type == XML_DOCUMENT_NODE) {
6172 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6173 if (tmp == NULL)
6174 node = node->children;
6175 else
6176 node = tmp;
6177
6178 if (node == NULL)
6179 return(0);
6180 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006181
6182 switch (node->type) {
6183 case XML_COMMENT_NODE:
6184 case XML_PI_NODE:
6185 case XML_CDATA_SECTION_NODE:
6186 case XML_TEXT_NODE:
6187 string = node->content;
6188 if (string == NULL)
6189 return(0);
6190 if (string[0] == 0)
6191 return(0);
6192 return(((unsigned int) string[0]) +
6193 (((unsigned int) string[1]) << 8));
6194 case XML_NAMESPACE_DECL:
6195 string = ((xmlNsPtr)node)->href;
6196 if (string == NULL)
6197 return(0);
6198 if (string[0] == 0)
6199 return(0);
6200 return(((unsigned int) string[0]) +
6201 (((unsigned int) string[1]) << 8));
6202 case XML_ATTRIBUTE_NODE:
6203 tmp = ((xmlAttrPtr) node)->children;
6204 break;
6205 case XML_ELEMENT_NODE:
6206 tmp = node->children;
6207 break;
6208 default:
6209 return(0);
6210 }
6211 while (tmp != NULL) {
6212 switch (tmp->type) {
6213 case XML_COMMENT_NODE:
6214 case XML_PI_NODE:
6215 case XML_CDATA_SECTION_NODE:
6216 case XML_TEXT_NODE:
6217 string = tmp->content;
6218 break;
6219 case XML_NAMESPACE_DECL:
6220 string = ((xmlNsPtr)tmp)->href;
6221 break;
6222 default:
6223 break;
6224 }
6225 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006226 if (len == 1) {
6227 return(ret + (((unsigned int) string[0]) << 8));
6228 }
6229 if (string[1] == 0) {
6230 len = 1;
6231 ret = (unsigned int) string[0];
6232 } else {
6233 return(((unsigned int) string[0]) +
6234 (((unsigned int) string[1]) << 8));
6235 }
6236 }
6237 /*
6238 * Skip to next node
6239 */
6240 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6241 if (tmp->children->type != XML_ENTITY_DECL) {
6242 tmp = tmp->children;
6243 continue;
6244 }
6245 }
6246 if (tmp == node)
6247 break;
6248
6249 if (tmp->next != NULL) {
6250 tmp = tmp->next;
6251 continue;
6252 }
6253
6254 do {
6255 tmp = tmp->parent;
6256 if (tmp == NULL)
6257 break;
6258 if (tmp == node) {
6259 tmp = NULL;
6260 break;
6261 }
6262 if (tmp->next != NULL) {
6263 tmp = tmp->next;
6264 break;
6265 }
6266 } while (tmp != NULL);
6267 }
6268 return(ret);
6269}
6270
6271/**
6272 * xmlXPathStringHash:
6273 * @string: a string
6274 *
6275 * Function computing the beginning of the string value of the node,
6276 * used to speed up comparisons
6277 *
6278 * Returns an int usable as a hash
6279 */
6280static unsigned int
6281xmlXPathStringHash(const xmlChar * string) {
6282 if (string == NULL)
6283 return((unsigned int) 0);
6284 if (string[0] == 0)
6285 return(0);
6286 return(((unsigned int) string[0]) +
6287 (((unsigned int) string[1]) << 8));
6288}
6289
6290/**
Owen Taylor3473f882001-02-23 17:55:21 +00006291 * xmlXPathCompareNodeSetFloat:
6292 * @ctxt: the XPath Parser context
6293 * @inf: less than (1) or greater than (0)
6294 * @strict: is the comparison strict
6295 * @arg: the node set
6296 * @f: the value
6297 *
6298 * Implement the compare operation between a nodeset and a number
6299 * @ns < @val (1, 1, ...
6300 * @ns <= @val (1, 0, ...
6301 * @ns > @val (0, 1, ...
6302 * @ns >= @val (0, 0, ...
6303 *
6304 * If one object to be compared is a node-set and the other is a number,
6305 * then the comparison will be true if and only if there is a node in the
6306 * node-set such that the result of performing the comparison on the number
6307 * to be compared and on the result of converting the string-value of that
6308 * node to a number using the number function is true.
6309 *
6310 * Returns 0 or 1 depending on the results of the test.
6311 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006312static int
Owen Taylor3473f882001-02-23 17:55:21 +00006313xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6314 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6315 int i, ret = 0;
6316 xmlNodeSetPtr ns;
6317 xmlChar *str2;
6318
6319 if ((f == NULL) || (arg == NULL) ||
6320 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006321 xmlXPathReleaseObject(ctxt->context, arg);
6322 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006323 return(0);
6324 }
6325 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006326 if (ns != NULL) {
6327 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006328 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006329 if (str2 != NULL) {
6330 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006331 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006332 xmlFree(str2);
6333 xmlXPathNumberFunction(ctxt, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006334 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006335 ret = xmlXPathCompareValues(ctxt, inf, strict);
6336 if (ret)
6337 break;
6338 }
6339 }
Owen Taylor3473f882001-02-23 17:55:21 +00006340 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006341 xmlXPathReleaseObject(ctxt->context, arg);
6342 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006343 return(ret);
6344}
6345
6346/**
6347 * xmlXPathCompareNodeSetString:
6348 * @ctxt: the XPath Parser context
6349 * @inf: less than (1) or greater than (0)
6350 * @strict: is the comparison strict
6351 * @arg: the node set
6352 * @s: the value
6353 *
6354 * Implement the compare operation between a nodeset and a string
6355 * @ns < @val (1, 1, ...
6356 * @ns <= @val (1, 0, ...
6357 * @ns > @val (0, 1, ...
6358 * @ns >= @val (0, 0, ...
6359 *
6360 * If one object to be compared is a node-set and the other is a string,
6361 * then the comparison will be true if and only if there is a node in
6362 * the node-set such that the result of performing the comparison on the
6363 * string-value of the node and the other string is true.
6364 *
6365 * Returns 0 or 1 depending on the results of the test.
6366 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006367static int
Owen Taylor3473f882001-02-23 17:55:21 +00006368xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6369 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6370 int i, ret = 0;
6371 xmlNodeSetPtr ns;
6372 xmlChar *str2;
6373
6374 if ((s == NULL) || (arg == NULL) ||
6375 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006376 xmlXPathReleaseObject(ctxt->context, arg);
6377 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006378 return(0);
6379 }
6380 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006381 if (ns != NULL) {
6382 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006383 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006384 if (str2 != NULL) {
6385 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006386 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006387 xmlFree(str2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006388 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006389 ret = xmlXPathCompareValues(ctxt, inf, strict);
6390 if (ret)
6391 break;
6392 }
6393 }
Owen Taylor3473f882001-02-23 17:55:21 +00006394 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006395 xmlXPathReleaseObject(ctxt->context, arg);
6396 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006397 return(ret);
6398}
6399
6400/**
6401 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006402 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00006403 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006404 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00006405 * @arg2: the second node set object
6406 *
6407 * Implement the compare operation on nodesets:
6408 *
6409 * If both objects to be compared are node-sets, then the comparison
6410 * will be true if and only if there is a node in the first node-set
6411 * and a node in the second node-set such that the result of performing
6412 * the comparison on the string-values of the two nodes is true.
6413 * ....
6414 * When neither object to be compared is a node-set and the operator
6415 * is <=, <, >= or >, then the objects are compared by converting both
6416 * objects to numbers and comparing the numbers according to IEEE 754.
6417 * ....
6418 * The number function converts its argument to a number as follows:
6419 * - a string that consists of optional whitespace followed by an
6420 * optional minus sign followed by a Number followed by whitespace
6421 * is converted to the IEEE 754 number that is nearest (according
6422 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6423 * represented by the string; any other string is converted to NaN
6424 *
6425 * Conclusion all nodes need to be converted first to their string value
6426 * and then the comparison must be done when possible
6427 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006428static int
6429xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00006430 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6431 int i, j, init = 0;
6432 double val1;
6433 double *values2;
6434 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006435 xmlNodeSetPtr ns1;
6436 xmlNodeSetPtr ns2;
6437
6438 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006439 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6440 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006441 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006442 }
Owen Taylor3473f882001-02-23 17:55:21 +00006443 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006444 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6445 xmlXPathFreeObject(arg1);
6446 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006447 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006448 }
Owen Taylor3473f882001-02-23 17:55:21 +00006449
6450 ns1 = arg1->nodesetval;
6451 ns2 = arg2->nodesetval;
6452
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006453 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006454 xmlXPathFreeObject(arg1);
6455 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006456 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006457 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006458 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006459 xmlXPathFreeObject(arg1);
6460 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006461 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006462 }
Owen Taylor3473f882001-02-23 17:55:21 +00006463
6464 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6465 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006466 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00006467 xmlXPathFreeObject(arg1);
6468 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006469 return(0);
6470 }
6471 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006472 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00006473 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00006474 continue;
6475 for (j = 0;j < ns2->nodeNr;j++) {
6476 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006477 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00006478 }
Daniel Veillardcda96922001-08-21 10:56:31 +00006479 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00006480 continue;
6481 if (inf && strict)
6482 ret = (val1 < values2[j]);
6483 else if (inf && !strict)
6484 ret = (val1 <= values2[j]);
6485 else if (!inf && strict)
6486 ret = (val1 > values2[j]);
6487 else if (!inf && !strict)
6488 ret = (val1 >= values2[j]);
6489 if (ret)
6490 break;
6491 }
6492 if (ret)
6493 break;
6494 init = 1;
6495 }
6496 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006497 xmlXPathFreeObject(arg1);
6498 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006499 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006500}
6501
6502/**
6503 * xmlXPathCompareNodeSetValue:
6504 * @ctxt: the XPath Parser context
6505 * @inf: less than (1) or greater than (0)
6506 * @strict: is the comparison strict
6507 * @arg: the node set
6508 * @val: the value
6509 *
6510 * Implement the compare operation between a nodeset and a value
6511 * @ns < @val (1, 1, ...
6512 * @ns <= @val (1, 0, ...
6513 * @ns > @val (0, 1, ...
6514 * @ns >= @val (0, 0, ...
6515 *
6516 * If one object to be compared is a node-set and the other is a boolean,
6517 * then the comparison will be true if and only if the result of performing
6518 * the comparison on the boolean and on the result of converting
6519 * the node-set to a boolean using the boolean function is true.
6520 *
6521 * Returns 0 or 1 depending on the results of the test.
6522 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006523static int
Owen Taylor3473f882001-02-23 17:55:21 +00006524xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6525 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6526 if ((val == NULL) || (arg == NULL) ||
6527 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6528 return(0);
6529
6530 switch(val->type) {
6531 case XPATH_NUMBER:
6532 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6533 case XPATH_NODESET:
6534 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006535 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00006536 case XPATH_STRING:
6537 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6538 case XPATH_BOOLEAN:
6539 valuePush(ctxt, arg);
6540 xmlXPathBooleanFunction(ctxt, 1);
6541 valuePush(ctxt, val);
6542 return(xmlXPathCompareValues(ctxt, inf, strict));
6543 default:
6544 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00006545 }
6546 return(0);
6547}
6548
6549/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006550 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00006551 * @arg: the nodeset object argument
6552 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00006553 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006554 *
6555 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6556 * If one object to be compared is a node-set and the other is a string,
6557 * then the comparison will be true if and only if there is a node in
6558 * the node-set such that the result of performing the comparison on the
6559 * string-value of the node and the other string is true.
6560 *
6561 * Returns 0 or 1 depending on the results of the test.
6562 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006563static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006564xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006565{
Owen Taylor3473f882001-02-23 17:55:21 +00006566 int i;
6567 xmlNodeSetPtr ns;
6568 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006569 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00006570
6571 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00006572 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6573 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006574 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00006575 /*
6576 * A NULL nodeset compared with a string is always false
6577 * (since there is no node equal, and no node not equal)
6578 */
6579 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00006580 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00006581 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006582 for (i = 0; i < ns->nodeNr; i++) {
6583 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6584 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6585 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6586 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006587 if (neq)
6588 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006589 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00006590 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6591 if (neq)
6592 continue;
6593 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006594 } else if (neq) {
6595 if (str2 != NULL)
6596 xmlFree(str2);
6597 return (1);
6598 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006599 if (str2 != NULL)
6600 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006601 } else if (neq)
6602 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00006603 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006604 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006605}
6606
6607/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006608 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00006609 * @arg: the nodeset object argument
6610 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00006611 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006612 *
6613 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6614 * If one object to be compared is a node-set and the other is a number,
6615 * then the comparison will be true if and only if there is a node in
6616 * the node-set such that the result of performing the comparison on the
6617 * number to be compared and on the result of converting the string-value
6618 * of that node to a number using the number function is true.
6619 *
6620 * Returns 0 or 1 depending on the results of the test.
6621 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006622static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006623xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6624 xmlXPathObjectPtr arg, double f, int neq) {
6625 int i, ret=0;
6626 xmlNodeSetPtr ns;
6627 xmlChar *str2;
6628 xmlXPathObjectPtr val;
6629 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00006630
6631 if ((arg == NULL) ||
6632 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6633 return(0);
6634
William M. Brack0c022ad2002-07-12 00:56:01 +00006635 ns = arg->nodesetval;
6636 if (ns != NULL) {
6637 for (i=0;i<ns->nodeNr;i++) {
6638 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6639 if (str2 != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006640 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
William M. Brack0c022ad2002-07-12 00:56:01 +00006641 xmlFree(str2);
6642 xmlXPathNumberFunction(ctxt, 1);
6643 val = valuePop(ctxt);
6644 v = val->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006645 xmlXPathReleaseObject(ctxt->context, val);
William M. Brack0c022ad2002-07-12 00:56:01 +00006646 if (!xmlXPathIsNaN(v)) {
6647 if ((!neq) && (v==f)) {
6648 ret = 1;
6649 break;
6650 } else if ((neq) && (v!=f)) {
6651 ret = 1;
6652 break;
6653 }
William M. Brack32f0f712005-07-14 07:00:33 +00006654 } else { /* NaN is unequal to any value */
6655 if (neq)
6656 ret = 1;
William M. Brack0c022ad2002-07-12 00:56:01 +00006657 }
6658 }
6659 }
6660 }
6661
6662 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006663}
6664
6665
6666/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006667 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00006668 * @arg1: first nodeset object argument
6669 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00006670 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006671 *
William M. Brack0c022ad2002-07-12 00:56:01 +00006672 * Implement the equal / not equal operation on XPath nodesets:
6673 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00006674 * If both objects to be compared are node-sets, then the comparison
6675 * will be true if and only if there is a node in the first node-set and
6676 * a node in the second node-set such that the result of performing the
6677 * comparison on the string-values of the two nodes is true.
6678 *
6679 * (needless to say, this is a costly operation)
6680 *
6681 * Returns 0 or 1 depending on the results of the test.
6682 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006683static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006684xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00006685 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006686 unsigned int *hashs1;
6687 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00006688 xmlChar **values1;
6689 xmlChar **values2;
6690 int ret = 0;
6691 xmlNodeSetPtr ns1;
6692 xmlNodeSetPtr ns2;
6693
6694 if ((arg1 == NULL) ||
6695 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6696 return(0);
6697 if ((arg2 == NULL) ||
6698 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6699 return(0);
6700
6701 ns1 = arg1->nodesetval;
6702 ns2 = arg2->nodesetval;
6703
Daniel Veillard911f49a2001-04-07 15:39:35 +00006704 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006705 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006706 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006707 return(0);
6708
6709 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00006710 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00006711 */
William M. Brack0c022ad2002-07-12 00:56:01 +00006712 if (neq == 0)
6713 for (i = 0;i < ns1->nodeNr;i++)
6714 for (j = 0;j < ns2->nodeNr;j++)
6715 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6716 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006717
6718 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006719 if (values1 == NULL) {
6720 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006721 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006722 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006723 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6724 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006725 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006726 xmlFree(values1);
6727 return(0);
6728 }
Owen Taylor3473f882001-02-23 17:55:21 +00006729 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6730 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6731 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006732 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006733 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00006734 xmlFree(values1);
6735 return(0);
6736 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006737 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6738 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006739 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006740 xmlFree(hashs1);
6741 xmlFree(values1);
6742 xmlFree(values2);
6743 return(0);
6744 }
Owen Taylor3473f882001-02-23 17:55:21 +00006745 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6746 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006747 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006748 for (j = 0;j < ns2->nodeNr;j++) {
6749 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006750 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006751 if (hashs1[i] != hashs2[j]) {
6752 if (neq) {
6753 ret = 1;
6754 break;
6755 }
6756 }
6757 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006758 if (values1[i] == NULL)
6759 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6760 if (values2[j] == NULL)
6761 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006762 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006763 if (ret)
6764 break;
6765 }
Owen Taylor3473f882001-02-23 17:55:21 +00006766 }
6767 if (ret)
6768 break;
6769 }
6770 for (i = 0;i < ns1->nodeNr;i++)
6771 if (values1[i] != NULL)
6772 xmlFree(values1[i]);
6773 for (j = 0;j < ns2->nodeNr;j++)
6774 if (values2[j] != NULL)
6775 xmlFree(values2[j]);
6776 xmlFree(values1);
6777 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006778 xmlFree(hashs1);
6779 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00006780 return(ret);
6781}
6782
William M. Brack0c022ad2002-07-12 00:56:01 +00006783static int
6784xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6785 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00006786 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00006787 /*
6788 *At this point we are assured neither arg1 nor arg2
6789 *is a nodeset, so we can just pick the appropriate routine.
6790 */
Owen Taylor3473f882001-02-23 17:55:21 +00006791 switch (arg1->type) {
6792 case XPATH_UNDEFINED:
6793#ifdef DEBUG_EXPR
6794 xmlGenericError(xmlGenericErrorContext,
6795 "Equal: undefined\n");
6796#endif
6797 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006798 case XPATH_BOOLEAN:
6799 switch (arg2->type) {
6800 case XPATH_UNDEFINED:
6801#ifdef DEBUG_EXPR
6802 xmlGenericError(xmlGenericErrorContext,
6803 "Equal: undefined\n");
6804#endif
6805 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006806 case XPATH_BOOLEAN:
6807#ifdef DEBUG_EXPR
6808 xmlGenericError(xmlGenericErrorContext,
6809 "Equal: %d boolean %d \n",
6810 arg1->boolval, arg2->boolval);
6811#endif
6812 ret = (arg1->boolval == arg2->boolval);
6813 break;
6814 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00006815 ret = (arg1->boolval ==
6816 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006817 break;
6818 case XPATH_STRING:
6819 if ((arg2->stringval == NULL) ||
6820 (arg2->stringval[0] == 0)) ret = 0;
6821 else
6822 ret = 1;
6823 ret = (arg1->boolval == ret);
6824 break;
6825 case XPATH_USERS:
6826 case XPATH_POINT:
6827 case XPATH_RANGE:
6828 case XPATH_LOCATIONSET:
6829 TODO
6830 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006831 case XPATH_NODESET:
6832 case XPATH_XSLT_TREE:
6833 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006834 }
6835 break;
6836 case XPATH_NUMBER:
6837 switch (arg2->type) {
6838 case XPATH_UNDEFINED:
6839#ifdef DEBUG_EXPR
6840 xmlGenericError(xmlGenericErrorContext,
6841 "Equal: undefined\n");
6842#endif
6843 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006844 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00006845 ret = (arg2->boolval==
6846 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006847 break;
6848 case XPATH_STRING:
6849 valuePush(ctxt, arg2);
6850 xmlXPathNumberFunction(ctxt, 1);
6851 arg2 = valuePop(ctxt);
6852 /* no break on purpose */
6853 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006854 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00006855 if (xmlXPathIsNaN(arg1->floatval) ||
6856 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00006857 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006858 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6859 if (xmlXPathIsInf(arg2->floatval) == 1)
6860 ret = 1;
6861 else
6862 ret = 0;
6863 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6864 if (xmlXPathIsInf(arg2->floatval) == -1)
6865 ret = 1;
6866 else
6867 ret = 0;
6868 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6869 if (xmlXPathIsInf(arg1->floatval) == 1)
6870 ret = 1;
6871 else
6872 ret = 0;
6873 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6874 if (xmlXPathIsInf(arg1->floatval) == -1)
6875 ret = 1;
6876 else
6877 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00006878 } else {
6879 ret = (arg1->floatval == arg2->floatval);
6880 }
Owen Taylor3473f882001-02-23 17:55:21 +00006881 break;
6882 case XPATH_USERS:
6883 case XPATH_POINT:
6884 case XPATH_RANGE:
6885 case XPATH_LOCATIONSET:
6886 TODO
6887 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006888 case XPATH_NODESET:
6889 case XPATH_XSLT_TREE:
6890 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006891 }
6892 break;
6893 case XPATH_STRING:
6894 switch (arg2->type) {
6895 case XPATH_UNDEFINED:
6896#ifdef DEBUG_EXPR
6897 xmlGenericError(xmlGenericErrorContext,
6898 "Equal: undefined\n");
6899#endif
6900 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006901 case XPATH_BOOLEAN:
6902 if ((arg1->stringval == NULL) ||
6903 (arg1->stringval[0] == 0)) ret = 0;
6904 else
6905 ret = 1;
6906 ret = (arg2->boolval == ret);
6907 break;
6908 case XPATH_STRING:
6909 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6910 break;
6911 case XPATH_NUMBER:
6912 valuePush(ctxt, arg1);
6913 xmlXPathNumberFunction(ctxt, 1);
6914 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006915 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00006916 if (xmlXPathIsNaN(arg1->floatval) ||
6917 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00006918 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006919 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6920 if (xmlXPathIsInf(arg2->floatval) == 1)
6921 ret = 1;
6922 else
6923 ret = 0;
6924 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6925 if (xmlXPathIsInf(arg2->floatval) == -1)
6926 ret = 1;
6927 else
6928 ret = 0;
6929 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6930 if (xmlXPathIsInf(arg1->floatval) == 1)
6931 ret = 1;
6932 else
6933 ret = 0;
6934 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6935 if (xmlXPathIsInf(arg1->floatval) == -1)
6936 ret = 1;
6937 else
6938 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00006939 } else {
6940 ret = (arg1->floatval == arg2->floatval);
6941 }
Owen Taylor3473f882001-02-23 17:55:21 +00006942 break;
6943 case XPATH_USERS:
6944 case XPATH_POINT:
6945 case XPATH_RANGE:
6946 case XPATH_LOCATIONSET:
6947 TODO
6948 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006949 case XPATH_NODESET:
6950 case XPATH_XSLT_TREE:
6951 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006952 }
6953 break;
6954 case XPATH_USERS:
6955 case XPATH_POINT:
6956 case XPATH_RANGE:
6957 case XPATH_LOCATIONSET:
6958 TODO
6959 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006960 case XPATH_NODESET:
6961 case XPATH_XSLT_TREE:
6962 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006963 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006964 xmlXPathReleaseObject(ctxt->context, arg1);
6965 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006966 return(ret);
6967}
6968
William M. Brack0c022ad2002-07-12 00:56:01 +00006969/**
6970 * xmlXPathEqualValues:
6971 * @ctxt: the XPath Parser context
6972 *
6973 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6974 *
6975 * Returns 0 or 1 depending on the results of the test.
6976 */
6977int
6978xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
6979 xmlXPathObjectPtr arg1, arg2, argtmp;
6980 int ret = 0;
6981
Daniel Veillard6128c012004-11-08 17:16:15 +00006982 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00006983 arg2 = valuePop(ctxt);
6984 arg1 = valuePop(ctxt);
6985 if ((arg1 == NULL) || (arg2 == NULL)) {
6986 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006987 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006988 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006989 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006990 XP_ERROR0(XPATH_INVALID_OPERAND);
6991 }
6992
6993 if (arg1 == arg2) {
6994#ifdef DEBUG_EXPR
6995 xmlGenericError(xmlGenericErrorContext,
6996 "Equal: by pointer\n");
6997#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00006998 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006999 return(1);
7000 }
7001
7002 /*
7003 *If either argument is a nodeset, it's a 'special case'
7004 */
7005 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7006 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7007 /*
7008 *Hack it to assure arg1 is the nodeset
7009 */
7010 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7011 argtmp = arg2;
7012 arg2 = arg1;
7013 arg1 = argtmp;
7014 }
7015 switch (arg2->type) {
7016 case XPATH_UNDEFINED:
7017#ifdef DEBUG_EXPR
7018 xmlGenericError(xmlGenericErrorContext,
7019 "Equal: undefined\n");
7020#endif
7021 break;
7022 case XPATH_NODESET:
7023 case XPATH_XSLT_TREE:
7024 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7025 break;
7026 case XPATH_BOOLEAN:
7027 if ((arg1->nodesetval == NULL) ||
7028 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7029 else
7030 ret = 1;
7031 ret = (ret == arg2->boolval);
7032 break;
7033 case XPATH_NUMBER:
7034 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7035 break;
7036 case XPATH_STRING:
7037 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7038 break;
7039 case XPATH_USERS:
7040 case XPATH_POINT:
7041 case XPATH_RANGE:
7042 case XPATH_LOCATIONSET:
7043 TODO
7044 break;
7045 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007046 xmlXPathReleaseObject(ctxt->context, arg1);
7047 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007048 return(ret);
7049 }
7050
7051 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7052}
7053
7054/**
7055 * xmlXPathNotEqualValues:
7056 * @ctxt: the XPath Parser context
7057 *
7058 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7059 *
7060 * Returns 0 or 1 depending on the results of the test.
7061 */
7062int
7063xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7064 xmlXPathObjectPtr arg1, arg2, argtmp;
7065 int ret = 0;
7066
Daniel Veillard6128c012004-11-08 17:16:15 +00007067 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00007068 arg2 = valuePop(ctxt);
7069 arg1 = valuePop(ctxt);
7070 if ((arg1 == NULL) || (arg2 == NULL)) {
7071 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007072 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007073 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007074 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007075 XP_ERROR0(XPATH_INVALID_OPERAND);
7076 }
7077
7078 if (arg1 == arg2) {
7079#ifdef DEBUG_EXPR
7080 xmlGenericError(xmlGenericErrorContext,
7081 "NotEqual: by pointer\n");
7082#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007083 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007084 return(0);
7085 }
7086
7087 /*
7088 *If either argument is a nodeset, it's a 'special case'
7089 */
7090 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7091 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7092 /*
7093 *Hack it to assure arg1 is the nodeset
7094 */
7095 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7096 argtmp = arg2;
7097 arg2 = arg1;
7098 arg1 = argtmp;
7099 }
7100 switch (arg2->type) {
7101 case XPATH_UNDEFINED:
7102#ifdef DEBUG_EXPR
7103 xmlGenericError(xmlGenericErrorContext,
7104 "NotEqual: undefined\n");
7105#endif
7106 break;
7107 case XPATH_NODESET:
7108 case XPATH_XSLT_TREE:
7109 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7110 break;
7111 case XPATH_BOOLEAN:
7112 if ((arg1->nodesetval == NULL) ||
7113 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7114 else
7115 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00007116 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00007117 break;
7118 case XPATH_NUMBER:
7119 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7120 break;
7121 case XPATH_STRING:
7122 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7123 break;
7124 case XPATH_USERS:
7125 case XPATH_POINT:
7126 case XPATH_RANGE:
7127 case XPATH_LOCATIONSET:
7128 TODO
7129 break;
7130 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007131 xmlXPathReleaseObject(ctxt->context, arg1);
7132 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007133 return(ret);
7134 }
7135
7136 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7137}
Owen Taylor3473f882001-02-23 17:55:21 +00007138
7139/**
7140 * xmlXPathCompareValues:
7141 * @ctxt: the XPath Parser context
7142 * @inf: less than (1) or greater than (0)
7143 * @strict: is the comparison strict
7144 *
7145 * Implement the compare operation on XPath objects:
7146 * @arg1 < @arg2 (1, 1, ...
7147 * @arg1 <= @arg2 (1, 0, ...
7148 * @arg1 > @arg2 (0, 1, ...
7149 * @arg1 >= @arg2 (0, 0, ...
7150 *
7151 * When neither object to be compared is a node-set and the operator is
7152 * <=, <, >=, >, then the objects are compared by converted both objects
7153 * to numbers and comparing the numbers according to IEEE 754. The <
7154 * comparison will be true if and only if the first number is less than the
7155 * second number. The <= comparison will be true if and only if the first
7156 * number is less than or equal to the second number. The > comparison
7157 * will be true if and only if the first number is greater than the second
7158 * number. The >= comparison will be true if and only if the first number
7159 * is greater than or equal to the second number.
7160 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007161 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00007162 */
7163int
7164xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007165 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007166 xmlXPathObjectPtr arg1, arg2;
7167
Daniel Veillard6128c012004-11-08 17:16:15 +00007168 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00007169 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007170 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007171 if ((arg1 == NULL) || (arg2 == NULL)) {
7172 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007173 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007174 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007175 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007176 XP_ERROR0(XPATH_INVALID_OPERAND);
7177 }
7178
William M. Brack0c022ad2002-07-12 00:56:01 +00007179 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7180 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
William M. Brackd6e347e2005-04-15 01:34:41 +00007181 /*
7182 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7183 * are not freed from within this routine; they will be freed from the
7184 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7185 */
William M. Brack0c022ad2002-07-12 00:56:01 +00007186 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7187 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007188 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007189 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00007190 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007191 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7192 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007193 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007194 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7195 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00007196 }
7197 }
7198 return(ret);
7199 }
7200
7201 if (arg1->type != XPATH_NUMBER) {
7202 valuePush(ctxt, arg1);
7203 xmlXPathNumberFunction(ctxt, 1);
7204 arg1 = valuePop(ctxt);
7205 }
7206 if (arg1->type != XPATH_NUMBER) {
7207 xmlXPathFreeObject(arg1);
7208 xmlXPathFreeObject(arg2);
7209 XP_ERROR0(XPATH_INVALID_OPERAND);
7210 }
7211 if (arg2->type != XPATH_NUMBER) {
7212 valuePush(ctxt, arg2);
7213 xmlXPathNumberFunction(ctxt, 1);
7214 arg2 = valuePop(ctxt);
7215 }
7216 if (arg2->type != XPATH_NUMBER) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007217 xmlXPathReleaseObject(ctxt->context, arg1);
7218 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007219 XP_ERROR0(XPATH_INVALID_OPERAND);
7220 }
7221 /*
7222 * Add tests for infinity and nan
7223 * => feedback on 3.4 for Inf and NaN
7224 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007225 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00007226 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007227 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007228 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007229 arg1i=xmlXPathIsInf(arg1->floatval);
7230 arg2i=xmlXPathIsInf(arg2->floatval);
7231 if (inf && strict) {
7232 if ((arg1i == -1 && arg2i != -1) ||
7233 (arg2i == 1 && arg1i != 1)) {
7234 ret = 1;
7235 } else if (arg1i == 0 && arg2i == 0) {
7236 ret = (arg1->floatval < arg2->floatval);
7237 } else {
7238 ret = 0;
7239 }
7240 }
7241 else if (inf && !strict) {
7242 if (arg1i == -1 || arg2i == 1) {
7243 ret = 1;
7244 } else if (arg1i == 0 && arg2i == 0) {
7245 ret = (arg1->floatval <= arg2->floatval);
7246 } else {
7247 ret = 0;
7248 }
7249 }
7250 else if (!inf && strict) {
7251 if ((arg1i == 1 && arg2i != 1) ||
7252 (arg2i == -1 && arg1i != -1)) {
7253 ret = 1;
7254 } else if (arg1i == 0 && arg2i == 0) {
7255 ret = (arg1->floatval > arg2->floatval);
7256 } else {
7257 ret = 0;
7258 }
7259 }
7260 else if (!inf && !strict) {
7261 if (arg1i == 1 || arg2i == -1) {
7262 ret = 1;
7263 } else if (arg1i == 0 && arg2i == 0) {
7264 ret = (arg1->floatval >= arg2->floatval);
7265 } else {
7266 ret = 0;
7267 }
7268 }
Daniel Veillard21458c82002-03-27 16:12:22 +00007269 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007270 xmlXPathReleaseObject(ctxt->context, arg1);
7271 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007272 return(ret);
7273}
7274
7275/**
7276 * xmlXPathValueFlipSign:
7277 * @ctxt: the XPath Parser context
7278 *
7279 * Implement the unary - operation on an XPath object
7280 * The numeric operators convert their operands to numbers as if
7281 * by calling the number function.
7282 */
7283void
7284xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007285 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007286 CAST_TO_NUMBER;
7287 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007288 if (xmlXPathIsNaN(ctxt->value->floatval))
7289 ctxt->value->floatval=xmlXPathNAN;
7290 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7291 ctxt->value->floatval=xmlXPathNINF;
7292 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7293 ctxt->value->floatval=xmlXPathPINF;
7294 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007295 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7296 ctxt->value->floatval = xmlXPathNZERO;
7297 else
7298 ctxt->value->floatval = 0;
7299 }
7300 else
7301 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00007302}
7303
7304/**
7305 * xmlXPathAddValues:
7306 * @ctxt: the XPath Parser context
7307 *
7308 * Implement the add operation on XPath objects:
7309 * The numeric operators convert their operands to numbers as if
7310 * by calling the number function.
7311 */
7312void
7313xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7314 xmlXPathObjectPtr arg;
7315 double val;
7316
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007317 arg = valuePop(ctxt);
7318 if (arg == NULL)
7319 XP_ERROR(XPATH_INVALID_OPERAND);
7320 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007321 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007322 CAST_TO_NUMBER;
7323 CHECK_TYPE(XPATH_NUMBER);
7324 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00007325}
7326
7327/**
7328 * xmlXPathSubValues:
7329 * @ctxt: the XPath Parser context
7330 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007331 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007332 * The numeric operators convert their operands to numbers as if
7333 * by calling the number function.
7334 */
7335void
7336xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7337 xmlXPathObjectPtr arg;
7338 double val;
7339
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007340 arg = valuePop(ctxt);
7341 if (arg == NULL)
7342 XP_ERROR(XPATH_INVALID_OPERAND);
7343 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007344 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007345 CAST_TO_NUMBER;
7346 CHECK_TYPE(XPATH_NUMBER);
7347 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007348}
7349
7350/**
7351 * xmlXPathMultValues:
7352 * @ctxt: the XPath Parser context
7353 *
7354 * Implement the multiply operation on XPath objects:
7355 * The numeric operators convert their operands to numbers as if
7356 * by calling the number function.
7357 */
7358void
7359xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7360 xmlXPathObjectPtr arg;
7361 double val;
7362
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007363 arg = valuePop(ctxt);
7364 if (arg == NULL)
7365 XP_ERROR(XPATH_INVALID_OPERAND);
7366 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007367 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007368 CAST_TO_NUMBER;
7369 CHECK_TYPE(XPATH_NUMBER);
7370 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007371}
7372
7373/**
7374 * xmlXPathDivValues:
7375 * @ctxt: the XPath Parser context
7376 *
7377 * Implement the div operation on XPath objects @arg1 / @arg2:
7378 * The numeric operators convert their operands to numbers as if
7379 * by calling the number function.
7380 */
7381void
7382xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7383 xmlXPathObjectPtr arg;
7384 double val;
7385
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007386 arg = valuePop(ctxt);
7387 if (arg == NULL)
7388 XP_ERROR(XPATH_INVALID_OPERAND);
7389 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007390 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007391 CAST_TO_NUMBER;
7392 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007393 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7394 ctxt->value->floatval = xmlXPathNAN;
7395 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007396 if (ctxt->value->floatval == 0)
7397 ctxt->value->floatval = xmlXPathNAN;
7398 else if (ctxt->value->floatval > 0)
7399 ctxt->value->floatval = xmlXPathNINF;
7400 else if (ctxt->value->floatval < 0)
7401 ctxt->value->floatval = xmlXPathPINF;
7402 }
7403 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007404 if (ctxt->value->floatval == 0)
7405 ctxt->value->floatval = xmlXPathNAN;
7406 else if (ctxt->value->floatval > 0)
7407 ctxt->value->floatval = xmlXPathPINF;
7408 else if (ctxt->value->floatval < 0)
7409 ctxt->value->floatval = xmlXPathNINF;
7410 } else
7411 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007412}
7413
7414/**
7415 * xmlXPathModValues:
7416 * @ctxt: the XPath Parser context
7417 *
7418 * Implement the mod operation on XPath objects: @arg1 / @arg2
7419 * The numeric operators convert their operands to numbers as if
7420 * by calling the number function.
7421 */
7422void
7423xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7424 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00007425 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00007426
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007427 arg = valuePop(ctxt);
7428 if (arg == NULL)
7429 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007430 arg2 = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007431 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007432 CAST_TO_NUMBER;
7433 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007434 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00007435 if (arg2 == 0)
7436 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007437 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00007438 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007439 }
Owen Taylor3473f882001-02-23 17:55:21 +00007440}
7441
7442/************************************************************************
7443 * *
7444 * The traversal functions *
7445 * *
7446 ************************************************************************/
7447
Owen Taylor3473f882001-02-23 17:55:21 +00007448/*
7449 * A traversal function enumerates nodes along an axis.
7450 * Initially it must be called with NULL, and it indicates
7451 * termination on the axis by returning NULL.
7452 */
7453typedef xmlNodePtr (*xmlXPathTraversalFunction)
7454 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7455
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007456/*
7457 * xmlXPathTraversalFunctionExt:
7458 * A traversal function enumerates nodes along an axis.
7459 * Initially it must be called with NULL, and it indicates
7460 * termination on the axis by returning NULL.
7461 * The context node of the traversal is specified via @contextNode.
7462 */
7463typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7464 (xmlNodePtr cur, xmlNodePtr contextNode);
7465
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00007466/*
7467 * xmlXPathNodeSetMergeFunction:
7468 * Used for merging node sets in xmlXPathCollectAndTest().
7469 */
7470typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7471 (xmlNodeSetPtr, xmlNodeSetPtr, int);
7472
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007473
Owen Taylor3473f882001-02-23 17:55:21 +00007474/**
7475 * xmlXPathNextSelf:
7476 * @ctxt: the XPath Parser context
7477 * @cur: the current node in the traversal
7478 *
7479 * Traversal function for the "self" direction
7480 * The self axis contains just the context node itself
7481 *
7482 * Returns the next element following that axis
7483 */
7484xmlNodePtr
7485xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007486 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007487 if (cur == NULL)
7488 return(ctxt->context->node);
7489 return(NULL);
7490}
7491
7492/**
7493 * xmlXPathNextChild:
7494 * @ctxt: the XPath Parser context
7495 * @cur: the current node in the traversal
7496 *
7497 * Traversal function for the "child" direction
7498 * The child axis contains the children of the context node in document order.
7499 *
7500 * Returns the next element following that axis
7501 */
7502xmlNodePtr
7503xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007504 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007505 if (cur == NULL) {
7506 if (ctxt->context->node == NULL) return(NULL);
7507 switch (ctxt->context->node->type) {
7508 case XML_ELEMENT_NODE:
7509 case XML_TEXT_NODE:
7510 case XML_CDATA_SECTION_NODE:
7511 case XML_ENTITY_REF_NODE:
7512 case XML_ENTITY_NODE:
7513 case XML_PI_NODE:
7514 case XML_COMMENT_NODE:
7515 case XML_NOTATION_NODE:
7516 case XML_DTD_NODE:
7517 return(ctxt->context->node->children);
7518 case XML_DOCUMENT_NODE:
7519 case XML_DOCUMENT_TYPE_NODE:
7520 case XML_DOCUMENT_FRAG_NODE:
7521 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007522#ifdef LIBXML_DOCB_ENABLED
7523 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007524#endif
7525 return(((xmlDocPtr) ctxt->context->node)->children);
7526 case XML_ELEMENT_DECL:
7527 case XML_ATTRIBUTE_DECL:
7528 case XML_ENTITY_DECL:
7529 case XML_ATTRIBUTE_NODE:
7530 case XML_NAMESPACE_DECL:
7531 case XML_XINCLUDE_START:
7532 case XML_XINCLUDE_END:
7533 return(NULL);
7534 }
7535 return(NULL);
7536 }
7537 if ((cur->type == XML_DOCUMENT_NODE) ||
7538 (cur->type == XML_HTML_DOCUMENT_NODE))
7539 return(NULL);
7540 return(cur->next);
7541}
7542
7543/**
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007544 * xmlXPathNextChildElement:
7545 * @ctxt: the XPath Parser context
7546 * @cur: the current node in the traversal
7547 *
7548 * Traversal function for the "child" direction and nodes of type element.
7549 * The child axis contains the children of the context node in document order.
7550 *
7551 * Returns the next element following that axis
7552 */
7553static xmlNodePtr
7554xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7555 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7556 if (cur == NULL) {
7557 cur = ctxt->context->node;
7558 if (cur == NULL) return(NULL);
7559 /*
7560 * Get the first element child.
7561 */
7562 switch (cur->type) {
7563 case XML_ELEMENT_NODE:
7564 case XML_DOCUMENT_FRAG_NODE:
7565 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7566 case XML_ENTITY_NODE:
7567 cur = cur->children;
7568 if (cur != NULL) {
7569 if (cur->type == XML_ELEMENT_NODE)
7570 return(cur);
7571 do {
7572 cur = cur->next;
7573 } while ((cur != NULL) &&
7574 (cur->type != XML_ELEMENT_NODE));
7575 return(cur);
7576 }
7577 return(NULL);
7578 case XML_DOCUMENT_NODE:
7579 case XML_HTML_DOCUMENT_NODE:
7580#ifdef LIBXML_DOCB_ENABLED
7581 case XML_DOCB_DOCUMENT_NODE:
7582#endif
7583 return(xmlDocGetRootElement((xmlDocPtr) cur));
7584 default:
7585 return(NULL);
7586 }
7587 return(NULL);
7588 }
7589 /*
7590 * Get the next sibling element node.
7591 */
7592 switch (cur->type) {
7593 case XML_ELEMENT_NODE:
7594 case XML_TEXT_NODE:
7595 case XML_ENTITY_REF_NODE:
7596 case XML_ENTITY_NODE:
7597 case XML_CDATA_SECTION_NODE:
7598 case XML_PI_NODE:
7599 case XML_COMMENT_NODE:
7600 case XML_XINCLUDE_END:
7601 break;
7602 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7603 default:
7604 return(NULL);
7605 }
7606 if (cur->next != NULL) {
7607 if (cur->next->type == XML_ELEMENT_NODE)
7608 return(cur->next);
7609 cur = cur->next;
7610 do {
7611 cur = cur->next;
7612 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7613 return(cur);
7614 }
7615 return(NULL);
7616}
7617
7618/**
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007619 * xmlXPathNextDescendantOrSelfElemParent:
7620 * @ctxt: the XPath Parser context
7621 * @cur: the current node in the traversal
7622 *
7623 * Traversal function for the "descendant-or-self" axis.
7624 * Additionally it returns only nodes which can be parents of
7625 * element nodes.
7626 *
7627 *
7628 * Returns the next element following that axis
7629 */
7630static xmlNodePtr
7631xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7632 xmlNodePtr contextNode)
7633{
7634 if (cur == NULL) {
7635 if (contextNode == NULL)
7636 return(NULL);
7637 switch (contextNode->type) {
7638 case XML_ELEMENT_NODE:
7639 case XML_XINCLUDE_START:
7640 case XML_DOCUMENT_FRAG_NODE:
7641 case XML_DOCUMENT_NODE:
7642#ifdef LIBXML_DOCB_ENABLED
7643 case XML_DOCB_DOCUMENT_NODE:
7644#endif
7645 case XML_HTML_DOCUMENT_NODE:
7646 return(contextNode);
7647 default:
7648 return(NULL);
7649 }
7650 return(NULL);
7651 } else {
7652 xmlNodePtr start = cur;
7653
7654 while (cur != NULL) {
7655 switch (cur->type) {
7656 case XML_ELEMENT_NODE:
7657 /* TODO: OK to have XInclude here? */
7658 case XML_XINCLUDE_START:
7659 case XML_DOCUMENT_FRAG_NODE:
7660 if (cur != start)
7661 return(cur);
7662 if (cur->children != NULL) {
7663 cur = cur->children;
7664 continue;
7665 }
7666 break;
7667#ifdef LIBXML_DOCB_ENABLED
7668 /* Not sure if we need those here. */
7669 case XML_DOCUMENT_NODE:
7670 case XML_DOCB_DOCUMENT_NODE:
7671#endif
7672 case XML_HTML_DOCUMENT_NODE:
7673 if (cur != start)
7674 return(cur);
7675 return(xmlDocGetRootElement((xmlDocPtr) cur));
7676 default:
7677 break;
7678 }
7679
7680next_sibling:
7681 if ((cur == NULL) || (cur == contextNode))
7682 return(NULL);
7683 if (cur->next != NULL) {
7684 cur = cur->next;
7685 } else {
7686 cur = cur->parent;
7687 goto next_sibling;
7688 }
7689 }
7690 }
7691 return(NULL);
7692}
7693
7694/**
Owen Taylor3473f882001-02-23 17:55:21 +00007695 * xmlXPathNextDescendant:
7696 * @ctxt: the XPath Parser context
7697 * @cur: the current node in the traversal
7698 *
7699 * Traversal function for the "descendant" direction
7700 * the descendant axis contains the descendants of the context node in document
7701 * order; a descendant is a child or a child of a child and so on.
7702 *
7703 * Returns the next element following that axis
7704 */
7705xmlNodePtr
7706xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007707 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007708 if (cur == NULL) {
7709 if (ctxt->context->node == NULL)
7710 return(NULL);
7711 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7712 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7713 return(NULL);
7714
7715 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7716 return(ctxt->context->doc->children);
7717 return(ctxt->context->node->children);
7718 }
7719
Daniel Veillard567e1b42001-08-01 15:53:47 +00007720 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007721 /*
7722 * Do not descend on entities declarations
7723 */
7724 if (cur->children->type != XML_ENTITY_DECL) {
7725 cur = cur->children;
7726 /*
7727 * Skip DTDs
7728 */
7729 if (cur->type != XML_DTD_NODE)
7730 return(cur);
7731 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00007732 }
7733
7734 if (cur == ctxt->context->node) return(NULL);
7735
Daniel Veillard68e9e742002-11-16 15:35:11 +00007736 while (cur->next != NULL) {
7737 cur = cur->next;
7738 if ((cur->type != XML_ENTITY_DECL) &&
7739 (cur->type != XML_DTD_NODE))
7740 return(cur);
7741 }
Owen Taylor3473f882001-02-23 17:55:21 +00007742
7743 do {
7744 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00007745 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00007746 if (cur == ctxt->context->node) return(NULL);
7747 if (cur->next != NULL) {
7748 cur = cur->next;
7749 return(cur);
7750 }
7751 } while (cur != NULL);
7752 return(cur);
7753}
7754
7755/**
7756 * xmlXPathNextDescendantOrSelf:
7757 * @ctxt: the XPath Parser context
7758 * @cur: the current node in the traversal
7759 *
7760 * Traversal function for the "descendant-or-self" direction
7761 * the descendant-or-self axis contains the context node and the descendants
7762 * of the context node in document order; thus the context node is the first
7763 * node on the axis, and the first child of the context node is the second node
7764 * on the axis
7765 *
7766 * Returns the next element following that axis
7767 */
7768xmlNodePtr
7769xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007770 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007771 if (cur == NULL) {
7772 if (ctxt->context->node == NULL)
7773 return(NULL);
7774 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7775 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7776 return(NULL);
7777 return(ctxt->context->node);
7778 }
7779
7780 return(xmlXPathNextDescendant(ctxt, cur));
7781}
7782
7783/**
7784 * xmlXPathNextParent:
7785 * @ctxt: the XPath Parser context
7786 * @cur: the current node in the traversal
7787 *
7788 * Traversal function for the "parent" direction
7789 * The parent axis contains the parent of the context node, if there is one.
7790 *
7791 * Returns the next element following that axis
7792 */
7793xmlNodePtr
7794xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007795 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007796 /*
7797 * the parent of an attribute or namespace node is the element
7798 * to which the attribute or namespace node is attached
7799 * Namespace handling !!!
7800 */
7801 if (cur == NULL) {
7802 if (ctxt->context->node == NULL) return(NULL);
7803 switch (ctxt->context->node->type) {
7804 case XML_ELEMENT_NODE:
7805 case XML_TEXT_NODE:
7806 case XML_CDATA_SECTION_NODE:
7807 case XML_ENTITY_REF_NODE:
7808 case XML_ENTITY_NODE:
7809 case XML_PI_NODE:
7810 case XML_COMMENT_NODE:
7811 case XML_NOTATION_NODE:
7812 case XML_DTD_NODE:
7813 case XML_ELEMENT_DECL:
7814 case XML_ATTRIBUTE_DECL:
7815 case XML_XINCLUDE_START:
7816 case XML_XINCLUDE_END:
7817 case XML_ENTITY_DECL:
7818 if (ctxt->context->node->parent == NULL)
7819 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007820 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007821 ((ctxt->context->node->parent->name[0] == ' ') ||
7822 (xmlStrEqual(ctxt->context->node->parent->name,
7823 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007824 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007825 return(ctxt->context->node->parent);
7826 case XML_ATTRIBUTE_NODE: {
7827 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7828
7829 return(att->parent);
7830 }
7831 case XML_DOCUMENT_NODE:
7832 case XML_DOCUMENT_TYPE_NODE:
7833 case XML_DOCUMENT_FRAG_NODE:
7834 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007835#ifdef LIBXML_DOCB_ENABLED
7836 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007837#endif
7838 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007839 case XML_NAMESPACE_DECL: {
7840 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7841
7842 if ((ns->next != NULL) &&
7843 (ns->next->type != XML_NAMESPACE_DECL))
7844 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00007845 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007846 }
Owen Taylor3473f882001-02-23 17:55:21 +00007847 }
7848 }
7849 return(NULL);
7850}
7851
7852/**
7853 * xmlXPathNextAncestor:
7854 * @ctxt: the XPath Parser context
7855 * @cur: the current node in the traversal
7856 *
7857 * Traversal function for the "ancestor" direction
7858 * the ancestor axis contains the ancestors of the context node; the ancestors
7859 * of the context node consist of the parent of context node and the parent's
7860 * parent and so on; the nodes are ordered in reverse document order; thus the
7861 * parent is the first node on the axis, and the parent's parent is the second
7862 * node on the axis
7863 *
7864 * Returns the next element following that axis
7865 */
7866xmlNodePtr
7867xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007868 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007869 /*
7870 * the parent of an attribute or namespace node is the element
7871 * to which the attribute or namespace node is attached
7872 * !!!!!!!!!!!!!
7873 */
7874 if (cur == NULL) {
7875 if (ctxt->context->node == NULL) return(NULL);
7876 switch (ctxt->context->node->type) {
7877 case XML_ELEMENT_NODE:
7878 case XML_TEXT_NODE:
7879 case XML_CDATA_SECTION_NODE:
7880 case XML_ENTITY_REF_NODE:
7881 case XML_ENTITY_NODE:
7882 case XML_PI_NODE:
7883 case XML_COMMENT_NODE:
7884 case XML_DTD_NODE:
7885 case XML_ELEMENT_DECL:
7886 case XML_ATTRIBUTE_DECL:
7887 case XML_ENTITY_DECL:
7888 case XML_NOTATION_NODE:
7889 case XML_XINCLUDE_START:
7890 case XML_XINCLUDE_END:
7891 if (ctxt->context->node->parent == NULL)
7892 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007893 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007894 ((ctxt->context->node->parent->name[0] == ' ') ||
7895 (xmlStrEqual(ctxt->context->node->parent->name,
7896 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007897 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007898 return(ctxt->context->node->parent);
7899 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007900 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00007901
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007902 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00007903 }
7904 case XML_DOCUMENT_NODE:
7905 case XML_DOCUMENT_TYPE_NODE:
7906 case XML_DOCUMENT_FRAG_NODE:
7907 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007908#ifdef LIBXML_DOCB_ENABLED
7909 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007910#endif
7911 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007912 case XML_NAMESPACE_DECL: {
7913 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7914
7915 if ((ns->next != NULL) &&
7916 (ns->next->type != XML_NAMESPACE_DECL))
7917 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00007918 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00007919 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007920 }
Owen Taylor3473f882001-02-23 17:55:21 +00007921 }
7922 return(NULL);
7923 }
7924 if (cur == ctxt->context->doc->children)
7925 return((xmlNodePtr) ctxt->context->doc);
7926 if (cur == (xmlNodePtr) ctxt->context->doc)
7927 return(NULL);
7928 switch (cur->type) {
7929 case XML_ELEMENT_NODE:
7930 case XML_TEXT_NODE:
7931 case XML_CDATA_SECTION_NODE:
7932 case XML_ENTITY_REF_NODE:
7933 case XML_ENTITY_NODE:
7934 case XML_PI_NODE:
7935 case XML_COMMENT_NODE:
7936 case XML_NOTATION_NODE:
7937 case XML_DTD_NODE:
7938 case XML_ELEMENT_DECL:
7939 case XML_ATTRIBUTE_DECL:
7940 case XML_ENTITY_DECL:
7941 case XML_XINCLUDE_START:
7942 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007943 if (cur->parent == NULL)
7944 return(NULL);
7945 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007946 ((cur->parent->name[0] == ' ') ||
7947 (xmlStrEqual(cur->parent->name,
7948 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007949 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007950 return(cur->parent);
7951 case XML_ATTRIBUTE_NODE: {
7952 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7953
7954 return(att->parent);
7955 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00007956 case XML_NAMESPACE_DECL: {
7957 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7958
7959 if ((ns->next != NULL) &&
7960 (ns->next->type != XML_NAMESPACE_DECL))
7961 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00007962 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00007963 return(NULL);
7964 }
Owen Taylor3473f882001-02-23 17:55:21 +00007965 case XML_DOCUMENT_NODE:
7966 case XML_DOCUMENT_TYPE_NODE:
7967 case XML_DOCUMENT_FRAG_NODE:
7968 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007969#ifdef LIBXML_DOCB_ENABLED
7970 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007971#endif
7972 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007973 }
7974 return(NULL);
7975}
7976
7977/**
7978 * xmlXPathNextAncestorOrSelf:
7979 * @ctxt: the XPath Parser context
7980 * @cur: the current node in the traversal
7981 *
7982 * Traversal function for the "ancestor-or-self" direction
7983 * he ancestor-or-self axis contains the context node and ancestors of
7984 * the context node in reverse document order; thus the context node is
7985 * the first node on the axis, and the context node's parent the second;
7986 * parent here is defined the same as with the parent axis.
7987 *
7988 * Returns the next element following that axis
7989 */
7990xmlNodePtr
7991xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007992 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007993 if (cur == NULL)
7994 return(ctxt->context->node);
7995 return(xmlXPathNextAncestor(ctxt, cur));
7996}
7997
7998/**
7999 * xmlXPathNextFollowingSibling:
8000 * @ctxt: the XPath Parser context
8001 * @cur: the current node in the traversal
8002 *
8003 * Traversal function for the "following-sibling" direction
8004 * The following-sibling axis contains the following siblings of the context
8005 * node in document order.
8006 *
8007 * Returns the next element following that axis
8008 */
8009xmlNodePtr
8010xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008011 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008012 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8013 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8014 return(NULL);
8015 if (cur == (xmlNodePtr) ctxt->context->doc)
8016 return(NULL);
8017 if (cur == NULL)
8018 return(ctxt->context->node->next);
8019 return(cur->next);
8020}
8021
8022/**
8023 * xmlXPathNextPrecedingSibling:
8024 * @ctxt: the XPath Parser context
8025 * @cur: the current node in the traversal
8026 *
8027 * Traversal function for the "preceding-sibling" direction
8028 * The preceding-sibling axis contains the preceding siblings of the context
8029 * node in reverse document order; the first preceding sibling is first on the
8030 * axis; the sibling preceding that node is the second on the axis and so on.
8031 *
8032 * Returns the next element following that axis
8033 */
8034xmlNodePtr
8035xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008036 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008037 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8038 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8039 return(NULL);
8040 if (cur == (xmlNodePtr) ctxt->context->doc)
8041 return(NULL);
8042 if (cur == NULL)
8043 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008044 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8045 cur = cur->prev;
8046 if (cur == NULL)
8047 return(ctxt->context->node->prev);
8048 }
Owen Taylor3473f882001-02-23 17:55:21 +00008049 return(cur->prev);
8050}
8051
8052/**
8053 * xmlXPathNextFollowing:
8054 * @ctxt: the XPath Parser context
8055 * @cur: the current node in the traversal
8056 *
8057 * Traversal function for the "following" direction
8058 * The following axis contains all nodes in the same document as the context
8059 * node that are after the context node in document order, excluding any
8060 * descendants and excluding attribute nodes and namespace nodes; the nodes
8061 * are ordered in document order
8062 *
8063 * Returns the next element following that axis
8064 */
8065xmlNodePtr
8066xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008067 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008068 if (cur != NULL && cur->children != NULL)
8069 return cur->children ;
8070 if (cur == NULL) cur = ctxt->context->node;
8071 if (cur == NULL) return(NULL) ; /* ERROR */
8072 if (cur->next != NULL) return(cur->next) ;
8073 do {
8074 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00008075 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00008076 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8077 if (cur->next != NULL) return(cur->next);
8078 } while (cur != NULL);
8079 return(cur);
8080}
8081
8082/*
8083 * xmlXPathIsAncestor:
8084 * @ancestor: the ancestor node
8085 * @node: the current node
8086 *
8087 * Check that @ancestor is a @node's ancestor
8088 *
8089 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8090 */
8091static int
8092xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8093 if ((ancestor == NULL) || (node == NULL)) return(0);
8094 /* nodes need to be in the same document */
8095 if (ancestor->doc != node->doc) return(0);
8096 /* avoid searching if ancestor or node is the root node */
8097 if (ancestor == (xmlNodePtr) node->doc) return(1);
8098 if (node == (xmlNodePtr) ancestor->doc) return(0);
8099 while (node->parent != NULL) {
8100 if (node->parent == ancestor)
8101 return(1);
8102 node = node->parent;
8103 }
8104 return(0);
8105}
8106
8107/**
8108 * xmlXPathNextPreceding:
8109 * @ctxt: the XPath Parser context
8110 * @cur: the current node in the traversal
8111 *
8112 * Traversal function for the "preceding" direction
8113 * the preceding axis contains all nodes in the same document as the context
8114 * node that are before the context node in document order, excluding any
8115 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8116 * ordered in reverse document order
8117 *
8118 * Returns the next element following that axis
8119 */
8120xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00008121xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8122{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008123 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008124 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008125 cur = ctxt->context->node;
8126 if (cur == NULL)
8127 return (NULL);
8128 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8129 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00008130 do {
8131 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008132 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8133 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008134 }
8135
8136 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008137 if (cur == NULL)
8138 return (NULL);
8139 if (cur == ctxt->context->doc->children)
8140 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008141 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00008142 return (cur);
8143}
8144
8145/**
8146 * xmlXPathNextPrecedingInternal:
8147 * @ctxt: the XPath Parser context
8148 * @cur: the current node in the traversal
8149 *
8150 * Traversal function for the "preceding" direction
8151 * the preceding axis contains all nodes in the same document as the context
8152 * node that are before the context node in document order, excluding any
8153 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8154 * ordered in reverse document order
8155 * This is a faster implementation but internal only since it requires a
8156 * state kept in the parser context: ctxt->ancestor.
8157 *
8158 * Returns the next element following that axis
8159 */
8160static xmlNodePtr
8161xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8162 xmlNodePtr cur)
8163{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008164 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008165 if (cur == NULL) {
8166 cur = ctxt->context->node;
8167 if (cur == NULL)
8168 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00008169 if (cur->type == XML_NAMESPACE_DECL)
8170 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008171 ctxt->ancestor = cur->parent;
8172 }
8173 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8174 cur = cur->prev;
8175 while (cur->prev == NULL) {
8176 cur = cur->parent;
8177 if (cur == NULL)
8178 return (NULL);
8179 if (cur == ctxt->context->doc->children)
8180 return (NULL);
8181 if (cur != ctxt->ancestor)
8182 return (cur);
8183 ctxt->ancestor = cur->parent;
8184 }
8185 cur = cur->prev;
8186 while (cur->last != NULL)
8187 cur = cur->last;
8188 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008189}
8190
8191/**
8192 * xmlXPathNextNamespace:
8193 * @ctxt: the XPath Parser context
8194 * @cur: the current attribute in the traversal
8195 *
8196 * Traversal function for the "namespace" direction
8197 * the namespace axis contains the namespace nodes of the context node;
8198 * the order of nodes on this axis is implementation-defined; the axis will
8199 * be empty unless the context node is an element
8200 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008201 * We keep the XML namespace node at the end of the list.
8202 *
Owen Taylor3473f882001-02-23 17:55:21 +00008203 * Returns the next element following that axis
8204 */
8205xmlNodePtr
8206xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008207 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008208 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00008209 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008210 if (ctxt->context->tmpNsList != NULL)
8211 xmlFree(ctxt->context->tmpNsList);
8212 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00008213 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008214 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00008215 if (ctxt->context->tmpNsList != NULL) {
8216 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8217 ctxt->context->tmpNsNr++;
8218 }
8219 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008220 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008221 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00008222 if (ctxt->context->tmpNsNr > 0) {
8223 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8224 } else {
8225 if (ctxt->context->tmpNsList != NULL)
8226 xmlFree(ctxt->context->tmpNsList);
8227 ctxt->context->tmpNsList = NULL;
8228 return(NULL);
8229 }
Owen Taylor3473f882001-02-23 17:55:21 +00008230}
8231
8232/**
8233 * xmlXPathNextAttribute:
8234 * @ctxt: the XPath Parser context
8235 * @cur: the current attribute in the traversal
8236 *
8237 * Traversal function for the "attribute" direction
8238 * TODO: support DTD inherited default attributes
8239 *
8240 * Returns the next element following that axis
8241 */
8242xmlNodePtr
8243xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008244 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00008245 if (ctxt->context->node == NULL)
8246 return(NULL);
8247 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8248 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008249 if (cur == NULL) {
8250 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8251 return(NULL);
8252 return((xmlNodePtr)ctxt->context->node->properties);
8253 }
8254 return((xmlNodePtr)cur->next);
8255}
8256
8257/************************************************************************
8258 * *
8259 * NodeTest Functions *
8260 * *
8261 ************************************************************************/
8262
Owen Taylor3473f882001-02-23 17:55:21 +00008263#define IS_FUNCTION 200
8264
Owen Taylor3473f882001-02-23 17:55:21 +00008265
8266/************************************************************************
8267 * *
8268 * Implicit tree core function library *
8269 * *
8270 ************************************************************************/
8271
8272/**
8273 * xmlXPathRoot:
8274 * @ctxt: the XPath Parser context
8275 *
8276 * Initialize the context to the root of the document
8277 */
8278void
8279xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008280 if ((ctxt == NULL) || (ctxt->context == NULL))
8281 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008282 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008283 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8284 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008285}
8286
8287/************************************************************************
8288 * *
8289 * The explicit core function library *
8290 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8291 * *
8292 ************************************************************************/
8293
8294
8295/**
8296 * xmlXPathLastFunction:
8297 * @ctxt: the XPath Parser context
8298 * @nargs: the number of arguments
8299 *
8300 * Implement the last() XPath function
8301 * number last()
8302 * The last function returns the number of nodes in the context node list.
8303 */
8304void
8305xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8306 CHECK_ARITY(0);
8307 if (ctxt->context->contextSize >= 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008308 valuePush(ctxt,
8309 xmlXPathCacheNewFloat(ctxt->context,
8310 (double) ctxt->context->contextSize));
Owen Taylor3473f882001-02-23 17:55:21 +00008311#ifdef DEBUG_EXPR
8312 xmlGenericError(xmlGenericErrorContext,
8313 "last() : %d\n", ctxt->context->contextSize);
8314#endif
8315 } else {
8316 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8317 }
8318}
8319
8320/**
8321 * xmlXPathPositionFunction:
8322 * @ctxt: the XPath Parser context
8323 * @nargs: the number of arguments
8324 *
8325 * Implement the position() XPath function
8326 * number position()
8327 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008328 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00008329 * will be equal to last().
8330 */
8331void
8332xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8333 CHECK_ARITY(0);
8334 if (ctxt->context->proximityPosition >= 0) {
8335 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008336 xmlXPathCacheNewFloat(ctxt->context,
8337 (double) ctxt->context->proximityPosition));
Owen Taylor3473f882001-02-23 17:55:21 +00008338#ifdef DEBUG_EXPR
8339 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8340 ctxt->context->proximityPosition);
8341#endif
8342 } else {
8343 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8344 }
8345}
8346
8347/**
8348 * xmlXPathCountFunction:
8349 * @ctxt: the XPath Parser context
8350 * @nargs: the number of arguments
8351 *
8352 * Implement the count() XPath function
8353 * number count(node-set)
8354 */
8355void
8356xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8357 xmlXPathObjectPtr cur;
8358
8359 CHECK_ARITY(1);
8360 if ((ctxt->value == NULL) ||
8361 ((ctxt->value->type != XPATH_NODESET) &&
8362 (ctxt->value->type != XPATH_XSLT_TREE)))
8363 XP_ERROR(XPATH_INVALID_TYPE);
8364 cur = valuePop(ctxt);
8365
Daniel Veillard911f49a2001-04-07 15:39:35 +00008366 if ((cur == NULL) || (cur->nodesetval == NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008367 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00008368 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008369 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8370 (double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00008371 } else {
8372 if ((cur->nodesetval->nodeNr != 1) ||
8373 (cur->nodesetval->nodeTab == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008374 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00008375 } else {
8376 xmlNodePtr tmp;
8377 int i = 0;
8378
8379 tmp = cur->nodesetval->nodeTab[0];
8380 if (tmp != NULL) {
8381 tmp = tmp->children;
8382 while (tmp != NULL) {
8383 tmp = tmp->next;
8384 i++;
8385 }
8386 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008387 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
Daniel Veillardfe703322001-08-14 12:18:09 +00008388 }
8389 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008390 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008391}
8392
8393/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008394 * xmlXPathGetElementsByIds:
8395 * @doc: the document
8396 * @ids: a whitespace separated list of IDs
8397 *
8398 * Selects elements by their unique ID.
8399 *
8400 * Returns a node-set of selected elements.
8401 */
8402static xmlNodeSetPtr
8403xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8404 xmlNodeSetPtr ret;
8405 const xmlChar *cur = ids;
8406 xmlChar *ID;
8407 xmlAttrPtr attr;
8408 xmlNodePtr elem = NULL;
8409
Daniel Veillard7a985a12003-07-06 17:57:42 +00008410 if (ids == NULL) return(NULL);
8411
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008412 ret = xmlXPathNodeSetCreate(NULL);
8413
William M. Brack76e95df2003-10-18 16:20:14 +00008414 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008415 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008416 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00008417 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008418
8419 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00008420 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00008421 /*
8422 * We used to check the fact that the value passed
8423 * was an NCName, but this generated much troubles for
8424 * me and Aleksey Sanin, people blatantly violated that
8425 * constaint, like Visa3D spec.
8426 * if (xmlValidateNCName(ID, 1) == 0)
8427 */
8428 attr = xmlGetID(doc, ID);
8429 if (attr != NULL) {
8430 if (attr->type == XML_ATTRIBUTE_NODE)
8431 elem = attr->parent;
8432 else if (attr->type == XML_ELEMENT_NODE)
8433 elem = (xmlNodePtr) attr;
8434 else
8435 elem = NULL;
8436 if (elem != NULL)
8437 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00008438 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008439 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00008440 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008441
William M. Brack76e95df2003-10-18 16:20:14 +00008442 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008443 ids = cur;
8444 }
8445 return(ret);
8446}
8447
8448/**
Owen Taylor3473f882001-02-23 17:55:21 +00008449 * xmlXPathIdFunction:
8450 * @ctxt: the XPath Parser context
8451 * @nargs: the number of arguments
8452 *
8453 * Implement the id() XPath function
8454 * node-set id(object)
8455 * The id function selects elements by their unique ID
8456 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8457 * then the result is the union of the result of applying id to the
8458 * string value of each of the nodes in the argument node-set. When the
8459 * argument to id is of any other type, the argument is converted to a
8460 * string as if by a call to the string function; the string is split
8461 * into a whitespace-separated list of tokens (whitespace is any sequence
8462 * of characters matching the production S); the result is a node-set
8463 * containing the elements in the same document as the context node that
8464 * have a unique ID equal to any of the tokens in the list.
8465 */
8466void
8467xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008468 xmlChar *tokens;
8469 xmlNodeSetPtr ret;
8470 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00008471
8472 CHECK_ARITY(1);
8473 obj = valuePop(ctxt);
8474 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00008475 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008476 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00008477 int i;
8478
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008479 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008480
Daniel Veillard911f49a2001-04-07 15:39:35 +00008481 if (obj->nodesetval != NULL) {
8482 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008483 tokens =
8484 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8485 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8486 ret = xmlXPathNodeSetMerge(ret, ns);
8487 xmlXPathFreeNodeSet(ns);
8488 if (tokens != NULL)
8489 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00008490 }
Owen Taylor3473f882001-02-23 17:55:21 +00008491 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008492 xmlXPathReleaseObject(ctxt->context, obj);
8493 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00008494 return;
8495 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008496 obj = xmlXPathCacheConvertString(ctxt->context, obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008497 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008498 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8499 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00008500 return;
8501}
8502
8503/**
8504 * xmlXPathLocalNameFunction:
8505 * @ctxt: the XPath Parser context
8506 * @nargs: the number of arguments
8507 *
8508 * Implement the local-name() XPath function
8509 * string local-name(node-set?)
8510 * The local-name function returns a string containing the local part
8511 * of the name of the node in the argument node-set that is first in
8512 * document order. If the node-set is empty or the first node has no
8513 * name, an empty string is returned. If the argument is omitted it
8514 * defaults to the context node.
8515 */
8516void
8517xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8518 xmlXPathObjectPtr cur;
8519
Daniel Veillarda82b1822004-11-08 16:24:57 +00008520 if (ctxt == NULL) return;
8521
Owen Taylor3473f882001-02-23 17:55:21 +00008522 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008523 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8524 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008525 nargs = 1;
8526 }
8527
8528 CHECK_ARITY(1);
8529 if ((ctxt->value == NULL) ||
8530 ((ctxt->value->type != XPATH_NODESET) &&
8531 (ctxt->value->type != XPATH_XSLT_TREE)))
8532 XP_ERROR(XPATH_INVALID_TYPE);
8533 cur = valuePop(ctxt);
8534
Daniel Veillard911f49a2001-04-07 15:39:35 +00008535 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008536 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008537 } else {
8538 int i = 0; /* Should be first in document order !!!!! */
8539 switch (cur->nodesetval->nodeTab[i]->type) {
8540 case XML_ELEMENT_NODE:
8541 case XML_ATTRIBUTE_NODE:
8542 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008543 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008544 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008545 else
8546 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008547 xmlXPathCacheNewString(ctxt->context,
8548 cur->nodesetval->nodeTab[i]->name));
Owen Taylor3473f882001-02-23 17:55:21 +00008549 break;
8550 case XML_NAMESPACE_DECL:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008551 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008552 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8553 break;
8554 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008555 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008556 }
8557 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008558 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008559}
8560
8561/**
8562 * xmlXPathNamespaceURIFunction:
8563 * @ctxt: the XPath Parser context
8564 * @nargs: the number of arguments
8565 *
8566 * Implement the namespace-uri() XPath function
8567 * string namespace-uri(node-set?)
8568 * The namespace-uri function returns a string containing the
8569 * namespace URI of the expanded name of the node in the argument
8570 * node-set that is first in document order. If the node-set is empty,
8571 * the first node has no name, or the expanded name has no namespace
8572 * URI, an empty string is returned. If the argument is omitted it
8573 * defaults to the context node.
8574 */
8575void
8576xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8577 xmlXPathObjectPtr cur;
8578
Daniel Veillarda82b1822004-11-08 16:24:57 +00008579 if (ctxt == NULL) return;
8580
Owen Taylor3473f882001-02-23 17:55:21 +00008581 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008582 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8583 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008584 nargs = 1;
8585 }
8586 CHECK_ARITY(1);
8587 if ((ctxt->value == NULL) ||
8588 ((ctxt->value->type != XPATH_NODESET) &&
8589 (ctxt->value->type != XPATH_XSLT_TREE)))
8590 XP_ERROR(XPATH_INVALID_TYPE);
8591 cur = valuePop(ctxt);
8592
Daniel Veillard911f49a2001-04-07 15:39:35 +00008593 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008594 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008595 } else {
8596 int i = 0; /* Should be first in document order !!!!! */
8597 switch (cur->nodesetval->nodeTab[i]->type) {
8598 case XML_ELEMENT_NODE:
8599 case XML_ATTRIBUTE_NODE:
8600 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008601 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008602 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008603 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008604 cur->nodesetval->nodeTab[i]->ns->href));
8605 break;
8606 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008607 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008608 }
8609 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008610 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008611}
8612
8613/**
8614 * xmlXPathNameFunction:
8615 * @ctxt: the XPath Parser context
8616 * @nargs: the number of arguments
8617 *
8618 * Implement the name() XPath function
8619 * string name(node-set?)
8620 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008621 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00008622 * order. The QName must represent the name with respect to the namespace
8623 * declarations in effect on the node whose name is being represented.
8624 * Typically, this will be the form in which the name occurred in the XML
8625 * source. This need not be the case if there are namespace declarations
8626 * in effect on the node that associate multiple prefixes with the same
8627 * namespace. However, an implementation may include information about
8628 * the original prefix in its representation of nodes; in this case, an
8629 * implementation can ensure that the returned string is always the same
8630 * as the QName used in the XML source. If the argument it omitted it
8631 * defaults to the context node.
8632 * Libxml keep the original prefix so the "real qualified name" used is
8633 * returned.
8634 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008635static void
Daniel Veillard04383752001-07-08 14:27:15 +00008636xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8637{
Owen Taylor3473f882001-02-23 17:55:21 +00008638 xmlXPathObjectPtr cur;
8639
8640 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008641 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8642 ctxt->context->node));
Daniel Veillard04383752001-07-08 14:27:15 +00008643 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008644 }
8645
8646 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00008647 if ((ctxt->value == NULL) ||
8648 ((ctxt->value->type != XPATH_NODESET) &&
8649 (ctxt->value->type != XPATH_XSLT_TREE)))
8650 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00008651 cur = valuePop(ctxt);
8652
Daniel Veillard911f49a2001-04-07 15:39:35 +00008653 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008654 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008655 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00008656 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00008657
Daniel Veillard04383752001-07-08 14:27:15 +00008658 switch (cur->nodesetval->nodeTab[i]->type) {
8659 case XML_ELEMENT_NODE:
8660 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008661 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008662 valuePush(ctxt,
8663 xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008664 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8665 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008666 valuePush(ctxt,
8667 xmlXPathCacheNewString(ctxt->context,
8668 cur->nodesetval->nodeTab[i]->name));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008669 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00008670 xmlChar *fullname;
8671
8672 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8673 cur->nodesetval->nodeTab[i]->ns->prefix,
8674 NULL, 0);
8675 if (fullname == cur->nodesetval->nodeTab[i]->name)
8676 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8677 if (fullname == NULL) {
8678 XP_ERROR(XPATH_MEMORY_ERROR);
8679 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008680 valuePush(ctxt, xmlXPathCacheWrapString(
8681 ctxt->context, fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00008682 }
8683 break;
8684 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008685 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8686 cur->nodesetval->nodeTab[i]));
Daniel Veillard04383752001-07-08 14:27:15 +00008687 xmlXPathLocalNameFunction(ctxt, 1);
8688 }
Owen Taylor3473f882001-02-23 17:55:21 +00008689 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008690 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008691}
8692
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008693
8694/**
Owen Taylor3473f882001-02-23 17:55:21 +00008695 * xmlXPathStringFunction:
8696 * @ctxt: the XPath Parser context
8697 * @nargs: the number of arguments
8698 *
8699 * Implement the string() XPath function
8700 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00008701 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00008702 * - A node-set is converted to a string by returning the value of
8703 * the node in the node-set that is first in document order.
8704 * If the node-set is empty, an empty string is returned.
8705 * - A number is converted to a string as follows
8706 * + NaN is converted to the string NaN
8707 * + positive zero is converted to the string 0
8708 * + negative zero is converted to the string 0
8709 * + positive infinity is converted to the string Infinity
8710 * + negative infinity is converted to the string -Infinity
8711 * + if the number is an integer, the number is represented in
8712 * decimal form as a Number with no decimal point and no leading
8713 * zeros, preceded by a minus sign (-) if the number is negative
8714 * + otherwise, the number is represented in decimal form as a
8715 * Number including a decimal point with at least one digit
8716 * before the decimal point and at least one digit after the
8717 * decimal point, preceded by a minus sign (-) if the number
8718 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008719 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00008720 * before the decimal point; beyond the one required digit
8721 * after the decimal point there must be as many, but only as
8722 * many, more digits as are needed to uniquely distinguish the
8723 * number from all other IEEE 754 numeric values.
8724 * - The boolean false value is converted to the string false.
8725 * The boolean true value is converted to the string true.
8726 *
8727 * If the argument is omitted, it defaults to a node-set with the
8728 * context node as its only member.
8729 */
8730void
8731xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8732 xmlXPathObjectPtr cur;
8733
Daniel Veillarda82b1822004-11-08 16:24:57 +00008734 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008735 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008736 valuePush(ctxt,
8737 xmlXPathCacheWrapString(ctxt->context,
8738 xmlXPathCastNodeToString(ctxt->context->node)));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008739 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008740 }
8741
8742 CHECK_ARITY(1);
8743 cur = valuePop(ctxt);
8744 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008745 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00008746}
8747
8748/**
8749 * xmlXPathStringLengthFunction:
8750 * @ctxt: the XPath Parser context
8751 * @nargs: the number of arguments
8752 *
8753 * Implement the string-length() XPath function
8754 * number string-length(string?)
8755 * The string-length returns the number of characters in the string
8756 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8757 * the context node converted to a string, in other words the value
8758 * of the context node.
8759 */
8760void
8761xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8762 xmlXPathObjectPtr cur;
8763
8764 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008765 if ((ctxt == NULL) || (ctxt->context == NULL))
8766 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008767 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008768 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008769 } else {
8770 xmlChar *content;
8771
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008772 content = xmlXPathCastNodeToString(ctxt->context->node);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008773 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8774 xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00008775 xmlFree(content);
8776 }
8777 return;
8778 }
8779 CHECK_ARITY(1);
8780 CAST_TO_STRING;
8781 CHECK_TYPE(XPATH_STRING);
8782 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008783 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8784 xmlUTF8Strlen(cur->stringval)));
8785 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008786}
8787
8788/**
8789 * xmlXPathConcatFunction:
8790 * @ctxt: the XPath Parser context
8791 * @nargs: the number of arguments
8792 *
8793 * Implement the concat() XPath function
8794 * string concat(string, string, string*)
8795 * The concat function returns the concatenation of its arguments.
8796 */
8797void
8798xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8799 xmlXPathObjectPtr cur, newobj;
8800 xmlChar *tmp;
8801
Daniel Veillarda82b1822004-11-08 16:24:57 +00008802 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008803 if (nargs < 2) {
8804 CHECK_ARITY(2);
8805 }
8806
8807 CAST_TO_STRING;
8808 cur = valuePop(ctxt);
8809 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008810 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008811 return;
8812 }
8813 nargs--;
8814
8815 while (nargs > 0) {
8816 CAST_TO_STRING;
8817 newobj = valuePop(ctxt);
8818 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008819 xmlXPathReleaseObject(ctxt->context, newobj);
8820 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008821 XP_ERROR(XPATH_INVALID_TYPE);
8822 }
8823 tmp = xmlStrcat(newobj->stringval, cur->stringval);
8824 newobj->stringval = cur->stringval;
8825 cur->stringval = tmp;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008826 xmlXPathReleaseObject(ctxt->context, newobj);
Owen Taylor3473f882001-02-23 17:55:21 +00008827 nargs--;
8828 }
8829 valuePush(ctxt, cur);
8830}
8831
8832/**
8833 * xmlXPathContainsFunction:
8834 * @ctxt: the XPath Parser context
8835 * @nargs: the number of arguments
8836 *
8837 * Implement the contains() XPath function
8838 * boolean contains(string, string)
8839 * The contains function returns true if the first argument string
8840 * contains the second argument string, and otherwise returns false.
8841 */
8842void
8843xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8844 xmlXPathObjectPtr hay, needle;
8845
8846 CHECK_ARITY(2);
8847 CAST_TO_STRING;
8848 CHECK_TYPE(XPATH_STRING);
8849 needle = valuePop(ctxt);
8850 CAST_TO_STRING;
8851 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008852
Owen Taylor3473f882001-02-23 17:55:21 +00008853 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008854 xmlXPathReleaseObject(ctxt->context, hay);
8855 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008856 XP_ERROR(XPATH_INVALID_TYPE);
8857 }
8858 if (xmlStrstr(hay->stringval, needle->stringval))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008859 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00008860 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008861 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8862 xmlXPathReleaseObject(ctxt->context, hay);
8863 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008864}
8865
8866/**
8867 * xmlXPathStartsWithFunction:
8868 * @ctxt: the XPath Parser context
8869 * @nargs: the number of arguments
8870 *
8871 * Implement the starts-with() XPath function
8872 * boolean starts-with(string, string)
8873 * The starts-with function returns true if the first argument string
8874 * starts with the second argument string, and otherwise returns false.
8875 */
8876void
8877xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8878 xmlXPathObjectPtr hay, needle;
8879 int n;
8880
8881 CHECK_ARITY(2);
8882 CAST_TO_STRING;
8883 CHECK_TYPE(XPATH_STRING);
8884 needle = valuePop(ctxt);
8885 CAST_TO_STRING;
8886 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008887
Owen Taylor3473f882001-02-23 17:55:21 +00008888 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008889 xmlXPathReleaseObject(ctxt->context, hay);
8890 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008891 XP_ERROR(XPATH_INVALID_TYPE);
8892 }
8893 n = xmlStrlen(needle->stringval);
8894 if (xmlStrncmp(hay->stringval, needle->stringval, n))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008895 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008896 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008897 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8898 xmlXPathReleaseObject(ctxt->context, hay);
8899 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008900}
8901
8902/**
8903 * xmlXPathSubstringFunction:
8904 * @ctxt: the XPath Parser context
8905 * @nargs: the number of arguments
8906 *
8907 * Implement the substring() XPath function
8908 * string substring(string, number, number?)
8909 * The substring function returns the substring of the first argument
8910 * starting at the position specified in the second argument with
8911 * length specified in the third argument. For example,
8912 * substring("12345",2,3) returns "234". If the third argument is not
8913 * specified, it returns the substring starting at the position specified
8914 * in the second argument and continuing to the end of the string. For
8915 * example, substring("12345",2) returns "2345". More precisely, each
8916 * character in the string (see [3.6 Strings]) is considered to have a
8917 * numeric position: the position of the first character is 1, the position
8918 * of the second character is 2 and so on. The returned substring contains
8919 * those characters for which the position of the character is greater than
8920 * or equal to the second argument and, if the third argument is specified,
8921 * less than the sum of the second and third arguments; the comparisons
8922 * and addition used for the above follow the standard IEEE 754 rules. Thus:
8923 * - substring("12345", 1.5, 2.6) returns "234"
8924 * - substring("12345", 0, 3) returns "12"
8925 * - substring("12345", 0 div 0, 3) returns ""
8926 * - substring("12345", 1, 0 div 0) returns ""
8927 * - substring("12345", -42, 1 div 0) returns "12345"
8928 * - substring("12345", -1 div 0, 1 div 0) returns ""
8929 */
8930void
8931xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8932 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00008933 double le=0, in;
8934 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00008935 xmlChar *ret;
8936
Owen Taylor3473f882001-02-23 17:55:21 +00008937 if (nargs < 2) {
8938 CHECK_ARITY(2);
8939 }
8940 if (nargs > 3) {
8941 CHECK_ARITY(3);
8942 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008943 /*
8944 * take care of possible last (position) argument
8945 */
Owen Taylor3473f882001-02-23 17:55:21 +00008946 if (nargs == 3) {
8947 CAST_TO_NUMBER;
8948 CHECK_TYPE(XPATH_NUMBER);
8949 len = valuePop(ctxt);
8950 le = len->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008951 xmlXPathReleaseObject(ctxt->context, len);
Owen Taylor3473f882001-02-23 17:55:21 +00008952 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008953
Owen Taylor3473f882001-02-23 17:55:21 +00008954 CAST_TO_NUMBER;
8955 CHECK_TYPE(XPATH_NUMBER);
8956 start = valuePop(ctxt);
8957 in = start->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008958 xmlXPathReleaseObject(ctxt->context, start);
Owen Taylor3473f882001-02-23 17:55:21 +00008959 CAST_TO_STRING;
8960 CHECK_TYPE(XPATH_STRING);
8961 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00008962 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00008963
Daniel Veillard97ac1312001-05-30 19:14:17 +00008964 /*
8965 * If last pos not present, calculate last position
8966 */
Daniel Veillard9e412302002-06-10 15:59:44 +00008967 if (nargs != 3) {
8968 le = (double)m;
8969 if (in < 1.0)
8970 in = 1.0;
8971 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008972
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008973 /* Need to check for the special cases where either
8974 * the index is NaN, the length is NaN, or both
8975 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00008976 */
Daniel Veillard9e412302002-06-10 15:59:44 +00008977 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008978 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00008979 * To meet the requirements of the spec, the arguments
8980 * must be converted to integer format before
8981 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008982 *
Daniel Veillard9e412302002-06-10 15:59:44 +00008983 * First we go to integer form, rounding up
8984 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008985 */
8986 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00008987 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00008988
Daniel Veillard9e412302002-06-10 15:59:44 +00008989 if (xmlXPathIsInf(le) == 1) {
8990 l = m;
8991 if (i < 1)
8992 i = 1;
8993 }
8994 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
8995 l = 0;
8996 else {
8997 l = (int) le;
8998 if (((double)l)+0.5 <= le) l++;
8999 }
9000
9001 /* Now we normalize inidices */
9002 i -= 1;
9003 l += i;
9004 if (i < 0)
9005 i = 0;
9006 if (l > m)
9007 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00009008
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009009 /* number of chars to copy */
9010 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00009011
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009012 ret = xmlUTF8Strsub(str->stringval, i, l);
9013 }
9014 else {
9015 ret = NULL;
9016 }
Owen Taylor3473f882001-02-23 17:55:21 +00009017 if (ret == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009018 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00009019 else {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009020 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009021 xmlFree(ret);
9022 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009023 xmlXPathReleaseObject(ctxt->context, str);
Owen Taylor3473f882001-02-23 17:55:21 +00009024}
9025
9026/**
9027 * xmlXPathSubstringBeforeFunction:
9028 * @ctxt: the XPath Parser context
9029 * @nargs: the number of arguments
9030 *
9031 * Implement the substring-before() XPath function
9032 * string substring-before(string, string)
9033 * The substring-before function returns the substring of the first
9034 * argument string that precedes the first occurrence of the second
9035 * argument string in the first argument string, or the empty string
9036 * if the first argument string does not contain the second argument
9037 * string. For example, substring-before("1999/04/01","/") returns 1999.
9038 */
9039void
9040xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9041 xmlXPathObjectPtr str;
9042 xmlXPathObjectPtr find;
9043 xmlBufferPtr target;
9044 const xmlChar *point;
9045 int offset;
9046
9047 CHECK_ARITY(2);
9048 CAST_TO_STRING;
9049 find = valuePop(ctxt);
9050 CAST_TO_STRING;
9051 str = valuePop(ctxt);
9052
9053 target = xmlBufferCreate();
9054 if (target) {
9055 point = xmlStrstr(str->stringval, find->stringval);
9056 if (point) {
9057 offset = (int)(point - str->stringval);
9058 xmlBufferAdd(target, str->stringval, offset);
9059 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009060 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9061 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00009062 xmlBufferFree(target);
9063 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009064 xmlXPathReleaseObject(ctxt->context, str);
9065 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009066}
9067
9068/**
9069 * xmlXPathSubstringAfterFunction:
9070 * @ctxt: the XPath Parser context
9071 * @nargs: the number of arguments
9072 *
9073 * Implement the substring-after() XPath function
9074 * string substring-after(string, string)
9075 * The substring-after function returns the substring of the first
9076 * argument string that follows the first occurrence of the second
9077 * argument string in the first argument string, or the empty stringi
9078 * if the first argument string does not contain the second argument
9079 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9080 * and substring-after("1999/04/01","19") returns 99/04/01.
9081 */
9082void
9083xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9084 xmlXPathObjectPtr str;
9085 xmlXPathObjectPtr find;
9086 xmlBufferPtr target;
9087 const xmlChar *point;
9088 int offset;
9089
9090 CHECK_ARITY(2);
9091 CAST_TO_STRING;
9092 find = valuePop(ctxt);
9093 CAST_TO_STRING;
9094 str = valuePop(ctxt);
9095
9096 target = xmlBufferCreate();
9097 if (target) {
9098 point = xmlStrstr(str->stringval, find->stringval);
9099 if (point) {
9100 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9101 xmlBufferAdd(target, &str->stringval[offset],
9102 xmlStrlen(str->stringval) - offset);
9103 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009104 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9105 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00009106 xmlBufferFree(target);
9107 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009108 xmlXPathReleaseObject(ctxt->context, str);
9109 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009110}
9111
9112/**
9113 * xmlXPathNormalizeFunction:
9114 * @ctxt: the XPath Parser context
9115 * @nargs: the number of arguments
9116 *
9117 * Implement the normalize-space() XPath function
9118 * string normalize-space(string?)
9119 * The normalize-space function returns the argument string with white
9120 * space normalized by stripping leading and trailing whitespace
9121 * and replacing sequences of whitespace characters by a single
9122 * space. Whitespace characters are the same allowed by the S production
9123 * in XML. If the argument is omitted, it defaults to the context
9124 * node converted to a string, in other words the value of the context node.
9125 */
9126void
9127xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9128 xmlXPathObjectPtr obj = NULL;
9129 xmlChar *source = NULL;
9130 xmlBufferPtr target;
9131 xmlChar blank;
9132
Daniel Veillarda82b1822004-11-08 16:24:57 +00009133 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009134 if (nargs == 0) {
9135 /* Use current context node */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009136 valuePush(ctxt,
9137 xmlXPathCacheWrapString(ctxt->context,
9138 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00009139 nargs = 1;
9140 }
9141
9142 CHECK_ARITY(1);
9143 CAST_TO_STRING;
9144 CHECK_TYPE(XPATH_STRING);
9145 obj = valuePop(ctxt);
9146 source = obj->stringval;
9147
9148 target = xmlBufferCreate();
9149 if (target && source) {
9150
9151 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00009152 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00009153 source++;
9154
9155 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9156 blank = 0;
9157 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00009158 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009159 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00009160 } else {
9161 if (blank) {
9162 xmlBufferAdd(target, &blank, 1);
9163 blank = 0;
9164 }
9165 xmlBufferAdd(target, source, 1);
9166 }
9167 source++;
9168 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009169 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9170 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00009171 xmlBufferFree(target);
9172 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009173 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00009174}
9175
9176/**
9177 * xmlXPathTranslateFunction:
9178 * @ctxt: the XPath Parser context
9179 * @nargs: the number of arguments
9180 *
9181 * Implement the translate() XPath function
9182 * string translate(string, string, string)
9183 * The translate function returns the first argument string with
9184 * occurrences of characters in the second argument string replaced
9185 * by the character at the corresponding position in the third argument
9186 * string. For example, translate("bar","abc","ABC") returns the string
9187 * BAr. If there is a character in the second argument string with no
9188 * character at a corresponding position in the third argument string
9189 * (because the second argument string is longer than the third argument
9190 * string), then occurrences of that character in the first argument
9191 * string are removed. For example, translate("--aaa--","abc-","ABC")
9192 * returns "AAA". If a character occurs more than once in second
9193 * argument string, then the first occurrence determines the replacement
9194 * character. If the third argument string is longer than the second
9195 * argument string, then excess characters are ignored.
9196 */
9197void
9198xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00009199 xmlXPathObjectPtr str;
9200 xmlXPathObjectPtr from;
9201 xmlXPathObjectPtr to;
9202 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009203 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009204 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00009205 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009206 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00009207
Daniel Veillarde043ee12001-04-16 14:08:07 +00009208 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00009209
Daniel Veillarde043ee12001-04-16 14:08:07 +00009210 CAST_TO_STRING;
9211 to = valuePop(ctxt);
9212 CAST_TO_STRING;
9213 from = valuePop(ctxt);
9214 CAST_TO_STRING;
9215 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009216
Daniel Veillarde043ee12001-04-16 14:08:07 +00009217 target = xmlBufferCreate();
9218 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009219 max = xmlUTF8Strlen(to->stringval);
9220 for (cptr = str->stringval; (ch=*cptr); ) {
9221 offset = xmlUTF8Strloc(from->stringval, cptr);
9222 if (offset >= 0) {
9223 if (offset < max) {
9224 point = xmlUTF8Strpos(to->stringval, offset);
9225 if (point)
9226 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
9227 }
9228 } else
9229 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9230
9231 /* Step to next character in input */
9232 cptr++;
9233 if ( ch & 0x80 ) {
9234 /* if not simple ascii, verify proper format */
9235 if ( (ch & 0xc0) != 0xc0 ) {
9236 xmlGenericError(xmlGenericErrorContext,
9237 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9238 break;
9239 }
9240 /* then skip over remaining bytes for this char */
9241 while ( (ch <<= 1) & 0x80 )
9242 if ( (*cptr++ & 0xc0) != 0x80 ) {
9243 xmlGenericError(xmlGenericErrorContext,
9244 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9245 break;
9246 }
9247 if (ch & 0x80) /* must have had error encountered */
9248 break;
9249 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00009250 }
Owen Taylor3473f882001-02-23 17:55:21 +00009251 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009252 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9253 xmlBufferContent(target)));
Daniel Veillarde043ee12001-04-16 14:08:07 +00009254 xmlBufferFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009255 xmlXPathReleaseObject(ctxt->context, str);
9256 xmlXPathReleaseObject(ctxt->context, from);
9257 xmlXPathReleaseObject(ctxt->context, to);
Owen Taylor3473f882001-02-23 17:55:21 +00009258}
9259
9260/**
9261 * xmlXPathBooleanFunction:
9262 * @ctxt: the XPath Parser context
9263 * @nargs: the number of arguments
9264 *
9265 * Implement the boolean() XPath function
9266 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00009267 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00009268 * - a number is true if and only if it is neither positive or
9269 * negative zero nor NaN
9270 * - a node-set is true if and only if it is non-empty
9271 * - a string is true if and only if its length is non-zero
9272 */
9273void
9274xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9275 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00009276
9277 CHECK_ARITY(1);
9278 cur = valuePop(ctxt);
9279 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009280 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009281 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009282}
9283
9284/**
9285 * xmlXPathNotFunction:
9286 * @ctxt: the XPath Parser context
9287 * @nargs: the number of arguments
9288 *
9289 * Implement the not() XPath function
9290 * boolean not(boolean)
9291 * The not function returns true if its argument is false,
9292 * and false otherwise.
9293 */
9294void
9295xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9296 CHECK_ARITY(1);
9297 CAST_TO_BOOLEAN;
9298 CHECK_TYPE(XPATH_BOOLEAN);
9299 ctxt->value->boolval = ! ctxt->value->boolval;
9300}
9301
9302/**
9303 * xmlXPathTrueFunction:
9304 * @ctxt: the XPath Parser context
9305 * @nargs: the number of arguments
9306 *
9307 * Implement the true() XPath function
9308 * boolean true()
9309 */
9310void
9311xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9312 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009313 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009314}
9315
9316/**
9317 * xmlXPathFalseFunction:
9318 * @ctxt: the XPath Parser context
9319 * @nargs: the number of arguments
9320 *
9321 * Implement the false() XPath function
9322 * boolean false()
9323 */
9324void
9325xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9326 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009327 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009328}
9329
9330/**
9331 * xmlXPathLangFunction:
9332 * @ctxt: the XPath Parser context
9333 * @nargs: the number of arguments
9334 *
9335 * Implement the lang() XPath function
9336 * boolean lang(string)
9337 * The lang function returns true or false depending on whether the
9338 * language of the context node as specified by xml:lang attributes
9339 * is the same as or is a sublanguage of the language specified by
9340 * the argument string. The language of the context node is determined
9341 * by the value of the xml:lang attribute on the context node, or, if
9342 * the context node has no xml:lang attribute, by the value of the
9343 * xml:lang attribute on the nearest ancestor of the context node that
9344 * has an xml:lang attribute. If there is no such attribute, then lang
9345 * returns false. If there is such an attribute, then lang returns
9346 * true if the attribute value is equal to the argument ignoring case,
9347 * or if there is some suffix starting with - such that the attribute
9348 * value is equal to the argument ignoring that suffix of the attribute
9349 * value and ignoring case.
9350 */
9351void
9352xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009353 xmlXPathObjectPtr val = NULL;
9354 const xmlChar *theLang = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009355 const xmlChar *lang;
9356 int ret = 0;
9357 int i;
9358
9359 CHECK_ARITY(1);
9360 CAST_TO_STRING;
9361 CHECK_TYPE(XPATH_STRING);
9362 val = valuePop(ctxt);
9363 lang = val->stringval;
9364 theLang = xmlNodeGetLang(ctxt->context->node);
9365 if ((theLang != NULL) && (lang != NULL)) {
9366 for (i = 0;lang[i] != 0;i++)
9367 if (toupper(lang[i]) != toupper(theLang[i]))
9368 goto not_equal;
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009369 if ((theLang[i] == 0) || (theLang[i] == '-'))
9370 ret = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009371 }
9372not_equal:
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009373 if (theLang != NULL)
9374 xmlFree((void *)theLang);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009375
9376 xmlXPathReleaseObject(ctxt->context, val);
9377 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009378}
9379
9380/**
9381 * xmlXPathNumberFunction:
9382 * @ctxt: the XPath Parser context
9383 * @nargs: the number of arguments
9384 *
9385 * Implement the number() XPath function
9386 * number number(object?)
9387 */
9388void
9389xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9390 xmlXPathObjectPtr cur;
9391 double res;
9392
Daniel Veillarda82b1822004-11-08 16:24:57 +00009393 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009394 if (nargs == 0) {
9395 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009396 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
Owen Taylor3473f882001-02-23 17:55:21 +00009397 } else {
9398 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9399
9400 res = xmlXPathStringEvalNumber(content);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009401 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
Owen Taylor3473f882001-02-23 17:55:21 +00009402 xmlFree(content);
9403 }
9404 return;
9405 }
9406
9407 CHECK_ARITY(1);
9408 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009409 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00009410}
9411
9412/**
9413 * xmlXPathSumFunction:
9414 * @ctxt: the XPath Parser context
9415 * @nargs: the number of arguments
9416 *
9417 * Implement the sum() XPath function
9418 * number sum(node-set)
9419 * The sum function returns the sum of the values of the nodes in
9420 * the argument node-set.
9421 */
9422void
9423xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9424 xmlXPathObjectPtr cur;
9425 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009426 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00009427
9428 CHECK_ARITY(1);
9429 if ((ctxt->value == NULL) ||
9430 ((ctxt->value->type != XPATH_NODESET) &&
9431 (ctxt->value->type != XPATH_XSLT_TREE)))
9432 XP_ERROR(XPATH_INVALID_TYPE);
9433 cur = valuePop(ctxt);
9434
William M. Brack08171912003-12-29 02:52:11 +00009435 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009436 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9437 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00009438 }
9439 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009440 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9441 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009442}
9443
William M. Brack3d426662005-04-19 14:40:28 +00009444/*
9445 * To assure working code on multiple platforms, we want to only depend
9446 * upon the characteristic truncation of converting a floating point value
9447 * to an integer. Unfortunately, because of the different storage sizes
9448 * of our internal floating point value (double) and integer (int), we
9449 * can't directly convert (see bug 301162). This macro is a messy
9450 * 'workaround'
9451 */
9452#define XTRUNC(f, v) \
9453 f = fmod((v), INT_MAX); \
9454 f = (v) - (f) + (double)((int)(f));
9455
Owen Taylor3473f882001-02-23 17:55:21 +00009456/**
9457 * xmlXPathFloorFunction:
9458 * @ctxt: the XPath Parser context
9459 * @nargs: the number of arguments
9460 *
9461 * Implement the floor() XPath function
9462 * number floor(number)
9463 * The floor function returns the largest (closest to positive infinity)
9464 * number that is not greater than the argument and that is an integer.
9465 */
9466void
9467xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009468 double f;
9469
Owen Taylor3473f882001-02-23 17:55:21 +00009470 CHECK_ARITY(1);
9471 CAST_TO_NUMBER;
9472 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009473
William M. Brack3d426662005-04-19 14:40:28 +00009474 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009475 if (f != ctxt->value->floatval) {
9476 if (ctxt->value->floatval > 0)
9477 ctxt->value->floatval = f;
9478 else
9479 ctxt->value->floatval = f - 1;
9480 }
Owen Taylor3473f882001-02-23 17:55:21 +00009481}
9482
9483/**
9484 * xmlXPathCeilingFunction:
9485 * @ctxt: the XPath Parser context
9486 * @nargs: the number of arguments
9487 *
9488 * Implement the ceiling() XPath function
9489 * number ceiling(number)
9490 * The ceiling function returns the smallest (closest to negative infinity)
9491 * number that is not less than the argument and that is an integer.
9492 */
9493void
9494xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9495 double f;
9496
9497 CHECK_ARITY(1);
9498 CAST_TO_NUMBER;
9499 CHECK_TYPE(XPATH_NUMBER);
9500
9501#if 0
9502 ctxt->value->floatval = ceil(ctxt->value->floatval);
9503#else
William M. Brack3d426662005-04-19 14:40:28 +00009504 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009505 if (f != ctxt->value->floatval) {
9506 if (ctxt->value->floatval > 0)
9507 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009508 else {
9509 if (ctxt->value->floatval < 0 && f == 0)
9510 ctxt->value->floatval = xmlXPathNZERO;
9511 else
9512 ctxt->value->floatval = f;
9513 }
9514
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009515 }
Owen Taylor3473f882001-02-23 17:55:21 +00009516#endif
9517}
9518
9519/**
9520 * xmlXPathRoundFunction:
9521 * @ctxt: the XPath Parser context
9522 * @nargs: the number of arguments
9523 *
9524 * Implement the round() XPath function
9525 * number round(number)
9526 * The round function returns the number that is closest to the
9527 * argument and that is an integer. If there are two such numbers,
9528 * then the one that is even is returned.
9529 */
9530void
9531xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9532 double f;
9533
9534 CHECK_ARITY(1);
9535 CAST_TO_NUMBER;
9536 CHECK_TYPE(XPATH_NUMBER);
9537
Daniel Veillardcda96922001-08-21 10:56:31 +00009538 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9539 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9540 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009541 (ctxt->value->floatval == 0.0))
9542 return;
9543
William M. Brack3d426662005-04-19 14:40:28 +00009544 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009545 if (ctxt->value->floatval < 0) {
9546 if (ctxt->value->floatval < f - 0.5)
9547 ctxt->value->floatval = f - 1;
9548 else
9549 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009550 if (ctxt->value->floatval == 0)
9551 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009552 } else {
9553 if (ctxt->value->floatval < f + 0.5)
9554 ctxt->value->floatval = f;
9555 else
9556 ctxt->value->floatval = f + 1;
9557 }
Owen Taylor3473f882001-02-23 17:55:21 +00009558}
9559
9560/************************************************************************
9561 * *
9562 * The Parser *
9563 * *
9564 ************************************************************************/
9565
9566/*
William M. Brack08171912003-12-29 02:52:11 +00009567 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00009568 * implementation.
9569 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009570static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009571static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009572static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009573static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00009574static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9575 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00009576
9577/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00009578 * xmlXPathCurrentChar:
9579 * @ctxt: the XPath parser context
9580 * @cur: pointer to the beginning of the char
9581 * @len: pointer to the length of the char read
9582 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009583 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00009584 * bytes in the input buffer.
9585 *
Daniel Veillard60087f32001-10-10 09:45:09 +00009586 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00009587 */
9588
9589static int
9590xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9591 unsigned char c;
9592 unsigned int val;
9593 const xmlChar *cur;
9594
9595 if (ctxt == NULL)
9596 return(0);
9597 cur = ctxt->cur;
9598
9599 /*
9600 * We are supposed to handle UTF8, check it's valid
9601 * From rfc2044: encoding of the Unicode values on UTF-8:
9602 *
9603 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9604 * 0000 0000-0000 007F 0xxxxxxx
9605 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
9606 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
9607 *
9608 * Check for the 0x110000 limit too
9609 */
9610 c = *cur;
9611 if (c & 0x80) {
9612 if ((cur[1] & 0xc0) != 0x80)
9613 goto encoding_error;
9614 if ((c & 0xe0) == 0xe0) {
9615
9616 if ((cur[2] & 0xc0) != 0x80)
9617 goto encoding_error;
9618 if ((c & 0xf0) == 0xf0) {
9619 if (((c & 0xf8) != 0xf0) ||
9620 ((cur[3] & 0xc0) != 0x80))
9621 goto encoding_error;
9622 /* 4-byte code */
9623 *len = 4;
9624 val = (cur[0] & 0x7) << 18;
9625 val |= (cur[1] & 0x3f) << 12;
9626 val |= (cur[2] & 0x3f) << 6;
9627 val |= cur[3] & 0x3f;
9628 } else {
9629 /* 3-byte code */
9630 *len = 3;
9631 val = (cur[0] & 0xf) << 12;
9632 val |= (cur[1] & 0x3f) << 6;
9633 val |= cur[2] & 0x3f;
9634 }
9635 } else {
9636 /* 2-byte code */
9637 *len = 2;
9638 val = (cur[0] & 0x1f) << 6;
9639 val |= cur[1] & 0x3f;
9640 }
9641 if (!IS_CHAR(val)) {
9642 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9643 }
9644 return(val);
9645 } else {
9646 /* 1-byte code */
9647 *len = 1;
9648 return((int) *cur);
9649 }
9650encoding_error:
9651 /*
William M. Brack08171912003-12-29 02:52:11 +00009652 * If we detect an UTF8 error that probably means that the
9653 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00009654 * declaration header. Report the error and switch the encoding
9655 * to ISO-Latin-1 (if you don't like this policy, just declare the
9656 * encoding !)
9657 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00009658 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00009659 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009660}
9661
9662/**
Owen Taylor3473f882001-02-23 17:55:21 +00009663 * xmlXPathParseNCName:
9664 * @ctxt: the XPath Parser context
9665 *
9666 * parse an XML namespace non qualified name.
9667 *
9668 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9669 *
9670 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9671 * CombiningChar | Extender
9672 *
9673 * Returns the namespace name or NULL
9674 */
9675
9676xmlChar *
9677xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00009678 const xmlChar *in;
9679 xmlChar *ret;
9680 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009681
Daniel Veillarda82b1822004-11-08 16:24:57 +00009682 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00009683 /*
9684 * Accelerator for simple ASCII names
9685 */
9686 in = ctxt->cur;
9687 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9688 ((*in >= 0x41) && (*in <= 0x5A)) ||
9689 (*in == '_')) {
9690 in++;
9691 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9692 ((*in >= 0x41) && (*in <= 0x5A)) ||
9693 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00009694 (*in == '_') || (*in == '.') ||
9695 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00009696 in++;
9697 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9698 (*in == '[') || (*in == ']') || (*in == ':') ||
9699 (*in == '@') || (*in == '*')) {
9700 count = in - ctxt->cur;
9701 if (count == 0)
9702 return(NULL);
9703 ret = xmlStrndup(ctxt->cur, count);
9704 ctxt->cur = in;
9705 return(ret);
9706 }
9707 }
9708 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009709}
9710
Daniel Veillard2156a562001-04-28 12:24:34 +00009711
Owen Taylor3473f882001-02-23 17:55:21 +00009712/**
9713 * xmlXPathParseQName:
9714 * @ctxt: the XPath Parser context
9715 * @prefix: a xmlChar **
9716 *
9717 * parse an XML qualified name
9718 *
9719 * [NS 5] QName ::= (Prefix ':')? LocalPart
9720 *
9721 * [NS 6] Prefix ::= NCName
9722 *
9723 * [NS 7] LocalPart ::= NCName
9724 *
9725 * Returns the function returns the local part, and prefix is updated
9726 * to get the Prefix if any.
9727 */
9728
Daniel Veillard56a4cb82001-03-24 17:00:36 +00009729static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00009730xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9731 xmlChar *ret = NULL;
9732
9733 *prefix = NULL;
9734 ret = xmlXPathParseNCName(ctxt);
9735 if (CUR == ':') {
9736 *prefix = ret;
9737 NEXT;
9738 ret = xmlXPathParseNCName(ctxt);
9739 }
9740 return(ret);
9741}
9742
9743/**
9744 * xmlXPathParseName:
9745 * @ctxt: the XPath Parser context
9746 *
9747 * parse an XML name
9748 *
9749 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9750 * CombiningChar | Extender
9751 *
9752 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9753 *
9754 * Returns the namespace name or NULL
9755 */
9756
9757xmlChar *
9758xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009759 const xmlChar *in;
9760 xmlChar *ret;
9761 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009762
Daniel Veillarda82b1822004-11-08 16:24:57 +00009763 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009764 /*
9765 * Accelerator for simple ASCII names
9766 */
9767 in = ctxt->cur;
9768 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9769 ((*in >= 0x41) && (*in <= 0x5A)) ||
9770 (*in == '_') || (*in == ':')) {
9771 in++;
9772 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9773 ((*in >= 0x41) && (*in <= 0x5A)) ||
9774 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00009775 (*in == '_') || (*in == '-') ||
9776 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00009777 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00009778 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009779 count = in - ctxt->cur;
9780 ret = xmlStrndup(ctxt->cur, count);
9781 ctxt->cur = in;
9782 return(ret);
9783 }
9784 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009785 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009786}
9787
Daniel Veillard61d80a22001-04-27 17:13:01 +00009788static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00009789xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009790 xmlChar buf[XML_MAX_NAMELEN + 5];
9791 int len = 0, l;
9792 int c;
9793
9794 /*
9795 * Handler for more complex cases
9796 */
9797 c = CUR_CHAR(l);
9798 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00009799 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9800 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00009801 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00009802 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009803 return(NULL);
9804 }
9805
9806 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9807 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9808 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00009809 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009810 (IS_COMBINING(c)) ||
9811 (IS_EXTENDER(c)))) {
9812 COPY_BUF(l,buf,len,c);
9813 NEXTL(l);
9814 c = CUR_CHAR(l);
9815 if (len >= XML_MAX_NAMELEN) {
9816 /*
9817 * Okay someone managed to make a huge name, so he's ready to pay
9818 * for the processing speed.
9819 */
9820 xmlChar *buffer;
9821 int max = len * 2;
9822
Daniel Veillard3c908dc2003-04-19 00:07:51 +00009823 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009824 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009825 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009826 }
9827 memcpy(buffer, buf, len);
9828 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9829 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00009830 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009831 (IS_COMBINING(c)) ||
9832 (IS_EXTENDER(c))) {
9833 if (len + 10 > max) {
9834 max *= 2;
9835 buffer = (xmlChar *) xmlRealloc(buffer,
9836 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009837 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009838 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009839 }
9840 }
9841 COPY_BUF(l,buffer,len,c);
9842 NEXTL(l);
9843 c = CUR_CHAR(l);
9844 }
9845 buffer[len] = 0;
9846 return(buffer);
9847 }
9848 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009849 if (len == 0)
9850 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009851 return(xmlStrndup(buf, len));
9852}
Daniel Veillard3cd72402002-05-13 10:33:30 +00009853
9854#define MAX_FRAC 20
9855
William M. Brack372a4452004-02-17 13:09:23 +00009856/*
9857 * These are used as divisors for the fractional part of a number.
9858 * Since the table includes 1.0 (representing '0' fractional digits),
9859 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
9860 */
9861static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +00009862 1.0, 10.0, 100.0, 1000.0, 10000.0,
9863 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
9864 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
9865 100000000000000.0,
9866 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +00009867 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +00009868};
9869
Owen Taylor3473f882001-02-23 17:55:21 +00009870/**
9871 * xmlXPathStringEvalNumber:
9872 * @str: A string to scan
9873 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00009874 * [30a] Float ::= Number ('e' Digits?)?
9875 *
Owen Taylor3473f882001-02-23 17:55:21 +00009876 * [30] Number ::= Digits ('.' Digits?)?
9877 * | '.' Digits
9878 * [31] Digits ::= [0-9]+
9879 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009880 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00009881 * In complement of the Number expression, this function also handles
9882 * negative values : '-' Number.
9883 *
9884 * Returns the double value.
9885 */
9886double
9887xmlXPathStringEvalNumber(const xmlChar *str) {
9888 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00009889 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009890 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009891 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009892 int exponent = 0;
9893 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009894#ifdef __GNUC__
9895 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00009896 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009897#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00009898 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00009899 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009900 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9901 return(xmlXPathNAN);
9902 }
9903 if (*cur == '-') {
9904 isneg = 1;
9905 cur++;
9906 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00009907
9908#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009909 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00009910 * tmp/temp is a workaround against a gcc compiler bug
9911 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009912 */
Daniel Veillard7b416132002-03-07 08:36:03 +00009913 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009914 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00009915 ret = ret * 10;
9916 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00009917 ok = 1;
9918 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00009919 temp = (double) tmp;
9920 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00009921 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00009922#else
Daniel Veillard7b416132002-03-07 08:36:03 +00009923 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009924 while ((*cur >= '0') && (*cur <= '9')) {
9925 ret = ret * 10 + (*cur - '0');
9926 ok = 1;
9927 cur++;
9928 }
9929#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009930
Owen Taylor3473f882001-02-23 17:55:21 +00009931 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00009932 int v, frac = 0;
9933 double fraction = 0;
9934
Owen Taylor3473f882001-02-23 17:55:21 +00009935 cur++;
9936 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
9937 return(xmlXPathNAN);
9938 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00009939 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
9940 v = (*cur - '0');
9941 fraction = fraction * 10 + v;
9942 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009943 cur++;
9944 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00009945 fraction /= my_pow10[frac];
9946 ret = ret + fraction;
9947 while ((*cur >= '0') && (*cur <= '9'))
9948 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009949 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00009950 if ((*cur == 'e') || (*cur == 'E')) {
9951 cur++;
9952 if (*cur == '-') {
9953 is_exponent_negative = 1;
9954 cur++;
William M. Brack99127052004-05-24 02:52:28 +00009955 } else if (*cur == '+') {
9956 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009957 }
9958 while ((*cur >= '0') && (*cur <= '9')) {
9959 exponent = exponent * 10 + (*cur - '0');
9960 cur++;
9961 }
9962 }
William M. Brack76e95df2003-10-18 16:20:14 +00009963 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009964 if (*cur != 0) return(xmlXPathNAN);
9965 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009966 if (is_exponent_negative) exponent = -exponent;
9967 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00009968 return(ret);
9969}
9970
9971/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009972 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00009973 * @ctxt: the XPath Parser context
9974 *
9975 * [30] Number ::= Digits ('.' Digits?)?
9976 * | '.' Digits
9977 * [31] Digits ::= [0-9]+
9978 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009979 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00009980 *
9981 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009982static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009983xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
9984{
Owen Taylor3473f882001-02-23 17:55:21 +00009985 double ret = 0.0;
9986 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00009987 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009988 int exponent = 0;
9989 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00009990#ifdef __GNUC__
9991 unsigned long tmp = 0;
9992 double temp;
9993#endif
Owen Taylor3473f882001-02-23 17:55:21 +00009994
9995 CHECK_ERROR;
9996 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
9997 XP_ERROR(XPATH_NUMBER_ERROR);
9998 }
Daniel Veillard7b416132002-03-07 08:36:03 +00009999#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010000 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010001 * tmp/temp is a workaround against a gcc compiler bug
10002 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010003 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010004 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010005 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010006 ret = ret * 10;
10007 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010008 ok = 1;
10009 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +000010010 temp = (double) tmp;
10011 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010012 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010013#else
10014 ret = 0;
10015 while ((CUR >= '0') && (CUR <= '9')) {
10016 ret = ret * 10 + (CUR - '0');
10017 ok = 1;
10018 NEXT;
10019 }
10020#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010021 if (CUR == '.') {
10022 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010023 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10024 XP_ERROR(XPATH_NUMBER_ERROR);
10025 }
10026 while ((CUR >= '0') && (CUR <= '9')) {
10027 mult /= 10;
10028 ret = ret + (CUR - '0') * mult;
10029 NEXT;
10030 }
Owen Taylor3473f882001-02-23 17:55:21 +000010031 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010032 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010033 NEXT;
10034 if (CUR == '-') {
10035 is_exponent_negative = 1;
10036 NEXT;
William M. Brack99127052004-05-24 02:52:28 +000010037 } else if (CUR == '+') {
10038 NEXT;
10039 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010040 while ((CUR >= '0') && (CUR <= '9')) {
10041 exponent = exponent * 10 + (CUR - '0');
10042 NEXT;
10043 }
10044 if (is_exponent_negative)
10045 exponent = -exponent;
10046 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +000010047 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010048 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010049 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010050}
10051
10052/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010053 * xmlXPathParseLiteral:
10054 * @ctxt: the XPath Parser context
10055 *
10056 * Parse a Literal
10057 *
10058 * [29] Literal ::= '"' [^"]* '"'
10059 * | "'" [^']* "'"
10060 *
10061 * Returns the value found or NULL in case of error
10062 */
10063static xmlChar *
10064xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10065 const xmlChar *q;
10066 xmlChar *ret = NULL;
10067
10068 if (CUR == '"') {
10069 NEXT;
10070 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010071 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010072 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010073 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010074 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010075 } else {
10076 ret = xmlStrndup(q, CUR_PTR - q);
10077 NEXT;
10078 }
10079 } else if (CUR == '\'') {
10080 NEXT;
10081 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010082 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010083 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010084 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010085 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010086 } else {
10087 ret = xmlStrndup(q, CUR_PTR - q);
10088 NEXT;
10089 }
10090 } else {
Daniel Veillard24505b02005-07-28 23:49:35 +000010091 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010092 }
10093 return(ret);
10094}
10095
10096/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010097 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +000010098 * @ctxt: the XPath Parser context
10099 *
10100 * Parse a Literal and push it on the stack.
10101 *
10102 * [29] Literal ::= '"' [^"]* '"'
10103 * | "'" [^']* "'"
10104 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010105 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +000010106 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010107static void
10108xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010109 const xmlChar *q;
10110 xmlChar *ret = NULL;
10111
10112 if (CUR == '"') {
10113 NEXT;
10114 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010115 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +000010116 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010117 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010118 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10119 } else {
10120 ret = xmlStrndup(q, CUR_PTR - q);
10121 NEXT;
10122 }
10123 } else if (CUR == '\'') {
10124 NEXT;
10125 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010126 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +000010127 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010128 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010129 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10130 } else {
10131 ret = xmlStrndup(q, CUR_PTR - q);
10132 NEXT;
10133 }
10134 } else {
10135 XP_ERROR(XPATH_START_LITERAL_ERROR);
10136 }
10137 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010138 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010139 xmlXPathCacheNewString(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010140 xmlFree(ret);
10141}
10142
10143/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010144 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +000010145 * @ctxt: the XPath Parser context
10146 *
10147 * Parse a VariableReference, evaluate it and push it on the stack.
10148 *
10149 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +000010150 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +000010151 * of any of the types that are possible for the value of an expression,
10152 * and may also be of additional types not specified here.
10153 *
10154 * Early evaluation is possible since:
10155 * The variable bindings [...] used to evaluate a subexpression are
10156 * always the same as those used to evaluate the containing expression.
10157 *
10158 * [36] VariableReference ::= '$' QName
10159 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010160static void
10161xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010162 xmlChar *name;
10163 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010164
10165 SKIP_BLANKS;
10166 if (CUR != '$') {
10167 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10168 }
10169 NEXT;
10170 name = xmlXPathParseQName(ctxt, &prefix);
10171 if (name == NULL) {
10172 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10173 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010174 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010175 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10176 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010177 SKIP_BLANKS;
Daniel Veillardb3d14912005-09-04 20:47:39 +000010178 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10179 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
10180 }
Owen Taylor3473f882001-02-23 17:55:21 +000010181}
10182
10183/**
10184 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +000010185 * @name: a name string
10186 *
10187 * Is the name given a NodeType one.
10188 *
10189 * [38] NodeType ::= 'comment'
10190 * | 'text'
10191 * | 'processing-instruction'
10192 * | 'node'
10193 *
10194 * Returns 1 if true 0 otherwise
10195 */
10196int
10197xmlXPathIsNodeType(const xmlChar *name) {
10198 if (name == NULL)
10199 return(0);
10200
Daniel Veillard1971ee22002-01-31 20:29:19 +000010201 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +000010202 return(1);
10203 if (xmlStrEqual(name, BAD_CAST "text"))
10204 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010205 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +000010206 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010207 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +000010208 return(1);
10209 return(0);
10210}
10211
10212/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010213 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +000010214 * @ctxt: the XPath Parser context
10215 *
10216 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10217 * [17] Argument ::= Expr
10218 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010219 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +000010220 * pushed on the stack
10221 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010222static void
10223xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010224 xmlChar *name;
10225 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010226 int nbargs = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010227 int sort = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010228
10229 name = xmlXPathParseQName(ctxt, &prefix);
10230 if (name == NULL) {
10231 XP_ERROR(XPATH_EXPR_ERROR);
10232 }
10233 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010234#ifdef DEBUG_EXPR
10235 if (prefix == NULL)
10236 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10237 name);
10238 else
10239 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10240 prefix, name);
10241#endif
10242
Owen Taylor3473f882001-02-23 17:55:21 +000010243 if (CUR != '(') {
10244 XP_ERROR(XPATH_EXPR_ERROR);
10245 }
10246 NEXT;
10247 SKIP_BLANKS;
10248
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010249 /*
10250 * Optimization for count(): we don't need the node-set to be sorted.
10251 */
10252 if ((prefix == NULL) && (name[0] == 'c') &&
10253 xmlStrEqual(name, BAD_CAST "count"))
10254 {
10255 sort = 0;
10256 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010257 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +000010258 if (CUR != ')') {
10259 while (CUR != 0) {
10260 int op1 = ctxt->comp->last;
10261 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010262 xmlXPathCompileExpr(ctxt, sort);
Daniel Veillard71f9d732003-01-14 16:07:16 +000010263 CHECK_ERROR;
10264 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10265 nbargs++;
10266 if (CUR == ')') break;
10267 if (CUR != ',') {
10268 XP_ERROR(XPATH_EXPR_ERROR);
10269 }
10270 NEXT;
10271 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010272 }
Owen Taylor3473f882001-02-23 17:55:21 +000010273 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010274 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10275 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010276 NEXT;
10277 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010278}
10279
10280/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010281 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010282 * @ctxt: the XPath Parser context
10283 *
10284 * [15] PrimaryExpr ::= VariableReference
10285 * | '(' Expr ')'
10286 * | Literal
10287 * | Number
10288 * | FunctionCall
10289 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010290 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010291 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010292static void
10293xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010294 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010295 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010296 else if (CUR == '(') {
10297 NEXT;
10298 SKIP_BLANKS;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010299 xmlXPathCompileExpr(ctxt, 1);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010300 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000010301 if (CUR != ')') {
10302 XP_ERROR(XPATH_EXPR_ERROR);
10303 }
10304 NEXT;
10305 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010306 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010307 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010308 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010309 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010310 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010311 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010312 }
10313 SKIP_BLANKS;
10314}
10315
10316/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010317 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010318 * @ctxt: the XPath Parser context
10319 *
10320 * [20] FilterExpr ::= PrimaryExpr
10321 * | FilterExpr Predicate
10322 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010323 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010324 * Square brackets are used to filter expressions in the same way that
10325 * they are used in location paths. It is an error if the expression to
10326 * be filtered does not evaluate to a node-set. The context node list
10327 * used for evaluating the expression in square brackets is the node-set
10328 * to be filtered listed in document order.
10329 */
10330
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010331static void
10332xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10333 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010334 CHECK_ERROR;
10335 SKIP_BLANKS;
10336
10337 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010338 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +000010339 SKIP_BLANKS;
10340 }
10341
10342
10343}
10344
10345/**
10346 * xmlXPathScanName:
10347 * @ctxt: the XPath Parser context
10348 *
10349 * Trickery: parse an XML name but without consuming the input flow
10350 * Needed to avoid insanity in the parser state.
10351 *
10352 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10353 * CombiningChar | Extender
10354 *
10355 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10356 *
10357 * [6] Names ::= Name (S Name)*
10358 *
10359 * Returns the Name parsed or NULL
10360 */
10361
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010362static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +000010363xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +000010364 int len = 0, l;
10365 int c;
Daniel Veillard03226812004-11-01 14:55:21 +000010366 const xmlChar *cur;
10367 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +000010368
Daniel Veillard03226812004-11-01 14:55:21 +000010369 cur = ctxt->cur;
10370
10371 c = CUR_CHAR(l);
10372 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10373 (!IS_LETTER(c) && (c != '_') &&
10374 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010375 return(NULL);
10376 }
10377
Daniel Veillard03226812004-11-01 14:55:21 +000010378 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10379 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10380 (c == '.') || (c == '-') ||
10381 (c == '_') || (c == ':') ||
10382 (IS_COMBINING(c)) ||
10383 (IS_EXTENDER(c)))) {
10384 len += l;
10385 NEXTL(l);
10386 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +000010387 }
Daniel Veillard03226812004-11-01 14:55:21 +000010388 ret = xmlStrndup(cur, ctxt->cur - cur);
10389 ctxt->cur = cur;
10390 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +000010391}
10392
10393/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010394 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010395 * @ctxt: the XPath Parser context
10396 *
10397 * [19] PathExpr ::= LocationPath
10398 * | FilterExpr
10399 * | FilterExpr '/' RelativeLocationPath
10400 * | FilterExpr '//' RelativeLocationPath
10401 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010402 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010403 * The / operator and // operators combine an arbitrary expression
10404 * and a relative location path. It is an error if the expression
10405 * does not evaluate to a node-set.
10406 * The / operator does composition in the same way as when / is
10407 * used in a location path. As in location paths, // is short for
10408 * /descendant-or-self::node()/.
10409 */
10410
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010411static void
10412xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010413 int lc = 1; /* Should we branch to LocationPath ? */
10414 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10415
10416 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010417 if ((CUR == '$') || (CUR == '(') ||
10418 (IS_ASCII_DIGIT(CUR)) ||
10419 (CUR == '\'') || (CUR == '"') ||
10420 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010421 lc = 0;
10422 } else if (CUR == '*') {
10423 /* relative or absolute location path */
10424 lc = 1;
10425 } else if (CUR == '/') {
10426 /* relative or absolute location path */
10427 lc = 1;
10428 } else if (CUR == '@') {
10429 /* relative abbreviated attribute location path */
10430 lc = 1;
10431 } else if (CUR == '.') {
10432 /* relative abbreviated attribute location path */
10433 lc = 1;
10434 } else {
10435 /*
10436 * Problem is finding if we have a name here whether it's:
10437 * - a nodetype
10438 * - a function call in which case it's followed by '('
10439 * - an axis in which case it's followed by ':'
10440 * - a element name
10441 * We do an a priori analysis here rather than having to
10442 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +000010443 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +000010444 * read/write/debug.
10445 */
10446 SKIP_BLANKS;
10447 name = xmlXPathScanName(ctxt);
10448 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10449#ifdef DEBUG_STEP
10450 xmlGenericError(xmlGenericErrorContext,
10451 "PathExpr: Axis\n");
10452#endif
10453 lc = 1;
10454 xmlFree(name);
10455 } else if (name != NULL) {
10456 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +000010457
10458
10459 while (NXT(len) != 0) {
10460 if (NXT(len) == '/') {
10461 /* element name */
10462#ifdef DEBUG_STEP
10463 xmlGenericError(xmlGenericErrorContext,
10464 "PathExpr: AbbrRelLocation\n");
10465#endif
10466 lc = 1;
10467 break;
William M. Brack76e95df2003-10-18 16:20:14 +000010468 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +000010469 /* ignore blanks */
10470 ;
Owen Taylor3473f882001-02-23 17:55:21 +000010471 } else if (NXT(len) == ':') {
10472#ifdef DEBUG_STEP
10473 xmlGenericError(xmlGenericErrorContext,
10474 "PathExpr: AbbrRelLocation\n");
10475#endif
10476 lc = 1;
10477 break;
10478 } else if ((NXT(len) == '(')) {
10479 /* Note Type or Function */
10480 if (xmlXPathIsNodeType(name)) {
10481#ifdef DEBUG_STEP
10482 xmlGenericError(xmlGenericErrorContext,
10483 "PathExpr: Type search\n");
10484#endif
10485 lc = 1;
10486 } else {
10487#ifdef DEBUG_STEP
10488 xmlGenericError(xmlGenericErrorContext,
10489 "PathExpr: function call\n");
10490#endif
10491 lc = 0;
10492 }
10493 break;
10494 } else if ((NXT(len) == '[')) {
10495 /* element name */
10496#ifdef DEBUG_STEP
10497 xmlGenericError(xmlGenericErrorContext,
10498 "PathExpr: AbbrRelLocation\n");
10499#endif
10500 lc = 1;
10501 break;
10502 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10503 (NXT(len) == '=')) {
10504 lc = 1;
10505 break;
10506 } else {
10507 lc = 1;
10508 break;
10509 }
10510 len++;
10511 }
10512 if (NXT(len) == 0) {
10513#ifdef DEBUG_STEP
10514 xmlGenericError(xmlGenericErrorContext,
10515 "PathExpr: AbbrRelLocation\n");
10516#endif
10517 /* element name */
10518 lc = 1;
10519 }
10520 xmlFree(name);
10521 } else {
William M. Brack08171912003-12-29 02:52:11 +000010522 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +000010523 XP_ERROR(XPATH_EXPR_ERROR);
10524 }
10525 }
10526
10527 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010528 if (CUR == '/') {
10529 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10530 } else {
10531 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010532 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010533 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010534 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010535 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010536 CHECK_ERROR;
10537 if ((CUR == '/') && (NXT(1) == '/')) {
10538 SKIP(2);
10539 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010540
10541 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10542 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10543 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10544
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010545 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010546 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010547 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010548 }
10549 }
10550 SKIP_BLANKS;
10551}
10552
10553/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010554 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010555 * @ctxt: the XPath Parser context
10556 *
10557 * [18] UnionExpr ::= PathExpr
10558 * | UnionExpr '|' PathExpr
10559 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010560 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010561 */
10562
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010563static void
10564xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10565 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010566 CHECK_ERROR;
10567 SKIP_BLANKS;
10568 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010569 int op1 = ctxt->comp->last;
10570 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010571
10572 NEXT;
10573 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010574 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010575
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010576 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10577
Owen Taylor3473f882001-02-23 17:55:21 +000010578 SKIP_BLANKS;
10579 }
Owen Taylor3473f882001-02-23 17:55:21 +000010580}
10581
10582/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010583 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010584 * @ctxt: the XPath Parser context
10585 *
10586 * [27] UnaryExpr ::= UnionExpr
10587 * | '-' UnaryExpr
10588 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010589 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010590 */
10591
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010592static void
10593xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010594 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010595 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010596
10597 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +000010598 while (CUR == '-') {
10599 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010600 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010601 NEXT;
10602 SKIP_BLANKS;
10603 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010604
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010605 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010606 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010607 if (found) {
10608 if (minus)
10609 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10610 else
10611 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010612 }
10613}
10614
10615/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010616 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010617 * @ctxt: the XPath Parser context
10618 *
10619 * [26] MultiplicativeExpr ::= UnaryExpr
10620 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10621 * | MultiplicativeExpr 'div' UnaryExpr
10622 * | MultiplicativeExpr 'mod' UnaryExpr
10623 * [34] MultiplyOperator ::= '*'
10624 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010625 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010626 */
10627
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010628static void
10629xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10630 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010631 CHECK_ERROR;
10632 SKIP_BLANKS;
10633 while ((CUR == '*') ||
10634 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10635 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10636 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010637 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010638
10639 if (CUR == '*') {
10640 op = 0;
10641 NEXT;
10642 } else if (CUR == 'd') {
10643 op = 1;
10644 SKIP(3);
10645 } else if (CUR == 'm') {
10646 op = 2;
10647 SKIP(3);
10648 }
10649 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010650 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010651 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010652 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010653 SKIP_BLANKS;
10654 }
10655}
10656
10657/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010658 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010659 * @ctxt: the XPath Parser context
10660 *
10661 * [25] AdditiveExpr ::= MultiplicativeExpr
10662 * | AdditiveExpr '+' MultiplicativeExpr
10663 * | AdditiveExpr '-' MultiplicativeExpr
10664 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010665 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010666 */
10667
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010668static void
10669xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010670
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010671 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010672 CHECK_ERROR;
10673 SKIP_BLANKS;
10674 while ((CUR == '+') || (CUR == '-')) {
10675 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010676 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010677
10678 if (CUR == '+') plus = 1;
10679 else plus = 0;
10680 NEXT;
10681 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010682 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010683 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010684 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010685 SKIP_BLANKS;
10686 }
10687}
10688
10689/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010690 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010691 * @ctxt: the XPath Parser context
10692 *
10693 * [24] RelationalExpr ::= AdditiveExpr
10694 * | RelationalExpr '<' AdditiveExpr
10695 * | RelationalExpr '>' AdditiveExpr
10696 * | RelationalExpr '<=' AdditiveExpr
10697 * | RelationalExpr '>=' AdditiveExpr
10698 *
10699 * A <= B > C is allowed ? Answer from James, yes with
10700 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10701 * which is basically what got implemented.
10702 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010703 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +000010704 * on the stack
10705 */
10706
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010707static void
10708xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10709 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010710 CHECK_ERROR;
10711 SKIP_BLANKS;
10712 while ((CUR == '<') ||
10713 (CUR == '>') ||
10714 ((CUR == '<') && (NXT(1) == '=')) ||
10715 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010716 int inf, strict;
10717 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010718
10719 if (CUR == '<') inf = 1;
10720 else inf = 0;
10721 if (NXT(1) == '=') strict = 0;
10722 else strict = 1;
10723 NEXT;
10724 if (!strict) NEXT;
10725 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010726 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010727 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010728 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +000010729 SKIP_BLANKS;
10730 }
10731}
10732
10733/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010734 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010735 * @ctxt: the XPath Parser context
10736 *
10737 * [23] EqualityExpr ::= RelationalExpr
10738 * | EqualityExpr '=' RelationalExpr
10739 * | EqualityExpr '!=' RelationalExpr
10740 *
10741 * A != B != C is allowed ? Answer from James, yes with
10742 * (RelationalExpr = RelationalExpr) = RelationalExpr
10743 * (RelationalExpr != RelationalExpr) != RelationalExpr
10744 * which is basically what got implemented.
10745 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010746 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010747 *
10748 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010749static void
10750xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10751 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010752 CHECK_ERROR;
10753 SKIP_BLANKS;
10754 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010755 int eq;
10756 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010757
10758 if (CUR == '=') eq = 1;
10759 else eq = 0;
10760 NEXT;
10761 if (!eq) NEXT;
10762 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010763 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010764 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010765 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010766 SKIP_BLANKS;
10767 }
10768}
10769
10770/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010771 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010772 * @ctxt: the XPath Parser context
10773 *
10774 * [22] AndExpr ::= EqualityExpr
10775 * | AndExpr 'and' EqualityExpr
10776 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010777 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010778 *
10779 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010780static void
10781xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10782 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010783 CHECK_ERROR;
10784 SKIP_BLANKS;
10785 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010786 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010787 SKIP(3);
10788 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010789 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010790 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010791 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010792 SKIP_BLANKS;
10793 }
10794}
10795
10796/**
Daniel Veillard591b4be2003-02-09 23:33:36 +000010797 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010798 * @ctxt: the XPath Parser context
10799 *
10800 * [14] Expr ::= OrExpr
10801 * [21] OrExpr ::= AndExpr
10802 * | OrExpr 'or' AndExpr
10803 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010804 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +000010805 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010806static void
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010807xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010808 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010809 CHECK_ERROR;
10810 SKIP_BLANKS;
10811 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010812 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010813 SKIP(2);
10814 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010815 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010816 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010817 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10818 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +000010819 SKIP_BLANKS;
10820 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010821 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010822 /* more ops could be optimized too */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010823 /*
10824 * This is the main place to eliminate sorting for
10825 * operations which don't require a sorted node-set.
10826 * E.g. count().
10827 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010828 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10829 }
Owen Taylor3473f882001-02-23 17:55:21 +000010830}
10831
10832/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010833 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +000010834 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010835 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +000010836 *
10837 * [8] Predicate ::= '[' PredicateExpr ']'
10838 * [9] PredicateExpr ::= Expr
10839 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010840 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +000010841 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010842static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010843xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010844 int op1 = ctxt->comp->last;
10845
10846 SKIP_BLANKS;
10847 if (CUR != '[') {
10848 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10849 }
10850 NEXT;
10851 SKIP_BLANKS;
10852
10853 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010854 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010855 CHECK_ERROR;
10856
10857 if (CUR != ']') {
10858 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10859 }
10860
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010861 if (filter)
10862 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10863 else
10864 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010865
10866 NEXT;
10867 SKIP_BLANKS;
10868}
10869
10870/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010871 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +000010872 * @ctxt: the XPath Parser context
10873 * @test: pointer to a xmlXPathTestVal
10874 * @type: pointer to a xmlXPathTypeVal
10875 * @prefix: placeholder for a possible name prefix
10876 *
10877 * [7] NodeTest ::= NameTest
10878 * | NodeType '(' ')'
10879 * | 'processing-instruction' '(' Literal ')'
10880 *
10881 * [37] NameTest ::= '*'
10882 * | NCName ':' '*'
10883 * | QName
10884 * [38] NodeType ::= 'comment'
10885 * | 'text'
10886 * | 'processing-instruction'
10887 * | 'node'
10888 *
William M. Brack08171912003-12-29 02:52:11 +000010889 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +000010890 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010891static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010892xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10893 xmlXPathTypeVal *type, const xmlChar **prefix,
10894 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +000010895 int blanks;
10896
10897 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10898 STRANGE;
10899 return(NULL);
10900 }
William M. Brack78637da2003-07-31 14:47:38 +000010901 *type = (xmlXPathTypeVal) 0;
10902 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010903 *prefix = NULL;
10904 SKIP_BLANKS;
10905
10906 if ((name == NULL) && (CUR == '*')) {
10907 /*
10908 * All elements
10909 */
10910 NEXT;
10911 *test = NODE_TEST_ALL;
10912 return(NULL);
10913 }
10914
10915 if (name == NULL)
10916 name = xmlXPathParseNCName(ctxt);
10917 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010918 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010919 }
10920
William M. Brack76e95df2003-10-18 16:20:14 +000010921 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +000010922 SKIP_BLANKS;
10923 if (CUR == '(') {
10924 NEXT;
10925 /*
10926 * NodeType or PI search
10927 */
10928 if (xmlStrEqual(name, BAD_CAST "comment"))
10929 *type = NODE_TYPE_COMMENT;
10930 else if (xmlStrEqual(name, BAD_CAST "node"))
10931 *type = NODE_TYPE_NODE;
10932 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10933 *type = NODE_TYPE_PI;
10934 else if (xmlStrEqual(name, BAD_CAST "text"))
10935 *type = NODE_TYPE_TEXT;
10936 else {
10937 if (name != NULL)
10938 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000010939 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010940 }
10941
10942 *test = NODE_TEST_TYPE;
10943
10944 SKIP_BLANKS;
10945 if (*type == NODE_TYPE_PI) {
10946 /*
10947 * Specific case: search a PI by name.
10948 */
Owen Taylor3473f882001-02-23 17:55:21 +000010949 if (name != NULL)
10950 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +000010951 name = NULL;
10952 if (CUR != ')') {
10953 name = xmlXPathParseLiteral(ctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000010954 CHECK_ERROR NULL;
Daniel Veillarded23b7d2002-05-27 12:16:02 +000010955 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +000010956 SKIP_BLANKS;
10957 }
Owen Taylor3473f882001-02-23 17:55:21 +000010958 }
10959 if (CUR != ')') {
10960 if (name != NULL)
10961 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000010962 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010963 }
10964 NEXT;
10965 return(name);
10966 }
10967 *test = NODE_TEST_NAME;
10968 if ((!blanks) && (CUR == ':')) {
10969 NEXT;
10970
10971 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010972 * Since currently the parser context don't have a
10973 * namespace list associated:
10974 * The namespace name for this prefix can be computed
10975 * only at evaluation time. The compilation is done
10976 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +000010977 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010978#if 0
Owen Taylor3473f882001-02-23 17:55:21 +000010979 *prefix = xmlXPathNsLookup(ctxt->context, name);
10980 if (name != NULL)
10981 xmlFree(name);
10982 if (*prefix == NULL) {
10983 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
10984 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010985#else
10986 *prefix = name;
10987#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010988
10989 if (CUR == '*') {
10990 /*
10991 * All elements
10992 */
10993 NEXT;
10994 *test = NODE_TEST_ALL;
10995 return(NULL);
10996 }
10997
10998 name = xmlXPathParseNCName(ctxt);
10999 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011000 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011001 }
11002 }
11003 return(name);
11004}
11005
11006/**
11007 * xmlXPathIsAxisName:
11008 * @name: a preparsed name token
11009 *
11010 * [6] AxisName ::= 'ancestor'
11011 * | 'ancestor-or-self'
11012 * | 'attribute'
11013 * | 'child'
11014 * | 'descendant'
11015 * | 'descendant-or-self'
11016 * | 'following'
11017 * | 'following-sibling'
11018 * | 'namespace'
11019 * | 'parent'
11020 * | 'preceding'
11021 * | 'preceding-sibling'
11022 * | 'self'
11023 *
11024 * Returns the axis or 0
11025 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011026static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +000011027xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +000011028 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011029 switch (name[0]) {
11030 case 'a':
11031 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11032 ret = AXIS_ANCESTOR;
11033 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11034 ret = AXIS_ANCESTOR_OR_SELF;
11035 if (xmlStrEqual(name, BAD_CAST "attribute"))
11036 ret = AXIS_ATTRIBUTE;
11037 break;
11038 case 'c':
11039 if (xmlStrEqual(name, BAD_CAST "child"))
11040 ret = AXIS_CHILD;
11041 break;
11042 case 'd':
11043 if (xmlStrEqual(name, BAD_CAST "descendant"))
11044 ret = AXIS_DESCENDANT;
11045 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11046 ret = AXIS_DESCENDANT_OR_SELF;
11047 break;
11048 case 'f':
11049 if (xmlStrEqual(name, BAD_CAST "following"))
11050 ret = AXIS_FOLLOWING;
11051 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11052 ret = AXIS_FOLLOWING_SIBLING;
11053 break;
11054 case 'n':
11055 if (xmlStrEqual(name, BAD_CAST "namespace"))
11056 ret = AXIS_NAMESPACE;
11057 break;
11058 case 'p':
11059 if (xmlStrEqual(name, BAD_CAST "parent"))
11060 ret = AXIS_PARENT;
11061 if (xmlStrEqual(name, BAD_CAST "preceding"))
11062 ret = AXIS_PRECEDING;
11063 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11064 ret = AXIS_PRECEDING_SIBLING;
11065 break;
11066 case 's':
11067 if (xmlStrEqual(name, BAD_CAST "self"))
11068 ret = AXIS_SELF;
11069 break;
11070 }
11071 return(ret);
11072}
11073
11074/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011075 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +000011076 * @ctxt: the XPath Parser context
11077 *
11078 * [4] Step ::= AxisSpecifier NodeTest Predicate*
11079 * | AbbreviatedStep
11080 *
11081 * [12] AbbreviatedStep ::= '.' | '..'
11082 *
11083 * [5] AxisSpecifier ::= AxisName '::'
11084 * | AbbreviatedAxisSpecifier
11085 *
11086 * [13] AbbreviatedAxisSpecifier ::= '@'?
11087 *
11088 * Modified for XPtr range support as:
11089 *
11090 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11091 * | AbbreviatedStep
11092 * | 'range-to' '(' Expr ')' Predicate*
11093 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011094 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +000011095 * A location step of . is short for self::node(). This is
11096 * particularly useful in conjunction with //. For example, the
11097 * location path .//para is short for
11098 * self::node()/descendant-or-self::node()/child::para
11099 * and so will select all para descendant elements of the context
11100 * node.
11101 * Similarly, a location step of .. is short for parent::node().
11102 * For example, ../title is short for parent::node()/child::title
11103 * and so will select the title children of the parent of the context
11104 * node.
11105 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011106static void
11107xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011108#ifdef LIBXML_XPTR_ENABLED
11109 int rangeto = 0;
11110 int op2 = -1;
11111#endif
11112
Owen Taylor3473f882001-02-23 17:55:21 +000011113 SKIP_BLANKS;
11114 if ((CUR == '.') && (NXT(1) == '.')) {
11115 SKIP(2);
11116 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011117 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11118 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011119 } else if (CUR == '.') {
11120 NEXT;
11121 SKIP_BLANKS;
11122 } else {
11123 xmlChar *name = NULL;
11124 const xmlChar *prefix = NULL;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011125 xmlXPathTestVal test = (xmlXPathTestVal) 0;
William M. Brack78637da2003-07-31 14:47:38 +000011126 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011127 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011128 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +000011129
11130 /*
11131 * The modification needed for XPointer change to the production
11132 */
11133#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011134 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +000011135 name = xmlXPathParseNCName(ctxt);
11136 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011137 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011138 xmlFree(name);
11139 SKIP_BLANKS;
11140 if (CUR != '(') {
11141 XP_ERROR(XPATH_EXPR_ERROR);
11142 }
11143 NEXT;
11144 SKIP_BLANKS;
11145
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011146 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011147 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +000011148 CHECK_ERROR;
11149
11150 SKIP_BLANKS;
11151 if (CUR != ')') {
11152 XP_ERROR(XPATH_EXPR_ERROR);
11153 }
11154 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011155 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000011156 goto eval_predicates;
11157 }
11158 }
11159#endif
Daniel Veillard2156a562001-04-28 12:24:34 +000011160 if (CUR == '*') {
11161 axis = AXIS_CHILD;
11162 } else {
11163 if (name == NULL)
11164 name = xmlXPathParseNCName(ctxt);
11165 if (name != NULL) {
11166 axis = xmlXPathIsAxisName(name);
11167 if (axis != 0) {
11168 SKIP_BLANKS;
11169 if ((CUR == ':') && (NXT(1) == ':')) {
11170 SKIP(2);
11171 xmlFree(name);
11172 name = NULL;
11173 } else {
11174 /* an element name can conflict with an axis one :-\ */
11175 axis = AXIS_CHILD;
11176 }
Owen Taylor3473f882001-02-23 17:55:21 +000011177 } else {
Owen Taylor3473f882001-02-23 17:55:21 +000011178 axis = AXIS_CHILD;
11179 }
Daniel Veillard2156a562001-04-28 12:24:34 +000011180 } else if (CUR == '@') {
11181 NEXT;
11182 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +000011183 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +000011184 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +000011185 }
Owen Taylor3473f882001-02-23 17:55:21 +000011186 }
11187
11188 CHECK_ERROR;
11189
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011190 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +000011191 if (test == 0)
11192 return;
11193
Daniel Veillarded6c5492005-07-23 15:00:22 +000011194 if ((prefix != NULL) && (ctxt->context != NULL) &&
11195 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11196 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11197 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11198 }
11199 }
Owen Taylor3473f882001-02-23 17:55:21 +000011200#ifdef DEBUG_STEP
11201 xmlGenericError(xmlGenericErrorContext,
11202 "Basis : computing new set\n");
11203#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011204
Owen Taylor3473f882001-02-23 17:55:21 +000011205#ifdef DEBUG_STEP
11206 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011207 if (ctxt->value == NULL)
11208 xmlGenericError(xmlGenericErrorContext, "no value\n");
11209 else if (ctxt->value->nodesetval == NULL)
11210 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11211 else
11212 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011213#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011214
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011215#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +000011216eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011217#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011218 op1 = ctxt->comp->last;
11219 ctxt->comp->last = -1;
11220
Owen Taylor3473f882001-02-23 17:55:21 +000011221 SKIP_BLANKS;
11222 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011223 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011224 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011225
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011226#ifdef LIBXML_XPTR_ENABLED
11227 if (rangeto) {
11228 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11229 } else
11230#endif
11231 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11232 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011233
Owen Taylor3473f882001-02-23 17:55:21 +000011234 }
11235#ifdef DEBUG_STEP
11236 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011237 if (ctxt->value == NULL)
11238 xmlGenericError(xmlGenericErrorContext, "no value\n");
11239 else if (ctxt->value->nodesetval == NULL)
11240 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11241 else
11242 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11243 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011244#endif
11245}
11246
11247/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011248 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011249 * @ctxt: the XPath Parser context
11250 *
11251 * [3] RelativeLocationPath ::= Step
11252 * | RelativeLocationPath '/' Step
11253 * | AbbreviatedRelativeLocationPath
11254 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
11255 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011256 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +000011257 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011258static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011259xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011260(xmlXPathParserContextPtr ctxt) {
11261 SKIP_BLANKS;
11262 if ((CUR == '/') && (NXT(1) == '/')) {
11263 SKIP(2);
11264 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011265 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11266 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011267 } else if (CUR == '/') {
11268 NEXT;
11269 SKIP_BLANKS;
11270 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011271 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011272 SKIP_BLANKS;
11273 while (CUR == '/') {
11274 if ((CUR == '/') && (NXT(1) == '/')) {
11275 SKIP(2);
11276 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011277 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +000011278 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011279 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011280 } else if (CUR == '/') {
11281 NEXT;
11282 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011283 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011284 }
11285 SKIP_BLANKS;
11286 }
11287}
11288
11289/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011290 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011291 * @ctxt: the XPath Parser context
11292 *
11293 * [1] LocationPath ::= RelativeLocationPath
11294 * | AbsoluteLocationPath
11295 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
11296 * | AbbreviatedAbsoluteLocationPath
11297 * [10] AbbreviatedAbsoluteLocationPath ::=
11298 * '//' RelativeLocationPath
11299 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011300 * Compile a location path
11301 *
Owen Taylor3473f882001-02-23 17:55:21 +000011302 * // is short for /descendant-or-self::node()/. For example,
11303 * //para is short for /descendant-or-self::node()/child::para and
11304 * so will select any para element in the document (even a para element
11305 * that is a document element will be selected by //para since the
11306 * document element node is a child of the root node); div//para is
11307 * short for div/descendant-or-self::node()/child::para and so will
11308 * select all para descendants of div children.
11309 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011310static void
11311xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000011312 SKIP_BLANKS;
11313 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011314 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011315 } else {
11316 while (CUR == '/') {
11317 if ((CUR == '/') && (NXT(1) == '/')) {
11318 SKIP(2);
11319 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011320 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11321 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011322 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011323 } else if (CUR == '/') {
11324 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +000011325 SKIP_BLANKS;
11326 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +000011327 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +000011328 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011329 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011330 }
11331 }
11332 }
11333}
11334
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011335/************************************************************************
11336 * *
11337 * XPath precompiled expression evaluation *
11338 * *
11339 ************************************************************************/
11340
Daniel Veillardf06307e2001-07-03 10:35:50 +000011341static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011342xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11343
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011344#ifdef DEBUG_STEP
11345static void
11346xmlXPathDebugDumpStepAxis(xmlXPathAxisVal axis,
11347 xmlXPathTestVal test,
11348 int nbNodes)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011349{
Daniel Veillardf06307e2001-07-03 10:35:50 +000011350 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011351 switch (axis) {
11352 case AXIS_ANCESTOR:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011353 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011354 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011355 case AXIS_ANCESTOR_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011356 xmlGenericError(xmlGenericErrorContext,
11357 "axis 'ancestors-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011358 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011359 case AXIS_ATTRIBUTE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011360 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011361 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011362 case AXIS_CHILD:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011363 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011364 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011365 case AXIS_DESCENDANT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011366 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011367 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011368 case AXIS_DESCENDANT_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011369 xmlGenericError(xmlGenericErrorContext,
11370 "axis 'descendant-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011371 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011372 case AXIS_FOLLOWING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011373 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011374 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011375 case AXIS_FOLLOWING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011376 xmlGenericError(xmlGenericErrorContext,
11377 "axis 'following-siblings' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011378 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011379 case AXIS_NAMESPACE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011380 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011381 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011382 case AXIS_PARENT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011383 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011384 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011385 case AXIS_PRECEDING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011386 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011387 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011388 case AXIS_PRECEDING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011389 xmlGenericError(xmlGenericErrorContext,
11390 "axis 'preceding-sibling' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011391 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011392 case AXIS_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011393 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011394 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011395 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011396 xmlGenericError(xmlGenericErrorContext,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011397 " context contains %d nodes\n", nbNodes);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011398 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011399 case NODE_TEST_NONE:
11400 xmlGenericError(xmlGenericErrorContext,
11401 " searching for none !!!\n");
11402 break;
11403 case NODE_TEST_TYPE:
11404 xmlGenericError(xmlGenericErrorContext,
11405 " searching for type %d\n", type);
11406 break;
11407 case NODE_TEST_PI:
11408 xmlGenericError(xmlGenericErrorContext,
11409 " searching for PI !!!\n");
11410 break;
11411 case NODE_TEST_ALL:
11412 xmlGenericError(xmlGenericErrorContext,
11413 " searching for *\n");
11414 break;
11415 case NODE_TEST_NS:
11416 xmlGenericError(xmlGenericErrorContext,
11417 " searching for namespace %s\n",
11418 prefix);
11419 break;
11420 case NODE_TEST_NAME:
11421 xmlGenericError(xmlGenericErrorContext,
11422 " searching for name %s\n", name);
11423 if (prefix != NULL)
11424 xmlGenericError(xmlGenericErrorContext,
11425 " with namespace %s\n", prefix);
11426 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011427 }
11428 xmlGenericError(xmlGenericErrorContext, "Testing : ");
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011429}
11430#endif /* DEBUG_STEP */
11431
11432static int
11433xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11434 xmlXPathStepOpPtr op,
11435 xmlNodeSetPtr set,
11436 int contextSize,
11437 int hasNsNodes)
11438{
11439 if (op->ch1 != -1) {
11440 xmlXPathCompExprPtr comp = ctxt->comp;
11441 /*
11442 * Process inner predicates first.
11443 */
11444 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11445 /*
11446 * TODO: raise an internal error.
11447 */
11448 }
11449 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11450 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11451 CHECK_ERROR0;
11452 if (contextSize <= 0)
11453 return(0);
11454 }
11455 if (op->ch2 != -1) {
11456 xmlXPathContextPtr xpctxt = ctxt->context;
11457 xmlNodePtr contextNode, oldContextNode;
11458 xmlDocPtr oldContextDoc;
11459 int i, contextPos = 0, newContextSize;
11460 xmlXPathStepOpPtr exprOp;
11461 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11462
11463#ifdef LIBXML_XPTR_ENABLED
11464 /*
11465 * URGENT TODO: Check the following:
11466 * We don't expect location sets if evaluating prediates, right?
11467 * Only filters should expect location sets, right?
11468 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011469#endif
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011470 /*
11471 * SPEC XPath 1.0:
11472 * "For each node in the node-set to be filtered, the
11473 * PredicateExpr is evaluated with that node as the
11474 * context node, with the number of nodes in the
11475 * node-set as the context size, and with the proximity
11476 * position of the node in the node-set with respect to
11477 * the axis as the context position;"
11478 * @oldset is the node-set" to be filtered.
11479 *
11480 * SPEC XPath 1.0:
11481 * "only predicates change the context position and
11482 * context size (see [2.4 Predicates])."
11483 * Example:
11484 * node-set context pos
11485 * nA 1
11486 * nB 2
11487 * nC 3
11488 * After applying predicate [position() > 1] :
11489 * node-set context pos
11490 * nB 1
11491 * nC 2
11492 */
11493 oldContextNode = xpctxt->node;
11494 oldContextDoc = xpctxt->doc;
11495 /*
11496 * Get the expression of this predicate.
11497 */
11498 exprOp = &ctxt->comp->steps[op->ch2];
11499 newContextSize = 0;
11500 for (i = 0; i < set->nodeNr; i++) {
11501 if (set->nodeTab[i] == NULL)
11502 continue;
11503
11504 contextNode = set->nodeTab[i];
11505 xpctxt->node = contextNode;
11506 xpctxt->contextSize = contextSize;
11507 xpctxt->proximityPosition = ++contextPos;
11508
11509 /*
11510 * Also set the xpath document in case things like
11511 * key() are evaluated in the predicate.
11512 */
11513 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11514 (contextNode->doc != NULL))
11515 xpctxt->doc = contextNode->doc;
11516 /*
11517 * Evaluate the predicate expression with 1 context node
11518 * at a time; this node is packaged into a node set; this
11519 * node set is handed over to the evaluation mechanism.
11520 */
11521 if (contextObj == NULL)
11522 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11523 else
11524 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11525 contextNode);
11526
11527 valuePush(ctxt, contextObj);
11528 xmlXPathCompOpEval(ctxt, exprOp);
11529
11530 if (ctxt->error != XPATH_EXPRESSION_OK)
11531 goto evaluation_error;
11532
11533 exprRes = valuePop(ctxt);
11534 /*
11535 * This checks if the result of the evaluation is 'true'.
11536 */
11537 if (! xmlXPathEvaluatePredicateResult(ctxt, exprRes)) {
11538 /*
11539 * Remove the entry from the initial node set.
11540 */
11541 set->nodeTab[i] = NULL;
11542 if (contextNode->type == XML_NAMESPACE_DECL)
11543 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11544 } else
11545 newContextSize++;
11546
11547 if (exprRes != NULL) {
11548 xmlXPathReleaseObject(ctxt->context, exprRes);
11549 exprRes = NULL;
11550 }
11551 if (ctxt->value == contextObj) {
11552 /*
11553 * Don't free the temporary XPath object holding the
11554 * context node, in order to avoid massive recreation
11555 * inside this loop.
11556 */
11557 valuePop(ctxt);
11558 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11559 } else {
11560 /*
11561 * TODO: The object was lost in the evaluation machinery.
11562 * Can this happen? Maybe in internal-error cases.
11563 */
11564 contextObj = NULL;
11565 }
11566 }
11567 goto evaluation_exit;
11568
11569evaluation_error:
11570 xmlXPathNodeSetClear(set, hasNsNodes);
11571 newContextSize = 0;
11572
11573evaluation_exit:
11574 if (contextObj != NULL) {
11575 if (ctxt->value == contextObj)
11576 valuePop(ctxt);
11577 xmlXPathReleaseObject(xpctxt, contextObj);
11578 }
11579 if (exprRes != NULL)
11580 xmlXPathReleaseObject(ctxt->context, exprRes);
11581 /*
11582 * Reset/invalidate the context.
11583 */
11584 xpctxt->node = oldContextNode;
11585 xpctxt->doc = oldContextDoc;
11586 xpctxt->contextSize = -1;
11587 xpctxt->proximityPosition = -1;
11588 return(newContextSize);
11589 }
11590 return(contextSize);
11591}
11592
11593static int
11594xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11595 xmlXPathStepOpPtr op,
11596 xmlNodeSetPtr set,
11597 int contextSize,
11598 int minPos,
11599 int maxPos,
11600 int hasNsNodes)
11601{
11602 if (op->ch1 != -1) {
11603 xmlXPathCompExprPtr comp = ctxt->comp;
11604 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11605 /*
11606 * TODO: raise an internal error.
11607 */
11608 }
11609 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11610 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11611 CHECK_ERROR0;
11612 if (contextSize <= 0)
11613 return(0);
11614 }
11615 /*
11616 * Check if the node set contains a sufficient number of nodes for
11617 * the requested range.
11618 */
11619 if (contextSize < minPos) {
11620 xmlXPathNodeSetClear(set, hasNsNodes);
11621 return(0);
11622 }
11623 if (op->ch2 == -1) {
11624 /*
11625 * TODO: Can this ever happen?
11626 */
11627 return (contextSize);
11628 } else {
11629 xmlDocPtr oldContextDoc;
11630 int i, pos = 0, newContextSize = 0, contextPos = 0, isTrue;
11631 xmlXPathStepOpPtr exprOp;
11632 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11633 xmlNodePtr oldContextNode, contextNode = NULL;
11634 xmlXPathContextPtr xpctxt = ctxt->context;
11635
11636#ifdef LIBXML_XPTR_ENABLED
11637 /*
11638 * URGENT TODO: Check the following:
11639 * We don't expect location sets if evaluating prediates, right?
11640 * Only filters should expect location sets, right?
11641 */
11642#endif /* LIBXML_XPTR_ENABLED */
11643
11644 /*
11645 * Save old context.
11646 */
11647 oldContextNode = xpctxt->node;
11648 oldContextDoc = xpctxt->doc;
11649 /*
11650 * Get the expression of this predicate.
11651 */
11652 exprOp = &ctxt->comp->steps[op->ch2];
11653 for (i = 0; i < set->nodeNr; i++) {
11654 if (set->nodeTab[i] == NULL)
11655 continue;
11656
11657 contextNode = set->nodeTab[i];
11658 xpctxt->node = contextNode;
11659 xpctxt->contextSize = contextSize;
11660 xpctxt->proximityPosition = ++contextPos;
11661
11662 /*
11663 * Initialize the new set.
11664 * Also set the xpath document in case things like
11665 * key() evaluation are attempted on the predicate
11666 */
11667 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11668 (contextNode->doc != NULL))
11669 xpctxt->doc = contextNode->doc;
11670 /*
11671 * Evaluate the predicate expression with 1 context node
11672 * at a time; this node is packaged into a node set; this
11673 * node set is handed over to the evaluation mechanism.
11674 */
11675 if (contextObj == NULL)
11676 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11677 else
11678 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11679 contextNode);
11680
11681 valuePush(ctxt, contextObj);
11682 xmlXPathCompOpEval(ctxt, exprOp);
11683
11684 if (ctxt->error != XPATH_EXPRESSION_OK)
11685 goto evaluation_error;
11686 /*
11687 * The result of the evaluation needs to be tested to
11688 * decide whether the filter succeeded or not
11689 */
11690 exprRes = valuePop(ctxt);
11691 /*
11692 * This checks if the result of the evaluate is 'true'.
11693 */
11694 if (xmlXPathEvaluatePredicateResult(ctxt, exprRes)) {
11695 pos++;
11696 isTrue = 1;
11697 } else
11698 isTrue = 0;
11699 if (isTrue && (pos >= minPos) && (pos <= maxPos)) {
11700 /*
11701 * Fits in the requested range.
11702 */
11703 newContextSize++;
11704 if (minPos == maxPos) {
11705 /*
11706 * Only 1 node was requested.
11707 */
11708 if (contextNode->type == XML_NAMESPACE_DECL) {
11709 /*
11710 * As always: take care of those nasty
11711 * namespace nodes.
11712 */
11713 set->nodeTab[i] = NULL;
11714 }
11715 xmlXPathNodeSetClear(set, hasNsNodes);
11716 set->nodeNr = 1;
11717 set->nodeTab[0] = contextNode;
11718 goto evaluation_exit;
11719 }
11720 if (pos == maxPos) {
11721 /*
11722 * We are done.
11723 */
11724 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11725 goto evaluation_exit;
11726 }
11727 } else {
11728 /*
11729 * Remove the entry from the initial node set.
11730 */
11731 set->nodeTab[i] = NULL;
11732 if (contextNode->type == XML_NAMESPACE_DECL)
11733 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11734 }
11735 if (exprRes != NULL) {
11736 xmlXPathReleaseObject(ctxt->context, exprRes);
11737 exprRes = NULL;
11738 }
11739 if (ctxt->value == contextObj) {
11740 /*
11741 * Don't free the temporary XPath object holding the
11742 * context node, in order to avoid massive recreation
11743 * inside this loop.
11744 */
11745 valuePop(ctxt);
11746 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11747 } else {
11748 /*
11749 * The object was lost in the evaluation machinery.
11750 * Can this happen? Maybe in case of internal-errors.
11751 */
11752 contextObj = NULL;
11753 }
11754 }
11755 goto evaluation_exit;
11756
11757evaluation_error:
11758 xmlXPathNodeSetClear(set, hasNsNodes);
11759 newContextSize = 0;
11760
11761evaluation_exit:
11762 if (contextObj != NULL) {
11763 if (ctxt->value == contextObj)
11764 valuePop(ctxt);
11765 xmlXPathReleaseObject(xpctxt, contextObj);
11766 }
11767 if (exprRes != NULL)
11768 xmlXPathReleaseObject(ctxt->context, exprRes);
11769 /*
11770 * Reset/invalidate the context.
11771 */
11772 xpctxt->node = oldContextNode;
11773 xpctxt->doc = oldContextDoc;
11774 xpctxt->contextSize = -1;
11775 xpctxt->proximityPosition = -1;
11776 return(newContextSize);
11777 }
11778 return(contextSize);
11779}
11780
11781static int
11782xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11783 xmlXPathStepOpPtr op,
11784 int *maxPos)
11785{
11786
11787 xmlXPathStepOpPtr exprOp;
11788
11789 /*
11790 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11791 */
11792
11793 /*
11794 * If not -1, then ch1 will point to:
11795 * 1) For predicates (XPATH_OP_PREDICATE):
11796 * - an inner predicate operator
11797 * 2) For filters (XPATH_OP_FILTER):
11798 * - an inner filter operater OR
11799 * - an expression selecting the node set.
11800 * E.g. "key('a', 'b')" or "(//foo | //bar)".
11801 */
11802 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11803 return(0);
11804
11805 if (op->ch2 != -1) {
11806 exprOp = &ctxt->comp->steps[op->ch2];
11807 } else
11808 return(0);
11809
11810 if ((exprOp != NULL) &&
11811 (exprOp->op == XPATH_OP_VALUE) &&
11812 (exprOp->value4 != NULL) &&
11813 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11814 {
11815 /*
11816 * We have a "[n]" predicate here.
11817 * TODO: Unfortunately this simplistic test here is not
11818 * able to detect a position() predicate in compound
11819 * expressions like "[@attr = 'a" and position() = 1],
11820 * and even not the usage of position() in
11821 * "[position() = 1]"; thus - obviously - a position-range,
11822 * like it "[position() < 5]", is also not detected.
11823 * Maybe we could rewrite the AST to ease the optimization.
11824 */
11825 *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11826
11827 if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
11828 (float) *maxPos)
11829 {
11830 return(1);
11831 }
11832 }
11833 return(0);
11834}
11835
11836static int
11837xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11838 xmlXPathStepOpPtr op,
11839 xmlNodePtr * first, xmlNodePtr * last)
11840{
11841
11842#define XP_TEST_HIT \
11843 if (hasAxisRange != 0) { \
11844 if (++pos == maxPos) { \
11845 addNode(seq, cur); \
11846 goto axis_range_end; } \
11847 } else addNode(seq, cur);
11848
11849#define XP_TEST_HIT_NS \
11850 if (hasAxisRange != 0) { \
11851 if (++pos == maxPos) { \
11852 hasNsNodes = 1; \
11853 xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
11854 goto axis_range_end; } \
11855 } else { \
11856 hasNsNodes = 1; \
11857 xmlXPathNodeSetAddNs(seq, \
11858 xpctxt->node, (xmlNsPtr) cur); }
11859
11860 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11861 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11862 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11863 const xmlChar *prefix = op->value4;
11864 const xmlChar *name = op->value5;
11865 const xmlChar *URI = NULL;
11866
11867#ifdef DEBUG_STEP
11868 int nbMatches = 0, prevMatches = 0;
11869#endif
11870 int total = 0, hasNsNodes = 0;
11871 /* The popped object holding the context nodes */
11872 xmlXPathObjectPtr obj;
11873 /* The set of context nodes for the node tests */
11874 xmlNodeSetPtr contextSeq;
11875 int contextIdx;
11876 xmlNodePtr contextNode;
11877 /* The context node for a compound traversal */
11878 xmlNodePtr outerContextNode;
11879 /* The final resulting node set wrt to all context nodes */
11880 xmlNodeSetPtr outSeq;
11881 /*
11882 * The temporary resulting node set wrt 1 context node.
11883 * Used to feed predicate evaluation.
11884 */
11885 xmlNodeSetPtr seq;
11886 xmlNodePtr cur;
11887 /* First predicate operator */
11888 xmlXPathStepOpPtr predOp;
11889 int maxPos; /* The requested position() (when a "[n]" predicate) */
11890 int hasPredicateRange, hasAxisRange, pos, size, newSize;
11891
11892 xmlXPathTraversalFunction next = NULL;
11893 /* compound axis traversal */
11894 xmlXPathTraversalFunctionExt outerNext = NULL;
11895 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
11896 xmlXPathNodeSetMergeFunction mergeAndClear;
11897 xmlNodePtr oldContextNode;
11898 xmlXPathContextPtr xpctxt = ctxt->context;
11899
11900
11901 CHECK_TYPE0(XPATH_NODESET);
11902 obj = valuePop(ctxt);
11903 /*
11904 * Setup namespaces.
11905 */
11906 if (prefix != NULL) {
11907 URI = xmlXPathNsLookup(xpctxt, prefix);
11908 if (URI == NULL) {
11909 xmlXPathReleaseObject(xpctxt, obj);
11910 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11911 }
11912 }
11913 /*
11914 * Setup axis.
11915 *
11916 * MAYBE FUTURE TODO: merging optimizations:
11917 * - If the nodes to be traversed wrt to the initial nodes and
11918 * the current axis cannot overlap, then we could avoid searching
11919 * for duplicates during the merge.
11920 * But the question is how/when to evaluate if they cannot overlap.
11921 * Example: if we know that for two initial nodes, the one is
11922 * not in the ancestor-or-self axis of the other, then we could safely
11923 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
11924 * the descendant-or-self axis.
11925 */
11926 addNode = xmlXPathNodeSetAdd;
11927 mergeAndClear = xmlXPathNodeSetMergeAndClear;
11928 switch (axis) {
11929 case AXIS_ANCESTOR:
11930 first = NULL;
11931 next = xmlXPathNextAncestor;
11932 break;
11933 case AXIS_ANCESTOR_OR_SELF:
11934 first = NULL;
11935 next = xmlXPathNextAncestorOrSelf;
11936 break;
11937 case AXIS_ATTRIBUTE:
11938 first = NULL;
11939 last = NULL;
11940 next = xmlXPathNextAttribute;
11941 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11942 break;
11943 case AXIS_CHILD:
11944 last = NULL;
11945 if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
11946 /*
11947 * This iterator will give us only nodes which can
11948 * hold element nodes.
11949 */
11950 outerNext = xmlXPathNextDescendantOrSelfElemParent;
11951 }
11952 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
11953 (type == NODE_TYPE_NODE))
11954 {
11955 /*
11956 * Optimization if an element node type is 'element'.
11957 */
11958 next = xmlXPathNextChildElement;
11959 } else
11960 next = xmlXPathNextChild;
11961 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11962 break;
11963 case AXIS_DESCENDANT:
11964 last = NULL;
11965 next = xmlXPathNextDescendant;
11966 break;
11967 case AXIS_DESCENDANT_OR_SELF:
11968 last = NULL;
11969 next = xmlXPathNextDescendantOrSelf;
11970 break;
11971 case AXIS_FOLLOWING:
11972 last = NULL;
11973 next = xmlXPathNextFollowing;
11974 break;
11975 case AXIS_FOLLOWING_SIBLING:
11976 last = NULL;
11977 next = xmlXPathNextFollowingSibling;
11978 break;
11979 case AXIS_NAMESPACE:
11980 first = NULL;
11981 last = NULL;
11982 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
11983 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11984 break;
11985 case AXIS_PARENT:
11986 first = NULL;
11987 next = xmlXPathNextParent;
11988 break;
11989 case AXIS_PRECEDING:
11990 first = NULL;
11991 next = xmlXPathNextPrecedingInternal;
11992 break;
11993 case AXIS_PRECEDING_SIBLING:
11994 first = NULL;
11995 next = xmlXPathNextPrecedingSibling;
11996 break;
11997 case AXIS_SELF:
11998 first = NULL;
11999 last = NULL;
12000 next = xmlXPathNextSelf;
12001 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12002 break;
12003 }
12004
12005#ifdef DEBUG_STEP
12006 xmlXPathDebugDumpStepAxis(axis, test,
12007 (obj->nodesetval != NULL) ? obj->nodsetval->nodeNr : 0);
12008#endif
12009
12010 if (next == NULL) {
12011 xmlXPathReleaseObject(xpctxt, obj);
12012 return(0);
12013 }
12014 contextSeq = obj->nodesetval;
12015 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12016 xmlXPathReleaseObject(xpctxt, obj);
12017 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12018 return(0);
12019 }
12020 /*
12021 * Predicate optimization ---------------------------------------------
12022 * If this step has a last predicate, which contains a position(),
12023 * then we'll optimize (although not exactly "position()", but only
12024 * the short-hand form, i.e., "[n]".
12025 *
12026 * Example - expression "/foo[parent::bar][1]":
12027 *
12028 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12029 * ROOT -- op->ch1
12030 * PREDICATE -- op->ch2 (predOp)
12031 * PREDICATE -- predOp->ch1 = [parent::bar]
12032 * SORT
12033 * COLLECT 'parent' 'name' 'node' bar
12034 * NODE
12035 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12036 *
12037 */
12038 maxPos = 0;
12039 predOp = NULL;
12040 hasPredicateRange = 0;
12041 hasAxisRange = 0;
12042 if (op->ch2 != -1) {
12043 /*
12044 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12045 */
12046 predOp = &ctxt->comp->steps[op->ch2];
12047 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12048 if (predOp->ch1 != -1) {
12049 /*
12050 * Use the next inner predicate operator.
12051 */
12052 predOp = &ctxt->comp->steps[predOp->ch1];
12053 hasPredicateRange = 1;
12054 } else {
12055 /*
12056 * There's no other predicate than the [n] predicate.
12057 */
12058 predOp = NULL;
12059 hasAxisRange = 1;
12060 }
12061 }
12062 }
12063 /*
12064 * Axis traversal -----------------------------------------------------
12065 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012066 /*
12067 * 2.3 Node Tests
12068 * - For the attribute axis, the principal node type is attribute.
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012069 * - For the namespace axis, the principal node type is namespace.
12070 * - For other axes, the principal node type is element.
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012071 *
12072 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012073 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012074 * select all element children of the context node
12075 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012076 oldContextNode = xpctxt->node;
12077 addNode = xmlXPathNodeSetAddUnique;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012078 outSeq = NULL;
12079 seq = NULL;
12080 outerContextNode = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012081 contextNode = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012082 contextIdx = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012083
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012084
12085 while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
12086 if (outerNext != NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012087 /*
12088 * This is a compound traversal.
12089 */
12090 if (contextNode == NULL) {
12091 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012092 * Set the context for the outer traversal.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012093 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012094 outerContextNode = contextSeq->nodeTab[contextIdx++];
12095 contextNode = outerNext(NULL, outerContextNode);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012096 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012097 contextNode = outerNext(contextNode, outerContextNode);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012098 if (contextNode == NULL)
12099 continue;
12100 /*
12101 * Set the context for the main traversal.
12102 */
12103 xpctxt->node = contextNode;
12104 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012105 xpctxt->node = contextSeq->nodeTab[contextIdx++];
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012106
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012107 if (seq == NULL) {
12108 seq = xmlXPathNodeSetCreate(NULL);
12109 if (seq == NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012110 total = 0;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012111 goto error;
12112 }
12113 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012114 /*
12115 * Traverse the axis and test the nodes.
12116 */
12117 pos = 0;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012118 cur = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012119 hasNsNodes = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012120 do {
12121 cur = next(ctxt, cur);
12122 if (cur == NULL)
12123 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012124
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012125 /*
12126 * QUESTION TODO: What does the "first" and "last" stuff do?
12127 */
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012128 if (first != NULL) {
12129 if (*first == cur)
12130 break;
12131 if ((*first != NULL) &&
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012132 ((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012133#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012134 (xmlXPathCmpNodesExt(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012135#else
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012136 (xmlXPathCmpNodes(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012137#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012138 {
12139 break;
12140 }
12141 }
12142 if (last != NULL) {
12143 if (*last == cur)
12144 break;
12145 if ((*last != NULL) &&
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012146 ((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012147#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012148 (xmlXPathCmpNodesExt(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012149#else
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012150 (xmlXPathCmpNodes(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012151#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012152 {
12153 break;
12154 }
12155 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012156
12157 total++;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012158
Daniel Veillardf06307e2001-07-03 10:35:50 +000012159#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012160 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12161#endif
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012162 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012163 case NODE_TEST_NONE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012164 total = 0;
12165 STRANGE
12166 goto error;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012167 case NODE_TEST_TYPE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012168 /*
12169 * TODO: Don't we need to use
12170 * xmlXPathNodeSetAddNs() for namespace nodes here?
12171 * Surprisingly, some c14n tests fail, if we do this.
12172 */
12173 if (type == NODE_TYPE_NODE) {
12174 switch (cur->type) {
12175 case XML_DOCUMENT_NODE:
12176 case XML_HTML_DOCUMENT_NODE:
12177#ifdef LIBXML_DOCB_ENABLED
12178 case XML_DOCB_DOCUMENT_NODE:
12179#endif
12180 case XML_ELEMENT_NODE:
12181 case XML_ATTRIBUTE_NODE:
12182 case XML_PI_NODE:
12183 case XML_COMMENT_NODE:
12184 case XML_CDATA_SECTION_NODE:
12185 case XML_TEXT_NODE:
12186 case XML_NAMESPACE_DECL:
12187 XP_TEST_HIT
12188 break;
12189 default:
12190 break;
12191 }
12192 } else if (cur->type == type) {
12193 XP_TEST_HIT
12194 } else if ((type == NODE_TYPE_TEXT) &&
12195 (cur->type == XML_CDATA_SECTION_NODE))
12196 {
12197 XP_TEST_HIT
12198 }
12199 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012200 case NODE_TEST_PI:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012201 if ((cur->type == XML_PI_NODE) &&
12202 ((name == NULL) || xmlStrEqual(name, cur->name)))
12203 {
12204 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012205 }
12206 break;
12207 case NODE_TEST_ALL:
12208 if (axis == AXIS_ATTRIBUTE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012209 if (cur->type == XML_ATTRIBUTE_NODE)
12210 {
12211 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012212 }
12213 } else if (axis == AXIS_NAMESPACE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012214 if (cur->type == XML_NAMESPACE_DECL)
12215 {
12216 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012217 }
12218 } else {
12219 if (cur->type == XML_ELEMENT_NODE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012220 if (prefix == NULL)
12221 {
12222 XP_TEST_HIT
12223
Daniel Veillardf06307e2001-07-03 10:35:50 +000012224 } else if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012225 (xmlStrEqual(URI, cur->ns->href)))
12226 {
12227 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012228 }
12229 }
12230 }
12231 break;
12232 case NODE_TEST_NS:{
12233 TODO;
12234 break;
12235 }
12236 case NODE_TEST_NAME:
12237 switch (cur->type) {
12238 case XML_ELEMENT_NODE:
12239 if (xmlStrEqual(name, cur->name)) {
12240 if (prefix == NULL) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012241 if (cur->ns == NULL)
12242 {
12243 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012244 }
12245 } else {
12246 if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012247 (xmlStrEqual(URI, cur->ns->href)))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012248 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012249 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012250 }
12251 }
12252 }
12253 break;
12254 case XML_ATTRIBUTE_NODE:{
12255 xmlAttrPtr attr = (xmlAttrPtr) cur;
12256
12257 if (xmlStrEqual(name, attr->name)) {
12258 if (prefix == NULL) {
12259 if ((attr->ns == NULL) ||
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012260 (attr->ns->prefix == NULL))
12261 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012262 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012263 }
12264 } else {
12265 if ((attr->ns != NULL) &&
12266 (xmlStrEqual(URI,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012267 attr->ns->href)))
12268 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012269 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012270 }
12271 }
12272 }
12273 break;
12274 }
12275 case XML_NAMESPACE_DECL:
12276 if (cur->type == XML_NAMESPACE_DECL) {
12277 xmlNsPtr ns = (xmlNsPtr) cur;
12278
12279 if ((ns->prefix != NULL) && (name != NULL)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012280 && (xmlStrEqual(ns->prefix, name)))
12281 {
12282 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012283 }
12284 }
12285 break;
12286 default:
12287 break;
12288 }
12289 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012290 } /* switch(test) */
12291 } while (cur != NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012292
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012293 goto apply_predicates;
12294
12295axis_range_end: /* ----------------------------------------------------- */
12296
12297 /*
12298 * We have a "/foo[n]", and position() = n was reached.
12299 * Note that we can have as well "/foo/::parent::foo[1]", so
12300 * a duplicate-aware merge is still needed.
12301 * Merge with the result.
12302 */
12303 if (outSeq == NULL) {
12304 outSeq = seq;
12305 seq = NULL;
12306 } else
12307 outSeq = mergeAndClear(outSeq, seq, 0);
12308 continue;
12309
12310#ifdef DEBUG_STEP
12311 if (seq != NULL)
12312 nbMatches += seq->nodeNr;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012313#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012314
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012315apply_predicates: /* --------------------------------------------------- */
12316 /*
12317 * Apply predicates.
12318 */
12319 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12320 /*
12321 * E.g. when we have a "/foo[some expression][n]".
12322 */
12323 /*
12324 * QUESTION TODO: The old predicate evaluation took into
12325 * account location-sets.
12326 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12327 * Do we expect such a set here?
12328 * All what I learned now from the evaluation semantics
12329 * does not indicate that a location-set will be processed
12330 * here, so this looks OK.
12331 */
12332 /*
12333 * Iterate over all predicates, starting with the outermost
12334 * predicate.
12335 * TODO: Problem: we cannot execute the inner predicates first
12336 * since we cannot go back *up* the operator tree!
12337 * Options we have:
12338 * 1) Use of recursive functions (like is it currently done
12339 * via xmlXPathCompOpEval())
12340 * 2) Add a predicate evaluation information stack to the
12341 * context struct
12342 * 3) Change the way the operators are linked; we need a
12343 * "parent" field on xmlXPathStepOp
12344 *
12345 * For the moment, I'll try to solve this with a recursive
12346 * function: xmlXPathCompOpEvalPredicate().
12347 */
12348 size = seq->nodeNr;
12349 if (hasPredicateRange != 0)
12350 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12351 predOp, seq, size, maxPos, maxPos, hasNsNodes);
12352 else
12353 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12354 predOp, seq, size, hasNsNodes);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012355
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012356 if (ctxt->error != XPATH_EXPRESSION_OK) {
12357 total = 0;
12358 goto error;
12359 }
12360 /*
12361 * Add the filtered set of nodes to the result node set.
12362 */
12363 if (newSize == 0) {
12364 /*
12365 * The predicates filtered all nodes out.
12366 */
12367 xmlXPathNodeSetClear(seq, hasNsNodes);
12368 } else if (seq->nodeNr > 0) {
12369 /*
12370 * Add to result set.
12371 */
12372 if (outSeq == NULL) {
12373 if (size != newSize) {
12374 /*
12375 * We need to merge and clear here, since
12376 * the sequence will contained NULLed entries.
12377 */
12378 outSeq = mergeAndClear(NULL, seq, 1);
12379 } else {
12380 outSeq = seq;
12381 seq = NULL;
12382 }
12383 } else
12384 outSeq = mergeAndClear(outSeq, seq,
12385 (size != newSize) ? 1: 0);
12386 }
12387 } else if (seq->nodeNr > 0) {
12388 /*
12389 * Add to result set.
12390 */
12391 if (outSeq == NULL) {
12392 outSeq = seq;
12393 seq = NULL;
12394 } else {
12395 outSeq = mergeAndClear(outSeq, seq, 0);
12396 }
12397 }
12398 }
12399
12400error:
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012401 if ((obj->boolval) && (obj->user != NULL)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012402 /*
12403 * QUESTION TODO: What does this do and why?
12404 * TODO: Do we have to do this also for the "error"
12405 * cleanup further down?
12406 */
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012407 ctxt->value->boolval = 1;
12408 ctxt->value->user = obj->user;
12409 obj->user = NULL;
12410 obj->boolval = 0;
12411 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012412 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012413
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012414 /*
12415 * Ensure we return at least an emtpy set.
12416 */
12417 if (outSeq == NULL) {
12418 if ((seq != NULL) && (seq->nodeNr == 0))
12419 outSeq = seq;
12420 else
12421 outSeq = xmlXPathNodeSetCreate(NULL);
12422 }
12423 if ((seq != NULL) && (seq != outSeq)) {
12424 xmlXPathFreeNodeSet(seq);
12425 }
12426 /*
12427 * Hand over the result. Better to push the set also in
12428 * case of errors.
12429 */
12430 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12431 /*
12432 * Reset the context node.
12433 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012434 xpctxt->node = oldContextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012435
12436#ifdef DEBUG_STEP
12437 xmlGenericError(xmlGenericErrorContext,
12438 "\nExamined %d nodes, found %d nodes at that step\n",
12439 total, nbMatches);
12440#endif
12441
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012442 return(total);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012443}
12444
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012445static int
12446xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12447 xmlXPathStepOpPtr op, xmlNodePtr * first);
12448
Daniel Veillardf06307e2001-07-03 10:35:50 +000012449/**
12450 * xmlXPathCompOpEvalFirst:
12451 * @ctxt: the XPath parser context with the compiled expression
12452 * @op: an XPath compiled operation
12453 * @first: the first elem found so far
12454 *
12455 * Evaluate the Precompiled XPath operation searching only the first
12456 * element in document order
12457 *
12458 * Returns the number of examined objects.
12459 */
12460static int
12461xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12462 xmlXPathStepOpPtr op, xmlNodePtr * first)
12463{
12464 int total = 0, cur;
12465 xmlXPathCompExprPtr comp;
12466 xmlXPathObjectPtr arg1, arg2;
12467
Daniel Veillard556c6682001-10-06 09:59:51 +000012468 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012469 comp = ctxt->comp;
12470 switch (op->op) {
12471 case XPATH_OP_END:
12472 return (0);
12473 case XPATH_OP_UNION:
12474 total =
12475 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12476 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012477 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012478 if ((ctxt->value != NULL)
12479 && (ctxt->value->type == XPATH_NODESET)
12480 && (ctxt->value->nodesetval != NULL)
12481 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12482 /*
12483 * limit tree traversing to first node in the result
12484 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012485 /*
12486 * OPTIMIZE TODO: This implicitely sorts
12487 * the result, even if not needed. E.g. if the argument
12488 * of the count() function, no sorting is needed.
12489 * OPTIMIZE TODO: How do we know if the node-list wasn't
12490 * aready sorted?
12491 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012492 if (ctxt->value->nodesetval->nodeNr > 1)
12493 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012494 *first = ctxt->value->nodesetval->nodeTab[0];
12495 }
12496 cur =
12497 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12498 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012499 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012500 CHECK_TYPE0(XPATH_NODESET);
12501 arg2 = valuePop(ctxt);
12502
12503 CHECK_TYPE0(XPATH_NODESET);
12504 arg1 = valuePop(ctxt);
12505
12506 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12507 arg2->nodesetval);
12508 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012509 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012510 /* optimizer */
12511 if (total > cur)
12512 xmlXPathCompSwap(op);
12513 return (total + cur);
12514 case XPATH_OP_ROOT:
12515 xmlXPathRoot(ctxt);
12516 return (0);
12517 case XPATH_OP_NODE:
12518 if (op->ch1 != -1)
12519 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012520 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012521 if (op->ch2 != -1)
12522 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012523 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012524 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12525 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012526 return (total);
12527 case XPATH_OP_RESET:
12528 if (op->ch1 != -1)
12529 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012530 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012531 if (op->ch2 != -1)
12532 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012533 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012534 ctxt->context->node = NULL;
12535 return (total);
12536 case XPATH_OP_COLLECT:{
12537 if (op->ch1 == -1)
12538 return (total);
12539
12540 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012541 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012542
Daniel Veillardf06307e2001-07-03 10:35:50 +000012543 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
12544 return (total);
12545 }
12546 case XPATH_OP_VALUE:
12547 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012548 xmlXPathCacheObjectCopy(ctxt->context,
12549 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012550 return (0);
12551 case XPATH_OP_SORT:
12552 if (op->ch1 != -1)
12553 total +=
12554 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12555 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012556 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012557 if ((ctxt->value != NULL)
12558 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012559 && (ctxt->value->nodesetval != NULL)
12560 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012561 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12562 return (total);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012563#ifdef XP_OPTIMIZED_FILTER_FIRST
12564 case XPATH_OP_FILTER:
12565 total =+ xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12566 return (total);
12567#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000012568 default:
12569 return (xmlXPathCompOpEval(ctxt, op));
12570 }
12571}
12572
12573/**
12574 * xmlXPathCompOpEvalLast:
12575 * @ctxt: the XPath parser context with the compiled expression
12576 * @op: an XPath compiled operation
12577 * @last: the last elem found so far
12578 *
12579 * Evaluate the Precompiled XPath operation searching only the last
12580 * element in document order
12581 *
William M. Brack08171912003-12-29 02:52:11 +000012582 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000012583 */
12584static int
12585xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12586 xmlNodePtr * last)
12587{
12588 int total = 0, cur;
12589 xmlXPathCompExprPtr comp;
12590 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +000012591 xmlNodePtr bak;
12592 xmlDocPtr bakd;
12593 int pp;
12594 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012595
Daniel Veillard556c6682001-10-06 09:59:51 +000012596 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012597 comp = ctxt->comp;
12598 switch (op->op) {
12599 case XPATH_OP_END:
12600 return (0);
12601 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +000012602 bakd = ctxt->context->doc;
12603 bak = ctxt->context->node;
12604 pp = ctxt->context->proximityPosition;
12605 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012606 total =
12607 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012608 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012609 if ((ctxt->value != NULL)
12610 && (ctxt->value->type == XPATH_NODESET)
12611 && (ctxt->value->nodesetval != NULL)
12612 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12613 /*
12614 * limit tree traversing to first node in the result
12615 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012616 if (ctxt->value->nodesetval->nodeNr > 1)
12617 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012618 *last =
12619 ctxt->value->nodesetval->nodeTab[ctxt->value->
12620 nodesetval->nodeNr -
12621 1];
12622 }
William M. Brackce4fc562004-01-22 02:47:18 +000012623 ctxt->context->doc = bakd;
12624 ctxt->context->node = bak;
12625 ctxt->context->proximityPosition = pp;
12626 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012627 cur =
12628 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012629 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012630 if ((ctxt->value != NULL)
12631 && (ctxt->value->type == XPATH_NODESET)
12632 && (ctxt->value->nodesetval != NULL)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012633 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012634 }
12635 CHECK_TYPE0(XPATH_NODESET);
12636 arg2 = valuePop(ctxt);
12637
12638 CHECK_TYPE0(XPATH_NODESET);
12639 arg1 = valuePop(ctxt);
12640
12641 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12642 arg2->nodesetval);
12643 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012644 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012645 /* optimizer */
12646 if (total > cur)
12647 xmlXPathCompSwap(op);
12648 return (total + cur);
12649 case XPATH_OP_ROOT:
12650 xmlXPathRoot(ctxt);
12651 return (0);
12652 case XPATH_OP_NODE:
12653 if (op->ch1 != -1)
12654 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012655 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012656 if (op->ch2 != -1)
12657 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012658 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012659 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12660 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012661 return (total);
12662 case XPATH_OP_RESET:
12663 if (op->ch1 != -1)
12664 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012665 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012666 if (op->ch2 != -1)
12667 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012668 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012669 ctxt->context->node = NULL;
12670 return (total);
12671 case XPATH_OP_COLLECT:{
12672 if (op->ch1 == -1)
12673 return (0);
12674
12675 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012676 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012677
Daniel Veillardf06307e2001-07-03 10:35:50 +000012678 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
12679 return (total);
12680 }
12681 case XPATH_OP_VALUE:
12682 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012683 xmlXPathCacheObjectCopy(ctxt->context,
12684 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012685 return (0);
12686 case XPATH_OP_SORT:
12687 if (op->ch1 != -1)
12688 total +=
12689 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12690 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012691 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012692 if ((ctxt->value != NULL)
12693 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012694 && (ctxt->value->nodesetval != NULL)
12695 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012696 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12697 return (total);
12698 default:
12699 return (xmlXPathCompOpEval(ctxt, op));
12700 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012701}
12702
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012703#ifdef XP_OPTIMIZED_FILTER_FIRST
12704static int
12705xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12706 xmlXPathStepOpPtr op, xmlNodePtr * first)
12707{
12708 int total = 0;
12709 xmlXPathCompExprPtr comp;
12710 xmlXPathObjectPtr res;
12711 xmlXPathObjectPtr obj;
12712 xmlNodeSetPtr oldset;
12713 xmlNodePtr oldnode;
12714 xmlDocPtr oldDoc;
12715 int i;
12716
12717 CHECK_ERROR0;
12718 comp = ctxt->comp;
12719 /*
12720 * Optimization for ()[last()] selection i.e. the last elem
12721 */
12722 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12723 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12724 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12725 int f = comp->steps[op->ch2].ch1;
12726
12727 if ((f != -1) &&
12728 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12729 (comp->steps[f].value5 == NULL) &&
12730 (comp->steps[f].value == 0) &&
12731 (comp->steps[f].value4 != NULL) &&
12732 (xmlStrEqual
12733 (comp->steps[f].value4, BAD_CAST "last"))) {
12734 xmlNodePtr last = NULL;
12735
12736 total +=
12737 xmlXPathCompOpEvalLast(ctxt,
12738 &comp->steps[op->ch1],
12739 &last);
12740 CHECK_ERROR0;
12741 /*
12742 * The nodeset should be in document order,
12743 * Keep only the last value
12744 */
12745 if ((ctxt->value != NULL) &&
12746 (ctxt->value->type == XPATH_NODESET) &&
12747 (ctxt->value->nodesetval != NULL) &&
12748 (ctxt->value->nodesetval->nodeTab != NULL) &&
12749 (ctxt->value->nodesetval->nodeNr > 1)) {
12750 ctxt->value->nodesetval->nodeTab[0] =
12751 ctxt->value->nodesetval->nodeTab[ctxt->
12752 value->
12753 nodesetval->
12754 nodeNr -
12755 1];
12756 ctxt->value->nodesetval->nodeNr = 1;
12757 *first = *(ctxt->value->nodesetval->nodeTab);
12758 }
12759 return (total);
12760 }
12761 }
12762
12763 if (op->ch1 != -1)
12764 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12765 CHECK_ERROR0;
12766 if (op->ch2 == -1)
12767 return (total);
12768 if (ctxt->value == NULL)
12769 return (total);
12770
12771#ifdef LIBXML_XPTR_ENABLED
12772 oldnode = ctxt->context->node;
12773 /*
12774 * Hum are we filtering the result of an XPointer expression
12775 */
12776 if (ctxt->value->type == XPATH_LOCATIONSET) {
12777 xmlXPathObjectPtr tmp = NULL;
12778 xmlLocationSetPtr newlocset = NULL;
12779 xmlLocationSetPtr oldlocset;
12780
12781 /*
12782 * Extract the old locset, and then evaluate the result of the
12783 * expression for all the element in the locset. use it to grow
12784 * up a new locset.
12785 */
12786 CHECK_TYPE0(XPATH_LOCATIONSET);
12787 obj = valuePop(ctxt);
12788 oldlocset = obj->user;
12789 ctxt->context->node = NULL;
12790
12791 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12792 ctxt->context->contextSize = 0;
12793 ctxt->context->proximityPosition = 0;
12794 if (op->ch2 != -1)
12795 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12796 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012797 if (res != NULL) {
12798 xmlXPathReleaseObject(ctxt->context, res);
12799 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012800 valuePush(ctxt, obj);
12801 CHECK_ERROR0;
12802 return (total);
12803 }
12804 newlocset = xmlXPtrLocationSetCreate(NULL);
12805
12806 for (i = 0; i < oldlocset->locNr; i++) {
12807 /*
12808 * Run the evaluation with a node list made of a
12809 * single item in the nodelocset.
12810 */
12811 ctxt->context->node = oldlocset->locTab[i]->user;
12812 ctxt->context->contextSize = oldlocset->locNr;
12813 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012814 if (tmp == NULL) {
12815 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12816 ctxt->context->node);
12817 } else {
12818 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12819 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012820 }
12821 valuePush(ctxt, tmp);
12822 if (op->ch2 != -1)
12823 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12824 if (ctxt->error != XPATH_EXPRESSION_OK) {
12825 xmlXPathFreeObject(obj);
12826 return(0);
12827 }
12828 /*
12829 * The result of the evaluation need to be tested to
12830 * decided whether the filter succeeded or not
12831 */
12832 res = valuePop(ctxt);
12833 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12834 xmlXPtrLocationSetAdd(newlocset,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012835 xmlXPathCacheObjectCopy(ctxt->context,
12836 oldlocset->locTab[i]));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012837 }
12838 /*
12839 * Cleanup
12840 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012841 if (res != NULL) {
12842 xmlXPathReleaseObject(ctxt->context, res);
12843 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012844 if (ctxt->value == tmp) {
12845 valuePop(ctxt);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012846 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012847 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012848 * REVISIT TODO: Don't create a temporary nodeset
12849 * for everly iteration.
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012850 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012851 /* OLD: xmlXPathFreeObject(res); */
12852 } else
12853 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012854 ctxt->context->node = NULL;
12855 /*
12856 * Only put the first node in the result, then leave.
12857 */
12858 if (newlocset->locNr > 0) {
12859 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
12860 break;
12861 }
12862 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012863 if (tmp != NULL) {
12864 xmlXPathReleaseObject(ctxt->context, tmp);
12865 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012866 /*
12867 * The result is used as the new evaluation locset.
12868 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012869 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012870 ctxt->context->node = NULL;
12871 ctxt->context->contextSize = -1;
12872 ctxt->context->proximityPosition = -1;
12873 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12874 ctxt->context->node = oldnode;
12875 return (total);
12876 }
12877#endif /* LIBXML_XPTR_ENABLED */
12878
12879 /*
12880 * Extract the old set, and then evaluate the result of the
12881 * expression for all the element in the set. use it to grow
12882 * up a new set.
12883 */
12884 CHECK_TYPE0(XPATH_NODESET);
12885 obj = valuePop(ctxt);
12886 oldset = obj->nodesetval;
12887
12888 oldnode = ctxt->context->node;
12889 oldDoc = ctxt->context->doc;
12890 ctxt->context->node = NULL;
12891
12892 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
12893 ctxt->context->contextSize = 0;
12894 ctxt->context->proximityPosition = 0;
12895 /* QUESTION TODO: Why was this code commented out?
12896 if (op->ch2 != -1)
12897 total +=
12898 xmlXPathCompOpEval(ctxt,
12899 &comp->steps[op->ch2]);
12900 CHECK_ERROR0;
12901 res = valuePop(ctxt);
12902 if (res != NULL)
12903 xmlXPathFreeObject(res);
12904 */
12905 valuePush(ctxt, obj);
12906 ctxt->context->node = oldnode;
12907 CHECK_ERROR0;
12908 } else {
12909 xmlNodeSetPtr newset;
12910 xmlXPathObjectPtr tmp = NULL;
12911 /*
12912 * Initialize the new set.
12913 * Also set the xpath document in case things like
12914 * key() evaluation are attempted on the predicate
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012915 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012916 newset = xmlXPathNodeSetCreate(NULL);
12917
12918 for (i = 0; i < oldset->nodeNr; i++) {
12919 /*
12920 * Run the evaluation with a node list made of
12921 * a single item in the nodeset.
12922 */
12923 ctxt->context->node = oldset->nodeTab[i];
12924 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
12925 (oldset->nodeTab[i]->doc != NULL))
12926 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012927 if (tmp == NULL) {
12928 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12929 ctxt->context->node);
12930 } else {
12931 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12932 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012933 }
12934 valuePush(ctxt, tmp);
12935 ctxt->context->contextSize = oldset->nodeNr;
12936 ctxt->context->proximityPosition = i + 1;
12937 if (op->ch2 != -1)
12938 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12939 if (ctxt->error != XPATH_EXPRESSION_OK) {
12940 xmlXPathFreeNodeSet(newset);
12941 xmlXPathFreeObject(obj);
12942 return(0);
12943 }
12944 /*
12945 * The result of the evaluation needs to be tested to
12946 * decide whether the filter succeeded or not
12947 */
12948 res = valuePop(ctxt);
12949 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12950 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
12951 }
12952 /*
12953 * Cleanup
12954 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012955 if (res != NULL) {
12956 xmlXPathReleaseObject(ctxt->context, res);
12957 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012958 if (ctxt->value == tmp) {
12959 valuePop(ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012960 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012961 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012962 * in order to avoid massive recreation inside this
12963 * loop.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012964 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012965 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012966 } else
12967 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012968 ctxt->context->node = NULL;
12969 /*
12970 * Only put the first node in the result, then leave.
12971 */
12972 if (newset->nodeNr > 0) {
12973 *first = *(newset->nodeTab);
12974 break;
12975 }
12976 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012977 if (tmp != NULL) {
12978 xmlXPathReleaseObject(ctxt->context, tmp);
12979 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012980 /*
12981 * The result is used as the new evaluation set.
12982 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012983 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012984 ctxt->context->node = NULL;
12985 ctxt->context->contextSize = -1;
12986 ctxt->context->proximityPosition = -1;
12987 /* may want to move this past the '}' later */
12988 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012989 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012990 }
12991 ctxt->context->node = oldnode;
12992 return(total);
12993}
12994#endif /* XP_OPTIMIZED_FILTER_FIRST */
12995
Owen Taylor3473f882001-02-23 17:55:21 +000012996/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012997 * xmlXPathCompOpEval:
12998 * @ctxt: the XPath parser context with the compiled expression
12999 * @op: an XPath compiled operation
13000 *
13001 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000013002 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013003 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013004static int
13005xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13006{
13007 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013008 int equal, ret;
13009 xmlXPathCompExprPtr comp;
13010 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013011 xmlNodePtr bak;
13012 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000013013 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000013014 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013015
Daniel Veillard556c6682001-10-06 09:59:51 +000013016 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013017 comp = ctxt->comp;
13018 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013019 case XPATH_OP_END:
13020 return (0);
13021 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013022 bakd = ctxt->context->doc;
13023 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013024 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013025 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013026 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013027 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013028 xmlXPathBooleanFunction(ctxt, 1);
13029 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13030 return (total);
13031 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013032 ctxt->context->doc = bakd;
13033 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013034 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013035 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013036 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013037 if (ctxt->error) {
13038 xmlXPathFreeObject(arg2);
13039 return(0);
13040 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013041 xmlXPathBooleanFunction(ctxt, 1);
13042 arg1 = valuePop(ctxt);
13043 arg1->boolval &= arg2->boolval;
13044 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013045 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013046 return (total);
13047 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013048 bakd = ctxt->context->doc;
13049 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013050 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013051 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013052 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013053 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013054 xmlXPathBooleanFunction(ctxt, 1);
13055 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13056 return (total);
13057 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013058 ctxt->context->doc = bakd;
13059 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013060 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013061 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013062 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013063 if (ctxt->error) {
13064 xmlXPathFreeObject(arg2);
13065 return(0);
13066 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013067 xmlXPathBooleanFunction(ctxt, 1);
13068 arg1 = valuePop(ctxt);
13069 arg1->boolval |= arg2->boolval;
13070 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013071 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013072 return (total);
13073 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013074 bakd = ctxt->context->doc;
13075 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013076 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013077 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013078 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013079 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013080 ctxt->context->doc = bakd;
13081 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013082 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013083 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013084 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013085 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000013086 if (op->value)
13087 equal = xmlXPathEqualValues(ctxt);
13088 else
13089 equal = xmlXPathNotEqualValues(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013090 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013091 return (total);
13092 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013093 bakd = ctxt->context->doc;
13094 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013095 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013096 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013097 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013098 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013099 ctxt->context->doc = bakd;
13100 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013101 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013102 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013103 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013104 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013105 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013106 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013107 return (total);
13108 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013109 bakd = ctxt->context->doc;
13110 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013111 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013112 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013113 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013114 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013115 if (op->ch2 != -1) {
13116 ctxt->context->doc = bakd;
13117 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013118 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013119 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013120 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013121 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013122 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013123 if (op->value == 0)
13124 xmlXPathSubValues(ctxt);
13125 else if (op->value == 1)
13126 xmlXPathAddValues(ctxt);
13127 else if (op->value == 2)
13128 xmlXPathValueFlipSign(ctxt);
13129 else if (op->value == 3) {
13130 CAST_TO_NUMBER;
13131 CHECK_TYPE0(XPATH_NUMBER);
13132 }
13133 return (total);
13134 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013135 bakd = ctxt->context->doc;
13136 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013137 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013138 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013139 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013140 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013141 ctxt->context->doc = bakd;
13142 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013143 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013144 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013145 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013146 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013147 if (op->value == 0)
13148 xmlXPathMultValues(ctxt);
13149 else if (op->value == 1)
13150 xmlXPathDivValues(ctxt);
13151 else if (op->value == 2)
13152 xmlXPathModValues(ctxt);
13153 return (total);
13154 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013155 bakd = ctxt->context->doc;
13156 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013157 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013158 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013159 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013160 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013161 ctxt->context->doc = bakd;
13162 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013163 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013164 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013165 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013166 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013167 CHECK_TYPE0(XPATH_NODESET);
13168 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013169
Daniel Veillardf06307e2001-07-03 10:35:50 +000013170 CHECK_TYPE0(XPATH_NODESET);
13171 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013172
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013173 if ((arg1->nodesetval == NULL) ||
13174 ((arg2->nodesetval != NULL) &&
13175 (arg2->nodesetval->nodeNr != 0)))
13176 {
13177 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13178 arg2->nodesetval);
13179 }
13180
Daniel Veillardf06307e2001-07-03 10:35:50 +000013181 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013182 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013183 return (total);
13184 case XPATH_OP_ROOT:
13185 xmlXPathRoot(ctxt);
13186 return (total);
13187 case XPATH_OP_NODE:
13188 if (op->ch1 != -1)
13189 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013190 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013191 if (op->ch2 != -1)
13192 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013193 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013194 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13195 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013196 return (total);
13197 case XPATH_OP_RESET:
13198 if (op->ch1 != -1)
13199 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013200 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013201 if (op->ch2 != -1)
13202 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013203 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013204 ctxt->context->node = NULL;
13205 return (total);
13206 case XPATH_OP_COLLECT:{
13207 if (op->ch1 == -1)
13208 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000013209
Daniel Veillardf06307e2001-07-03 10:35:50 +000013210 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013211 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013212
Daniel Veillardf06307e2001-07-03 10:35:50 +000013213 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
13214 return (total);
13215 }
13216 case XPATH_OP_VALUE:
13217 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013218 xmlXPathCacheObjectCopy(ctxt->context,
13219 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013220 return (total);
13221 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000013222 xmlXPathObjectPtr val;
13223
Daniel Veillardf06307e2001-07-03 10:35:50 +000013224 if (op->ch1 != -1)
13225 total +=
13226 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013227 if (op->value5 == NULL) {
13228 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13229 if (val == NULL) {
13230 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13231 return(0);
13232 }
13233 valuePush(ctxt, val);
13234 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013235 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013236
Daniel Veillardf06307e2001-07-03 10:35:50 +000013237 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13238 if (URI == NULL) {
13239 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013240 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000013241 op->value4, op->value5);
13242 return (total);
13243 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013244 val = xmlXPathVariableLookupNS(ctxt->context,
13245 op->value4, URI);
13246 if (val == NULL) {
13247 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13248 return(0);
13249 }
13250 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013251 }
13252 return (total);
13253 }
13254 case XPATH_OP_FUNCTION:{
13255 xmlXPathFunction func;
13256 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000013257 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013258
13259 if (op->ch1 != -1)
13260 total +=
13261 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013262 if (ctxt->valueNr < op->value) {
13263 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013264 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013265 ctxt->error = XPATH_INVALID_OPERAND;
13266 return (total);
13267 }
13268 for (i = 0; i < op->value; i++)
13269 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13270 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013271 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013272 ctxt->error = XPATH_INVALID_OPERAND;
13273 return (total);
13274 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013275 if (op->cache != NULL)
William M. Brackad0e67c2004-12-01 14:35:10 +000013276 XML_CAST_FPTR(func) = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013277 else {
13278 const xmlChar *URI = NULL;
13279
13280 if (op->value5 == NULL)
13281 func =
13282 xmlXPathFunctionLookup(ctxt->context,
13283 op->value4);
13284 else {
13285 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13286 if (URI == NULL) {
13287 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013288 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000013289 op->value4, op->value5);
13290 return (total);
13291 }
13292 func = xmlXPathFunctionLookupNS(ctxt->context,
13293 op->value4, URI);
13294 }
13295 if (func == NULL) {
13296 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013297 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000013298 op->value4);
13299 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013300 }
William M. Brackad0e67c2004-12-01 14:35:10 +000013301 op->cache = XML_CAST_FPTR(func);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013302 op->cacheURI = (void *) URI;
13303 }
13304 oldFunc = ctxt->context->function;
13305 oldFuncURI = ctxt->context->functionURI;
13306 ctxt->context->function = op->value4;
13307 ctxt->context->functionURI = op->cacheURI;
13308 func(ctxt, op->value);
13309 ctxt->context->function = oldFunc;
13310 ctxt->context->functionURI = oldFuncURI;
13311 return (total);
13312 }
13313 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000013314 bakd = ctxt->context->doc;
13315 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000013316 pp = ctxt->context->proximityPosition;
13317 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013318 if (op->ch1 != -1)
13319 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
William M. Brack645a9242004-11-09 12:20:42 +000013320 ctxt->context->contextSize = cs;
13321 ctxt->context->proximityPosition = pp;
Daniel Veillard088bf112002-05-14 11:03:59 +000013322 ctxt->context->node = bak;
William M. Brack645a9242004-11-09 12:20:42 +000013323 ctxt->context->doc = bakd;
Daniel Veillard556c6682001-10-06 09:59:51 +000013324 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000013325 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013326 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000013327 ctxt->context->doc = bakd;
13328 ctxt->context->node = bak;
13329 CHECK_ERROR0;
13330 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013331 return (total);
13332 case XPATH_OP_PREDICATE:
13333 case XPATH_OP_FILTER:{
13334 xmlXPathObjectPtr res;
13335 xmlXPathObjectPtr obj, tmp;
13336 xmlNodeSetPtr newset = NULL;
13337 xmlNodeSetPtr oldset;
13338 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000013339 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013340 int i;
13341
13342 /*
13343 * Optimization for ()[1] selection i.e. the first elem
13344 */
13345 if ((op->ch1 != -1) && (op->ch2 != -1) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013346#ifdef XP_OPTIMIZED_FILTER_FIRST
13347 /*
13348 * FILTER TODO: Can we assume that the inner processing
13349 * will result in an ordered list if we have an
13350 * XPATH_OP_FILTER?
13351 * What about an additional field or flag on
13352 * xmlXPathObject like @sorted ? This way we wouln'd need
13353 * to assume anything, so it would be more robust and
13354 * easier to optimize.
13355 */
13356 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13357 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13358#else
13359 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13360#endif
13361 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013362 xmlXPathObjectPtr val;
13363
13364 val = comp->steps[op->ch2].value4;
13365 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13366 (val->floatval == 1.0)) {
13367 xmlNodePtr first = NULL;
13368
13369 total +=
13370 xmlXPathCompOpEvalFirst(ctxt,
13371 &comp->steps[op->ch1],
13372 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000013373 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013374 /*
13375 * The nodeset should be in document order,
13376 * Keep only the first value
13377 */
13378 if ((ctxt->value != NULL) &&
13379 (ctxt->value->type == XPATH_NODESET) &&
13380 (ctxt->value->nodesetval != NULL) &&
13381 (ctxt->value->nodesetval->nodeNr > 1))
13382 ctxt->value->nodesetval->nodeNr = 1;
13383 return (total);
13384 }
13385 }
13386 /*
13387 * Optimization for ()[last()] selection i.e. the last elem
13388 */
13389 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13390 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13391 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13392 int f = comp->steps[op->ch2].ch1;
13393
13394 if ((f != -1) &&
13395 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13396 (comp->steps[f].value5 == NULL) &&
13397 (comp->steps[f].value == 0) &&
13398 (comp->steps[f].value4 != NULL) &&
13399 (xmlStrEqual
13400 (comp->steps[f].value4, BAD_CAST "last"))) {
13401 xmlNodePtr last = NULL;
13402
13403 total +=
13404 xmlXPathCompOpEvalLast(ctxt,
13405 &comp->steps[op->ch1],
13406 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000013407 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013408 /*
13409 * The nodeset should be in document order,
13410 * Keep only the last value
13411 */
13412 if ((ctxt->value != NULL) &&
13413 (ctxt->value->type == XPATH_NODESET) &&
13414 (ctxt->value->nodesetval != NULL) &&
13415 (ctxt->value->nodesetval->nodeTab != NULL) &&
13416 (ctxt->value->nodesetval->nodeNr > 1)) {
13417 ctxt->value->nodesetval->nodeTab[0] =
13418 ctxt->value->nodesetval->nodeTab[ctxt->
13419 value->
13420 nodesetval->
13421 nodeNr -
13422 1];
13423 ctxt->value->nodesetval->nodeNr = 1;
13424 }
13425 return (total);
13426 }
13427 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013428 /*
13429 * Process inner predicates first.
13430 * Example "index[parent::book][1]":
13431 * ...
13432 * PREDICATE <-- we are here "[1]"
13433 * PREDICATE <-- process "[parent::book]" first
13434 * SORT
13435 * COLLECT 'parent' 'name' 'node' book
13436 * NODE
13437 * ELEM Object is a number : 1
13438 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013439 if (op->ch1 != -1)
13440 total +=
13441 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013442 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013443 if (op->ch2 == -1)
13444 return (total);
13445 if (ctxt->value == NULL)
13446 return (total);
13447
13448 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013449
13450#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013451 /*
13452 * Hum are we filtering the result of an XPointer expression
13453 */
13454 if (ctxt->value->type == XPATH_LOCATIONSET) {
13455 xmlLocationSetPtr newlocset = NULL;
13456 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013457
Daniel Veillardf06307e2001-07-03 10:35:50 +000013458 /*
13459 * Extract the old locset, and then evaluate the result of the
13460 * expression for all the element in the locset. use it to grow
13461 * up a new locset.
13462 */
13463 CHECK_TYPE0(XPATH_LOCATIONSET);
13464 obj = valuePop(ctxt);
13465 oldlocset = obj->user;
13466 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013467
Daniel Veillardf06307e2001-07-03 10:35:50 +000013468 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13469 ctxt->context->contextSize = 0;
13470 ctxt->context->proximityPosition = 0;
13471 if (op->ch2 != -1)
13472 total +=
13473 xmlXPathCompOpEval(ctxt,
13474 &comp->steps[op->ch2]);
13475 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013476 if (res != NULL) {
13477 xmlXPathReleaseObject(ctxt->context, res);
13478 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013479 valuePush(ctxt, obj);
13480 CHECK_ERROR0;
13481 return (total);
13482 }
13483 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013484
Daniel Veillardf06307e2001-07-03 10:35:50 +000013485 for (i = 0; i < oldlocset->locNr; i++) {
13486 /*
13487 * Run the evaluation with a node list made of a
13488 * single item in the nodelocset.
13489 */
13490 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013491 ctxt->context->contextSize = oldlocset->locNr;
13492 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013493 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13494 ctxt->context->node);
William M. Brackf7eb7942003-12-31 07:59:17 +000013495 valuePush(ctxt, tmp);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013496
Daniel Veillardf06307e2001-07-03 10:35:50 +000013497 if (op->ch2 != -1)
13498 total +=
13499 xmlXPathCompOpEval(ctxt,
13500 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013501 if (ctxt->error != XPATH_EXPRESSION_OK) {
13502 xmlXPathFreeObject(obj);
13503 return(0);
13504 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013505
Daniel Veillardf06307e2001-07-03 10:35:50 +000013506 /*
13507 * The result of the evaluation need to be tested to
13508 * decided whether the filter succeeded or not
13509 */
13510 res = valuePop(ctxt);
13511 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13512 xmlXPtrLocationSetAdd(newlocset,
13513 xmlXPathObjectCopy
13514 (oldlocset->locTab[i]));
13515 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013516
Daniel Veillardf06307e2001-07-03 10:35:50 +000013517 /*
13518 * Cleanup
13519 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013520 if (res != NULL) {
13521 xmlXPathReleaseObject(ctxt->context, res);
13522 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013523 if (ctxt->value == tmp) {
13524 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013525 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013526 }
13527
13528 ctxt->context->node = NULL;
13529 }
13530
13531 /*
13532 * The result is used as the new evaluation locset.
13533 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013534 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013535 ctxt->context->node = NULL;
13536 ctxt->context->contextSize = -1;
13537 ctxt->context->proximityPosition = -1;
13538 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13539 ctxt->context->node = oldnode;
13540 return (total);
13541 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013542#endif /* LIBXML_XPTR_ENABLED */
13543
Daniel Veillardf06307e2001-07-03 10:35:50 +000013544 /*
13545 * Extract the old set, and then evaluate the result of the
13546 * expression for all the element in the set. use it to grow
13547 * up a new set.
13548 */
13549 CHECK_TYPE0(XPATH_NODESET);
13550 obj = valuePop(ctxt);
13551 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000013552
Daniel Veillardf06307e2001-07-03 10:35:50 +000013553 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000013554 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013555 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013556
Daniel Veillardf06307e2001-07-03 10:35:50 +000013557 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13558 ctxt->context->contextSize = 0;
13559 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000013560/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000013561 if (op->ch2 != -1)
13562 total +=
13563 xmlXPathCompOpEval(ctxt,
13564 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013565 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013566 res = valuePop(ctxt);
13567 if (res != NULL)
13568 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000013569*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000013570 valuePush(ctxt, obj);
13571 ctxt->context->node = oldnode;
13572 CHECK_ERROR0;
13573 } else {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013574 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013575 /*
13576 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000013577 * Also set the xpath document in case things like
13578 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000013579 */
13580 newset = xmlXPathNodeSetCreate(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013581 /*
13582 * SPEC XPath 1.0:
13583 * "For each node in the node-set to be filtered, the
13584 * PredicateExpr is evaluated with that node as the
13585 * context node, with the number of nodes in the
13586 * node-set as the context size, and with the proximity
13587 * position of the node in the node-set with respect to
13588 * the axis as the context position;"
13589 * @oldset is the node-set" to be filtered.
13590 *
13591 * SPEC XPath 1.0:
13592 * "only predicates change the context position and
13593 * context size (see [2.4 Predicates])."
13594 * Example:
13595 * node-set context pos
13596 * nA 1
13597 * nB 2
13598 * nC 3
13599 * After applying predicate [position() > 1] :
13600 * node-set context pos
13601 * nB 1
13602 * nC 2
13603 *
13604 * removed the first node in the node-set, then
13605 * the context position of the
13606 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013607 for (i = 0; i < oldset->nodeNr; i++) {
13608 /*
13609 * Run the evaluation with a node list made of
13610 * a single item in the nodeset.
13611 */
13612 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000013613 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13614 (oldset->nodeTab[i]->doc != NULL))
13615 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013616 if (tmp == NULL) {
13617 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13618 ctxt->context->node);
13619 } else {
13620 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13621 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013622 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013623 valuePush(ctxt, tmp);
13624 ctxt->context->contextSize = oldset->nodeNr;
13625 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013626 /*
13627 * Evaluate the predicate against the context node.
13628 * Can/should we optimize position() predicates
13629 * here (e.g. "[1]")?
13630 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013631 if (op->ch2 != -1)
13632 total +=
13633 xmlXPathCompOpEval(ctxt,
13634 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013635 if (ctxt->error != XPATH_EXPRESSION_OK) {
13636 xmlXPathFreeNodeSet(newset);
13637 xmlXPathFreeObject(obj);
13638 return(0);
13639 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013640
Daniel Veillardf06307e2001-07-03 10:35:50 +000013641 /*
William M. Brack08171912003-12-29 02:52:11 +000013642 * The result of the evaluation needs to be tested to
13643 * decide whether the filter succeeded or not
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013644 */
13645 /*
13646 * OPTIMIZE TODO: Can we use
13647 * xmlXPathNodeSetAdd*Unique()* instead?
13648 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013649 res = valuePop(ctxt);
13650 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13651 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13652 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013653
Daniel Veillardf06307e2001-07-03 10:35:50 +000013654 /*
13655 * Cleanup
13656 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013657 if (res != NULL) {
13658 xmlXPathReleaseObject(ctxt->context, res);
13659 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013660 if (ctxt->value == tmp) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013661 valuePop(ctxt);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000013662 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013663 /*
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013664 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013665 * in order to avoid massive recreation inside this
13666 * loop.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013667 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013668 } else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013669 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013670 ctxt->context->node = NULL;
13671 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013672 if (tmp != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013673 xmlXPathReleaseObject(ctxt->context, tmp);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013674 /*
13675 * The result is used as the new evaluation set.
13676 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013677 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013678 ctxt->context->node = NULL;
13679 ctxt->context->contextSize = -1;
13680 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000013681 /* may want to move this past the '}' later */
13682 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013683 valuePush(ctxt,
13684 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013685 }
13686 ctxt->context->node = oldnode;
13687 return (total);
13688 }
13689 case XPATH_OP_SORT:
13690 if (op->ch1 != -1)
13691 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013692 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013693 if ((ctxt->value != NULL) &&
13694 (ctxt->value->type == XPATH_NODESET) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013695 (ctxt->value->nodesetval != NULL) &&
13696 (ctxt->value->nodesetval->nodeNr > 1))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013697 {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013698 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013699 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013700 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013701#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013702 case XPATH_OP_RANGETO:{
13703 xmlXPathObjectPtr range;
13704 xmlXPathObjectPtr res, obj;
13705 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000013706 xmlLocationSetPtr newlocset = NULL;
13707 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013708 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000013709 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013710
Daniel Veillardf06307e2001-07-03 10:35:50 +000013711 if (op->ch1 != -1)
13712 total +=
13713 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13714 if (op->ch2 == -1)
13715 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013716
William M. Brack08171912003-12-29 02:52:11 +000013717 if (ctxt->value->type == XPATH_LOCATIONSET) {
13718 /*
13719 * Extract the old locset, and then evaluate the result of the
13720 * expression for all the element in the locset. use it to grow
13721 * up a new locset.
13722 */
13723 CHECK_TYPE0(XPATH_LOCATIONSET);
13724 obj = valuePop(ctxt);
13725 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013726
William M. Brack08171912003-12-29 02:52:11 +000013727 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000013728 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000013729 ctxt->context->contextSize = 0;
13730 ctxt->context->proximityPosition = 0;
13731 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13732 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013733 if (res != NULL) {
13734 xmlXPathReleaseObject(ctxt->context, res);
13735 }
William M. Brack08171912003-12-29 02:52:11 +000013736 valuePush(ctxt, obj);
13737 CHECK_ERROR0;
13738 return (total);
13739 }
13740 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013741
William M. Brack08171912003-12-29 02:52:11 +000013742 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013743 /*
William M. Brack08171912003-12-29 02:52:11 +000013744 * Run the evaluation with a node list made of a
13745 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000013746 */
William M. Brackf7eb7942003-12-31 07:59:17 +000013747 ctxt->context->node = oldlocset->locTab[i]->user;
13748 ctxt->context->contextSize = oldlocset->locNr;
13749 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013750 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13751 ctxt->context->node);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013752 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013753
Daniel Veillardf06307e2001-07-03 10:35:50 +000013754 if (op->ch2 != -1)
13755 total +=
13756 xmlXPathCompOpEval(ctxt,
13757 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013758 if (ctxt->error != XPATH_EXPRESSION_OK) {
13759 xmlXPathFreeObject(obj);
13760 return(0);
13761 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013762
Daniel Veillardf06307e2001-07-03 10:35:50 +000013763 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000013764 if (res->type == XPATH_LOCATIONSET) {
13765 xmlLocationSetPtr rloc =
13766 (xmlLocationSetPtr)res->user;
13767 for (j=0; j<rloc->locNr; j++) {
13768 range = xmlXPtrNewRange(
13769 oldlocset->locTab[i]->user,
13770 oldlocset->locTab[i]->index,
13771 rloc->locTab[j]->user2,
13772 rloc->locTab[j]->index2);
13773 if (range != NULL) {
13774 xmlXPtrLocationSetAdd(newlocset, range);
13775 }
13776 }
13777 } else {
13778 range = xmlXPtrNewRangeNodeObject(
13779 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13780 if (range != NULL) {
13781 xmlXPtrLocationSetAdd(newlocset,range);
13782 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013783 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013784
Daniel Veillardf06307e2001-07-03 10:35:50 +000013785 /*
13786 * Cleanup
13787 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013788 if (res != NULL) {
13789 xmlXPathReleaseObject(ctxt->context, res);
13790 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013791 if (ctxt->value == tmp) {
13792 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013793 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013794 }
13795
13796 ctxt->context->node = NULL;
13797 }
William M. Brack72ee48d2003-12-30 08:30:19 +000013798 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000013799 CHECK_TYPE0(XPATH_NODESET);
13800 obj = valuePop(ctxt);
13801 oldset = obj->nodesetval;
13802 ctxt->context->node = NULL;
13803
13804 newlocset = xmlXPtrLocationSetCreate(NULL);
13805
13806 if (oldset != NULL) {
13807 for (i = 0; i < oldset->nodeNr; i++) {
13808 /*
13809 * Run the evaluation with a node list made of a single item
13810 * in the nodeset.
13811 */
13812 ctxt->context->node = oldset->nodeTab[i];
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013813 /*
13814 * OPTIMIZE TODO: Avoid recreation for every iteration.
13815 */
13816 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13817 ctxt->context->node);
William M. Brack08171912003-12-29 02:52:11 +000013818 valuePush(ctxt, tmp);
13819
13820 if (op->ch2 != -1)
13821 total +=
13822 xmlXPathCompOpEval(ctxt,
13823 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013824 if (ctxt->error != XPATH_EXPRESSION_OK) {
13825 xmlXPathFreeObject(obj);
13826 return(0);
13827 }
William M. Brack08171912003-12-29 02:52:11 +000013828
William M. Brack08171912003-12-29 02:52:11 +000013829 res = valuePop(ctxt);
13830 range =
13831 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13832 res);
13833 if (range != NULL) {
13834 xmlXPtrLocationSetAdd(newlocset, range);
13835 }
13836
13837 /*
13838 * Cleanup
13839 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013840 if (res != NULL) {
13841 xmlXPathReleaseObject(ctxt->context, res);
13842 }
William M. Brack08171912003-12-29 02:52:11 +000013843 if (ctxt->value == tmp) {
13844 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013845 xmlXPathReleaseObject(ctxt->context, res);
William M. Brack08171912003-12-29 02:52:11 +000013846 }
13847
13848 ctxt->context->node = NULL;
13849 }
13850 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013851 }
13852
13853 /*
13854 * The result is used as the new evaluation set.
13855 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013856 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013857 ctxt->context->node = NULL;
13858 ctxt->context->contextSize = -1;
13859 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000013860 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013861 return (total);
13862 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013863#endif /* LIBXML_XPTR_ENABLED */
13864 }
13865 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000013866 "XPath: unknown precompiled operation %d\n", op->op);
13867 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013868}
13869
Daniel Veillard56de87e2005-02-16 00:22:29 +000013870#ifdef XPATH_STREAMING
13871/**
13872 * xmlXPathRunStreamEval:
13873 * @ctxt: the XPath parser context with the compiled expression
13874 *
13875 * Evaluate the Precompiled Streamable XPath expression in the given context.
13876 */
13877static xmlXPathObjectPtr
13878xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp) {
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013879 int max_depth, min_depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013880 int from_root;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013881 int ret, depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013882#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
13883 int eval_all_nodes;
13884#endif
William M. Brack12d37ab2005-02-21 13:54:07 +000013885 xmlNodePtr cur = NULL, limit = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013886 xmlXPathObjectPtr retval;
13887 xmlStreamCtxtPtr patstream;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013888
13889 int nb_nodes = 0;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013890
13891 if ((ctxt == NULL) || (comp == NULL))
13892 return(NULL);
13893 max_depth = xmlPatternMaxDepth(comp);
13894 if (max_depth == -1)
13895 return(NULL);
13896 if (max_depth == -2)
13897 max_depth = 10000;
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013898 min_depth = xmlPatternMinDepth(comp);
13899 if (min_depth == -1)
13900 return(NULL);
Daniel Veillard56de87e2005-02-16 00:22:29 +000013901 from_root = xmlPatternFromRoot(comp);
13902 if (from_root < 0)
13903 return(NULL);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000013904#if 0
13905 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
13906#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000013907
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013908 retval = xmlXPathCacheNewNodeSet(ctxt, NULL);
Daniel Veillard56de87e2005-02-16 00:22:29 +000013909 if (retval == NULL)
13910 return(NULL);
13911
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013912 /*
13913 * handle the special cases of / amd . being matched
13914 */
13915 if (min_depth == 0) {
13916 if (from_root) {
13917 xmlXPathNodeSetAddUnique(retval->nodesetval, (xmlNodePtr) ctxt->doc);
13918 } else {
13919 xmlXPathNodeSetAddUnique(retval->nodesetval, ctxt->node);
13920 }
13921 }
13922 if (max_depth == 0) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000013923 return(retval);
13924 }
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013925
Daniel Veillard56de87e2005-02-16 00:22:29 +000013926 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000013927 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013928 } else if (ctxt->node != NULL) {
13929 switch (ctxt->node->type) {
13930 case XML_ELEMENT_NODE:
13931 case XML_DOCUMENT_NODE:
13932 case XML_DOCUMENT_FRAG_NODE:
13933 case XML_HTML_DOCUMENT_NODE:
13934#ifdef LIBXML_DOCB_ENABLED
13935 case XML_DOCB_DOCUMENT_NODE:
13936#endif
13937 cur = ctxt->node;
13938 break;
13939 case XML_ATTRIBUTE_NODE:
13940 case XML_TEXT_NODE:
13941 case XML_CDATA_SECTION_NODE:
13942 case XML_ENTITY_REF_NODE:
13943 case XML_ENTITY_NODE:
13944 case XML_PI_NODE:
13945 case XML_COMMENT_NODE:
13946 case XML_NOTATION_NODE:
13947 case XML_DTD_NODE:
13948 case XML_DOCUMENT_TYPE_NODE:
13949 case XML_ELEMENT_DECL:
13950 case XML_ATTRIBUTE_DECL:
13951 case XML_ENTITY_DECL:
13952 case XML_NAMESPACE_DECL:
13953 case XML_XINCLUDE_START:
13954 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000013955 break;
13956 }
13957 limit = cur;
13958 }
13959 if (cur == NULL)
13960 return(retval);
13961
13962 patstream = xmlPatternGetStreamCtxt(comp);
13963 if (patstream == NULL) {
13964 return(retval);
13965 }
13966
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013967#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
13968 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
13969#endif
13970
Daniel Veillard56de87e2005-02-16 00:22:29 +000013971 if (from_root) {
13972 ret = xmlStreamPush(patstream, NULL, NULL);
13973 if (ret < 0) {
13974 } else if (ret == 1) {
13975 xmlXPathNodeSetAddUnique(retval->nodesetval, cur);
13976 }
13977 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000013978 depth = 0;
13979 goto scan_children;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013980next_node:
Daniel Veillardd3ff7ef2006-02-27 19:43:17 +000013981 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000013982 nb_nodes++;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013983
13984 switch (cur->type) {
13985 case XML_ELEMENT_NODE:
13986#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
13987 case XML_TEXT_NODE:
13988 case XML_CDATA_SECTION_NODE:
13989 case XML_COMMENT_NODE:
13990 case XML_PI_NODE:
13991#endif
13992 if (cur->type == XML_ELEMENT_NODE) {
13993 ret = xmlStreamPush(patstream, cur->name,
Daniel Veillard56de87e2005-02-16 00:22:29 +000013994 (cur->ns ? cur->ns->href : NULL));
William M. Brackfbb619f2005-06-06 13:49:18 +000013995 }
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013996#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
13997 else if (eval_all_nodes)
13998 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
13999 else
14000 break;
14001#endif
14002
14003 if (ret < 0) {
14004 /* NOP. */
14005 } else if (ret == 1) {
14006 xmlXPathNodeSetAddUnique(retval->nodesetval, cur);
14007 }
14008 if ((cur->children == NULL) || (depth >= max_depth)) {
14009 ret = xmlStreamPop(patstream);
14010 while (cur->next != NULL) {
14011 cur = cur->next;
14012 if ((cur->type != XML_ENTITY_DECL) &&
14013 (cur->type != XML_DTD_NODE))
14014 goto next_node;
14015 }
14016 }
14017 default:
14018 break;
14019 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014020
14021scan_children:
14022 if ((cur->children != NULL) && (depth < max_depth)) {
14023 /*
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014024 * Do not descend on entities declarations
Daniel Veillard56de87e2005-02-16 00:22:29 +000014025 */
14026 if (cur->children->type != XML_ENTITY_DECL) {
14027 cur = cur->children;
14028 depth++;
14029 /*
14030 * Skip DTDs
14031 */
14032 if (cur->type != XML_DTD_NODE)
14033 continue;
14034 }
14035 }
14036
14037 if (cur == limit)
14038 break;
14039
14040 while (cur->next != NULL) {
14041 cur = cur->next;
14042 if ((cur->type != XML_ENTITY_DECL) &&
14043 (cur->type != XML_DTD_NODE))
14044 goto next_node;
14045 }
14046
14047 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014048 cur = cur->parent;
14049 depth--;
14050 if ((cur == NULL) || (cur == limit))
14051 goto done;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014052 if (cur->type == XML_ELEMENT_NODE) {
14053 ret = xmlStreamPop(patstream);
14054 }
14055#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
14056 else if ((eval_all_nodes) &&
14057 ((cur->type == XML_TEXT_NODE) ||
14058 (cur->type == XML_CDATA_SECTION_NODE) ||
14059 (cur->type == XML_COMMENT_NODE) ||
14060 (cur->type == XML_PI_NODE)))
14061 {
14062 ret = xmlStreamPop(patstream);
14063 }
14064#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000014065 if (cur->next != NULL) {
14066 cur = cur->next;
14067 break;
14068 }
14069 } while (cur != NULL);
14070
14071 } while ((cur != NULL) && (depth >= 0));
14072done:
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014073#if 0
14074 printf("stream eval: checked %d nodes selected %d\n",
14075 nb_nodes, retval->nodesetval->nodeNr);
14076#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000014077 xmlFreeStreamCtxt(patstream);
14078 return(retval);
14079}
14080#endif /* XPATH_STREAMING */
14081
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014082/**
14083 * xmlXPathRunEval:
14084 * @ctxt: the XPath parser context with the compiled expression
14085 *
14086 * Evaluate the Precompiled XPath expression in the given context.
14087 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014088static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014089xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
14090 xmlXPathCompExprPtr comp;
14091
14092 if ((ctxt == NULL) || (ctxt->comp == NULL))
14093 return;
14094
14095 if (ctxt->valueTab == NULL) {
14096 /* Allocate the value stack */
14097 ctxt->valueTab = (xmlXPathObjectPtr *)
14098 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14099 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000014100 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014101 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014102 }
14103 ctxt->valueNr = 0;
14104 ctxt->valueMax = 10;
14105 ctxt->value = NULL;
14106 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014107#ifdef XPATH_STREAMING
14108 if (ctxt->comp->stream) {
14109 xmlXPathObjectPtr ret;
14110 ret = xmlXPathRunStreamEval(ctxt->context, ctxt->comp->stream);
14111 if (ret != NULL) {
14112 valuePush(ctxt, ret);
14113 return;
14114 }
14115 }
14116#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014117 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014118 if(comp->last < 0) {
14119 xmlGenericError(xmlGenericErrorContext,
14120 "xmlXPathRunEval: last is less than zero\n");
14121 return;
14122 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014123 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14124}
14125
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014126/************************************************************************
14127 * *
14128 * Public interfaces *
14129 * *
14130 ************************************************************************/
14131
14132/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014133 * xmlXPathEvalPredicate:
14134 * @ctxt: the XPath context
14135 * @res: the Predicate Expression evaluation result
14136 *
14137 * Evaluate a predicate result for the current node.
14138 * A PredicateExpr is evaluated by evaluating the Expr and converting
14139 * the result to a boolean. If the result is a number, the result will
14140 * be converted to true if the number is equal to the position of the
14141 * context node in the context node list (as returned by the position
14142 * function) and will be converted to false otherwise; if the result
14143 * is not a number, then the result will be converted as if by a call
14144 * to the boolean function.
14145 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014146 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014147 */
14148int
14149xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014150 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014151 switch (res->type) {
14152 case XPATH_BOOLEAN:
14153 return(res->boolval);
14154 case XPATH_NUMBER:
14155 return(res->floatval == ctxt->proximityPosition);
14156 case XPATH_NODESET:
14157 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000014158 if (res->nodesetval == NULL)
14159 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014160 return(res->nodesetval->nodeNr != 0);
14161 case XPATH_STRING:
14162 return((res->stringval != NULL) &&
14163 (xmlStrlen(res->stringval) != 0));
14164 default:
14165 STRANGE
14166 }
14167 return(0);
14168}
14169
14170/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014171 * xmlXPathEvaluatePredicateResult:
14172 * @ctxt: the XPath Parser context
14173 * @res: the Predicate Expression evaluation result
14174 *
14175 * Evaluate a predicate result for the current node.
14176 * A PredicateExpr is evaluated by evaluating the Expr and converting
14177 * the result to a boolean. If the result is a number, the result will
14178 * be converted to true if the number is equal to the position of the
14179 * context node in the context node list (as returned by the position
14180 * function) and will be converted to false otherwise; if the result
14181 * is not a number, then the result will be converted as if by a call
14182 * to the boolean function.
14183 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014184 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014185 */
14186int
14187xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14188 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014189 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014190 switch (res->type) {
14191 case XPATH_BOOLEAN:
14192 return(res->boolval);
14193 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000014194#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000014195 return((res->floatval == ctxt->context->proximityPosition) &&
14196 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000014197#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014198 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000014199#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014200 case XPATH_NODESET:
14201 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000014202 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000014203 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014204 return(res->nodesetval->nodeNr != 0);
14205 case XPATH_STRING:
14206 return((res->stringval != NULL) &&
14207 (xmlStrlen(res->stringval) != 0));
William M. Brack08171912003-12-29 02:52:11 +000014208#ifdef LIBXML_XPTR_ENABLED
14209 case XPATH_LOCATIONSET:{
14210 xmlLocationSetPtr ptr = res->user;
14211 if (ptr == NULL)
14212 return(0);
14213 return (ptr->locNr != 0);
14214 }
14215#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014216 default:
14217 STRANGE
14218 }
14219 return(0);
14220}
14221
Daniel Veillard56de87e2005-02-16 00:22:29 +000014222#ifdef XPATH_STREAMING
14223/**
14224 * xmlXPathTryStreamCompile:
14225 * @ctxt: an XPath context
14226 * @str: the XPath expression
14227 *
14228 * Try to compile the XPath expression as a streamable subset.
14229 *
14230 * Returns the compiled expression or NULL if failed to compile.
14231 */
14232static xmlXPathCompExprPtr
14233xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14234 /*
14235 * Optimization: use streaming patterns when the XPath expression can
14236 * be compiled to a stream lookup
14237 */
14238 xmlPatternPtr stream;
14239 xmlXPathCompExprPtr comp;
14240 xmlDictPtr dict = NULL;
14241 const xmlChar **namespaces = NULL;
14242 xmlNsPtr ns;
14243 int i, j;
14244
14245 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14246 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014247 const xmlChar *tmp;
14248
14249 /*
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014250 * We don't try to handle expressions using the verbose axis
14251 * specifiers ("::"), just the simplied form at this point.
14252 * Additionally, if there is no list of namespaces available and
14253 * there's a ":" in the expression, indicating a prefixed QName,
14254 * then we won't try to compile either. xmlPatterncompile() needs
14255 * to have a list of namespaces at compilation time in order to
14256 * compile prefixed name tests.
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014257 */
14258 tmp = xmlStrchr(str, ':');
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014259 if ((tmp != NULL) &&
14260 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14261 return(NULL);
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014262
Daniel Veillard56de87e2005-02-16 00:22:29 +000014263 if (ctxt != NULL) {
14264 dict = ctxt->dict;
14265 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000014266 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000014267 if (namespaces == NULL) {
14268 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14269 return(NULL);
14270 }
14271 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14272 ns = ctxt->namespaces[j];
14273 namespaces[i++] = ns->href;
14274 namespaces[i++] = ns->prefix;
14275 }
14276 namespaces[i++] = NULL;
14277 namespaces[i++] = NULL;
14278 }
14279 }
14280
William M. Brackea152c02005-06-09 18:12:28 +000014281 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14282 &namespaces[0]);
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014283 if (namespaces != NULL) {
14284 xmlFree((xmlChar **)namespaces);
14285 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014286 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14287 comp = xmlXPathNewCompExpr();
14288 if (comp == NULL) {
14289 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14290 return(NULL);
14291 }
14292 comp->stream = stream;
14293 comp->dict = dict;
14294 if (comp->dict)
14295 xmlDictReference(comp->dict);
14296 return(comp);
14297 }
14298 xmlFreePattern(stream);
14299 }
14300 return(NULL);
14301}
14302#endif /* XPATH_STREAMING */
14303
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014304static int
14305xmlXPathCanRewriteDosExpression(xmlChar *expr)
14306{
14307 if (expr == NULL)
14308 return(0);
14309 do {
14310 if ((*expr == '/') && (*(++expr) == '/'))
14311 return(1);
14312 } while (*expr++);
14313 return(0);
14314}
14315static void
14316xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14317{
14318 /*
14319 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14320 * internal representation.
14321 */
14322 if (op->ch1 != -1) {
14323 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14324 ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
14325 ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14326 ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14327 {
14328 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014329 * This is a "child::foo"
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014330 */
14331 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14332
14333 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14334 (prevop->ch1 != -1) &&
14335 ((xmlXPathAxisVal) prevop->value ==
14336 AXIS_DESCENDANT_OR_SELF) &&
14337 (prevop->ch2 == -1) &&
14338 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014339 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
14340 (comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014341 {
14342 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014343 * This is a "/descendant-or-self::node()" without predicates.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014344 * Eliminate it.
14345 */
14346 op->ch1 = prevop->ch1;
14347 op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
14348 }
14349 }
14350 if (op->ch1 != -1)
14351 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14352 }
14353 if (op->ch2 != -1)
14354 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14355}
14356
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014357/**
Daniel Veillard4773df22004-01-23 13:15:13 +000014358 * xmlXPathCtxtCompile:
14359 * @ctxt: an XPath context
14360 * @str: the XPath expression
14361 *
14362 * Compile an XPath expression
14363 *
14364 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14365 * the caller has to free the object.
14366 */
14367xmlXPathCompExprPtr
14368xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14369 xmlXPathParserContextPtr pctxt;
14370 xmlXPathCompExprPtr comp;
14371
Daniel Veillard56de87e2005-02-16 00:22:29 +000014372#ifdef XPATH_STREAMING
14373 comp = xmlXPathTryStreamCompile(ctxt, str);
14374 if (comp != NULL)
14375 return(comp);
14376#endif
14377
Daniel Veillard4773df22004-01-23 13:15:13 +000014378 xmlXPathInit();
14379
14380 pctxt = xmlXPathNewParserContext(str, ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014381 xmlXPathCompileExpr(pctxt, 1);
Daniel Veillard4773df22004-01-23 13:15:13 +000014382
14383 if( pctxt->error != XPATH_EXPRESSION_OK )
14384 {
14385 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000014386 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000014387 }
14388
14389 if (*pctxt->cur != 0) {
14390 /*
14391 * aleksey: in some cases this line prints *second* error message
14392 * (see bug #78858) and probably this should be fixed.
14393 * However, we are not sure that all error messages are printed
14394 * out in other places. It's not critical so we leave it as-is for now
14395 */
14396 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14397 comp = NULL;
14398 } else {
14399 comp = pctxt->comp;
14400 pctxt->comp = NULL;
14401 }
14402 xmlXPathFreeParserContext(pctxt);
14403 if (comp != NULL) {
14404 comp->expr = xmlStrdup(str);
14405#ifdef DEBUG_EVAL_COUNTS
14406 comp->string = xmlStrdup(str);
14407 comp->nb = 0;
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014408#endif
14409 if ((comp->expr != NULL) &&
14410 (comp->nbStep > 2) &&
14411 (comp->last >= 0) &&
Kasimier T. Buchcik7cb3fa92006-06-06 15:27:46 +000014412 (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14413 {
14414 xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014415 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014416 }
Daniel Veillard4773df22004-01-23 13:15:13 +000014417 return(comp);
14418}
14419
14420/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014421 * xmlXPathCompile:
14422 * @str: the XPath expression
14423 *
14424 * Compile an XPath expression
14425 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000014426 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014427 * the caller has to free the object.
14428 */
14429xmlXPathCompExprPtr
14430xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000014431 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014432}
14433
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014434/**
14435 * xmlXPathCompiledEval:
14436 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000014437 * @ctx: the XPath context
14438 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014439 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000014440 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014441 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000014442 * the caller has to free the object.
14443 */
14444xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014445xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000014446 xmlXPathParserContextPtr ctxt;
14447 xmlXPathObjectPtr res, tmp, init = NULL;
14448 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000014449#ifndef LIBXML_THREAD_ENABLED
14450 static int reentance = 0;
14451#endif
Owen Taylor3473f882001-02-23 17:55:21 +000014452
William M. Brackf13f77f2004-11-12 16:03:48 +000014453 CHECK_CTXT(ctx)
14454
14455 if (comp == NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014456 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000014457 xmlXPathInit();
14458
Daniel Veillard81463942001-10-16 12:34:39 +000014459#ifndef LIBXML_THREAD_ENABLED
14460 reentance++;
14461 if (reentance > 1)
14462 xmlXPathDisableOptimizer = 1;
14463#endif
14464
Daniel Veillardf06307e2001-07-03 10:35:50 +000014465#ifdef DEBUG_EVAL_COUNTS
14466 comp->nb++;
14467 if ((comp->string != NULL) && (comp->nb > 100)) {
14468 fprintf(stderr, "100 x %s\n", comp->string);
14469 comp->nb = 0;
14470 }
14471#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014472 ctxt = xmlXPathCompParserContext(comp, ctx);
14473 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000014474
14475 if (ctxt->value == NULL) {
14476 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014477 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000014478 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000014479 } else {
14480 res = valuePop(ctxt);
14481 }
14482
Daniel Veillardf06307e2001-07-03 10:35:50 +000014483
Owen Taylor3473f882001-02-23 17:55:21 +000014484 do {
14485 tmp = valuePop(ctxt);
14486 if (tmp != NULL) {
14487 if (tmp != init)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014488 stack++;
14489 xmlXPathReleaseObject(ctx, tmp);
Owen Taylor3473f882001-02-23 17:55:21 +000014490 }
14491 } while (tmp != NULL);
14492 if ((stack != 0) && (res != NULL)) {
14493 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014494 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000014495 stack);
14496 }
14497 if (ctxt->error != XPATH_EXPRESSION_OK) {
14498 xmlXPathFreeObject(res);
14499 res = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014500 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014501 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014502 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000014503#ifndef LIBXML_THREAD_ENABLED
14504 reentance--;
14505#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014506 return(res);
14507}
14508
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014509/**
14510 * xmlXPathEvalExpr:
14511 * @ctxt: the XPath Parser context
14512 *
14513 * Parse and evaluate an XPath expression in the given context,
14514 * then push the result on the context stack
14515 */
14516void
14517xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014518#ifdef XPATH_STREAMING
14519 xmlXPathCompExprPtr comp;
14520#endif
14521
Daniel Veillarda82b1822004-11-08 16:24:57 +000014522 if (ctxt == NULL) return;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014523
14524#ifdef XPATH_STREAMING
14525 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14526 if (comp != NULL) {
14527 if (ctxt->comp != NULL)
14528 xmlXPathFreeCompExpr(ctxt->comp);
14529 ctxt->comp = comp;
14530 if (ctxt->cur != NULL)
14531 while (*ctxt->cur != 0) ctxt->cur++;
14532 } else
14533#endif
14534 {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014535 xmlXPathCompileExpr(ctxt, 1);
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014536 /*
14537 * In this scenario the expression string will sit in ctxt->base.
14538 */
14539 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14540 (ctxt->comp != NULL) &&
14541 (ctxt->base != NULL) &&
Kasimier T. Buchcik7cb3fa92006-06-06 15:27:46 +000014542 (ctxt->comp->nbStep > 2) &&
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014543 (ctxt->comp->last >= 0) &&
14544 (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014545 {
14546 xmlXPathRewriteDOSExpression(ctxt->comp,
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014547 &ctxt->comp->steps[ctxt->comp->last]);
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014548 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014549 }
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000014550 CHECK_ERROR;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000014551 xmlXPathRunEval(ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014552}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014553
14554/**
14555 * xmlXPathEval:
14556 * @str: the XPath expression
14557 * @ctx: the XPath context
14558 *
14559 * Evaluate the XPath Location Path in the given context.
14560 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014561 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014562 * the caller has to free the object.
14563 */
14564xmlXPathObjectPtr
14565xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14566 xmlXPathParserContextPtr ctxt;
14567 xmlXPathObjectPtr res, tmp, init = NULL;
14568 int stack = 0;
14569
William M. Brackf13f77f2004-11-12 16:03:48 +000014570 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014571
William M. Brackf13f77f2004-11-12 16:03:48 +000014572 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014573
14574 ctxt = xmlXPathNewParserContext(str, ctx);
14575 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014576
14577 if (ctxt->value == NULL) {
14578 xmlGenericError(xmlGenericErrorContext,
14579 "xmlXPathEval: evaluation failed\n");
14580 res = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014581 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
14582#ifdef XPATH_STREAMING
14583 && (ctxt->comp->stream == NULL)
14584#endif
14585 ) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014586 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14587 res = NULL;
14588 } else {
14589 res = valuePop(ctxt);
14590 }
14591
14592 do {
14593 tmp = valuePop(ctxt);
14594 if (tmp != NULL) {
14595 if (tmp != init)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014596 stack++;
14597 xmlXPathReleaseObject(ctx, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014598 }
14599 } while (tmp != NULL);
14600 if ((stack != 0) && (res != NULL)) {
14601 xmlGenericError(xmlGenericErrorContext,
14602 "xmlXPathEval: %d object left on the stack\n",
14603 stack);
14604 }
14605 if (ctxt->error != XPATH_EXPRESSION_OK) {
14606 xmlXPathFreeObject(res);
14607 res = NULL;
14608 }
14609
Owen Taylor3473f882001-02-23 17:55:21 +000014610 xmlXPathFreeParserContext(ctxt);
14611 return(res);
14612}
14613
14614/**
14615 * xmlXPathEvalExpression:
14616 * @str: the XPath expression
14617 * @ctxt: the XPath context
14618 *
14619 * Evaluate the XPath expression in the given context.
14620 *
14621 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14622 * the caller has to free the object.
14623 */
14624xmlXPathObjectPtr
14625xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14626 xmlXPathParserContextPtr pctxt;
14627 xmlXPathObjectPtr res, tmp;
14628 int stack = 0;
14629
William M. Brackf13f77f2004-11-12 16:03:48 +000014630 CHECK_CTXT(ctxt)
Owen Taylor3473f882001-02-23 17:55:21 +000014631
William M. Brackf13f77f2004-11-12 16:03:48 +000014632 xmlXPathInit();
Owen Taylor3473f882001-02-23 17:55:21 +000014633
14634 pctxt = xmlXPathNewParserContext(str, ctxt);
14635 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000014636
14637 if (*pctxt->cur != 0) {
14638 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14639 res = NULL;
14640 } else {
14641 res = valuePop(pctxt);
14642 }
14643 do {
14644 tmp = valuePop(pctxt);
14645 if (tmp != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014646 xmlXPathReleaseObject(ctxt, tmp);
Owen Taylor3473f882001-02-23 17:55:21 +000014647 stack++;
14648 }
14649 } while (tmp != NULL);
14650 if ((stack != 0) && (res != NULL)) {
14651 xmlGenericError(xmlGenericErrorContext,
14652 "xmlXPathEvalExpression: %d object left on the stack\n",
14653 stack);
14654 }
14655 xmlXPathFreeParserContext(pctxt);
14656 return(res);
14657}
14658
Daniel Veillard42766c02002-08-22 20:52:17 +000014659/************************************************************************
14660 * *
14661 * Extra functions not pertaining to the XPath spec *
14662 * *
14663 ************************************************************************/
14664/**
14665 * xmlXPathEscapeUriFunction:
14666 * @ctxt: the XPath Parser context
14667 * @nargs: the number of arguments
14668 *
14669 * Implement the escape-uri() XPath function
14670 * string escape-uri(string $str, bool $escape-reserved)
14671 *
14672 * This function applies the URI escaping rules defined in section 2 of [RFC
14673 * 2396] to the string supplied as $uri-part, which typically represents all
14674 * or part of a URI. The effect of the function is to replace any special
14675 * character in the string by an escape sequence of the form %xx%yy...,
14676 * where xxyy... is the hexadecimal representation of the octets used to
14677 * represent the character in UTF-8.
14678 *
14679 * The set of characters that are escaped depends on the setting of the
14680 * boolean argument $escape-reserved.
14681 *
14682 * If $escape-reserved is true, all characters are escaped other than lower
14683 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14684 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14685 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14686 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14687 * A-F).
14688 *
14689 * If $escape-reserved is false, the behavior differs in that characters
14690 * referred to in [RFC 2396] as reserved characters are not escaped. These
14691 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14692 *
14693 * [RFC 2396] does not define whether escaped URIs should use lower case or
14694 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14695 * compared using string comparison functions, this function must always use
14696 * the upper-case letters A-F.
14697 *
14698 * Generally, $escape-reserved should be set to true when escaping a string
14699 * that is to form a single part of a URI, and to false when escaping an
14700 * entire URI or URI reference.
14701 *
14702 * In the case of non-ascii characters, the string is encoded according to
14703 * utf-8 and then converted according to RFC 2396.
14704 *
14705 * Examples
14706 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14707 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14708 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14709 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14710 *
14711 */
Daniel Veillard118aed72002-09-24 14:13:13 +000014712static void
Daniel Veillard42766c02002-08-22 20:52:17 +000014713xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14714 xmlXPathObjectPtr str;
14715 int escape_reserved;
14716 xmlBufferPtr target;
14717 xmlChar *cptr;
14718 xmlChar escape[4];
14719
14720 CHECK_ARITY(2);
14721
14722 escape_reserved = xmlXPathPopBoolean(ctxt);
14723
14724 CAST_TO_STRING;
14725 str = valuePop(ctxt);
14726
14727 target = xmlBufferCreate();
14728
14729 escape[0] = '%';
14730 escape[3] = 0;
14731
14732 if (target) {
14733 for (cptr = str->stringval; *cptr; cptr++) {
14734 if ((*cptr >= 'A' && *cptr <= 'Z') ||
14735 (*cptr >= 'a' && *cptr <= 'z') ||
14736 (*cptr >= '0' && *cptr <= '9') ||
14737 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
14738 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
14739 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14740 (*cptr == '%' &&
14741 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14742 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14743 (cptr[1] >= '0' && cptr[1] <= '9')) &&
14744 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14745 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14746 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14747 (!escape_reserved &&
14748 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14749 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14750 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14751 *cptr == ','))) {
14752 xmlBufferAdd(target, cptr, 1);
14753 } else {
14754 if ((*cptr >> 4) < 10)
14755 escape[1] = '0' + (*cptr >> 4);
14756 else
14757 escape[1] = 'A' - 10 + (*cptr >> 4);
14758 if ((*cptr & 0xF) < 10)
14759 escape[2] = '0' + (*cptr & 0xF);
14760 else
14761 escape[2] = 'A' - 10 + (*cptr & 0xF);
14762
14763 xmlBufferAdd(target, &escape[0], 3);
14764 }
14765 }
14766 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014767 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
14768 xmlBufferContent(target)));
Daniel Veillard42766c02002-08-22 20:52:17 +000014769 xmlBufferFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014770 xmlXPathReleaseObject(ctxt->context, str);
Daniel Veillard42766c02002-08-22 20:52:17 +000014771}
14772
Owen Taylor3473f882001-02-23 17:55:21 +000014773/**
14774 * xmlXPathRegisterAllFunctions:
14775 * @ctxt: the XPath context
14776 *
14777 * Registers all default XPath functions in this context
14778 */
14779void
14780xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
14781{
14782 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
14783 xmlXPathBooleanFunction);
14784 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
14785 xmlXPathCeilingFunction);
14786 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
14787 xmlXPathCountFunction);
14788 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
14789 xmlXPathConcatFunction);
14790 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
14791 xmlXPathContainsFunction);
14792 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
14793 xmlXPathIdFunction);
14794 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
14795 xmlXPathFalseFunction);
14796 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
14797 xmlXPathFloorFunction);
14798 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
14799 xmlXPathLastFunction);
14800 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
14801 xmlXPathLangFunction);
14802 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
14803 xmlXPathLocalNameFunction);
14804 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
14805 xmlXPathNotFunction);
14806 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
14807 xmlXPathNameFunction);
14808 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
14809 xmlXPathNamespaceURIFunction);
14810 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
14811 xmlXPathNormalizeFunction);
14812 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
14813 xmlXPathNumberFunction);
14814 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
14815 xmlXPathPositionFunction);
14816 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
14817 xmlXPathRoundFunction);
14818 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
14819 xmlXPathStringFunction);
14820 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
14821 xmlXPathStringLengthFunction);
14822 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
14823 xmlXPathStartsWithFunction);
14824 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
14825 xmlXPathSubstringFunction);
14826 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
14827 xmlXPathSubstringBeforeFunction);
14828 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
14829 xmlXPathSubstringAfterFunction);
14830 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
14831 xmlXPathSumFunction);
14832 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
14833 xmlXPathTrueFunction);
14834 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
14835 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000014836
14837 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
14838 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
14839 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000014840}
14841
14842#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000014843#define bottom_xpath
14844#include "elfgcchack.h"