blob: ff2f2da55c5c199a0809e48ae763719f56024dcf [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;
739 comp->steps[comp->nbStep].ch1 = ch1;
740 comp->steps[comp->nbStep].ch2 = ch2;
741 comp->steps[comp->nbStep].op = op;
742 comp->steps[comp->nbStep].value = value;
743 comp->steps[comp->nbStep].value2 = value2;
744 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +0000745 if ((comp->dict != NULL) &&
746 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
747 (op == XPATH_OP_COLLECT))) {
748 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000749 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000750 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000751 xmlFree(value4);
752 } else
753 comp->steps[comp->nbStep].value4 = NULL;
754 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000755 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000756 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000757 xmlFree(value5);
758 } else
759 comp->steps[comp->nbStep].value5 = NULL;
760 } else {
761 comp->steps[comp->nbStep].value4 = value4;
762 comp->steps[comp->nbStep].value5 = value5;
763 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000764 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000765 return(comp->nbStep++);
766}
767
Daniel Veillardf06307e2001-07-03 10:35:50 +0000768/**
769 * xmlXPathCompSwap:
770 * @comp: the compiled expression
771 * @op: operation index
772 *
773 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000774 */
775static void
776xmlXPathCompSwap(xmlXPathStepOpPtr op) {
777 int tmp;
778
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000779#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000780 /*
781 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +0000782 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +0000783 * application
784 */
785 if (xmlXPathDisableOptimizer)
786 return;
787#endif
788
Daniel Veillardf06307e2001-07-03 10:35:50 +0000789 tmp = op->ch1;
790 op->ch1 = op->ch2;
791 op->ch2 = tmp;
792}
793
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000794#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
795 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
796 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000797#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
798 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
799 (op), (val), (val2), (val3), (val4), (val5))
800
801#define PUSH_LEAVE_EXPR(op, val, val2) \
802xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
803
804#define PUSH_UNARY_EXPR(op, ch, val, val2) \
805xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
806
807#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +0000808xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
809 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000810
811/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000812 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000813 * XPath object cache structures *
814 * *
815 ************************************************************************/
816
817/* #define XP_DEFAULT_CACHE_ON */
818
Kasimier T. Buchcik58694692006-05-31 12:37:28 +0000819#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000820
Kasimier T. Buchcik58694692006-05-31 12:37:28 +0000821typedef struct _xmlXPathContextCache xmlXPathContextCache;
822typedef xmlXPathContextCache *xmlXPathContextCachePtr;
823struct _xmlXPathContextCache {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +0000824 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
825 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
826 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
827 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
828 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000829 int maxNodeset;
830 int maxString;
831 int maxBoolean;
832 int maxNumber;
833 int maxMisc;
834#ifdef XP_DEBUG_OBJ_USAGE
835 int dbgCachedAll;
836 int dbgCachedNodeset;
837 int dbgCachedString;
838 int dbgCachedBool;
839 int dbgCachedNumber;
840 int dbgCachedPoint;
841 int dbgCachedRange;
842 int dbgCachedLocset;
843 int dbgCachedUsers;
844 int dbgCachedXSLTTree;
845 int dbgCachedUndefined;
846
847
848 int dbgReusedAll;
849 int dbgReusedNodeset;
850 int dbgReusedString;
851 int dbgReusedBool;
852 int dbgReusedNumber;
853 int dbgReusedPoint;
854 int dbgReusedRange;
855 int dbgReusedLocset;
856 int dbgReusedUsers;
857 int dbgReusedXSLTTree;
858 int dbgReusedUndefined;
859
860#endif
861};
862
863/************************************************************************
864 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000865 * Debugging related functions *
866 * *
867 ************************************************************************/
868
Owen Taylor3473f882001-02-23 17:55:21 +0000869#define STRANGE \
870 xmlGenericError(xmlGenericErrorContext, \
871 "Internal error at %s:%d\n", \
872 __FILE__, __LINE__);
873
874#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000875static void
876xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000877 int i;
878 char shift[100];
879
880 for (i = 0;((i < depth) && (i < 25));i++)
881 shift[2 * i] = shift[2 * i + 1] = ' ';
882 shift[2 * i] = shift[2 * i + 1] = 0;
883 if (cur == NULL) {
884 fprintf(output, shift);
885 fprintf(output, "Node is NULL !\n");
886 return;
887
888 }
889
890 if ((cur->type == XML_DOCUMENT_NODE) ||
891 (cur->type == XML_HTML_DOCUMENT_NODE)) {
892 fprintf(output, shift);
893 fprintf(output, " /\n");
894 } else if (cur->type == XML_ATTRIBUTE_NODE)
895 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
896 else
897 xmlDebugDumpOneNode(output, cur, depth);
898}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000899static void
900xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000901 xmlNodePtr tmp;
902 int i;
903 char shift[100];
904
905 for (i = 0;((i < depth) && (i < 25));i++)
906 shift[2 * i] = shift[2 * i + 1] = ' ';
907 shift[2 * i] = shift[2 * i + 1] = 0;
908 if (cur == NULL) {
909 fprintf(output, shift);
910 fprintf(output, "Node is NULL !\n");
911 return;
912
913 }
914
915 while (cur != NULL) {
916 tmp = cur;
917 cur = cur->next;
918 xmlDebugDumpOneNode(output, tmp, depth);
919 }
920}
Owen Taylor3473f882001-02-23 17:55:21 +0000921
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000922static void
923xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000924 int i;
925 char shift[100];
926
927 for (i = 0;((i < depth) && (i < 25));i++)
928 shift[2 * i] = shift[2 * i + 1] = ' ';
929 shift[2 * i] = shift[2 * i + 1] = 0;
930
931 if (cur == NULL) {
932 fprintf(output, shift);
933 fprintf(output, "NodeSet is NULL !\n");
934 return;
935
936 }
937
Daniel Veillard911f49a2001-04-07 15:39:35 +0000938 if (cur != NULL) {
939 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
940 for (i = 0;i < cur->nodeNr;i++) {
941 fprintf(output, shift);
942 fprintf(output, "%d", i + 1);
943 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
944 }
Owen Taylor3473f882001-02-23 17:55:21 +0000945 }
946}
947
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000948static void
949xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000950 int i;
951 char shift[100];
952
953 for (i = 0;((i < depth) && (i < 25));i++)
954 shift[2 * i] = shift[2 * i + 1] = ' ';
955 shift[2 * i] = shift[2 * i + 1] = 0;
956
957 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
958 fprintf(output, shift);
959 fprintf(output, "Value Tree is NULL !\n");
960 return;
961
962 }
963
964 fprintf(output, shift);
965 fprintf(output, "%d", i + 1);
966 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
967}
Owen Taylor3473f882001-02-23 17:55:21 +0000968#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000969static void
970xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000971 int i;
972 char shift[100];
973
974 for (i = 0;((i < depth) && (i < 25));i++)
975 shift[2 * i] = shift[2 * i + 1] = ' ';
976 shift[2 * i] = shift[2 * i + 1] = 0;
977
978 if (cur == NULL) {
979 fprintf(output, shift);
980 fprintf(output, "LocationSet is NULL !\n");
981 return;
982
983 }
984
985 for (i = 0;i < cur->locNr;i++) {
986 fprintf(output, shift);
987 fprintf(output, "%d : ", i + 1);
988 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
989 }
990}
Daniel Veillard017b1082001-06-21 11:20:21 +0000991#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000992
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000993/**
994 * xmlXPathDebugDumpObject:
995 * @output: the FILE * to dump the output
996 * @cur: the object to inspect
997 * @depth: indentation level
998 *
999 * Dump the content of the object for debugging purposes
1000 */
1001void
1002xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001003 int i;
1004 char shift[100];
1005
Daniel Veillarda82b1822004-11-08 16:24:57 +00001006 if (output == NULL) return;
1007
Owen Taylor3473f882001-02-23 17:55:21 +00001008 for (i = 0;((i < depth) && (i < 25));i++)
1009 shift[2 * i] = shift[2 * i + 1] = ' ';
1010 shift[2 * i] = shift[2 * i + 1] = 0;
1011
Kasimier T. Buchcik97258712006-01-05 12:30:43 +00001012
1013 fprintf(output, shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001014
1015 if (cur == NULL) {
1016 fprintf(output, "Object is empty (NULL)\n");
1017 return;
1018 }
1019 switch(cur->type) {
1020 case XPATH_UNDEFINED:
1021 fprintf(output, "Object is uninitialized\n");
1022 break;
1023 case XPATH_NODESET:
1024 fprintf(output, "Object is a Node Set :\n");
1025 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1026 break;
1027 case XPATH_XSLT_TREE:
1028 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001029 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +00001030 break;
1031 case XPATH_BOOLEAN:
1032 fprintf(output, "Object is a Boolean : ");
1033 if (cur->boolval) fprintf(output, "true\n");
1034 else fprintf(output, "false\n");
1035 break;
1036 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +00001037 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001038 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001039 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001040 break;
1041 case -1:
1042 fprintf(output, "Object is a number : -Infinity\n");
1043 break;
1044 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001045 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001046 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001047 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1048 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001049 } else {
1050 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1051 }
1052 }
Owen Taylor3473f882001-02-23 17:55:21 +00001053 break;
1054 case XPATH_STRING:
1055 fprintf(output, "Object is a string : ");
1056 xmlDebugDumpString(output, cur->stringval);
1057 fprintf(output, "\n");
1058 break;
1059 case XPATH_POINT:
1060 fprintf(output, "Object is a point : index %d in node", cur->index);
1061 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1062 fprintf(output, "\n");
1063 break;
1064 case XPATH_RANGE:
1065 if ((cur->user2 == NULL) ||
1066 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1067 fprintf(output, "Object is a collapsed range :\n");
1068 fprintf(output, shift);
1069 if (cur->index >= 0)
1070 fprintf(output, "index %d in ", cur->index);
1071 fprintf(output, "node\n");
1072 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1073 depth + 1);
1074 } else {
1075 fprintf(output, "Object is a range :\n");
1076 fprintf(output, shift);
1077 fprintf(output, "From ");
1078 if (cur->index >= 0)
1079 fprintf(output, "index %d in ", cur->index);
1080 fprintf(output, "node\n");
1081 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1082 depth + 1);
1083 fprintf(output, shift);
1084 fprintf(output, "To ");
1085 if (cur->index2 >= 0)
1086 fprintf(output, "index %d in ", cur->index2);
1087 fprintf(output, "node\n");
1088 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1089 depth + 1);
1090 fprintf(output, "\n");
1091 }
1092 break;
1093 case XPATH_LOCATIONSET:
1094#if defined(LIBXML_XPTR_ENABLED)
1095 fprintf(output, "Object is a Location Set:\n");
1096 xmlXPathDebugDumpLocationSet(output,
1097 (xmlLocationSetPtr) cur->user, depth);
1098#endif
1099 break;
1100 case XPATH_USERS:
1101 fprintf(output, "Object is user defined\n");
1102 break;
1103 }
1104}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001105
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001106static void
1107xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001108 xmlXPathStepOpPtr op, int depth) {
1109 int i;
1110 char shift[100];
1111
1112 for (i = 0;((i < depth) && (i < 25));i++)
1113 shift[2 * i] = shift[2 * i + 1] = ' ';
1114 shift[2 * i] = shift[2 * i + 1] = 0;
1115
1116 fprintf(output, shift);
1117 if (op == NULL) {
1118 fprintf(output, "Step is NULL\n");
1119 return;
1120 }
1121 switch (op->op) {
1122 case XPATH_OP_END:
1123 fprintf(output, "END"); break;
1124 case XPATH_OP_AND:
1125 fprintf(output, "AND"); break;
1126 case XPATH_OP_OR:
1127 fprintf(output, "OR"); break;
1128 case XPATH_OP_EQUAL:
1129 if (op->value)
1130 fprintf(output, "EQUAL =");
1131 else
1132 fprintf(output, "EQUAL !=");
1133 break;
1134 case XPATH_OP_CMP:
1135 if (op->value)
1136 fprintf(output, "CMP <");
1137 else
1138 fprintf(output, "CMP >");
1139 if (!op->value2)
1140 fprintf(output, "=");
1141 break;
1142 case XPATH_OP_PLUS:
1143 if (op->value == 0)
1144 fprintf(output, "PLUS -");
1145 else if (op->value == 1)
1146 fprintf(output, "PLUS +");
1147 else if (op->value == 2)
1148 fprintf(output, "PLUS unary -");
1149 else if (op->value == 3)
1150 fprintf(output, "PLUS unary - -");
1151 break;
1152 case XPATH_OP_MULT:
1153 if (op->value == 0)
1154 fprintf(output, "MULT *");
1155 else if (op->value == 1)
1156 fprintf(output, "MULT div");
1157 else
1158 fprintf(output, "MULT mod");
1159 break;
1160 case XPATH_OP_UNION:
1161 fprintf(output, "UNION"); break;
1162 case XPATH_OP_ROOT:
1163 fprintf(output, "ROOT"); break;
1164 case XPATH_OP_NODE:
1165 fprintf(output, "NODE"); break;
1166 case XPATH_OP_RESET:
1167 fprintf(output, "RESET"); break;
1168 case XPATH_OP_SORT:
1169 fprintf(output, "SORT"); break;
1170 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +00001171 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1172 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1173 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001174 const xmlChar *prefix = op->value4;
1175 const xmlChar *name = op->value5;
1176
1177 fprintf(output, "COLLECT ");
1178 switch (axis) {
1179 case AXIS_ANCESTOR:
1180 fprintf(output, " 'ancestors' "); break;
1181 case AXIS_ANCESTOR_OR_SELF:
1182 fprintf(output, " 'ancestors-or-self' "); break;
1183 case AXIS_ATTRIBUTE:
1184 fprintf(output, " 'attributes' "); break;
1185 case AXIS_CHILD:
1186 fprintf(output, " 'child' "); break;
1187 case AXIS_DESCENDANT:
1188 fprintf(output, " 'descendant' "); break;
1189 case AXIS_DESCENDANT_OR_SELF:
1190 fprintf(output, " 'descendant-or-self' "); break;
1191 case AXIS_FOLLOWING:
1192 fprintf(output, " 'following' "); break;
1193 case AXIS_FOLLOWING_SIBLING:
1194 fprintf(output, " 'following-siblings' "); break;
1195 case AXIS_NAMESPACE:
1196 fprintf(output, " 'namespace' "); break;
1197 case AXIS_PARENT:
1198 fprintf(output, " 'parent' "); break;
1199 case AXIS_PRECEDING:
1200 fprintf(output, " 'preceding' "); break;
1201 case AXIS_PRECEDING_SIBLING:
1202 fprintf(output, " 'preceding-sibling' "); break;
1203 case AXIS_SELF:
1204 fprintf(output, " 'self' "); break;
1205 }
1206 switch (test) {
1207 case NODE_TEST_NONE:
1208 fprintf(output, "'none' "); break;
1209 case NODE_TEST_TYPE:
1210 fprintf(output, "'type' "); break;
1211 case NODE_TEST_PI:
1212 fprintf(output, "'PI' "); break;
1213 case NODE_TEST_ALL:
1214 fprintf(output, "'all' "); break;
1215 case NODE_TEST_NS:
1216 fprintf(output, "'namespace' "); break;
1217 case NODE_TEST_NAME:
1218 fprintf(output, "'name' "); break;
1219 }
1220 switch (type) {
1221 case NODE_TYPE_NODE:
1222 fprintf(output, "'node' "); break;
1223 case NODE_TYPE_COMMENT:
1224 fprintf(output, "'comment' "); break;
1225 case NODE_TYPE_TEXT:
1226 fprintf(output, "'text' "); break;
1227 case NODE_TYPE_PI:
1228 fprintf(output, "'PI' "); break;
1229 }
1230 if (prefix != NULL)
1231 fprintf(output, "%s:", prefix);
1232 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001233 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001234 break;
1235
1236 }
1237 case XPATH_OP_VALUE: {
1238 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1239
1240 fprintf(output, "ELEM ");
1241 xmlXPathDebugDumpObject(output, object, 0);
1242 goto finish;
1243 }
1244 case XPATH_OP_VARIABLE: {
1245 const xmlChar *prefix = op->value5;
1246 const xmlChar *name = op->value4;
1247
1248 if (prefix != NULL)
1249 fprintf(output, "VARIABLE %s:%s", prefix, name);
1250 else
1251 fprintf(output, "VARIABLE %s", name);
1252 break;
1253 }
1254 case XPATH_OP_FUNCTION: {
1255 int nbargs = op->value;
1256 const xmlChar *prefix = op->value5;
1257 const xmlChar *name = op->value4;
1258
1259 if (prefix != NULL)
1260 fprintf(output, "FUNCTION %s:%s(%d args)",
1261 prefix, name, nbargs);
1262 else
1263 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1264 break;
1265 }
1266 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1267 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001268 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001269#ifdef LIBXML_XPTR_ENABLED
1270 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1271#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001272 default:
1273 fprintf(output, "UNKNOWN %d\n", op->op); return;
1274 }
1275 fprintf(output, "\n");
1276finish:
1277 if (op->ch1 >= 0)
1278 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1279 if (op->ch2 >= 0)
1280 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1281}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001282
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001283/**
1284 * xmlXPathDebugDumpCompExpr:
1285 * @output: the FILE * for the output
1286 * @comp: the precompiled XPath expression
1287 * @depth: the indentation level.
1288 *
1289 * Dumps the tree of the compiled XPath expression.
1290 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001291void
1292xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1293 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001294 int i;
1295 char shift[100];
1296
Daniel Veillarda82b1822004-11-08 16:24:57 +00001297 if ((output == NULL) || (comp == NULL)) return;
1298
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001299 for (i = 0;((i < depth) && (i < 25));i++)
1300 shift[2 * i] = shift[2 * i + 1] = ' ';
1301 shift[2 * i] = shift[2 * i + 1] = 0;
1302
1303 fprintf(output, shift);
1304
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001305 fprintf(output, "Compiled Expression : %d elements\n",
1306 comp->nbStep);
1307 i = comp->last;
1308 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1309}
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001310
1311#ifdef XP_DEBUG_OBJ_USAGE
1312
1313/*
1314* XPath object usage related debugging variables.
1315*/
1316static int xmlXPathDebugObjCounterUndefined = 0;
1317static int xmlXPathDebugObjCounterNodeset = 0;
1318static int xmlXPathDebugObjCounterBool = 0;
1319static int xmlXPathDebugObjCounterNumber = 0;
1320static int xmlXPathDebugObjCounterString = 0;
1321static int xmlXPathDebugObjCounterPoint = 0;
1322static int xmlXPathDebugObjCounterRange = 0;
1323static int xmlXPathDebugObjCounterLocset = 0;
1324static int xmlXPathDebugObjCounterUsers = 0;
1325static int xmlXPathDebugObjCounterXSLTTree = 0;
1326static int xmlXPathDebugObjCounterAll = 0;
1327
1328static int xmlXPathDebugObjTotalUndefined = 0;
1329static int xmlXPathDebugObjTotalNodeset = 0;
1330static int xmlXPathDebugObjTotalBool = 0;
1331static int xmlXPathDebugObjTotalNumber = 0;
1332static int xmlXPathDebugObjTotalString = 0;
1333static int xmlXPathDebugObjTotalPoint = 0;
1334static int xmlXPathDebugObjTotalRange = 0;
1335static int xmlXPathDebugObjTotalLocset = 0;
1336static int xmlXPathDebugObjTotalUsers = 0;
1337static int xmlXPathDebugObjTotalXSLTTree = 0;
1338static int xmlXPathDebugObjTotalAll = 0;
1339
1340static int xmlXPathDebugObjMaxUndefined = 0;
1341static int xmlXPathDebugObjMaxNodeset = 0;
1342static int xmlXPathDebugObjMaxBool = 0;
1343static int xmlXPathDebugObjMaxNumber = 0;
1344static int xmlXPathDebugObjMaxString = 0;
1345static int xmlXPathDebugObjMaxPoint = 0;
1346static int xmlXPathDebugObjMaxRange = 0;
1347static int xmlXPathDebugObjMaxLocset = 0;
1348static int xmlXPathDebugObjMaxUsers = 0;
1349static int xmlXPathDebugObjMaxXSLTTree = 0;
1350static int xmlXPathDebugObjMaxAll = 0;
1351
1352/* REVISIT TODO: Make this static when committing */
1353static void
1354xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1355{
1356 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001357 if (ctxt->cache != NULL) {
1358 xmlXPathContextCachePtr cache =
1359 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001360
1361 cache->dbgCachedAll = 0;
1362 cache->dbgCachedNodeset = 0;
1363 cache->dbgCachedString = 0;
1364 cache->dbgCachedBool = 0;
1365 cache->dbgCachedNumber = 0;
1366 cache->dbgCachedPoint = 0;
1367 cache->dbgCachedRange = 0;
1368 cache->dbgCachedLocset = 0;
1369 cache->dbgCachedUsers = 0;
1370 cache->dbgCachedXSLTTree = 0;
1371 cache->dbgCachedUndefined = 0;
1372
1373 cache->dbgReusedAll = 0;
1374 cache->dbgReusedNodeset = 0;
1375 cache->dbgReusedString = 0;
1376 cache->dbgReusedBool = 0;
1377 cache->dbgReusedNumber = 0;
1378 cache->dbgReusedPoint = 0;
1379 cache->dbgReusedRange = 0;
1380 cache->dbgReusedLocset = 0;
1381 cache->dbgReusedUsers = 0;
1382 cache->dbgReusedXSLTTree = 0;
1383 cache->dbgReusedUndefined = 0;
1384 }
1385 }
1386
1387 xmlXPathDebugObjCounterUndefined = 0;
1388 xmlXPathDebugObjCounterNodeset = 0;
1389 xmlXPathDebugObjCounterBool = 0;
1390 xmlXPathDebugObjCounterNumber = 0;
1391 xmlXPathDebugObjCounterString = 0;
1392 xmlXPathDebugObjCounterPoint = 0;
1393 xmlXPathDebugObjCounterRange = 0;
1394 xmlXPathDebugObjCounterLocset = 0;
1395 xmlXPathDebugObjCounterUsers = 0;
1396 xmlXPathDebugObjCounterXSLTTree = 0;
1397 xmlXPathDebugObjCounterAll = 0;
1398
1399 xmlXPathDebugObjTotalUndefined = 0;
1400 xmlXPathDebugObjTotalNodeset = 0;
1401 xmlXPathDebugObjTotalBool = 0;
1402 xmlXPathDebugObjTotalNumber = 0;
1403 xmlXPathDebugObjTotalString = 0;
1404 xmlXPathDebugObjTotalPoint = 0;
1405 xmlXPathDebugObjTotalRange = 0;
1406 xmlXPathDebugObjTotalLocset = 0;
1407 xmlXPathDebugObjTotalUsers = 0;
1408 xmlXPathDebugObjTotalXSLTTree = 0;
1409 xmlXPathDebugObjTotalAll = 0;
1410
1411 xmlXPathDebugObjMaxUndefined = 0;
1412 xmlXPathDebugObjMaxNodeset = 0;
1413 xmlXPathDebugObjMaxBool = 0;
1414 xmlXPathDebugObjMaxNumber = 0;
1415 xmlXPathDebugObjMaxString = 0;
1416 xmlXPathDebugObjMaxPoint = 0;
1417 xmlXPathDebugObjMaxRange = 0;
1418 xmlXPathDebugObjMaxLocset = 0;
1419 xmlXPathDebugObjMaxUsers = 0;
1420 xmlXPathDebugObjMaxXSLTTree = 0;
1421 xmlXPathDebugObjMaxAll = 0;
1422
1423}
1424
1425static void
1426xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1427 xmlXPathObjectType objType)
1428{
1429 int isCached = 0;
1430
1431 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001432 if (ctxt->cache != NULL) {
1433 xmlXPathContextCachePtr cache =
1434 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001435
1436 isCached = 1;
1437
1438 cache->dbgReusedAll++;
1439 switch (objType) {
1440 case XPATH_UNDEFINED:
1441 cache->dbgReusedUndefined++;
1442 break;
1443 case XPATH_NODESET:
1444 cache->dbgReusedNodeset++;
1445 break;
1446 case XPATH_BOOLEAN:
1447 cache->dbgReusedBool++;
1448 break;
1449 case XPATH_NUMBER:
1450 cache->dbgReusedNumber++;
1451 break;
1452 case XPATH_STRING:
1453 cache->dbgReusedString++;
1454 break;
1455 case XPATH_POINT:
1456 cache->dbgReusedPoint++;
1457 break;
1458 case XPATH_RANGE:
1459 cache->dbgReusedRange++;
1460 break;
1461 case XPATH_LOCATIONSET:
1462 cache->dbgReusedLocset++;
1463 break;
1464 case XPATH_USERS:
1465 cache->dbgReusedUsers++;
1466 break;
1467 case XPATH_XSLT_TREE:
1468 cache->dbgReusedXSLTTree++;
1469 break;
1470 default:
1471 break;
1472 }
1473 }
1474 }
1475
1476 switch (objType) {
1477 case XPATH_UNDEFINED:
1478 if (! isCached)
1479 xmlXPathDebugObjTotalUndefined++;
1480 xmlXPathDebugObjCounterUndefined++;
1481 if (xmlXPathDebugObjCounterUndefined >
1482 xmlXPathDebugObjMaxUndefined)
1483 xmlXPathDebugObjMaxUndefined =
1484 xmlXPathDebugObjCounterUndefined;
1485 break;
1486 case XPATH_NODESET:
1487 if (! isCached)
1488 xmlXPathDebugObjTotalNodeset++;
1489 xmlXPathDebugObjCounterNodeset++;
1490 if (xmlXPathDebugObjCounterNodeset >
1491 xmlXPathDebugObjMaxNodeset)
1492 xmlXPathDebugObjMaxNodeset =
1493 xmlXPathDebugObjCounterNodeset;
1494 break;
1495 case XPATH_BOOLEAN:
1496 if (! isCached)
1497 xmlXPathDebugObjTotalBool++;
1498 xmlXPathDebugObjCounterBool++;
1499 if (xmlXPathDebugObjCounterBool >
1500 xmlXPathDebugObjMaxBool)
1501 xmlXPathDebugObjMaxBool =
1502 xmlXPathDebugObjCounterBool;
1503 break;
1504 case XPATH_NUMBER:
1505 if (! isCached)
1506 xmlXPathDebugObjTotalNumber++;
1507 xmlXPathDebugObjCounterNumber++;
1508 if (xmlXPathDebugObjCounterNumber >
1509 xmlXPathDebugObjMaxNumber)
1510 xmlXPathDebugObjMaxNumber =
1511 xmlXPathDebugObjCounterNumber;
1512 break;
1513 case XPATH_STRING:
1514 if (! isCached)
1515 xmlXPathDebugObjTotalString++;
1516 xmlXPathDebugObjCounterString++;
1517 if (xmlXPathDebugObjCounterString >
1518 xmlXPathDebugObjMaxString)
1519 xmlXPathDebugObjMaxString =
1520 xmlXPathDebugObjCounterString;
1521 break;
1522 case XPATH_POINT:
1523 if (! isCached)
1524 xmlXPathDebugObjTotalPoint++;
1525 xmlXPathDebugObjCounterPoint++;
1526 if (xmlXPathDebugObjCounterPoint >
1527 xmlXPathDebugObjMaxPoint)
1528 xmlXPathDebugObjMaxPoint =
1529 xmlXPathDebugObjCounterPoint;
1530 break;
1531 case XPATH_RANGE:
1532 if (! isCached)
1533 xmlXPathDebugObjTotalRange++;
1534 xmlXPathDebugObjCounterRange++;
1535 if (xmlXPathDebugObjCounterRange >
1536 xmlXPathDebugObjMaxRange)
1537 xmlXPathDebugObjMaxRange =
1538 xmlXPathDebugObjCounterRange;
1539 break;
1540 case XPATH_LOCATIONSET:
1541 if (! isCached)
1542 xmlXPathDebugObjTotalLocset++;
1543 xmlXPathDebugObjCounterLocset++;
1544 if (xmlXPathDebugObjCounterLocset >
1545 xmlXPathDebugObjMaxLocset)
1546 xmlXPathDebugObjMaxLocset =
1547 xmlXPathDebugObjCounterLocset;
1548 break;
1549 case XPATH_USERS:
1550 if (! isCached)
1551 xmlXPathDebugObjTotalUsers++;
1552 xmlXPathDebugObjCounterUsers++;
1553 if (xmlXPathDebugObjCounterUsers >
1554 xmlXPathDebugObjMaxUsers)
1555 xmlXPathDebugObjMaxUsers =
1556 xmlXPathDebugObjCounterUsers;
1557 break;
1558 case XPATH_XSLT_TREE:
1559 if (! isCached)
1560 xmlXPathDebugObjTotalXSLTTree++;
1561 xmlXPathDebugObjCounterXSLTTree++;
1562 if (xmlXPathDebugObjCounterXSLTTree >
1563 xmlXPathDebugObjMaxXSLTTree)
1564 xmlXPathDebugObjMaxXSLTTree =
1565 xmlXPathDebugObjCounterXSLTTree;
1566 break;
1567 default:
1568 break;
1569 }
1570 if (! isCached)
1571 xmlXPathDebugObjTotalAll++;
1572 xmlXPathDebugObjCounterAll++;
1573 if (xmlXPathDebugObjCounterAll >
1574 xmlXPathDebugObjMaxAll)
1575 xmlXPathDebugObjMaxAll =
1576 xmlXPathDebugObjCounterAll;
1577}
1578
1579static void
1580xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1581 xmlXPathObjectType objType)
1582{
1583 int isCached = 0;
1584
1585 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001586 if (ctxt->cache != NULL) {
1587 xmlXPathContextCachePtr cache =
1588 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001589
1590 isCached = 1;
1591
1592 cache->dbgCachedAll++;
1593 switch (objType) {
1594 case XPATH_UNDEFINED:
1595 cache->dbgCachedUndefined++;
1596 break;
1597 case XPATH_NODESET:
1598 cache->dbgCachedNodeset++;
1599 break;
1600 case XPATH_BOOLEAN:
1601 cache->dbgCachedBool++;
1602 break;
1603 case XPATH_NUMBER:
1604 cache->dbgCachedNumber++;
1605 break;
1606 case XPATH_STRING:
1607 cache->dbgCachedString++;
1608 break;
1609 case XPATH_POINT:
1610 cache->dbgCachedPoint++;
1611 break;
1612 case XPATH_RANGE:
1613 cache->dbgCachedRange++;
1614 break;
1615 case XPATH_LOCATIONSET:
1616 cache->dbgCachedLocset++;
1617 break;
1618 case XPATH_USERS:
1619 cache->dbgCachedUsers++;
1620 break;
1621 case XPATH_XSLT_TREE:
1622 cache->dbgCachedXSLTTree++;
1623 break;
1624 default:
1625 break;
1626 }
1627
1628 }
1629 }
1630 switch (objType) {
1631 case XPATH_UNDEFINED:
1632 xmlXPathDebugObjCounterUndefined--;
1633 break;
1634 case XPATH_NODESET:
1635 xmlXPathDebugObjCounterNodeset--;
1636 break;
1637 case XPATH_BOOLEAN:
1638 xmlXPathDebugObjCounterBool--;
1639 break;
1640 case XPATH_NUMBER:
1641 xmlXPathDebugObjCounterNumber--;
1642 break;
1643 case XPATH_STRING:
1644 xmlXPathDebugObjCounterString--;
1645 break;
1646 case XPATH_POINT:
1647 xmlXPathDebugObjCounterPoint--;
1648 break;
1649 case XPATH_RANGE:
1650 xmlXPathDebugObjCounterRange--;
1651 break;
1652 case XPATH_LOCATIONSET:
1653 xmlXPathDebugObjCounterLocset--;
1654 break;
1655 case XPATH_USERS:
1656 xmlXPathDebugObjCounterUsers--;
1657 break;
1658 case XPATH_XSLT_TREE:
1659 xmlXPathDebugObjCounterXSLTTree--;
1660 break;
1661 default:
1662 break;
1663 }
1664 xmlXPathDebugObjCounterAll--;
1665}
1666
1667/* REVISIT TODO: Make this static when committing */
1668static void
1669xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
1670{
1671 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
1672 reqXSLTTree, reqUndefined;
1673 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
1674 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
1675 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
1676 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
1677 int leftObjs = xmlXPathDebugObjCounterAll;
1678
1679 reqAll = xmlXPathDebugObjTotalAll;
1680 reqNodeset = xmlXPathDebugObjTotalNodeset;
1681 reqString = xmlXPathDebugObjTotalString;
1682 reqBool = xmlXPathDebugObjTotalBool;
1683 reqNumber = xmlXPathDebugObjTotalNumber;
1684 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
1685 reqUndefined = xmlXPathDebugObjTotalUndefined;
1686
1687 printf("# XPath object usage:\n");
1688
1689 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001690 if (ctxt->cache != NULL) {
1691 xmlXPathContextCachePtr cache =
1692 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001693
1694 reAll = cache->dbgReusedAll;
1695 reqAll += reAll;
1696 reNodeset = cache->dbgReusedNodeset;
1697 reqNodeset += reNodeset;
1698 reString = cache->dbgReusedString;
1699 reqString += reString;
1700 reBool = cache->dbgReusedBool;
1701 reqBool += reBool;
1702 reNumber = cache->dbgReusedNumber;
1703 reqNumber += reNumber;
1704 reXSLTTree = cache->dbgReusedXSLTTree;
1705 reqXSLTTree += reXSLTTree;
1706 reUndefined = cache->dbgReusedUndefined;
1707 reqUndefined += reUndefined;
1708
1709 caAll = cache->dbgCachedAll;
1710 caBool = cache->dbgCachedBool;
1711 caNodeset = cache->dbgCachedNodeset;
1712 caString = cache->dbgCachedString;
1713 caNumber = cache->dbgCachedNumber;
1714 caXSLTTree = cache->dbgCachedXSLTTree;
1715 caUndefined = cache->dbgCachedUndefined;
1716
1717 if (cache->nodesetObjs)
1718 leftObjs -= cache->nodesetObjs->number;
1719 if (cache->stringObjs)
1720 leftObjs -= cache->stringObjs->number;
1721 if (cache->booleanObjs)
1722 leftObjs -= cache->booleanObjs->number;
1723 if (cache->numberObjs)
1724 leftObjs -= cache->numberObjs->number;
1725 if (cache->miscObjs)
1726 leftObjs -= cache->miscObjs->number;
1727 }
1728 }
1729
1730 printf("# all\n");
1731 printf("# total : %d\n", reqAll);
1732 printf("# left : %d\n", leftObjs);
1733 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
1734 printf("# reused : %d\n", reAll);
1735 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
1736
1737 printf("# node-sets\n");
1738 printf("# total : %d\n", reqNodeset);
1739 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
1740 printf("# reused : %d\n", reNodeset);
1741 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
1742
1743 printf("# strings\n");
1744 printf("# total : %d\n", reqString);
1745 printf("# created: %d\n", xmlXPathDebugObjTotalString);
1746 printf("# reused : %d\n", reString);
1747 printf("# max : %d\n", xmlXPathDebugObjMaxString);
1748
1749 printf("# booleans\n");
1750 printf("# total : %d\n", reqBool);
1751 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
1752 printf("# reused : %d\n", reBool);
1753 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
1754
1755 printf("# numbers\n");
1756 printf("# total : %d\n", reqNumber);
1757 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
1758 printf("# reused : %d\n", reNumber);
1759 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
1760
1761 printf("# XSLT result tree fragments\n");
1762 printf("# total : %d\n", reqXSLTTree);
1763 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
1764 printf("# reused : %d\n", reXSLTTree);
1765 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
1766
1767 printf("# undefined\n");
1768 printf("# total : %d\n", reqUndefined);
1769 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
1770 printf("# reused : %d\n", reUndefined);
1771 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
1772
1773}
1774
1775#endif /* XP_DEBUG_OBJ_USAGE */
1776
Daniel Veillard017b1082001-06-21 11:20:21 +00001777#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001778
1779/************************************************************************
1780 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001781 * XPath object caching *
1782 * *
1783 ************************************************************************/
1784
1785/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001786 * xmlXPathNewCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001787 *
1788 * Create a new object cache
1789 *
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001790 * Returns the xmlXPathCache just allocated.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001791 */
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001792static xmlXPathContextCachePtr
1793xmlXPathNewCache(void)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001794{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001795 xmlXPathContextCachePtr ret;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001796
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001797 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001798 if (ret == NULL) {
1799 xmlXPathErrMemory(NULL, "creating object cache\n");
1800 return(NULL);
1801 }
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001802 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001803 ret->maxNodeset = 100;
1804 ret->maxString = 100;
1805 ret->maxBoolean = 100;
1806 ret->maxNumber = 100;
1807 ret->maxMisc = 100;
1808 return(ret);
1809}
1810
1811static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001812xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001813{
1814 int i;
1815 xmlXPathObjectPtr obj;
1816
1817 if (list == NULL)
1818 return;
1819
1820 for (i = 0; i < list->number; i++) {
1821 obj = list->items[i];
1822 /*
1823 * Note that it is already assured that we don't need to
1824 * look out for namespace nodes in the node-set.
1825 */
1826 if (obj->nodesetval != NULL) {
1827 if (obj->nodesetval->nodeTab != NULL)
1828 xmlFree(obj->nodesetval->nodeTab);
1829 xmlFree(obj->nodesetval);
1830 }
1831 xmlFree(obj);
1832#ifdef XP_DEBUG_OBJ_USAGE
1833 xmlXPathDebugObjCounterAll--;
1834#endif
1835 }
1836 xmlPointerListFree(list);
1837}
1838
1839static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001840xmlXPathFreeCache(xmlXPathContextCachePtr cache)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001841{
1842 if (cache == NULL)
1843 return;
1844 if (cache->nodesetObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001845 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001846 if (cache->stringObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001847 xmlXPathCacheFreeObjectList(cache->stringObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001848 if (cache->booleanObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001849 xmlXPathCacheFreeObjectList(cache->booleanObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001850 if (cache->numberObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001851 xmlXPathCacheFreeObjectList(cache->numberObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001852 if (cache->miscObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001853 xmlXPathCacheFreeObjectList(cache->miscObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001854 xmlFree(cache);
1855}
1856
1857/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001858 * xmlXPathContextSetCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001859 *
1860 * @ctxt: the XPath context
1861 * @active: enables/disables (creates/frees) the cache
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001862 * @value: a value with semantics dependant on @options
1863 * @options: options (currently only the value 0 is used)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001864 *
1865 * Creates/frees an object cache on the XPath context.
1866 * If activates XPath objects (xmlXPathObject) will be cached internally
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001867 * to be reused.
1868 * @options:
1869 * 0: This will set the XPath object caching:
1870 * @value:
1871 * This will set the maximum number of XPath objects
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001872 * to be cached per slot
1873 * There are 5 slots for: node-set, string, number, boolean, and
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001874 * misc objects. Use <0 for the default number (100).
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001875 * Other values for @options have currently no effect.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001876 *
1877 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1878 */
1879int
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001880xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1881 int active,
1882 int value,
1883 int options)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001884{
1885 if (ctxt == NULL)
1886 return(-1);
1887 if (active) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001888 xmlXPathContextCachePtr cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001889
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001890 if (ctxt->cache == NULL) {
1891 ctxt->cache = xmlXPathNewCache();
1892 if (ctxt->cache == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001893 return(-1);
1894 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001895 cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001896 if (options == 0) {
1897 if (value < 0)
1898 value = 100;
1899 cache->maxNodeset = value;
1900 cache->maxString = value;
1901 cache->maxNumber = value;
1902 cache->maxBoolean = value;
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001903 cache->maxMisc = value;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001904 }
1905 } else if (ctxt->cache != NULL) {
1906 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1907 ctxt->cache = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001908 }
1909 return(0);
1910}
1911
1912/**
1913 * xmlXPathCacheWrapNodeSet:
1914 * @ctxt: the XPath context
1915 * @val: the NodePtr value
1916 *
1917 * This is the cached version of xmlXPathWrapNodeSet().
1918 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1919 *
1920 * Returns the created or reused object.
1921 */
1922static xmlXPathObjectPtr
1923xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
1924{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001925 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1926 xmlXPathContextCachePtr cache =
1927 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001928
1929 if ((cache->miscObjs != NULL) &&
1930 (cache->miscObjs->number != 0))
1931 {
1932 xmlXPathObjectPtr ret;
1933
1934 ret = (xmlXPathObjectPtr)
1935 cache->miscObjs->items[--cache->miscObjs->number];
1936 ret->type = XPATH_NODESET;
1937 ret->nodesetval = val;
1938#ifdef XP_DEBUG_OBJ_USAGE
1939 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
1940#endif
1941 return(ret);
1942 }
1943 }
1944
1945 return(xmlXPathWrapNodeSet(val));
1946
1947}
1948
1949/**
1950 * xmlXPathCacheWrapString:
1951 * @ctxt: the XPath context
1952 * @val: the xmlChar * value
1953 *
1954 * This is the cached version of xmlXPathWrapString().
1955 * Wraps the @val string into an XPath object.
1956 *
1957 * Returns the created or reused object.
1958 */
1959static xmlXPathObjectPtr
1960xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
1961{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001962 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1963 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001964
1965 if ((cache->stringObjs != NULL) &&
1966 (cache->stringObjs->number != 0))
1967 {
1968
1969 xmlXPathObjectPtr ret;
1970
1971 ret = (xmlXPathObjectPtr)
1972 cache->stringObjs->items[--cache->stringObjs->number];
1973 ret->type = XPATH_STRING;
1974 ret->stringval = val;
1975#ifdef XP_DEBUG_OBJ_USAGE
1976 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1977#endif
1978 return(ret);
1979 } else if ((cache->miscObjs != NULL) &&
1980 (cache->miscObjs->number != 0))
1981 {
1982 xmlXPathObjectPtr ret;
1983 /*
1984 * Fallback to misc-cache.
1985 */
1986 ret = (xmlXPathObjectPtr)
1987 cache->miscObjs->items[--cache->miscObjs->number];
1988
1989 ret->type = XPATH_STRING;
1990 ret->stringval = val;
1991#ifdef XP_DEBUG_OBJ_USAGE
1992 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1993#endif
1994 return(ret);
1995 }
1996 }
1997 return(xmlXPathWrapString(val));
1998}
1999
2000/**
2001 * xmlXPathCacheNewNodeSet:
2002 * @ctxt: the XPath context
2003 * @val: the NodePtr value
2004 *
2005 * This is the cached version of xmlXPathNewNodeSet().
2006 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2007 * it with the single Node @val
2008 *
2009 * Returns the created or reused object.
2010 */
2011static xmlXPathObjectPtr
2012xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2013{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002014 if ((ctxt != NULL) && (ctxt->cache)) {
2015 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002016
2017 if ((cache->nodesetObjs != NULL) &&
2018 (cache->nodesetObjs->number != 0))
2019 {
2020 xmlXPathObjectPtr ret;
2021 /*
2022 * Use the nodset-cache.
2023 */
2024 ret = (xmlXPathObjectPtr)
2025 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2026 ret->type = XPATH_NODESET;
2027 ret->boolval = 0;
2028 if (val) {
2029 if ((ret->nodesetval->nodeMax == 0) ||
2030 (val->type == XML_NAMESPACE_DECL))
2031 {
2032 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2033 } else {
2034 ret->nodesetval->nodeTab[0] = val;
2035 ret->nodesetval->nodeNr = 1;
2036 }
2037 }
2038#ifdef XP_DEBUG_OBJ_USAGE
2039 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2040#endif
2041 return(ret);
2042 } else if ((cache->miscObjs != NULL) &&
2043 (cache->miscObjs->number != 0))
2044 {
2045 xmlXPathObjectPtr ret;
2046 /*
2047 * Fallback to misc-cache.
2048 */
2049
2050 ret = (xmlXPathObjectPtr)
2051 cache->miscObjs->items[--cache->miscObjs->number];
2052
2053 ret->type = XPATH_NODESET;
2054 ret->boolval = 0;
2055 ret->nodesetval = xmlXPathNodeSetCreate(val);
2056#ifdef XP_DEBUG_OBJ_USAGE
2057 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2058#endif
2059 return(ret);
2060 }
2061 }
2062 return(xmlXPathNewNodeSet(val));
2063}
2064
2065/**
2066 * xmlXPathCacheNewCString:
2067 * @ctxt: the XPath context
2068 * @val: the char * value
2069 *
2070 * This is the cached version of xmlXPathNewCString().
2071 * Acquire an xmlXPathObjectPtr of type string and of value @val
2072 *
2073 * Returns the created or reused object.
2074 */
2075static xmlXPathObjectPtr
2076xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2077{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002078 if ((ctxt != NULL) && (ctxt->cache)) {
2079 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002080
2081 if ((cache->stringObjs != NULL) &&
2082 (cache->stringObjs->number != 0))
2083 {
2084 xmlXPathObjectPtr ret;
2085
2086 ret = (xmlXPathObjectPtr)
2087 cache->stringObjs->items[--cache->stringObjs->number];
2088
2089 ret->type = XPATH_STRING;
2090 ret->stringval = xmlStrdup(BAD_CAST val);
2091#ifdef XP_DEBUG_OBJ_USAGE
2092 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2093#endif
2094 return(ret);
2095 } else if ((cache->miscObjs != NULL) &&
2096 (cache->miscObjs->number != 0))
2097 {
2098 xmlXPathObjectPtr ret;
2099
2100 ret = (xmlXPathObjectPtr)
2101 cache->miscObjs->items[--cache->miscObjs->number];
2102
2103 ret->type = XPATH_STRING;
2104 ret->stringval = xmlStrdup(BAD_CAST val);
2105#ifdef XP_DEBUG_OBJ_USAGE
2106 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2107#endif
2108 return(ret);
2109 }
2110 }
2111 return(xmlXPathNewCString(val));
2112}
2113
2114/**
2115 * xmlXPathCacheNewString:
2116 * @ctxt: the XPath context
2117 * @val: the xmlChar * value
2118 *
2119 * This is the cached version of xmlXPathNewString().
2120 * Acquire an xmlXPathObjectPtr of type string and of value @val
2121 *
2122 * Returns the created or reused object.
2123 */
2124static xmlXPathObjectPtr
2125xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2126{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002127 if ((ctxt != NULL) && (ctxt->cache)) {
2128 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002129
2130 if ((cache->stringObjs != NULL) &&
2131 (cache->stringObjs->number != 0))
2132 {
2133 xmlXPathObjectPtr ret;
2134
2135 ret = (xmlXPathObjectPtr)
2136 cache->stringObjs->items[--cache->stringObjs->number];
2137 ret->type = XPATH_STRING;
2138 if (val != NULL)
2139 ret->stringval = xmlStrdup(val);
2140 else
2141 ret->stringval = xmlStrdup((const xmlChar *)"");
2142#ifdef XP_DEBUG_OBJ_USAGE
2143 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2144#endif
2145 return(ret);
2146 } else if ((cache->miscObjs != NULL) &&
2147 (cache->miscObjs->number != 0))
2148 {
2149 xmlXPathObjectPtr ret;
2150
2151 ret = (xmlXPathObjectPtr)
2152 cache->miscObjs->items[--cache->miscObjs->number];
2153
2154 ret->type = XPATH_STRING;
2155 if (val != NULL)
2156 ret->stringval = xmlStrdup(val);
2157 else
2158 ret->stringval = xmlStrdup((const xmlChar *)"");
2159#ifdef XP_DEBUG_OBJ_USAGE
2160 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2161#endif
2162 return(ret);
2163 }
2164 }
2165 return(xmlXPathNewString(val));
2166}
2167
2168/**
2169 * xmlXPathCacheNewBoolean:
2170 * @ctxt: the XPath context
2171 * @val: the boolean value
2172 *
2173 * This is the cached version of xmlXPathNewBoolean().
2174 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2175 *
2176 * Returns the created or reused object.
2177 */
2178static xmlXPathObjectPtr
2179xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2180{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002181 if ((ctxt != NULL) && (ctxt->cache)) {
2182 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002183
2184 if ((cache->booleanObjs != NULL) &&
2185 (cache->booleanObjs->number != 0))
2186 {
2187 xmlXPathObjectPtr ret;
2188
2189 ret = (xmlXPathObjectPtr)
2190 cache->booleanObjs->items[--cache->booleanObjs->number];
2191 ret->type = XPATH_BOOLEAN;
2192 ret->boolval = (val != 0);
2193#ifdef XP_DEBUG_OBJ_USAGE
2194 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2195#endif
2196 return(ret);
2197 } else if ((cache->miscObjs != NULL) &&
2198 (cache->miscObjs->number != 0))
2199 {
2200 xmlXPathObjectPtr ret;
2201
2202 ret = (xmlXPathObjectPtr)
2203 cache->miscObjs->items[--cache->miscObjs->number];
2204
2205 ret->type = XPATH_BOOLEAN;
2206 ret->boolval = (val != 0);
2207#ifdef XP_DEBUG_OBJ_USAGE
2208 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2209#endif
2210 return(ret);
2211 }
2212 }
2213 return(xmlXPathNewBoolean(val));
2214}
2215
2216/**
2217 * xmlXPathCacheNewFloat:
2218 * @ctxt: the XPath context
2219 * @val: the double value
2220 *
2221 * This is the cached version of xmlXPathNewFloat().
2222 * Acquires an xmlXPathObjectPtr of type double and of value @val
2223 *
2224 * Returns the created or reused object.
2225 */
2226static xmlXPathObjectPtr
2227xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2228{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002229 if ((ctxt != NULL) && (ctxt->cache)) {
2230 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002231
2232 if ((cache->numberObjs != NULL) &&
2233 (cache->numberObjs->number != 0))
2234 {
2235 xmlXPathObjectPtr ret;
2236
2237 ret = (xmlXPathObjectPtr)
2238 cache->numberObjs->items[--cache->numberObjs->number];
2239 ret->type = XPATH_NUMBER;
2240 ret->floatval = val;
2241#ifdef XP_DEBUG_OBJ_USAGE
2242 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2243#endif
2244 return(ret);
2245 } else if ((cache->miscObjs != NULL) &&
2246 (cache->miscObjs->number != 0))
2247 {
2248 xmlXPathObjectPtr ret;
2249
2250 ret = (xmlXPathObjectPtr)
2251 cache->miscObjs->items[--cache->miscObjs->number];
2252
2253 ret->type = XPATH_NUMBER;
2254 ret->floatval = val;
2255#ifdef XP_DEBUG_OBJ_USAGE
2256 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2257#endif
2258 return(ret);
2259 }
2260 }
2261 return(xmlXPathNewFloat(val));
2262}
2263
2264/**
2265 * xmlXPathCacheConvertString:
2266 * @ctxt: the XPath context
2267 * @val: an XPath object
2268 *
2269 * This is the cached version of xmlXPathConvertString().
2270 * Converts an existing object to its string() equivalent
2271 *
2272 * Returns a created or reused object, the old one is freed (cached)
2273 * (or the operation is done directly on @val)
2274 */
2275
2276static xmlXPathObjectPtr
2277xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2278 xmlChar *res = NULL;
2279
2280 if (val == NULL)
2281 return(xmlXPathCacheNewCString(ctxt, ""));
2282
2283 switch (val->type) {
2284 case XPATH_UNDEFINED:
2285#ifdef DEBUG_EXPR
2286 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2287#endif
2288 break;
2289 case XPATH_NODESET:
2290 case XPATH_XSLT_TREE:
2291 res = xmlXPathCastNodeSetToString(val->nodesetval);
2292 break;
2293 case XPATH_STRING:
2294 return(val);
2295 case XPATH_BOOLEAN:
2296 res = xmlXPathCastBooleanToString(val->boolval);
2297 break;
2298 case XPATH_NUMBER:
2299 res = xmlXPathCastNumberToString(val->floatval);
2300 break;
2301 case XPATH_USERS:
2302 case XPATH_POINT:
2303 case XPATH_RANGE:
2304 case XPATH_LOCATIONSET:
2305 TODO;
2306 break;
2307 }
2308 xmlXPathReleaseObject(ctxt, val);
2309 if (res == NULL)
2310 return(xmlXPathCacheNewCString(ctxt, ""));
2311 return(xmlXPathCacheWrapString(ctxt, res));
2312}
2313
2314/**
2315 * xmlXPathCacheObjectCopy:
2316 * @ctxt: the XPath context
2317 * @val: the original object
2318 *
2319 * This is the cached version of xmlXPathObjectCopy().
2320 * Acquire a copy of a given object
2321 *
2322 * Returns a created or reused created object.
2323 */
2324static xmlXPathObjectPtr
2325xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2326{
2327 if (val == NULL)
2328 return(NULL);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002329
2330 switch (val->type) {
2331 case XPATH_NODESET:
2332 if (XP_HAS_CACHE(ctxt))
2333 return(xmlXPathCacheWrapNodeSet(ctxt,
2334 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2335 case XPATH_STRING:
2336 if (XP_HAS_CACHE(ctxt))
2337 return(xmlXPathCacheNewString(ctxt, val->stringval));
2338 case XPATH_BOOLEAN:
2339 if (XP_HAS_CACHE(ctxt))
2340 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2341 case XPATH_NUMBER:
2342 if (XP_HAS_CACHE(ctxt))
2343 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2344 default:
2345 break;
2346 }
2347 return(xmlXPathObjectCopy(val));
2348}
2349
2350/**
2351 * xmlXPathCacheConvertBoolean:
2352 * @ctxt: the XPath context
2353 * @val: an XPath object
2354 *
2355 * This is the cached version of xmlXPathConvertBoolean().
2356 * Converts an existing object to its boolean() equivalent
2357 *
2358 * Returns a created or reused object, the old one is freed (or the operation
2359 * is done directly on @val)
2360 */
2361static xmlXPathObjectPtr
2362xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2363 xmlXPathObjectPtr ret;
2364
2365 if (val == NULL)
2366 return(xmlXPathCacheNewBoolean(ctxt, 0));
2367 if (val->type == XPATH_BOOLEAN)
2368 return(val);
2369 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2370 xmlXPathReleaseObject(ctxt, val);
2371 return(ret);
2372}
2373
2374/**
2375 * xmlXPathCacheConvertNumber:
2376 * @ctxt: the XPath context
2377 * @val: an XPath object
2378 *
2379 * This is the cached version of xmlXPathConvertNumber().
2380 * Converts an existing object to its number() equivalent
2381 *
2382 * Returns a created or reused object, the old one is freed (or the operation
2383 * is done directly on @val)
2384 */
2385static xmlXPathObjectPtr
2386xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2387 xmlXPathObjectPtr ret;
2388
2389 if (val == NULL)
2390 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2391 if (val->type == XPATH_NUMBER)
2392 return(val);
2393 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2394 xmlXPathReleaseObject(ctxt, val);
2395 return(ret);
2396}
2397
2398/************************************************************************
2399 * *
Owen Taylor3473f882001-02-23 17:55:21 +00002400 * Parser stacks related functions and macros *
2401 * *
2402 ************************************************************************/
2403
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002404/**
2405 * valuePop:
2406 * @ctxt: an XPath evaluation context
2407 *
2408 * Pops the top XPath object from the value stack
2409 *
2410 * Returns the XPath object just removed
2411 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002412xmlXPathObjectPtr
Daniel Veillard1c732d22002-11-30 11:22:59 +00002413valuePop(xmlXPathParserContextPtr ctxt)
2414{
2415 xmlXPathObjectPtr ret;
2416
Daniel Veillarda82b1822004-11-08 16:24:57 +00002417 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard24505b02005-07-28 23:49:35 +00002418 return (NULL);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002419 ctxt->valueNr--;
2420 if (ctxt->valueNr > 0)
2421 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2422 else
2423 ctxt->value = NULL;
2424 ret = ctxt->valueTab[ctxt->valueNr];
Daniel Veillard24505b02005-07-28 23:49:35 +00002425 ctxt->valueTab[ctxt->valueNr] = NULL;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002426 return (ret);
2427}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002428/**
2429 * valuePush:
2430 * @ctxt: an XPath evaluation context
2431 * @value: the XPath object
2432 *
2433 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002434 *
2435 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002436 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002437int
Daniel Veillard1c732d22002-11-30 11:22:59 +00002438valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2439{
Daniel Veillarda82b1822004-11-08 16:24:57 +00002440 if ((ctxt == NULL) || (value == NULL)) return(-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002441 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002442 xmlXPathObjectPtr *tmp;
2443
2444 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2445 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00002446 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002447 if (tmp == NULL) {
Daniel Veillard1c732d22002-11-30 11:22:59 +00002448 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
2449 return (0);
2450 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002451 ctxt->valueMax *= 2;
2452 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002453 }
2454 ctxt->valueTab[ctxt->valueNr] = value;
2455 ctxt->value = value;
2456 return (ctxt->valueNr++);
2457}
Owen Taylor3473f882001-02-23 17:55:21 +00002458
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002459/**
2460 * xmlXPathPopBoolean:
2461 * @ctxt: an XPath parser context
2462 *
2463 * Pops a boolean from the stack, handling conversion if needed.
2464 * Check error with #xmlXPathCheckError.
2465 *
2466 * Returns the boolean
2467 */
2468int
2469xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2470 xmlXPathObjectPtr obj;
2471 int ret;
2472
2473 obj = valuePop(ctxt);
2474 if (obj == NULL) {
2475 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2476 return(0);
2477 }
William M. Brack08171912003-12-29 02:52:11 +00002478 if (obj->type != XPATH_BOOLEAN)
2479 ret = xmlXPathCastToBoolean(obj);
2480 else
2481 ret = obj->boolval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002482 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002483 return(ret);
2484}
2485
2486/**
2487 * xmlXPathPopNumber:
2488 * @ctxt: an XPath parser context
2489 *
2490 * Pops a number from the stack, handling conversion if needed.
2491 * Check error with #xmlXPathCheckError.
2492 *
2493 * Returns the number
2494 */
2495double
2496xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2497 xmlXPathObjectPtr obj;
2498 double ret;
2499
2500 obj = valuePop(ctxt);
2501 if (obj == NULL) {
2502 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2503 return(0);
2504 }
William M. Brack08171912003-12-29 02:52:11 +00002505 if (obj->type != XPATH_NUMBER)
2506 ret = xmlXPathCastToNumber(obj);
2507 else
2508 ret = obj->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002509 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002510 return(ret);
2511}
2512
2513/**
2514 * xmlXPathPopString:
2515 * @ctxt: an XPath parser context
2516 *
2517 * Pops a string from the stack, handling conversion if needed.
2518 * Check error with #xmlXPathCheckError.
2519 *
2520 * Returns the string
2521 */
2522xmlChar *
2523xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2524 xmlXPathObjectPtr obj;
2525 xmlChar * ret;
2526
2527 obj = valuePop(ctxt);
2528 if (obj == NULL) {
2529 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2530 return(NULL);
2531 }
William M. Brack08171912003-12-29 02:52:11 +00002532 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002533 /* TODO: needs refactoring somewhere else */
2534 if (obj->stringval == ret)
2535 obj->stringval = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002536 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002537 return(ret);
2538}
2539
2540/**
2541 * xmlXPathPopNodeSet:
2542 * @ctxt: an XPath parser context
2543 *
2544 * Pops a node-set from the stack, handling conversion if needed.
2545 * Check error with #xmlXPathCheckError.
2546 *
2547 * Returns the node-set
2548 */
2549xmlNodeSetPtr
2550xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2551 xmlXPathObjectPtr obj;
2552 xmlNodeSetPtr ret;
2553
Daniel Veillardf2a36f92004-11-08 17:55:01 +00002554 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002555 if (ctxt->value == NULL) {
2556 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2557 return(NULL);
2558 }
2559 if (!xmlXPathStackIsNodeSet(ctxt)) {
2560 xmlXPathSetTypeError(ctxt);
2561 return(NULL);
2562 }
2563 obj = valuePop(ctxt);
2564 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00002565#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00002566 /* to fix memory leak of not clearing obj->user */
2567 if (obj->boolval && obj->user != NULL)
2568 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00002569#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002570 obj->nodesetval = NULL;
2571 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002572 return(ret);
2573}
2574
2575/**
2576 * xmlXPathPopExternal:
2577 * @ctxt: an XPath parser context
2578 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002579 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002580 * Check error with #xmlXPathCheckError.
2581 *
2582 * Returns the object
2583 */
2584void *
2585xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2586 xmlXPathObjectPtr obj;
2587 void * ret;
2588
Daniel Veillarda82b1822004-11-08 16:24:57 +00002589 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002590 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2591 return(NULL);
2592 }
2593 if (ctxt->value->type != XPATH_USERS) {
2594 xmlXPathSetTypeError(ctxt);
2595 return(NULL);
2596 }
2597 obj = valuePop(ctxt);
2598 ret = obj->user;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002599 obj->user = NULL;
2600 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002601 return(ret);
2602}
2603
Owen Taylor3473f882001-02-23 17:55:21 +00002604/*
2605 * Macros for accessing the content. Those should be used only by the parser,
2606 * and not exported.
2607 *
2608 * Dirty macros, i.e. one need to make assumption on the context to use them
2609 *
2610 * CUR_PTR return the current pointer to the xmlChar to be parsed.
2611 * CUR returns the current xmlChar value, i.e. a 8 bit value
2612 * in ISO-Latin or UTF-8.
2613 * This should be used internally by the parser
2614 * only to compare to ASCII values otherwise it would break when
2615 * running with UTF-8 encoding.
2616 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
2617 * to compare on ASCII based substring.
2618 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2619 * strings within the parser.
2620 * CURRENT Returns the current char value, with the full decoding of
2621 * UTF-8 if we are using this mode. It returns an int.
2622 * NEXT Skip to the next character, this does the proper decoding
2623 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
2624 * It returns the pointer to the current xmlChar.
2625 */
2626
2627#define CUR (*ctxt->cur)
2628#define SKIP(val) ctxt->cur += (val)
2629#define NXT(val) ctxt->cur[(val)]
2630#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00002631#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2632
2633#define COPY_BUF(l,b,i,v) \
2634 if (l == 1) b[i++] = (xmlChar) v; \
2635 else i += xmlCopyChar(l,&b[i],v)
2636
2637#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00002638
2639#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00002640 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00002641
2642#define CURRENT (*ctxt->cur)
2643#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
2644
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002645
2646#ifndef DBL_DIG
2647#define DBL_DIG 16
2648#endif
2649#ifndef DBL_EPSILON
2650#define DBL_EPSILON 1E-9
2651#endif
2652
2653#define UPPER_DOUBLE 1E9
2654#define LOWER_DOUBLE 1E-5
2655
2656#define INTEGER_DIGITS DBL_DIG
2657#define FRACTION_DIGITS (DBL_DIG + 1)
2658#define EXPONENT_DIGITS (3 + 2)
2659
2660/**
2661 * xmlXPathFormatNumber:
2662 * @number: number to format
2663 * @buffer: output buffer
2664 * @buffersize: size of output buffer
2665 *
2666 * Convert the number into a string representation.
2667 */
2668static void
2669xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2670{
Daniel Veillardcda96922001-08-21 10:56:31 +00002671 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002672 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00002673 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002674 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002675 break;
2676 case -1:
2677 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002678 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002679 break;
2680 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00002681 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002682 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002683 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00002684 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002685 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002686 } else if (number == ((int) number)) {
2687 char work[30];
2688 char *ptr, *cur;
Daniel Veillardb3d14912005-09-04 20:47:39 +00002689 int value = (int) number;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002690
2691 ptr = &buffer[0];
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002692 if (value == 0) {
2693 *ptr++ = '0';
2694 } else {
Daniel Veillardb3d14912005-09-04 20:47:39 +00002695 snprintf(work, 29, "%d", value);
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002696 cur = &work[0];
Daniel Veillardb3d14912005-09-04 20:47:39 +00002697 while ((*cur) && (ptr - buffer < buffersize)) {
2698 *ptr++ = *cur++;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002699 }
2700 }
2701 if (ptr - buffer < buffersize) {
2702 *ptr = 0;
2703 } else if (buffersize > 0) {
2704 ptr--;
2705 *ptr = 0;
2706 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002707 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002708 /* 3 is sign, decimal point, and terminating zero */
2709 char work[DBL_DIG + EXPONENT_DIGITS + 3];
2710 int integer_place, fraction_place;
2711 char *ptr;
2712 char *after_fraction;
2713 double absolute_value;
2714 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002715
Bjorn Reese70a9da52001-04-21 16:57:29 +00002716 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002717
Bjorn Reese70a9da52001-04-21 16:57:29 +00002718 /*
2719 * First choose format - scientific or regular floating point.
2720 * In either case, result is in work, and after_fraction points
2721 * just past the fractional part.
2722 */
2723 if ( ((absolute_value > UPPER_DOUBLE) ||
2724 (absolute_value < LOWER_DOUBLE)) &&
2725 (absolute_value != 0.0) ) {
2726 /* Use scientific notation */
2727 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2728 fraction_place = DBL_DIG - 1;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002729 size = snprintf(work, sizeof(work),"%*.*e",
Bjorn Reese70a9da52001-04-21 16:57:29 +00002730 integer_place, fraction_place, number);
Daniel Veillard11ce4002006-03-10 00:36:23 +00002731 while ((size > 0) && (work[size] != 'e')) size--;
2732 after_fraction = work + size;
2733
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002734 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002735 else {
2736 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00002737 if (absolute_value > 0.0)
2738 integer_place = 1 + (int)log10(absolute_value);
2739 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00002740 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002741 fraction_place = (integer_place > 0)
2742 ? DBL_DIG - integer_place
2743 : DBL_DIG;
2744 size = snprintf(work, sizeof(work), "%0.*f",
2745 fraction_place, number);
2746 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002747 }
2748
Bjorn Reese70a9da52001-04-21 16:57:29 +00002749 /* Remove fractional trailing zeroes */
2750 ptr = after_fraction;
2751 while (*(--ptr) == '0')
2752 ;
2753 if (*ptr != '.')
2754 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002755 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002756
2757 /* Finally copy result back to caller */
2758 size = strlen(work) + 1;
2759 if (size > buffersize) {
2760 work[buffersize - 1] = 0;
2761 size = buffersize;
2762 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002763 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002764 }
2765 break;
2766 }
2767}
2768
Owen Taylor3473f882001-02-23 17:55:21 +00002769
2770/************************************************************************
2771 * *
2772 * Routines to handle NodeSets *
2773 * *
2774 ************************************************************************/
2775
2776/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002777 * xmlXPathOrderDocElems:
2778 * @doc: an input document
2779 *
2780 * Call this routine to speed up XPath computation on static documents.
2781 * This stamps all the element nodes with the document order
2782 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00002783 * field, the value stored is actually - the node number (starting at -1)
2784 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002785 *
William M. Brack08171912003-12-29 02:52:11 +00002786 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002787 * of error.
2788 */
2789long
2790xmlXPathOrderDocElems(xmlDocPtr doc) {
2791 long count = 0;
2792 xmlNodePtr cur;
2793
2794 if (doc == NULL)
2795 return(-1);
2796 cur = doc->children;
2797 while (cur != NULL) {
2798 if (cur->type == XML_ELEMENT_NODE) {
2799 cur->content = (void *) (-(++count));
2800 if (cur->children != NULL) {
2801 cur = cur->children;
2802 continue;
2803 }
2804 }
2805 if (cur->next != NULL) {
2806 cur = cur->next;
2807 continue;
2808 }
2809 do {
2810 cur = cur->parent;
2811 if (cur == NULL)
2812 break;
2813 if (cur == (xmlNodePtr) doc) {
2814 cur = NULL;
2815 break;
2816 }
2817 if (cur->next != NULL) {
2818 cur = cur->next;
2819 break;
2820 }
2821 } while (cur != NULL);
2822 }
2823 return(count);
2824}
2825
2826/**
Owen Taylor3473f882001-02-23 17:55:21 +00002827 * xmlXPathCmpNodes:
2828 * @node1: the first node
2829 * @node2: the second node
2830 *
2831 * Compare two nodes w.r.t document order
2832 *
2833 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00002834 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00002835 */
2836int
2837xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2838 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002839 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002840 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002841 xmlNodePtr cur, root;
2842
2843 if ((node1 == NULL) || (node2 == NULL))
2844 return(-2);
2845 /*
2846 * a couple of optimizations which will avoid computations in most cases
2847 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00002848 if (node1->type == XML_ATTRIBUTE_NODE) {
2849 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002850 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002851 node1 = node1->parent;
2852 }
2853 if (node2->type == XML_ATTRIBUTE_NODE) {
2854 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002855 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002856 node2 = node2->parent;
2857 }
2858 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00002859 if (attr1 == attr2) {
2860 /* not required, but we keep attributes in order */
2861 if (attr1 != 0) {
2862 cur = attrNode2->prev;
2863 while (cur != NULL) {
2864 if (cur == attrNode1)
2865 return (1);
2866 cur = cur->prev;
2867 }
2868 return (-1);
2869 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00002870 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00002871 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00002872 if (attr2 == 1)
2873 return(1);
2874 return(-1);
2875 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002876 if ((node1->type == XML_NAMESPACE_DECL) ||
2877 (node2->type == XML_NAMESPACE_DECL))
2878 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00002879 if (node1 == node2->prev)
2880 return(1);
2881 if (node1 == node2->next)
2882 return(-1);
2883
2884 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002885 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002886 */
2887 if ((node1->type == XML_ELEMENT_NODE) &&
2888 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002889 (0 > (long) node1->content) &&
2890 (0 > (long) node2->content) &&
2891 (node1->doc == node2->doc)) {
2892 long l1, l2;
2893
2894 l1 = -((long) node1->content);
2895 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002896 if (l1 < l2)
2897 return(1);
2898 if (l1 > l2)
2899 return(-1);
2900 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002901
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002902 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002903 * compute depth to root
2904 */
2905 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2906 if (cur == node1)
2907 return(1);
2908 depth2++;
2909 }
2910 root = cur;
2911 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2912 if (cur == node2)
2913 return(-1);
2914 depth1++;
2915 }
2916 /*
2917 * Distinct document (or distinct entities :-( ) case.
2918 */
2919 if (root != cur) {
2920 return(-2);
2921 }
2922 /*
2923 * get the nearest common ancestor.
2924 */
2925 while (depth1 > depth2) {
2926 depth1--;
2927 node1 = node1->parent;
2928 }
2929 while (depth2 > depth1) {
2930 depth2--;
2931 node2 = node2->parent;
2932 }
2933 while (node1->parent != node2->parent) {
2934 node1 = node1->parent;
2935 node2 = node2->parent;
2936 /* should not happen but just in case ... */
2937 if ((node1 == NULL) || (node2 == NULL))
2938 return(-2);
2939 }
2940 /*
2941 * Find who's first.
2942 */
Daniel Veillardf49be472004-02-17 11:48:18 +00002943 if (node1 == node2->prev)
2944 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00002945 if (node1 == node2->next)
2946 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00002947 /*
2948 * Speedup using document order if availble.
2949 */
2950 if ((node1->type == XML_ELEMENT_NODE) &&
2951 (node2->type == XML_ELEMENT_NODE) &&
2952 (0 > (long) node1->content) &&
2953 (0 > (long) node2->content) &&
2954 (node1->doc == node2->doc)) {
2955 long l1, l2;
2956
2957 l1 = -((long) node1->content);
2958 l2 = -((long) node2->content);
2959 if (l1 < l2)
2960 return(1);
2961 if (l1 > l2)
2962 return(-1);
2963 }
2964
Owen Taylor3473f882001-02-23 17:55:21 +00002965 for (cur = node1->next;cur != NULL;cur = cur->next)
2966 if (cur == node2)
2967 return(1);
2968 return(-1); /* assume there is no sibling list corruption */
2969}
2970
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00002971#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002972/**
2973 * xmlXPathCmpNodesExt:
2974 * @node1: the first node
2975 * @node2: the second node
2976 *
2977 * Compare two nodes w.r.t document order.
2978 * This one is optimized for handling of non-element nodes.
2979 *
2980 * Returns -2 in case of error 1 if first point < second point, 0 if
2981 * it's the same node, -1 otherwise
2982 */
2983static int
2984xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
2985 int depth1, depth2;
2986 int misc = 0, precedence1 = 0, precedence2 = 0;
2987 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
2988 xmlNodePtr cur, root;
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00002989 long l1, l2;
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002990
2991 if ((node1 == NULL) || (node2 == NULL))
2992 return(-2);
2993
2994 if (node1 == node2)
2995 return(0);
2996
2997 /*
2998 * a couple of optimizations which will avoid computations in most cases
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00002999 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003000 switch (node1->type) {
3001 case XML_ELEMENT_NODE:
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003002 if (node2->type == XML_ELEMENT_NODE) {
3003 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
3004 (0 > (long) node2->content) &&
3005 (node1->doc == node2->doc))
3006 {
3007 l1 = -((long) node1->content);
3008 l2 = -((long) node2->content);
3009 if (l1 < l2)
3010 return(1);
3011 if (l1 > l2)
3012 return(-1);
3013 } else
3014 goto turtle_comparison;
3015 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003016 break;
3017 case XML_ATTRIBUTE_NODE:
3018 precedence1 = 1; /* element is owner */
3019 miscNode1 = node1;
3020 node1 = node1->parent;
3021 misc = 1;
3022 break;
3023 case XML_TEXT_NODE:
3024 case XML_CDATA_SECTION_NODE:
3025 case XML_COMMENT_NODE:
3026 case XML_PI_NODE: {
3027 miscNode1 = node1;
3028 /*
3029 * Find nearest element node.
3030 */
3031 if (node1->prev != NULL) {
3032 do {
3033 node1 = node1->prev;
3034 if (node1->type == XML_ELEMENT_NODE) {
3035 precedence1 = 3; /* element in prev-sibl axis */
3036 break;
3037 }
3038 if (node1->prev == NULL) {
3039 precedence1 = 2; /* element is parent */
3040 /*
3041 * URGENT TODO: Are there any cases, where the
3042 * parent of such a node is not an element node?
3043 */
3044 node1 = node1->parent;
3045 break;
3046 }
3047 } while (1);
3048 } else {
3049 precedence1 = 2; /* element is parent */
3050 node1 = node1->parent;
3051 }
3052 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE)) {
3053 /*
3054 * Fallback for whatever case.
3055 */
3056 node1 = miscNode1;
3057 precedence1 = 0;
3058 } else
3059 misc = 1;
3060 }
3061 break;
3062 case XML_NAMESPACE_DECL:
3063 /*
3064 * TODO: why do we return 1 for namespace nodes?
3065 */
3066 return(1);
3067 default:
3068 break;
3069 }
3070 switch (node2->type) {
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003071 case XML_ELEMENT_NODE:
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003072 break;
3073 case XML_ATTRIBUTE_NODE:
3074 precedence2 = 1; /* element is owner */
3075 miscNode2 = node2;
3076 node2 = node2->parent;
3077 misc = 1;
3078 break;
3079 case XML_TEXT_NODE:
3080 case XML_CDATA_SECTION_NODE:
3081 case XML_COMMENT_NODE:
3082 case XML_PI_NODE: {
3083 miscNode2 = node2;
3084 if (node2->prev != NULL) {
3085 do {
3086 node2 = node2->prev;
3087 if (node2->type == XML_ELEMENT_NODE) {
3088 precedence2 = 3; /* element in prev-sibl axis */
3089 break;
3090 }
3091 if (node2->prev == NULL) {
3092 precedence2 = 2; /* element is parent */
3093 node2 = node2->parent;
3094 break;
3095 }
3096 } while (1);
3097 } else {
3098 precedence2 = 2; /* element is parent */
3099 node2 = node2->parent;
3100 }
3101 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3102 (0 <= (long) node1->content))
3103 {
3104 node2 = miscNode2;
3105 precedence2 = 0;
3106 } else
3107 misc = 1;
3108 }
3109 break;
3110 case XML_NAMESPACE_DECL:
3111 return(1);
3112 default:
3113 break;
3114 }
3115 if (misc) {
3116 if (node1 == node2) {
3117 if (precedence1 == precedence2) {
3118 /*
3119 * The ugly case; but normally there aren't many
3120 * adjacent non-element nodes around.
3121 */
3122 cur = miscNode2->prev;
3123 while (cur != NULL) {
3124 if (cur == miscNode1)
3125 return(1);
3126 if (cur->type == XML_ELEMENT_NODE)
3127 return(-1);
3128 cur = cur->prev;
3129 }
3130 return (-1);
3131 } else {
3132 /*
3133 * Evaluate based on higher precedence wrt to the element.
3134 * TODO: This assumes attributes are sorted before content.
3135 * Is this 100% correct?
3136 */
3137 if (precedence1 < precedence2)
3138 return(1);
3139 else
3140 return(-1);
3141 }
3142 }
3143 /*
3144 * Special case: One of the helper-elements is contained by the other.
3145 * <foo>
3146 * <node2>
3147 * <node1>Text-1(precedence1 == 2)</node1>
3148 * </node2>
3149 * Text-6(precedence2 == 3)
3150 * </foo>
3151 */
3152 if ((precedence2 == 3) && (precedence1 > 1)) {
3153 cur = node1->parent;
3154 while (cur) {
3155 if (cur == node2)
3156 return(1);
3157 cur = cur->parent;
3158 }
3159 }
3160 if ((precedence1 == 3) && (precedence2 > 1)) {
3161 cur = node2->parent;
3162 while (cur) {
3163 if (cur == node1)
3164 return(-1);
3165 cur = cur->parent;
3166 }
3167 }
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003168 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003169
3170 /*
3171 * Speedup using document order if availble.
3172 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003173 if ((node1->type == XML_ELEMENT_NODE) &&
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003174 (node2->type == XML_ELEMENT_NODE) &&
3175 (0 > (long) node1->content) &&
3176 (0 > (long) node2->content) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003177 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003178
3179 l1 = -((long) node1->content);
3180 l2 = -((long) node2->content);
3181 if (l1 < l2)
3182 return(1);
3183 if (l1 > l2)
3184 return(-1);
3185 }
3186
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003187turtle_comparison:
3188
3189 if (node1 == node2->prev)
3190 return(1);
3191 if (node1 == node2->next)
3192 return(-1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003193 /*
3194 * compute depth to root
3195 */
3196 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3197 if (cur == node1)
3198 return(1);
3199 depth2++;
3200 }
3201 root = cur;
3202 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3203 if (cur == node2)
3204 return(-1);
3205 depth1++;
3206 }
3207 /*
3208 * Distinct document (or distinct entities :-( ) case.
3209 */
3210 if (root != cur) {
3211 return(-2);
3212 }
3213 /*
3214 * get the nearest common ancestor.
3215 */
3216 while (depth1 > depth2) {
3217 depth1--;
3218 node1 = node1->parent;
3219 }
3220 while (depth2 > depth1) {
3221 depth2--;
3222 node2 = node2->parent;
3223 }
3224 while (node1->parent != node2->parent) {
3225 node1 = node1->parent;
3226 node2 = node2->parent;
3227 /* should not happen but just in case ... */
3228 if ((node1 == NULL) || (node2 == NULL))
3229 return(-2);
3230 }
3231 /*
3232 * Find who's first.
3233 */
3234 if (node1 == node2->prev)
3235 return(1);
3236 if (node1 == node2->next)
3237 return(-1);
3238 /*
3239 * Speedup using document order if availble.
3240 */
3241 if ((node1->type == XML_ELEMENT_NODE) &&
3242 (node2->type == XML_ELEMENT_NODE) &&
3243 (0 > (long) node1->content) &&
3244 (0 > (long) node2->content) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003245 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003246
3247 l1 = -((long) node1->content);
3248 l2 = -((long) node2->content);
3249 if (l1 < l2)
3250 return(1);
3251 if (l1 > l2)
3252 return(-1);
3253 }
3254
3255 for (cur = node1->next;cur != NULL;cur = cur->next)
3256 if (cur == node2)
3257 return(1);
3258 return(-1); /* assume there is no sibling list corruption */
3259}
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003260#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003261
Owen Taylor3473f882001-02-23 17:55:21 +00003262/**
3263 * xmlXPathNodeSetSort:
3264 * @set: the node set
3265 *
3266 * Sort the node set in document order
3267 */
3268void
3269xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003270 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003271 xmlNodePtr tmp;
3272
3273 if (set == NULL)
3274 return;
3275
3276 /* Use Shell's sort to sort the node-set */
3277 len = set->nodeNr;
3278 for (incr = len / 2; incr > 0; incr /= 2) {
3279 for (i = incr; i < len; i++) {
3280 j = i - incr;
3281 while (j >= 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003282#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003283 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3284 set->nodeTab[j + incr]) == -1)
3285#else
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003286 if (xmlXPathCmpNodes(set->nodeTab[j],
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003287 set->nodeTab[j + incr]) == -1)
3288#endif
3289 {
Owen Taylor3473f882001-02-23 17:55:21 +00003290 tmp = set->nodeTab[j];
3291 set->nodeTab[j] = set->nodeTab[j + incr];
3292 set->nodeTab[j + incr] = tmp;
3293 j -= incr;
3294 } else
3295 break;
3296 }
3297 }
3298 }
3299}
3300
3301#define XML_NODESET_DEFAULT 10
3302/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003303 * xmlXPathNodeSetDupNs:
3304 * @node: the parent node of the namespace XPath node
3305 * @ns: the libxml namespace declaration node.
3306 *
3307 * Namespace node in libxml don't match the XPath semantic. In a node set
3308 * the namespace nodes are duplicated and the next pointer is set to the
3309 * parent node in the XPath semantic.
3310 *
3311 * Returns the newly created object.
3312 */
3313static xmlNodePtr
3314xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3315 xmlNsPtr cur;
3316
3317 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3318 return(NULL);
3319 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3320 return((xmlNodePtr) ns);
3321
3322 /*
3323 * Allocate a new Namespace and fill the fields.
3324 */
3325 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3326 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003327 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003328 return(NULL);
3329 }
3330 memset(cur, 0, sizeof(xmlNs));
3331 cur->type = XML_NAMESPACE_DECL;
3332 if (ns->href != NULL)
3333 cur->href = xmlStrdup(ns->href);
3334 if (ns->prefix != NULL)
3335 cur->prefix = xmlStrdup(ns->prefix);
3336 cur->next = (xmlNsPtr) node;
3337 return((xmlNodePtr) cur);
3338}
3339
3340/**
3341 * xmlXPathNodeSetFreeNs:
3342 * @ns: the XPath namespace node found in a nodeset.
3343 *
William M. Brack08171912003-12-29 02:52:11 +00003344 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003345 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00003346 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003347 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00003348void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003349xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3350 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3351 return;
3352
3353 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3354 if (ns->href != NULL)
3355 xmlFree((xmlChar *)ns->href);
3356 if (ns->prefix != NULL)
3357 xmlFree((xmlChar *)ns->prefix);
3358 xmlFree(ns);
3359 }
3360}
3361
3362/**
Owen Taylor3473f882001-02-23 17:55:21 +00003363 * xmlXPathNodeSetCreate:
3364 * @val: an initial xmlNodePtr, or NULL
3365 *
3366 * Create a new xmlNodeSetPtr of type double and of value @val
3367 *
3368 * Returns the newly created object.
3369 */
3370xmlNodeSetPtr
3371xmlXPathNodeSetCreate(xmlNodePtr val) {
3372 xmlNodeSetPtr ret;
3373
3374 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3375 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003376 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003377 return(NULL);
3378 }
3379 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3380 if (val != NULL) {
3381 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3382 sizeof(xmlNodePtr));
3383 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003384 xmlXPathErrMemory(NULL, "creating nodeset\n");
3385 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003386 return(NULL);
3387 }
3388 memset(ret->nodeTab, 0 ,
3389 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3390 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003391 if (val->type == XML_NAMESPACE_DECL) {
3392 xmlNsPtr ns = (xmlNsPtr) val;
3393
3394 ret->nodeTab[ret->nodeNr++] =
3395 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3396 } else
3397 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003398 }
3399 return(ret);
3400}
3401
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003402/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003403 * xmlXPathNodeSetCreateSize:
3404 * @size: the initial size of the set
3405 *
3406 * Create a new xmlNodeSetPtr of type double and of value @val
3407 *
3408 * Returns the newly created object.
3409 */
3410static xmlNodeSetPtr
3411xmlXPathNodeSetCreateSize(int size) {
3412 xmlNodeSetPtr ret;
3413
3414 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3415 if (ret == NULL) {
3416 xmlXPathErrMemory(NULL, "creating nodeset\n");
3417 return(NULL);
3418 }
3419 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3420 if (size < XML_NODESET_DEFAULT)
3421 size = XML_NODESET_DEFAULT;
3422 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3423 if (ret->nodeTab == NULL) {
3424 xmlXPathErrMemory(NULL, "creating nodeset\n");
3425 xmlFree(ret);
3426 return(NULL);
3427 }
3428 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3429 ret->nodeMax = size;
3430 return(ret);
3431}
3432
3433/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003434 * xmlXPathNodeSetContains:
3435 * @cur: the node-set
3436 * @val: the node
3437 *
3438 * checks whether @cur contains @val
3439 *
3440 * Returns true (1) if @cur contains @val, false (0) otherwise
3441 */
3442int
3443xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3444 int i;
3445
Daniel Veillarda82b1822004-11-08 16:24:57 +00003446 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003447 if (val->type == XML_NAMESPACE_DECL) {
3448 for (i = 0; i < cur->nodeNr; i++) {
3449 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3450 xmlNsPtr ns1, ns2;
3451
3452 ns1 = (xmlNsPtr) val;
3453 ns2 = (xmlNsPtr) cur->nodeTab[i];
3454 if (ns1 == ns2)
3455 return(1);
3456 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3457 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3458 return(1);
3459 }
3460 }
3461 } else {
3462 for (i = 0; i < cur->nodeNr; i++) {
3463 if (cur->nodeTab[i] == val)
3464 return(1);
3465 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003466 }
3467 return(0);
3468}
3469
3470/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003471 * xmlXPathNodeSetAddNs:
3472 * @cur: the initial node set
3473 * @node: the hosting node
3474 * @ns: a the namespace node
3475 *
3476 * add a new namespace node to an existing NodeSet
3477 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00003478void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003479xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3480 int i;
3481
Daniel Veillarda82b1822004-11-08 16:24:57 +00003482
3483 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3484 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003485 (node->type != XML_ELEMENT_NODE))
3486 return;
3487
William M. Brack08171912003-12-29 02:52:11 +00003488 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003489 /*
William M. Brack08171912003-12-29 02:52:11 +00003490 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003491 */
3492 for (i = 0;i < cur->nodeNr;i++) {
3493 if ((cur->nodeTab[i] != NULL) &&
3494 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00003495 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003496 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3497 return;
3498 }
3499
3500 /*
3501 * grow the nodeTab if needed
3502 */
3503 if (cur->nodeMax == 0) {
3504 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3505 sizeof(xmlNodePtr));
3506 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003507 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003508 return;
3509 }
3510 memset(cur->nodeTab, 0 ,
3511 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3512 cur->nodeMax = XML_NODESET_DEFAULT;
3513 } else if (cur->nodeNr == cur->nodeMax) {
3514 xmlNodePtr *temp;
3515
3516 cur->nodeMax *= 2;
3517 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3518 sizeof(xmlNodePtr));
3519 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003520 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003521 return;
3522 }
3523 cur->nodeTab = temp;
3524 }
3525 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3526}
3527
3528/**
Owen Taylor3473f882001-02-23 17:55:21 +00003529 * xmlXPathNodeSetAdd:
3530 * @cur: the initial node set
3531 * @val: a new xmlNodePtr
3532 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003533 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00003534 */
3535void
3536xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3537 int i;
3538
Daniel Veillarda82b1822004-11-08 16:24:57 +00003539 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003540
Daniel Veillardef0b4502003-03-24 13:57:34 +00003541#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00003542 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3543 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00003544#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00003545
William M. Brack08171912003-12-29 02:52:11 +00003546 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003547 /*
William M. Brack08171912003-12-29 02:52:11 +00003548 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00003549 */
3550 for (i = 0;i < cur->nodeNr;i++)
3551 if (cur->nodeTab[i] == val) return;
3552
3553 /*
3554 * grow the nodeTab if needed
3555 */
3556 if (cur->nodeMax == 0) {
3557 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3558 sizeof(xmlNodePtr));
3559 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003560 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003561 return;
3562 }
3563 memset(cur->nodeTab, 0 ,
3564 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3565 cur->nodeMax = XML_NODESET_DEFAULT;
3566 } else if (cur->nodeNr == cur->nodeMax) {
3567 xmlNodePtr *temp;
3568
3569 cur->nodeMax *= 2;
3570 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3571 sizeof(xmlNodePtr));
3572 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003573 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003574 return;
3575 }
3576 cur->nodeTab = temp;
3577 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003578 if (val->type == XML_NAMESPACE_DECL) {
3579 xmlNsPtr ns = (xmlNsPtr) val;
3580
3581 cur->nodeTab[cur->nodeNr++] =
3582 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3583 } else
3584 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003585}
3586
3587/**
3588 * xmlXPathNodeSetAddUnique:
3589 * @cur: the initial node set
3590 * @val: a new xmlNodePtr
3591 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003592 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00003593 * when we are sure the node is not already in the set.
3594 */
3595void
3596xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00003597 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003598
Daniel Veillardef0b4502003-03-24 13:57:34 +00003599#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00003600 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3601 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00003602#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00003603
William M. Brack08171912003-12-29 02:52:11 +00003604 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003605 /*
3606 * grow the nodeTab if needed
3607 */
3608 if (cur->nodeMax == 0) {
3609 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3610 sizeof(xmlNodePtr));
3611 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003612 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003613 return;
3614 }
3615 memset(cur->nodeTab, 0 ,
3616 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3617 cur->nodeMax = XML_NODESET_DEFAULT;
3618 } else if (cur->nodeNr == cur->nodeMax) {
3619 xmlNodePtr *temp;
3620
3621 cur->nodeMax *= 2;
3622 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3623 sizeof(xmlNodePtr));
3624 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003625 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003626 return;
3627 }
3628 cur->nodeTab = temp;
3629 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003630 if (val->type == XML_NAMESPACE_DECL) {
3631 xmlNsPtr ns = (xmlNsPtr) val;
3632
3633 cur->nodeTab[cur->nodeNr++] =
3634 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3635 } else
3636 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003637}
3638
3639/**
3640 * xmlXPathNodeSetMerge:
3641 * @val1: the first NodeSet or NULL
3642 * @val2: the second NodeSet
3643 *
3644 * Merges two nodesets, all nodes from @val2 are added to @val1
3645 * if @val1 is NULL, a new set is created and copied from @val2
3646 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003647 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003648 */
3649xmlNodeSetPtr
3650xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003651 int i, j, initNr, skip;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003652 xmlNodePtr n1, n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003653
3654 if (val2 == NULL) return(val1);
3655 if (val1 == NULL) {
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003656 val1 = xmlXPathNodeSetCreate(NULL);
3657#if 0
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003658 /*
3659 * TODO: The optimization won't work in every case, since
3660 * those nasty namespace nodes need to be added with
3661 * xmlXPathNodeSetDupNs() to the set; thus a pure
3662 * memcpy is not possible.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00003663 * If there was a flag on the nodesetval, indicating that
3664 * some temporary nodes are in, that would be helpfull.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003665 */
3666 /*
3667 * Optimization: Create an equally sized node-set
3668 * and memcpy the content.
3669 */
3670 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3671 if (val1 == NULL)
3672 return(NULL);
3673 if (val2->nodeNr != 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003674 if (val2->nodeNr == 1)
3675 *(val1->nodeTab) = *(val2->nodeTab);
3676 else {
3677 memcpy(val1->nodeTab, val2->nodeTab,
3678 val2->nodeNr * sizeof(xmlNodePtr));
3679 }
3680 val1->nodeNr = val2->nodeNr;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003681 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003682 return(val1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003683#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003684 }
3685
William M. Brack08171912003-12-29 02:52:11 +00003686 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003687 initNr = val1->nodeNr;
3688
3689 for (i = 0;i < val2->nodeNr;i++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003690 n2 = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00003691 /*
William M. Brack08171912003-12-29 02:52:11 +00003692 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003693 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003694 skip = 0;
3695 for (j = 0; j < initNr; j++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003696 n1 = val1->nodeTab[j];
3697 if (n1 == n2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003698 skip = 1;
3699 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003700 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3701 (n2->type == XML_NAMESPACE_DECL)) {
3702 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3703 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3704 ((xmlNsPtr) n2)->prefix)))
3705 {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003706 skip = 1;
3707 break;
3708 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003709 }
3710 }
3711 if (skip)
3712 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00003713
3714 /*
3715 * grow the nodeTab if needed
3716 */
3717 if (val1->nodeMax == 0) {
3718 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3719 sizeof(xmlNodePtr));
3720 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003721 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003722 return(NULL);
3723 }
3724 memset(val1->nodeTab, 0 ,
3725 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3726 val1->nodeMax = XML_NODESET_DEFAULT;
3727 } else if (val1->nodeNr == val1->nodeMax) {
3728 xmlNodePtr *temp;
3729
3730 val1->nodeMax *= 2;
3731 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3732 sizeof(xmlNodePtr));
3733 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003734 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003735 return(NULL);
3736 }
3737 val1->nodeTab = temp;
3738 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003739 if (n2->type == XML_NAMESPACE_DECL) {
3740 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003741
3742 val1->nodeTab[val1->nodeNr++] =
3743 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3744 } else
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003745 val1->nodeTab[val1->nodeNr++] = n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003746 }
3747
3748 return(val1);
3749}
3750
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003751#if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
Owen Taylor3473f882001-02-23 17:55:21 +00003752/**
Daniel Veillard75be0132002-03-13 10:03:35 +00003753 * xmlXPathNodeSetMergeUnique:
3754 * @val1: the first NodeSet or NULL
3755 * @val2: the second NodeSet
3756 *
3757 * Merges two nodesets, all nodes from @val2 are added to @val1
3758 * if @val1 is NULL, a new set is created and copied from @val2
3759 *
3760 * Returns @val1 once extended or NULL in case of error.
3761 */
3762static xmlNodeSetPtr
3763xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00003764 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00003765
3766 if (val2 == NULL) return(val1);
3767 if (val1 == NULL) {
3768 val1 = xmlXPathNodeSetCreate(NULL);
3769 }
3770
William M. Brack08171912003-12-29 02:52:11 +00003771 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00003772
3773 for (i = 0;i < val2->nodeNr;i++) {
3774 /*
3775 * grow the nodeTab if needed
3776 */
3777 if (val1->nodeMax == 0) {
3778 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3779 sizeof(xmlNodePtr));
3780 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003781 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00003782 return(NULL);
3783 }
3784 memset(val1->nodeTab, 0 ,
3785 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3786 val1->nodeMax = XML_NODESET_DEFAULT;
3787 } else if (val1->nodeNr == val1->nodeMax) {
3788 xmlNodePtr *temp;
3789
3790 val1->nodeMax *= 2;
3791 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3792 sizeof(xmlNodePtr));
3793 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003794 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00003795 return(NULL);
3796 }
3797 val1->nodeTab = temp;
3798 }
3799 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3800 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
3801
3802 val1->nodeTab[val1->nodeNr++] =
3803 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3804 } else
3805 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
3806 }
3807
3808 return(val1);
3809}
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003810#endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3811
3812/**
3813 * xmlXPathNodeSetMergeAndClear:
3814 * @set1: the first NodeSet or NULL
3815 * @set2: the second NodeSet
3816 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3817 *
3818 * Merges two nodesets, all nodes from @set2 are added to @set1
3819 * if @set1 is NULL, a new set is created and copied from @set2.
3820 * Checks for duplicate nodes. Clears set2.
3821 *
3822 * Returns @set1 once extended or NULL in case of error.
3823 */
3824static xmlNodeSetPtr
3825xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3826 int hasNullEntries)
3827{
3828 if ((set1 == NULL) && (hasNullEntries == 0)) {
3829 /*
3830 * Note that doing a memcpy of the list, namespace nodes are
3831 * just assigned to set1, since set2 is cleared anyway.
3832 */
3833 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3834 if (set1 == NULL)
3835 return(NULL);
3836 if (set2->nodeNr != 0) {
3837 memcpy(set1->nodeTab, set2->nodeTab,
3838 set2->nodeNr * sizeof(xmlNodePtr));
3839 set1->nodeNr = set2->nodeNr;
3840 }
3841 } else {
3842 int i, j, initNbSet1;
3843 xmlNodePtr n1, n2;
3844
3845 if (set1 == NULL)
3846 set1 = xmlXPathNodeSetCreate(NULL);
3847
3848 initNbSet1 = set1->nodeNr;
3849 for (i = 0;i < set2->nodeNr;i++) {
3850 n2 = set2->nodeTab[i];
3851 /*
3852 * Skip NULLed entries.
3853 */
3854 if (n2 == NULL)
3855 continue;
3856 /*
3857 * Skip duplicates.
3858 */
3859 for (j = 0; j < initNbSet1; j++) {
3860 n1 = set1->nodeTab[j];
3861 if (n1 == n2) {
3862 goto skip_node;
3863 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3864 (n2->type == XML_NAMESPACE_DECL))
3865 {
3866 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3867 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3868 ((xmlNsPtr) n2)->prefix)))
3869 {
3870 /*
3871 * Free the namespace node.
3872 */
3873 set2->nodeTab[i] = NULL;
3874 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3875 goto skip_node;
3876 }
3877 }
3878 }
3879 /*
3880 * grow the nodeTab if needed
3881 */
3882 if (set1->nodeMax == 0) {
3883 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3884 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3885 if (set1->nodeTab == NULL) {
3886 xmlXPathErrMemory(NULL, "merging nodeset\n");
3887 return(NULL);
3888 }
3889 memset(set1->nodeTab, 0,
3890 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3891 set1->nodeMax = XML_NODESET_DEFAULT;
3892 } else if (set1->nodeNr >= set1->nodeMax) {
3893 xmlNodePtr *temp;
3894
3895 set1->nodeMax *= 2;
3896 temp = (xmlNodePtr *) xmlRealloc(
3897 set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3898 if (temp == NULL) {
3899 xmlXPathErrMemory(NULL, "merging nodeset\n");
3900 return(NULL);
3901 }
3902 set1->nodeTab = temp;
3903 }
3904 if (n2->type == XML_NAMESPACE_DECL) {
3905 xmlNsPtr ns = (xmlNsPtr) n2;
3906
3907 set1->nodeTab[set1->nodeNr++] =
3908 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3909 } else
3910 set1->nodeTab[set1->nodeNr++] = n2;
3911skip_node:
3912 {}
3913 }
3914 }
3915 set2->nodeNr = 0;
3916 return(set1);
3917}
3918
3919/**
3920 * xmlXPathNodeSetMergeAndClearNoDupls:
3921 * @set1: the first NodeSet or NULL
3922 * @set2: the second NodeSet
3923 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3924 *
3925 * Merges two nodesets, all nodes from @set2 are added to @set1
3926 * if @set1 is NULL, a new set is created and copied from @set2.
3927 * Doesn't chack for duplicate nodes. Clears set2.
3928 *
3929 * Returns @set1 once extended or NULL in case of error.
3930 */
3931static xmlNodeSetPtr
3932xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3933 int hasNullEntries)
3934{
3935 if (set2 == NULL)
3936 return(set1);
3937 if ((set1 == NULL) && (hasNullEntries == 0)) {
3938 /*
3939 * Note that doing a memcpy of the list, namespace nodes are
3940 * just assigned to set1, since set2 is cleared anyway.
3941 */
3942 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3943 if (set1 == NULL)
3944 return(NULL);
3945 if (set2->nodeNr != 0) {
3946 memcpy(set1->nodeTab, set2->nodeTab,
3947 set2->nodeNr * sizeof(xmlNodePtr));
3948 set1->nodeNr = set2->nodeNr;
3949 }
3950 } else {
3951 int i;
3952 xmlNodePtr n2;
3953
3954 if (set1 == NULL)
3955 set1 = xmlXPathNodeSetCreate(NULL);
3956
3957 for (i = 0;i < set2->nodeNr;i++) {
3958 n2 = set2->nodeTab[i];
3959 /*
3960 * Skip NULLed entries.
3961 */
3962 if (n2 == NULL)
3963 continue;
3964 if (set1->nodeMax == 0) {
3965 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3966 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3967 if (set1->nodeTab == NULL) {
3968 xmlXPathErrMemory(NULL, "merging nodeset\n");
3969 return(NULL);
3970 }
3971 memset(set1->nodeTab, 0,
3972 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3973 set1->nodeMax = XML_NODESET_DEFAULT;
3974 } else if (set1->nodeNr >= set1->nodeMax) {
3975 xmlNodePtr *temp;
3976
3977 set1->nodeMax *= 2;
3978 temp = (xmlNodePtr *) xmlRealloc(
3979 set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3980 if (temp == NULL) {
3981 xmlXPathErrMemory(NULL, "merging nodeset\n");
3982 return(NULL);
3983 }
3984 set1->nodeTab = temp;
3985 }
3986 set1->nodeTab[set1->nodeNr++] = n2;
3987 }
3988 }
3989 set2->nodeNr = 0;
3990 return(set1);
3991}
Daniel Veillard75be0132002-03-13 10:03:35 +00003992
3993/**
Owen Taylor3473f882001-02-23 17:55:21 +00003994 * xmlXPathNodeSetDel:
3995 * @cur: the initial node set
3996 * @val: an xmlNodePtr
3997 *
3998 * Removes an xmlNodePtr from an existing NodeSet
3999 */
4000void
4001xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4002 int i;
4003
4004 if (cur == NULL) return;
4005 if (val == NULL) return;
4006
4007 /*
William M. Brack08171912003-12-29 02:52:11 +00004008 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00004009 */
4010 for (i = 0;i < cur->nodeNr;i++)
4011 if (cur->nodeTab[i] == val) break;
4012
William M. Brack08171912003-12-29 02:52:11 +00004013 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00004014#ifdef DEBUG
4015 xmlGenericError(xmlGenericErrorContext,
4016 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4017 val->name);
4018#endif
4019 return;
4020 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004021 if ((cur->nodeTab[i] != NULL) &&
4022 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4023 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004024 cur->nodeNr--;
4025 for (;i < cur->nodeNr;i++)
4026 cur->nodeTab[i] = cur->nodeTab[i + 1];
4027 cur->nodeTab[cur->nodeNr] = NULL;
4028}
4029
4030/**
4031 * xmlXPathNodeSetRemove:
4032 * @cur: the initial node set
4033 * @val: the index to remove
4034 *
4035 * Removes an entry from an existing NodeSet list.
4036 */
4037void
4038xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4039 if (cur == NULL) return;
4040 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004041 if ((cur->nodeTab[val] != NULL) &&
4042 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4043 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00004044 cur->nodeNr--;
4045 for (;val < cur->nodeNr;val++)
4046 cur->nodeTab[val] = cur->nodeTab[val + 1];
4047 cur->nodeTab[cur->nodeNr] = NULL;
4048}
4049
4050/**
4051 * xmlXPathFreeNodeSet:
4052 * @obj: the xmlNodeSetPtr to free
4053 *
4054 * Free the NodeSet compound (not the actual nodes !).
4055 */
4056void
4057xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4058 if (obj == NULL) return;
4059 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004060 int i;
4061
William M. Brack08171912003-12-29 02:52:11 +00004062 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004063 for (i = 0;i < obj->nodeNr;i++)
4064 if ((obj->nodeTab[i] != NULL) &&
4065 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4066 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004067 xmlFree(obj->nodeTab);
4068 }
Owen Taylor3473f882001-02-23 17:55:21 +00004069 xmlFree(obj);
4070}
4071
4072/**
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004073 * xmlXPathNodeSetClear:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004074 * @set: the node set to clear
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004075 *
4076 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4077 * are feed), but does *not* free the list itself. Sets the length of the
4078 * list to 0.
4079 */
4080static void
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004081xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4082{
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004083 if ((set == NULL) || (set->nodeNr <= 0))
4084 return;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004085 else if (hasNsNodes) {
4086 int i;
4087 xmlNodePtr node;
4088
4089 for (i = 0; i < set->nodeNr; i++) {
4090 node = set->nodeTab[i];
4091 if ((node != NULL) &&
4092 (node->type == XML_NAMESPACE_DECL))
4093 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4094 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004095 }
4096 set->nodeNr = 0;
4097}
4098
4099/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004100 * xmlXPathNodeSetClearFromPos:
4101 * @set: the node set to be cleared
4102 * @pos: the start position to clear from
4103 *
4104 * Clears the list from temporary XPath objects (e.g. namespace nodes
4105 * are feed) starting with the entry at @pos, but does *not* free the list
4106 * itself. Sets the length of the list to @pos.
4107 */
4108static void
4109xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4110{
4111 if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4112 return;
4113 else if ((hasNsNodes)) {
4114 int i;
4115 xmlNodePtr node;
4116
4117 for (i = pos; i < set->nodeNr; i++) {
4118 node = set->nodeTab[i];
4119 if ((node != NULL) &&
4120 (node->type == XML_NAMESPACE_DECL))
4121 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4122 }
4123 }
4124 set->nodeNr = pos;
4125}
4126
4127/**
Owen Taylor3473f882001-02-23 17:55:21 +00004128 * xmlXPathFreeValueTree:
4129 * @obj: the xmlNodeSetPtr to free
4130 *
4131 * Free the NodeSet compound and the actual tree, this is different
4132 * from xmlXPathFreeNodeSet()
4133 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004134static void
Owen Taylor3473f882001-02-23 17:55:21 +00004135xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4136 int i;
4137
4138 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00004139
4140 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004141 for (i = 0;i < obj->nodeNr;i++) {
4142 if (obj->nodeTab[i] != NULL) {
4143 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4144 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4145 } else {
4146 xmlFreeNodeList(obj->nodeTab[i]);
4147 }
4148 }
4149 }
Owen Taylor3473f882001-02-23 17:55:21 +00004150 xmlFree(obj->nodeTab);
4151 }
Owen Taylor3473f882001-02-23 17:55:21 +00004152 xmlFree(obj);
4153}
4154
4155#if defined(DEBUG) || defined(DEBUG_STEP)
4156/**
4157 * xmlGenericErrorContextNodeSet:
4158 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00004159 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00004160 *
4161 * Quick display of a NodeSet
4162 */
4163void
4164xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4165 int i;
4166
4167 if (output == NULL) output = xmlGenericErrorContext;
4168 if (obj == NULL) {
4169 fprintf(output, "NodeSet == NULL !\n");
4170 return;
4171 }
4172 if (obj->nodeNr == 0) {
4173 fprintf(output, "NodeSet is empty\n");
4174 return;
4175 }
4176 if (obj->nodeTab == NULL) {
4177 fprintf(output, " nodeTab == NULL !\n");
4178 return;
4179 }
4180 for (i = 0; i < obj->nodeNr; i++) {
4181 if (obj->nodeTab[i] == NULL) {
4182 fprintf(output, " NULL !\n");
4183 return;
4184 }
4185 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4186 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4187 fprintf(output, " /");
4188 else if (obj->nodeTab[i]->name == NULL)
4189 fprintf(output, " noname!");
4190 else fprintf(output, " %s", obj->nodeTab[i]->name);
4191 }
4192 fprintf(output, "\n");
4193}
4194#endif
4195
4196/**
4197 * xmlXPathNewNodeSet:
4198 * @val: the NodePtr value
4199 *
4200 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4201 * it with the single Node @val
4202 *
4203 * Returns the newly created object.
4204 */
4205xmlXPathObjectPtr
4206xmlXPathNewNodeSet(xmlNodePtr val) {
4207 xmlXPathObjectPtr ret;
4208
4209 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4210 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004211 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004212 return(NULL);
4213 }
4214 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4215 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00004216 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004217 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00004218 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004219#ifdef XP_DEBUG_OBJ_USAGE
4220 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4221#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004222 return(ret);
4223}
4224
4225/**
4226 * xmlXPathNewValueTree:
4227 * @val: the NodePtr value
4228 *
4229 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4230 * it with the tree root @val
4231 *
4232 * Returns the newly created object.
4233 */
4234xmlXPathObjectPtr
4235xmlXPathNewValueTree(xmlNodePtr val) {
4236 xmlXPathObjectPtr ret;
4237
4238 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4239 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004240 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004241 return(NULL);
4242 }
4243 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4244 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00004245 ret->boolval = 1;
4246 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00004247 ret->nodesetval = xmlXPathNodeSetCreate(val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004248#ifdef XP_DEBUG_OBJ_USAGE
4249 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4250#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004251 return(ret);
4252}
4253
4254/**
4255 * xmlXPathNewNodeSetList:
4256 * @val: an existing NodeSet
4257 *
4258 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4259 * it with the Nodeset @val
4260 *
4261 * Returns the newly created object.
4262 */
4263xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004264xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4265{
Owen Taylor3473f882001-02-23 17:55:21 +00004266 xmlXPathObjectPtr ret;
4267 int i;
4268
4269 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004270 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00004271 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004272 ret = xmlXPathNewNodeSet(NULL);
4273 else {
4274 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4275 for (i = 1; i < val->nodeNr; ++i)
4276 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
4277 }
Owen Taylor3473f882001-02-23 17:55:21 +00004278
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004279 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004280}
4281
4282/**
4283 * xmlXPathWrapNodeSet:
4284 * @val: the NodePtr value
4285 *
4286 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4287 *
4288 * Returns the newly created object.
4289 */
4290xmlXPathObjectPtr
4291xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4292 xmlXPathObjectPtr ret;
4293
4294 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4295 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004296 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004297 return(NULL);
4298 }
4299 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4300 ret->type = XPATH_NODESET;
4301 ret->nodesetval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004302#ifdef XP_DEBUG_OBJ_USAGE
4303 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4304#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004305 return(ret);
4306}
4307
4308/**
4309 * xmlXPathFreeNodeSetList:
4310 * @obj: an existing NodeSetList object
4311 *
4312 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4313 * the list contrary to xmlXPathFreeObject().
4314 */
4315void
4316xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4317 if (obj == NULL) return;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004318#ifdef XP_DEBUG_OBJ_USAGE
4319 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4320#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004321 xmlFree(obj);
4322}
4323
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004324/**
4325 * xmlXPathDifference:
4326 * @nodes1: a node-set
4327 * @nodes2: a node-set
4328 *
4329 * Implements the EXSLT - Sets difference() function:
4330 * node-set set:difference (node-set, node-set)
4331 *
4332 * Returns the difference between the two node sets, or nodes1 if
4333 * nodes2 is empty
4334 */
4335xmlNodeSetPtr
4336xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4337 xmlNodeSetPtr ret;
4338 int i, l1;
4339 xmlNodePtr cur;
4340
4341 if (xmlXPathNodeSetIsEmpty(nodes2))
4342 return(nodes1);
4343
4344 ret = xmlXPathNodeSetCreate(NULL);
4345 if (xmlXPathNodeSetIsEmpty(nodes1))
4346 return(ret);
4347
4348 l1 = xmlXPathNodeSetGetLength(nodes1);
4349
4350 for (i = 0; i < l1; i++) {
4351 cur = xmlXPathNodeSetItem(nodes1, i);
4352 if (!xmlXPathNodeSetContains(nodes2, cur))
4353 xmlXPathNodeSetAddUnique(ret, cur);
4354 }
4355 return(ret);
4356}
4357
4358/**
4359 * xmlXPathIntersection:
4360 * @nodes1: a node-set
4361 * @nodes2: a node-set
4362 *
4363 * Implements the EXSLT - Sets intersection() function:
4364 * node-set set:intersection (node-set, node-set)
4365 *
4366 * Returns a node set comprising the nodes that are within both the
4367 * node sets passed as arguments
4368 */
4369xmlNodeSetPtr
4370xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4371 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4372 int i, l1;
4373 xmlNodePtr cur;
4374
4375 if (xmlXPathNodeSetIsEmpty(nodes1))
4376 return(ret);
4377 if (xmlXPathNodeSetIsEmpty(nodes2))
4378 return(ret);
4379
4380 l1 = xmlXPathNodeSetGetLength(nodes1);
4381
4382 for (i = 0; i < l1; i++) {
4383 cur = xmlXPathNodeSetItem(nodes1, i);
4384 if (xmlXPathNodeSetContains(nodes2, cur))
4385 xmlXPathNodeSetAddUnique(ret, cur);
4386 }
4387 return(ret);
4388}
4389
4390/**
4391 * xmlXPathDistinctSorted:
4392 * @nodes: a node-set, sorted by document order
4393 *
4394 * Implements the EXSLT - Sets distinct() function:
4395 * node-set set:distinct (node-set)
4396 *
4397 * Returns a subset of the nodes contained in @nodes, or @nodes if
4398 * it is empty
4399 */
4400xmlNodeSetPtr
4401xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4402 xmlNodeSetPtr ret;
4403 xmlHashTablePtr hash;
4404 int i, l;
4405 xmlChar * strval;
4406 xmlNodePtr cur;
4407
4408 if (xmlXPathNodeSetIsEmpty(nodes))
4409 return(nodes);
4410
4411 ret = xmlXPathNodeSetCreate(NULL);
4412 l = xmlXPathNodeSetGetLength(nodes);
4413 hash = xmlHashCreate (l);
4414 for (i = 0; i < l; i++) {
4415 cur = xmlXPathNodeSetItem(nodes, i);
4416 strval = xmlXPathCastNodeToString(cur);
4417 if (xmlHashLookup(hash, strval) == NULL) {
4418 xmlHashAddEntry(hash, strval, strval);
4419 xmlXPathNodeSetAddUnique(ret, cur);
4420 } else {
4421 xmlFree(strval);
4422 }
4423 }
4424 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4425 return(ret);
4426}
4427
4428/**
4429 * xmlXPathDistinct:
4430 * @nodes: a node-set
4431 *
4432 * Implements the EXSLT - Sets distinct() function:
4433 * node-set set:distinct (node-set)
4434 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4435 * is called with the sorted node-set
4436 *
4437 * Returns a subset of the nodes contained in @nodes, or @nodes if
4438 * it is empty
4439 */
4440xmlNodeSetPtr
4441xmlXPathDistinct (xmlNodeSetPtr nodes) {
4442 if (xmlXPathNodeSetIsEmpty(nodes))
4443 return(nodes);
4444
4445 xmlXPathNodeSetSort(nodes);
4446 return(xmlXPathDistinctSorted(nodes));
4447}
4448
4449/**
4450 * xmlXPathHasSameNodes:
4451 * @nodes1: a node-set
4452 * @nodes2: a node-set
4453 *
4454 * Implements the EXSLT - Sets has-same-nodes function:
4455 * boolean set:has-same-node(node-set, node-set)
4456 *
4457 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4458 * otherwise
4459 */
4460int
4461xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4462 int i, l;
4463 xmlNodePtr cur;
4464
4465 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4466 xmlXPathNodeSetIsEmpty(nodes2))
4467 return(0);
4468
4469 l = xmlXPathNodeSetGetLength(nodes1);
4470 for (i = 0; i < l; i++) {
4471 cur = xmlXPathNodeSetItem(nodes1, i);
4472 if (xmlXPathNodeSetContains(nodes2, cur))
4473 return(1);
4474 }
4475 return(0);
4476}
4477
4478/**
4479 * xmlXPathNodeLeadingSorted:
4480 * @nodes: a node-set, sorted by document order
4481 * @node: a node
4482 *
4483 * Implements the EXSLT - Sets leading() function:
4484 * node-set set:leading (node-set, node-set)
4485 *
4486 * Returns the nodes in @nodes that precede @node in document order,
4487 * @nodes if @node is NULL or an empty node-set if @nodes
4488 * doesn't contain @node
4489 */
4490xmlNodeSetPtr
4491xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4492 int i, l;
4493 xmlNodePtr cur;
4494 xmlNodeSetPtr ret;
4495
4496 if (node == NULL)
4497 return(nodes);
4498
4499 ret = xmlXPathNodeSetCreate(NULL);
4500 if (xmlXPathNodeSetIsEmpty(nodes) ||
4501 (!xmlXPathNodeSetContains(nodes, node)))
4502 return(ret);
4503
4504 l = xmlXPathNodeSetGetLength(nodes);
4505 for (i = 0; i < l; i++) {
4506 cur = xmlXPathNodeSetItem(nodes, i);
4507 if (cur == node)
4508 break;
4509 xmlXPathNodeSetAddUnique(ret, cur);
4510 }
4511 return(ret);
4512}
4513
4514/**
4515 * xmlXPathNodeLeading:
4516 * @nodes: a node-set
4517 * @node: a node
4518 *
4519 * Implements the EXSLT - Sets leading() function:
4520 * node-set set:leading (node-set, node-set)
4521 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4522 * is called.
4523 *
4524 * Returns the nodes in @nodes that precede @node in document order,
4525 * @nodes if @node is NULL or an empty node-set if @nodes
4526 * doesn't contain @node
4527 */
4528xmlNodeSetPtr
4529xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4530 xmlXPathNodeSetSort(nodes);
4531 return(xmlXPathNodeLeadingSorted(nodes, node));
4532}
4533
4534/**
4535 * xmlXPathLeadingSorted:
4536 * @nodes1: a node-set, sorted by document order
4537 * @nodes2: a node-set, sorted by document order
4538 *
4539 * Implements the EXSLT - Sets leading() function:
4540 * node-set set:leading (node-set, node-set)
4541 *
4542 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4543 * in document order, @nodes1 if @nodes2 is NULL or empty or
4544 * an empty node-set if @nodes1 doesn't contain @nodes2
4545 */
4546xmlNodeSetPtr
4547xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4548 if (xmlXPathNodeSetIsEmpty(nodes2))
4549 return(nodes1);
4550 return(xmlXPathNodeLeadingSorted(nodes1,
4551 xmlXPathNodeSetItem(nodes2, 1)));
4552}
4553
4554/**
4555 * xmlXPathLeading:
4556 * @nodes1: a node-set
4557 * @nodes2: a node-set
4558 *
4559 * Implements the EXSLT - Sets leading() function:
4560 * node-set set:leading (node-set, node-set)
4561 * @nodes1 and @nodes2 are sorted by document order, then
4562 * #exslSetsLeadingSorted is called.
4563 *
4564 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4565 * in document order, @nodes1 if @nodes2 is NULL or empty or
4566 * an empty node-set if @nodes1 doesn't contain @nodes2
4567 */
4568xmlNodeSetPtr
4569xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4570 if (xmlXPathNodeSetIsEmpty(nodes2))
4571 return(nodes1);
4572 if (xmlXPathNodeSetIsEmpty(nodes1))
4573 return(xmlXPathNodeSetCreate(NULL));
4574 xmlXPathNodeSetSort(nodes1);
4575 xmlXPathNodeSetSort(nodes2);
4576 return(xmlXPathNodeLeadingSorted(nodes1,
4577 xmlXPathNodeSetItem(nodes2, 1)));
4578}
4579
4580/**
4581 * xmlXPathNodeTrailingSorted:
4582 * @nodes: a node-set, sorted by document order
4583 * @node: a node
4584 *
4585 * Implements the EXSLT - Sets trailing() function:
4586 * node-set set:trailing (node-set, node-set)
4587 *
4588 * Returns the nodes in @nodes that follow @node in document order,
4589 * @nodes if @node is NULL or an empty node-set if @nodes
4590 * doesn't contain @node
4591 */
4592xmlNodeSetPtr
4593xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4594 int i, l;
4595 xmlNodePtr cur;
4596 xmlNodeSetPtr ret;
4597
4598 if (node == NULL)
4599 return(nodes);
4600
4601 ret = xmlXPathNodeSetCreate(NULL);
4602 if (xmlXPathNodeSetIsEmpty(nodes) ||
4603 (!xmlXPathNodeSetContains(nodes, node)))
4604 return(ret);
4605
4606 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00004607 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004608 cur = xmlXPathNodeSetItem(nodes, i);
4609 if (cur == node)
4610 break;
4611 xmlXPathNodeSetAddUnique(ret, cur);
4612 }
4613 return(ret);
4614}
4615
4616/**
4617 * xmlXPathNodeTrailing:
4618 * @nodes: a node-set
4619 * @node: a node
4620 *
4621 * Implements the EXSLT - Sets trailing() function:
4622 * node-set set:trailing (node-set, node-set)
4623 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4624 * is called.
4625 *
4626 * Returns the nodes in @nodes that follow @node in document order,
4627 * @nodes if @node is NULL or an empty node-set if @nodes
4628 * doesn't contain @node
4629 */
4630xmlNodeSetPtr
4631xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4632 xmlXPathNodeSetSort(nodes);
4633 return(xmlXPathNodeTrailingSorted(nodes, node));
4634}
4635
4636/**
4637 * xmlXPathTrailingSorted:
4638 * @nodes1: a node-set, sorted by document order
4639 * @nodes2: a node-set, sorted by document order
4640 *
4641 * Implements the EXSLT - Sets trailing() function:
4642 * node-set set:trailing (node-set, node-set)
4643 *
4644 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4645 * in document order, @nodes1 if @nodes2 is NULL or empty or
4646 * an empty node-set if @nodes1 doesn't contain @nodes2
4647 */
4648xmlNodeSetPtr
4649xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4650 if (xmlXPathNodeSetIsEmpty(nodes2))
4651 return(nodes1);
4652 return(xmlXPathNodeTrailingSorted(nodes1,
4653 xmlXPathNodeSetItem(nodes2, 0)));
4654}
4655
4656/**
4657 * xmlXPathTrailing:
4658 * @nodes1: a node-set
4659 * @nodes2: a node-set
4660 *
4661 * Implements the EXSLT - Sets trailing() function:
4662 * node-set set:trailing (node-set, node-set)
4663 * @nodes1 and @nodes2 are sorted by document order, then
4664 * #xmlXPathTrailingSorted is called.
4665 *
4666 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4667 * in document order, @nodes1 if @nodes2 is NULL or empty or
4668 * an empty node-set if @nodes1 doesn't contain @nodes2
4669 */
4670xmlNodeSetPtr
4671xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4672 if (xmlXPathNodeSetIsEmpty(nodes2))
4673 return(nodes1);
4674 if (xmlXPathNodeSetIsEmpty(nodes1))
4675 return(xmlXPathNodeSetCreate(NULL));
4676 xmlXPathNodeSetSort(nodes1);
4677 xmlXPathNodeSetSort(nodes2);
4678 return(xmlXPathNodeTrailingSorted(nodes1,
4679 xmlXPathNodeSetItem(nodes2, 0)));
4680}
4681
Owen Taylor3473f882001-02-23 17:55:21 +00004682/************************************************************************
4683 * *
4684 * Routines to handle extra functions *
4685 * *
4686 ************************************************************************/
4687
4688/**
4689 * xmlXPathRegisterFunc:
4690 * @ctxt: the XPath context
4691 * @name: the function name
4692 * @f: the function implementation or NULL
4693 *
4694 * Register a new function. If @f is NULL it unregisters the function
4695 *
4696 * Returns 0 in case of success, -1 in case of error
4697 */
4698int
4699xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4700 xmlXPathFunction f) {
4701 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4702}
4703
4704/**
4705 * xmlXPathRegisterFuncNS:
4706 * @ctxt: the XPath context
4707 * @name: the function name
4708 * @ns_uri: the function namespace URI
4709 * @f: the function implementation or NULL
4710 *
4711 * Register a new function. If @f is NULL it unregisters the function
4712 *
4713 * Returns 0 in case of success, -1 in case of error
4714 */
4715int
4716xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4717 const xmlChar *ns_uri, xmlXPathFunction f) {
4718 if (ctxt == NULL)
4719 return(-1);
4720 if (name == NULL)
4721 return(-1);
4722
4723 if (ctxt->funcHash == NULL)
4724 ctxt->funcHash = xmlHashCreate(0);
4725 if (ctxt->funcHash == NULL)
4726 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004727 if (f == NULL)
4728 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
William M. Brackad0e67c2004-12-01 14:35:10 +00004729 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
Owen Taylor3473f882001-02-23 17:55:21 +00004730}
4731
4732/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00004733 * xmlXPathRegisterFuncLookup:
4734 * @ctxt: the XPath context
4735 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004736 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00004737 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004738 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00004739 */
4740void
4741xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4742 xmlXPathFuncLookupFunc f,
4743 void *funcCtxt) {
4744 if (ctxt == NULL)
4745 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004746 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004747 ctxt->funcLookupData = funcCtxt;
4748}
4749
4750/**
Owen Taylor3473f882001-02-23 17:55:21 +00004751 * xmlXPathFunctionLookup:
4752 * @ctxt: the XPath context
4753 * @name: the function name
4754 *
4755 * Search in the Function array of the context for the given
4756 * function.
4757 *
4758 * Returns the xmlXPathFunction or NULL if not found
4759 */
4760xmlXPathFunction
4761xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00004762 if (ctxt == NULL)
4763 return (NULL);
4764
4765 if (ctxt->funcLookupFunc != NULL) {
4766 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004767 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004768
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004769 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004770 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004771 if (ret != NULL)
4772 return(ret);
4773 }
Owen Taylor3473f882001-02-23 17:55:21 +00004774 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4775}
4776
4777/**
4778 * xmlXPathFunctionLookupNS:
4779 * @ctxt: the XPath context
4780 * @name: the function name
4781 * @ns_uri: the function namespace URI
4782 *
4783 * Search in the Function array of the context for the given
4784 * function.
4785 *
4786 * Returns the xmlXPathFunction or NULL if not found
4787 */
4788xmlXPathFunction
4789xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4790 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00004791 xmlXPathFunction ret;
4792
Owen Taylor3473f882001-02-23 17:55:21 +00004793 if (ctxt == NULL)
4794 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004795 if (name == NULL)
4796 return(NULL);
4797
Thomas Broyerba4ad322001-07-26 16:55:21 +00004798 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004799 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004800
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004801 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004802 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004803 if (ret != NULL)
4804 return(ret);
4805 }
4806
4807 if (ctxt->funcHash == NULL)
4808 return(NULL);
4809
William M. Brackad0e67c2004-12-01 14:35:10 +00004810 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4811 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004812}
4813
4814/**
4815 * xmlXPathRegisteredFuncsCleanup:
4816 * @ctxt: the XPath context
4817 *
4818 * Cleanup the XPath context data associated to registered functions
4819 */
4820void
4821xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4822 if (ctxt == NULL)
4823 return;
4824
4825 xmlHashFree(ctxt->funcHash, NULL);
4826 ctxt->funcHash = NULL;
4827}
4828
4829/************************************************************************
4830 * *
William M. Brack08171912003-12-29 02:52:11 +00004831 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00004832 * *
4833 ************************************************************************/
4834
4835/**
4836 * xmlXPathRegisterVariable:
4837 * @ctxt: the XPath context
4838 * @name: the variable name
4839 * @value: the variable value or NULL
4840 *
4841 * Register a new variable value. If @value is NULL it unregisters
4842 * the variable
4843 *
4844 * Returns 0 in case of success, -1 in case of error
4845 */
4846int
4847xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4848 xmlXPathObjectPtr value) {
4849 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4850}
4851
4852/**
4853 * xmlXPathRegisterVariableNS:
4854 * @ctxt: the XPath context
4855 * @name: the variable name
4856 * @ns_uri: the variable namespace URI
4857 * @value: the variable value or NULL
4858 *
4859 * Register a new variable value. If @value is NULL it unregisters
4860 * the variable
4861 *
4862 * Returns 0 in case of success, -1 in case of error
4863 */
4864int
4865xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4866 const xmlChar *ns_uri,
4867 xmlXPathObjectPtr value) {
4868 if (ctxt == NULL)
4869 return(-1);
4870 if (name == NULL)
4871 return(-1);
4872
4873 if (ctxt->varHash == NULL)
4874 ctxt->varHash = xmlHashCreate(0);
4875 if (ctxt->varHash == NULL)
4876 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004877 if (value == NULL)
4878 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4879 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00004880 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4881 (void *) value,
4882 (xmlHashDeallocator)xmlXPathFreeObject));
4883}
4884
4885/**
4886 * xmlXPathRegisterVariableLookup:
4887 * @ctxt: the XPath context
4888 * @f: the lookup function
4889 * @data: the lookup data
4890 *
4891 * register an external mechanism to do variable lookup
4892 */
4893void
4894xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4895 xmlXPathVariableLookupFunc f, void *data) {
4896 if (ctxt == NULL)
4897 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004898 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00004899 ctxt->varLookupData = data;
4900}
4901
4902/**
4903 * xmlXPathVariableLookup:
4904 * @ctxt: the XPath context
4905 * @name: the variable name
4906 *
4907 * Search in the Variable array of the context for the given
4908 * variable value.
4909 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00004910 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00004911 */
4912xmlXPathObjectPtr
4913xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4914 if (ctxt == NULL)
4915 return(NULL);
4916
4917 if (ctxt->varLookupFunc != NULL) {
4918 xmlXPathObjectPtr ret;
4919
4920 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4921 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00004922 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004923 }
4924 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4925}
4926
4927/**
4928 * xmlXPathVariableLookupNS:
4929 * @ctxt: the XPath context
4930 * @name: the variable name
4931 * @ns_uri: the variable namespace URI
4932 *
4933 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00004934 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00004935 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00004936 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00004937 */
4938xmlXPathObjectPtr
4939xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4940 const xmlChar *ns_uri) {
4941 if (ctxt == NULL)
4942 return(NULL);
4943
4944 if (ctxt->varLookupFunc != NULL) {
4945 xmlXPathObjectPtr ret;
4946
4947 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4948 (ctxt->varLookupData, name, ns_uri);
4949 if (ret != NULL) return(ret);
4950 }
4951
4952 if (ctxt->varHash == NULL)
4953 return(NULL);
4954 if (name == NULL)
4955 return(NULL);
4956
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004957 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
Daniel Veillard8c357d52001-07-03 23:43:33 +00004958 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00004959}
4960
4961/**
4962 * xmlXPathRegisteredVariablesCleanup:
4963 * @ctxt: the XPath context
4964 *
4965 * Cleanup the XPath context data associated to registered variables
4966 */
4967void
4968xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4969 if (ctxt == NULL)
4970 return;
4971
Daniel Veillard76d66f42001-05-16 21:05:17 +00004972 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00004973 ctxt->varHash = NULL;
4974}
4975
4976/**
4977 * xmlXPathRegisterNs:
4978 * @ctxt: the XPath context
4979 * @prefix: the namespace prefix
4980 * @ns_uri: the namespace name
4981 *
4982 * Register a new namespace. If @ns_uri is NULL it unregisters
4983 * the namespace
4984 *
4985 * Returns 0 in case of success, -1 in case of error
4986 */
4987int
4988xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
4989 const xmlChar *ns_uri) {
4990 if (ctxt == NULL)
4991 return(-1);
4992 if (prefix == NULL)
4993 return(-1);
4994
4995 if (ctxt->nsHash == NULL)
4996 ctxt->nsHash = xmlHashCreate(10);
4997 if (ctxt->nsHash == NULL)
4998 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00004999 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00005000 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00005001 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00005002 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00005003 (xmlHashDeallocator)xmlFree));
5004}
5005
5006/**
5007 * xmlXPathNsLookup:
5008 * @ctxt: the XPath context
5009 * @prefix: the namespace prefix value
5010 *
5011 * Search in the namespace declaration array of the context for the given
5012 * namespace name associated to the given prefix
5013 *
5014 * Returns the value or NULL if not found
5015 */
5016const xmlChar *
5017xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5018 if (ctxt == NULL)
5019 return(NULL);
5020 if (prefix == NULL)
5021 return(NULL);
5022
5023#ifdef XML_XML_NAMESPACE
5024 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5025 return(XML_XML_NAMESPACE);
5026#endif
5027
Daniel Veillardc8f620b2001-04-30 20:31:33 +00005028 if (ctxt->namespaces != NULL) {
5029 int i;
5030
5031 for (i = 0;i < ctxt->nsNr;i++) {
5032 if ((ctxt->namespaces[i] != NULL) &&
5033 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5034 return(ctxt->namespaces[i]->href);
5035 }
5036 }
Owen Taylor3473f882001-02-23 17:55:21 +00005037
5038 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5039}
5040
5041/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005042 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00005043 * @ctxt: the XPath context
5044 *
5045 * Cleanup the XPath context data associated to registered variables
5046 */
5047void
5048xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5049 if (ctxt == NULL)
5050 return;
5051
Daniel Veillard42766c02002-08-22 20:52:17 +00005052 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00005053 ctxt->nsHash = NULL;
5054}
5055
5056/************************************************************************
5057 * *
5058 * Routines to handle Values *
5059 * *
5060 ************************************************************************/
5061
William M. Brack08171912003-12-29 02:52:11 +00005062/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005063
5064/**
5065 * xmlXPathNewFloat:
5066 * @val: the double value
5067 *
5068 * Create a new xmlXPathObjectPtr of type double and of value @val
5069 *
5070 * Returns the newly created object.
5071 */
5072xmlXPathObjectPtr
5073xmlXPathNewFloat(double val) {
5074 xmlXPathObjectPtr ret;
5075
5076 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5077 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005078 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005079 return(NULL);
5080 }
5081 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5082 ret->type = XPATH_NUMBER;
5083 ret->floatval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005084#ifdef XP_DEBUG_OBJ_USAGE
5085 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5086#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005087 return(ret);
5088}
5089
5090/**
5091 * xmlXPathNewBoolean:
5092 * @val: the boolean value
5093 *
5094 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5095 *
5096 * Returns the newly created object.
5097 */
5098xmlXPathObjectPtr
5099xmlXPathNewBoolean(int val) {
5100 xmlXPathObjectPtr ret;
5101
5102 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5103 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005104 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005105 return(NULL);
5106 }
5107 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5108 ret->type = XPATH_BOOLEAN;
5109 ret->boolval = (val != 0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005110#ifdef XP_DEBUG_OBJ_USAGE
5111 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5112#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005113 return(ret);
5114}
5115
5116/**
5117 * xmlXPathNewString:
5118 * @val: the xmlChar * value
5119 *
5120 * Create a new xmlXPathObjectPtr of type string and of value @val
5121 *
5122 * Returns the newly created object.
5123 */
5124xmlXPathObjectPtr
5125xmlXPathNewString(const xmlChar *val) {
5126 xmlXPathObjectPtr ret;
5127
5128 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5129 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005130 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005131 return(NULL);
5132 }
5133 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5134 ret->type = XPATH_STRING;
5135 if (val != NULL)
5136 ret->stringval = xmlStrdup(val);
5137 else
5138 ret->stringval = xmlStrdup((const xmlChar *)"");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005139#ifdef XP_DEBUG_OBJ_USAGE
5140 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5141#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005142 return(ret);
5143}
5144
5145/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005146 * xmlXPathWrapString:
5147 * @val: the xmlChar * value
5148 *
5149 * Wraps the @val string into an XPath object.
5150 *
5151 * Returns the newly created object.
5152 */
5153xmlXPathObjectPtr
5154xmlXPathWrapString (xmlChar *val) {
5155 xmlXPathObjectPtr ret;
5156
5157 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5158 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005159 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005160 return(NULL);
5161 }
5162 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5163 ret->type = XPATH_STRING;
5164 ret->stringval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005165#ifdef XP_DEBUG_OBJ_USAGE
5166 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5167#endif
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005168 return(ret);
5169}
5170
5171/**
Owen Taylor3473f882001-02-23 17:55:21 +00005172 * xmlXPathNewCString:
5173 * @val: the char * value
5174 *
5175 * Create a new xmlXPathObjectPtr of type string and of value @val
5176 *
5177 * Returns the newly created object.
5178 */
5179xmlXPathObjectPtr
5180xmlXPathNewCString(const char *val) {
5181 xmlXPathObjectPtr ret;
5182
5183 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5184 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005185 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005186 return(NULL);
5187 }
5188 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5189 ret->type = XPATH_STRING;
5190 ret->stringval = xmlStrdup(BAD_CAST val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005191#ifdef XP_DEBUG_OBJ_USAGE
5192 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5193#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005194 return(ret);
5195}
5196
5197/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005198 * xmlXPathWrapCString:
5199 * @val: the char * value
5200 *
5201 * Wraps a string into an XPath object.
5202 *
5203 * Returns the newly created object.
5204 */
5205xmlXPathObjectPtr
5206xmlXPathWrapCString (char * val) {
5207 return(xmlXPathWrapString((xmlChar *)(val)));
5208}
5209
5210/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005211 * xmlXPathWrapExternal:
5212 * @val: the user data
5213 *
5214 * Wraps the @val data into an XPath object.
5215 *
5216 * Returns the newly created object.
5217 */
5218xmlXPathObjectPtr
5219xmlXPathWrapExternal (void *val) {
5220 xmlXPathObjectPtr ret;
5221
5222 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5223 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005224 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005225 return(NULL);
5226 }
5227 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5228 ret->type = XPATH_USERS;
5229 ret->user = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005230#ifdef XP_DEBUG_OBJ_USAGE
5231 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5232#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005233 return(ret);
5234}
5235
5236/**
Owen Taylor3473f882001-02-23 17:55:21 +00005237 * xmlXPathObjectCopy:
5238 * @val: the original object
5239 *
5240 * allocate a new copy of a given object
5241 *
5242 * Returns the newly created object.
5243 */
5244xmlXPathObjectPtr
5245xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5246 xmlXPathObjectPtr ret;
5247
5248 if (val == NULL)
5249 return(NULL);
5250
5251 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5252 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005253 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005254 return(NULL);
5255 }
5256 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005257#ifdef XP_DEBUG_OBJ_USAGE
5258 xmlXPathDebugObjUsageRequested(NULL, val->type);
5259#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005260 switch (val->type) {
5261 case XPATH_BOOLEAN:
5262 case XPATH_NUMBER:
5263 case XPATH_POINT:
5264 case XPATH_RANGE:
5265 break;
5266 case XPATH_STRING:
5267 ret->stringval = xmlStrdup(val->stringval);
5268 break;
5269 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00005270#if 0
5271/*
5272 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5273 this previous handling is no longer correct, and can cause some serious
5274 problems (ref. bug 145547)
5275*/
Owen Taylor3473f882001-02-23 17:55:21 +00005276 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005277 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005278 xmlNodePtr cur, tmp;
5279 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005280
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005281 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005282 top = xmlNewDoc(NULL);
5283 top->name = (char *)
5284 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005285 ret->user = top;
5286 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005287 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005288 cur = val->nodesetval->nodeTab[0]->children;
5289 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005290 tmp = xmlDocCopyNode(cur, top, 1);
5291 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005292 cur = cur->next;
5293 }
5294 }
William M. Bracke9449c52004-07-11 14:41:20 +00005295
Daniel Veillard9adc0462003-03-24 18:39:54 +00005296 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005297 } else
Owen Taylor3473f882001-02-23 17:55:21 +00005298 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005299 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00005300 break;
William M. Bracke9449c52004-07-11 14:41:20 +00005301#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005302 case XPATH_NODESET:
5303 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005304 /* Do not deallocate the copied tree value */
5305 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005306 break;
5307 case XPATH_LOCATIONSET:
5308#ifdef LIBXML_XPTR_ENABLED
5309 {
5310 xmlLocationSetPtr loc = val->user;
5311 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5312 break;
5313 }
5314#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00005315 case XPATH_USERS:
5316 ret->user = val->user;
5317 break;
5318 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00005319 xmlGenericError(xmlGenericErrorContext,
5320 "xmlXPathObjectCopy: unsupported type %d\n",
5321 val->type);
5322 break;
5323 }
5324 return(ret);
5325}
5326
5327/**
5328 * xmlXPathFreeObject:
5329 * @obj: the object to free
5330 *
5331 * Free up an xmlXPathObjectPtr object.
5332 */
5333void
5334xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5335 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005336 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00005337 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00005338#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005339 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005340 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00005341 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00005342 } else
5343#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005344 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
William M. Bracke9449c52004-07-11 14:41:20 +00005345 if (obj->nodesetval != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005346 xmlXPathFreeValueTree(obj->nodesetval);
Daniel Veillard77851712001-02-27 21:54:07 +00005347 } else {
5348 if (obj->nodesetval != NULL)
5349 xmlXPathFreeNodeSet(obj->nodesetval);
5350 }
Owen Taylor3473f882001-02-23 17:55:21 +00005351#ifdef LIBXML_XPTR_ENABLED
5352 } else if (obj->type == XPATH_LOCATIONSET) {
5353 if (obj->user != NULL)
5354 xmlXPtrFreeLocationSet(obj->user);
5355#endif
5356 } else if (obj->type == XPATH_STRING) {
5357 if (obj->stringval != NULL)
5358 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005359 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005360#ifdef XP_DEBUG_OBJ_USAGE
5361 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5362#endif
5363 xmlFree(obj);
5364}
Owen Taylor3473f882001-02-23 17:55:21 +00005365
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005366/**
5367 * xmlXPathReleaseObject:
5368 * @obj: the xmlXPathObjectPtr to free or to cache
5369 *
5370 * Depending on the state of the cache this frees the given
5371 * XPath object or stores it in the cache.
5372 */
5373static void
5374xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5375{
5376#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5377 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5378 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5379
5380#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5381
5382 if (obj == NULL)
5383 return;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005384 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005385 xmlXPathFreeObject(obj);
5386 } else {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005387 xmlXPathContextCachePtr cache =
5388 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005389
5390 switch (obj->type) {
5391 case XPATH_NODESET:
5392 case XPATH_XSLT_TREE:
5393 if (obj->nodesetval != NULL) {
5394 if (obj->boolval) {
5395 /*
5396 * It looks like the @boolval is used for
5397 * evaluation if this an XSLT Result Tree Fragment.
5398 * TODO: Check if this assumption is correct.
5399 */
5400 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5401 xmlXPathFreeValueTree(obj->nodesetval);
5402 obj->nodesetval = NULL;
5403 } else if ((obj->nodesetval->nodeMax <= 40) &&
5404 (XP_CACHE_WANTS(cache->nodesetObjs,
5405 cache->maxNodeset)))
5406 {
5407 XP_CACHE_ADD(cache->nodesetObjs, obj);
5408 goto obj_cached;
5409 } else {
5410 xmlXPathFreeNodeSet(obj->nodesetval);
5411 obj->nodesetval = NULL;
5412 }
5413 }
5414 break;
5415 case XPATH_STRING:
5416 if (obj->stringval != NULL)
5417 xmlFree(obj->stringval);
5418
5419 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5420 XP_CACHE_ADD(cache->stringObjs, obj);
5421 goto obj_cached;
5422 }
5423 break;
5424 case XPATH_BOOLEAN:
5425 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5426 XP_CACHE_ADD(cache->booleanObjs, obj);
5427 goto obj_cached;
5428 }
5429 break;
5430 case XPATH_NUMBER:
5431 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5432 XP_CACHE_ADD(cache->numberObjs, obj);
5433 goto obj_cached;
5434 }
5435 break;
5436#ifdef LIBXML_XPTR_ENABLED
5437 case XPATH_LOCATIONSET:
5438 if (obj->user != NULL) {
5439 xmlXPtrFreeLocationSet(obj->user);
5440 }
5441 goto free_obj;
5442#endif
5443 default:
5444 goto free_obj;
5445 }
5446
5447 /*
5448 * Fallback to adding to the misc-objects slot.
5449 */
5450 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5451 XP_CACHE_ADD(cache->miscObjs, obj);
5452 } else
5453 goto free_obj;
5454
5455obj_cached:
5456
5457#ifdef XP_DEBUG_OBJ_USAGE
5458 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5459#endif
5460
5461 if (obj->nodesetval != NULL) {
5462 xmlNodeSetPtr tmpset = obj->nodesetval;
5463
5464 /*
5465 * TODO: Due to those nasty ns-nodes, we need to traverse
5466 * the list and free the ns-nodes.
5467 * URGENT TODO: Check if it's actually slowing things down.
5468 * Maybe we shouldn't try to preserve the list.
5469 */
5470 if (tmpset->nodeNr > 1) {
5471 int i;
5472 xmlNodePtr node;
5473
5474 for (i = 0; i < tmpset->nodeNr; i++) {
5475 node = tmpset->nodeTab[i];
5476 if ((node != NULL) &&
5477 (node->type == XML_NAMESPACE_DECL))
5478 {
5479 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5480 }
5481 }
5482 } else if (tmpset->nodeNr == 1) {
5483 if ((tmpset->nodeTab[0] != NULL) &&
5484 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5485 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5486 }
5487 tmpset->nodeNr = 0;
5488 memset(obj, 0, sizeof(xmlXPathObject));
5489 obj->nodesetval = tmpset;
5490 } else
5491 memset(obj, 0, sizeof(xmlXPathObject));
5492
5493 return;
5494
5495free_obj:
5496 /*
5497 * Cache is full; free the object.
5498 */
5499 if (obj->nodesetval != NULL)
5500 xmlXPathFreeNodeSet(obj->nodesetval);
5501#ifdef XP_DEBUG_OBJ_USAGE
5502 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5503#endif
5504 xmlFree(obj);
5505 }
5506 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005507}
5508
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005509
5510/************************************************************************
5511 * *
5512 * Type Casting Routines *
5513 * *
5514 ************************************************************************/
5515
5516/**
5517 * xmlXPathCastBooleanToString:
5518 * @val: a boolean
5519 *
5520 * Converts a boolean to its string value.
5521 *
5522 * Returns a newly allocated string.
5523 */
5524xmlChar *
5525xmlXPathCastBooleanToString (int val) {
5526 xmlChar *ret;
5527 if (val)
5528 ret = xmlStrdup((const xmlChar *) "true");
5529 else
5530 ret = xmlStrdup((const xmlChar *) "false");
5531 return(ret);
5532}
5533
5534/**
5535 * xmlXPathCastNumberToString:
5536 * @val: a number
5537 *
5538 * Converts a number to its string value.
5539 *
5540 * Returns a newly allocated string.
5541 */
5542xmlChar *
5543xmlXPathCastNumberToString (double val) {
5544 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00005545 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005546 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005547 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005548 break;
5549 case -1:
5550 ret = xmlStrdup((const xmlChar *) "-Infinity");
5551 break;
5552 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00005553 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005554 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005555 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5556 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005557 } else {
5558 /* could be improved */
5559 char buf[100];
Daniel Veillard11ce4002006-03-10 00:36:23 +00005560 xmlXPathFormatNumber(val, buf, 99);
5561 buf[99] = 0;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005562 ret = xmlStrdup((const xmlChar *) buf);
5563 }
5564 }
5565 return(ret);
5566}
5567
5568/**
5569 * xmlXPathCastNodeToString:
5570 * @node: a node
5571 *
5572 * Converts a node to its string value.
5573 *
5574 * Returns a newly allocated string.
5575 */
5576xmlChar *
5577xmlXPathCastNodeToString (xmlNodePtr node) {
5578 return(xmlNodeGetContent(node));
5579}
5580
5581/**
5582 * xmlXPathCastNodeSetToString:
5583 * @ns: a node-set
5584 *
5585 * Converts a node-set to its string value.
5586 *
5587 * Returns a newly allocated string.
5588 */
5589xmlChar *
5590xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5591 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5592 return(xmlStrdup((const xmlChar *) ""));
5593
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00005594 if (ns->nodeNr > 1)
5595 xmlXPathNodeSetSort(ns);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005596 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5597}
5598
5599/**
5600 * xmlXPathCastToString:
5601 * @val: an XPath object
5602 *
5603 * Converts an existing object to its string() equivalent
5604 *
5605 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005606 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005607 * string object).
5608 */
5609xmlChar *
5610xmlXPathCastToString(xmlXPathObjectPtr val) {
5611 xmlChar *ret = NULL;
5612
5613 if (val == NULL)
5614 return(xmlStrdup((const xmlChar *) ""));
5615 switch (val->type) {
5616 case XPATH_UNDEFINED:
5617#ifdef DEBUG_EXPR
5618 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5619#endif
5620 ret = xmlStrdup((const xmlChar *) "");
5621 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005622 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005623 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005624 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5625 break;
5626 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00005627 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005628 case XPATH_BOOLEAN:
5629 ret = xmlXPathCastBooleanToString(val->boolval);
5630 break;
5631 case XPATH_NUMBER: {
5632 ret = xmlXPathCastNumberToString(val->floatval);
5633 break;
5634 }
5635 case XPATH_USERS:
5636 case XPATH_POINT:
5637 case XPATH_RANGE:
5638 case XPATH_LOCATIONSET:
5639 TODO
5640 ret = xmlStrdup((const xmlChar *) "");
5641 break;
5642 }
5643 return(ret);
5644}
5645
5646/**
5647 * xmlXPathConvertString:
5648 * @val: an XPath object
5649 *
5650 * Converts an existing object to its string() equivalent
5651 *
5652 * Returns the new object, the old one is freed (or the operation
5653 * is done directly on @val)
5654 */
5655xmlXPathObjectPtr
5656xmlXPathConvertString(xmlXPathObjectPtr val) {
5657 xmlChar *res = NULL;
5658
5659 if (val == NULL)
5660 return(xmlXPathNewCString(""));
5661
5662 switch (val->type) {
5663 case XPATH_UNDEFINED:
5664#ifdef DEBUG_EXPR
5665 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5666#endif
5667 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005668 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005669 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005670 res = xmlXPathCastNodeSetToString(val->nodesetval);
5671 break;
5672 case XPATH_STRING:
5673 return(val);
5674 case XPATH_BOOLEAN:
5675 res = xmlXPathCastBooleanToString(val->boolval);
5676 break;
5677 case XPATH_NUMBER:
5678 res = xmlXPathCastNumberToString(val->floatval);
5679 break;
5680 case XPATH_USERS:
5681 case XPATH_POINT:
5682 case XPATH_RANGE:
5683 case XPATH_LOCATIONSET:
5684 TODO;
5685 break;
5686 }
5687 xmlXPathFreeObject(val);
5688 if (res == NULL)
5689 return(xmlXPathNewCString(""));
5690 return(xmlXPathWrapString(res));
5691}
5692
5693/**
5694 * xmlXPathCastBooleanToNumber:
5695 * @val: a boolean
5696 *
5697 * Converts a boolean to its number value
5698 *
5699 * Returns the number value
5700 */
5701double
5702xmlXPathCastBooleanToNumber(int val) {
5703 if (val)
5704 return(1.0);
5705 return(0.0);
5706}
5707
5708/**
5709 * xmlXPathCastStringToNumber:
5710 * @val: a string
5711 *
5712 * Converts a string to its number value
5713 *
5714 * Returns the number value
5715 */
5716double
5717xmlXPathCastStringToNumber(const xmlChar * val) {
5718 return(xmlXPathStringEvalNumber(val));
5719}
5720
5721/**
5722 * xmlXPathCastNodeToNumber:
5723 * @node: a node
5724 *
5725 * Converts a node to its number value
5726 *
5727 * Returns the number value
5728 */
5729double
5730xmlXPathCastNodeToNumber (xmlNodePtr node) {
5731 xmlChar *strval;
5732 double ret;
5733
5734 if (node == NULL)
5735 return(xmlXPathNAN);
5736 strval = xmlXPathCastNodeToString(node);
5737 if (strval == NULL)
5738 return(xmlXPathNAN);
5739 ret = xmlXPathCastStringToNumber(strval);
5740 xmlFree(strval);
5741
5742 return(ret);
5743}
5744
5745/**
5746 * xmlXPathCastNodeSetToNumber:
5747 * @ns: a node-set
5748 *
5749 * Converts a node-set to its number value
5750 *
5751 * Returns the number value
5752 */
5753double
5754xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5755 xmlChar *str;
5756 double ret;
5757
5758 if (ns == NULL)
5759 return(xmlXPathNAN);
5760 str = xmlXPathCastNodeSetToString(ns);
5761 ret = xmlXPathCastStringToNumber(str);
5762 xmlFree(str);
5763 return(ret);
5764}
5765
5766/**
5767 * xmlXPathCastToNumber:
5768 * @val: an XPath object
5769 *
5770 * Converts an XPath object to its number value
5771 *
5772 * Returns the number value
5773 */
5774double
5775xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5776 double ret = 0.0;
5777
5778 if (val == NULL)
5779 return(xmlXPathNAN);
5780 switch (val->type) {
5781 case XPATH_UNDEFINED:
5782#ifdef DEGUB_EXPR
5783 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5784#endif
5785 ret = xmlXPathNAN;
5786 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005787 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005788 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005789 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5790 break;
5791 case XPATH_STRING:
5792 ret = xmlXPathCastStringToNumber(val->stringval);
5793 break;
5794 case XPATH_NUMBER:
5795 ret = val->floatval;
5796 break;
5797 case XPATH_BOOLEAN:
5798 ret = xmlXPathCastBooleanToNumber(val->boolval);
5799 break;
5800 case XPATH_USERS:
5801 case XPATH_POINT:
5802 case XPATH_RANGE:
5803 case XPATH_LOCATIONSET:
5804 TODO;
5805 ret = xmlXPathNAN;
5806 break;
5807 }
5808 return(ret);
5809}
5810
5811/**
5812 * xmlXPathConvertNumber:
5813 * @val: an XPath object
5814 *
5815 * Converts an existing object to its number() equivalent
5816 *
5817 * Returns the new object, the old one is freed (or the operation
5818 * is done directly on @val)
5819 */
5820xmlXPathObjectPtr
5821xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5822 xmlXPathObjectPtr ret;
5823
5824 if (val == NULL)
5825 return(xmlXPathNewFloat(0.0));
5826 if (val->type == XPATH_NUMBER)
5827 return(val);
5828 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5829 xmlXPathFreeObject(val);
5830 return(ret);
5831}
5832
5833/**
5834 * xmlXPathCastNumberToBoolean:
5835 * @val: a number
5836 *
5837 * Converts a number to its boolean value
5838 *
5839 * Returns the boolean value
5840 */
5841int
5842xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00005843 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005844 return(0);
5845 return(1);
5846}
5847
5848/**
5849 * xmlXPathCastStringToBoolean:
5850 * @val: a string
5851 *
5852 * Converts a string to its boolean value
5853 *
5854 * Returns the boolean value
5855 */
5856int
5857xmlXPathCastStringToBoolean (const xmlChar *val) {
5858 if ((val == NULL) || (xmlStrlen(val) == 0))
5859 return(0);
5860 return(1);
5861}
5862
5863/**
5864 * xmlXPathCastNodeSetToBoolean:
5865 * @ns: a node-set
5866 *
5867 * Converts a node-set to its boolean value
5868 *
5869 * Returns the boolean value
5870 */
5871int
5872xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5873 if ((ns == NULL) || (ns->nodeNr == 0))
5874 return(0);
5875 return(1);
5876}
5877
5878/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005879 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005880 * @val: an XPath object
5881 *
5882 * Converts an XPath object to its boolean value
5883 *
5884 * Returns the boolean value
5885 */
5886int
5887xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5888 int ret = 0;
5889
5890 if (val == NULL)
5891 return(0);
5892 switch (val->type) {
5893 case XPATH_UNDEFINED:
5894#ifdef DEBUG_EXPR
5895 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
5896#endif
5897 ret = 0;
5898 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005899 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005900 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005901 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5902 break;
5903 case XPATH_STRING:
5904 ret = xmlXPathCastStringToBoolean(val->stringval);
5905 break;
5906 case XPATH_NUMBER:
5907 ret = xmlXPathCastNumberToBoolean(val->floatval);
5908 break;
5909 case XPATH_BOOLEAN:
5910 ret = val->boolval;
5911 break;
5912 case XPATH_USERS:
5913 case XPATH_POINT:
5914 case XPATH_RANGE:
5915 case XPATH_LOCATIONSET:
5916 TODO;
5917 ret = 0;
5918 break;
5919 }
5920 return(ret);
5921}
5922
5923
5924/**
5925 * xmlXPathConvertBoolean:
5926 * @val: an XPath object
5927 *
5928 * Converts an existing object to its boolean() equivalent
5929 *
5930 * Returns the new object, the old one is freed (or the operation
5931 * is done directly on @val)
5932 */
5933xmlXPathObjectPtr
5934xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
5935 xmlXPathObjectPtr ret;
5936
5937 if (val == NULL)
5938 return(xmlXPathNewBoolean(0));
5939 if (val->type == XPATH_BOOLEAN)
5940 return(val);
5941 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
5942 xmlXPathFreeObject(val);
5943 return(ret);
5944}
5945
Owen Taylor3473f882001-02-23 17:55:21 +00005946/************************************************************************
5947 * *
5948 * Routines to handle XPath contexts *
5949 * *
5950 ************************************************************************/
5951
5952/**
5953 * xmlXPathNewContext:
5954 * @doc: the XML document
5955 *
5956 * Create a new xmlXPathContext
5957 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00005958 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00005959 */
5960xmlXPathContextPtr
5961xmlXPathNewContext(xmlDocPtr doc) {
5962 xmlXPathContextPtr ret;
5963
5964 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
5965 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005966 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005967 return(NULL);
5968 }
5969 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
5970 ret->doc = doc;
5971 ret->node = NULL;
5972
5973 ret->varHash = NULL;
5974
5975 ret->nb_types = 0;
5976 ret->max_types = 0;
5977 ret->types = NULL;
5978
5979 ret->funcHash = xmlHashCreate(0);
5980
5981 ret->nb_axis = 0;
5982 ret->max_axis = 0;
5983 ret->axis = NULL;
5984
5985 ret->nsHash = NULL;
5986 ret->user = NULL;
5987
5988 ret->contextSize = -1;
5989 ret->proximityPosition = -1;
5990
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005991#ifdef XP_DEFAULT_CACHE_ON
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005992 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005993 xmlXPathFreeContext(ret);
5994 return(NULL);
5995 }
5996#endif
5997
5998 xmlXPathRegisterAllFunctions(ret);
5999
Owen Taylor3473f882001-02-23 17:55:21 +00006000 return(ret);
6001}
6002
6003/**
6004 * xmlXPathFreeContext:
6005 * @ctxt: the context to free
6006 *
6007 * Free up an xmlXPathContext
6008 */
6009void
6010xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006011 if (ctxt == NULL) return;
6012
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006013 if (ctxt->cache != NULL)
6014 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
Owen Taylor3473f882001-02-23 17:55:21 +00006015 xmlXPathRegisteredNsCleanup(ctxt);
6016 xmlXPathRegisteredFuncsCleanup(ctxt);
6017 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006018 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00006019 xmlFree(ctxt);
6020}
6021
6022/************************************************************************
6023 * *
6024 * Routines to handle XPath parser contexts *
6025 * *
6026 ************************************************************************/
6027
6028#define CHECK_CTXT(ctxt) \
6029 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00006030 __xmlRaiseError(NULL, NULL, NULL, \
6031 NULL, NULL, XML_FROM_XPATH, \
6032 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6033 __FILE__, __LINE__, \
6034 NULL, NULL, NULL, 0, 0, \
6035 "NULL context pointer\n"); \
6036 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00006037 } \
6038
6039
6040#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00006041 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
6042 (ctxt->doc->children == NULL)) { \
6043 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00006044 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00006045 }
Owen Taylor3473f882001-02-23 17:55:21 +00006046
6047
6048/**
6049 * xmlXPathNewParserContext:
6050 * @str: the XPath expression
6051 * @ctxt: the XPath context
6052 *
6053 * Create a new xmlXPathParserContext
6054 *
6055 * Returns the xmlXPathParserContext just allocated.
6056 */
6057xmlXPathParserContextPtr
6058xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6059 xmlXPathParserContextPtr ret;
6060
6061 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6062 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006063 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006064 return(NULL);
6065 }
6066 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6067 ret->cur = ret->base = str;
6068 ret->context = ctxt;
6069
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006070 ret->comp = xmlXPathNewCompExpr();
6071 if (ret->comp == NULL) {
6072 xmlFree(ret->valueTab);
6073 xmlFree(ret);
6074 return(NULL);
6075 }
Daniel Veillard4773df22004-01-23 13:15:13 +00006076 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6077 ret->comp->dict = ctxt->dict;
6078 xmlDictReference(ret->comp->dict);
6079 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006080
6081 return(ret);
6082}
6083
6084/**
6085 * xmlXPathCompParserContext:
6086 * @comp: the XPath compiled expression
6087 * @ctxt: the XPath context
6088 *
6089 * Create a new xmlXPathParserContext when processing a compiled expression
6090 *
6091 * Returns the xmlXPathParserContext just allocated.
6092 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006093static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006094xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6095 xmlXPathParserContextPtr ret;
6096
6097 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6098 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006099 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006100 return(NULL);
6101 }
6102 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6103
Owen Taylor3473f882001-02-23 17:55:21 +00006104 /* Allocate the value stack */
6105 ret->valueTab = (xmlXPathObjectPtr *)
6106 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006107 if (ret->valueTab == NULL) {
6108 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006109 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006110 return(NULL);
6111 }
Owen Taylor3473f882001-02-23 17:55:21 +00006112 ret->valueNr = 0;
6113 ret->valueMax = 10;
6114 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006115
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006116 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006117 ret->comp = comp;
6118
Owen Taylor3473f882001-02-23 17:55:21 +00006119 return(ret);
6120}
6121
6122/**
6123 * xmlXPathFreeParserContext:
6124 * @ctxt: the context to free
6125 *
6126 * Free up an xmlXPathParserContext
6127 */
6128void
6129xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6130 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006131 xmlFree(ctxt->valueTab);
6132 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00006133 if (ctxt->comp != NULL) {
6134#ifdef XPATH_STREAMING
6135 if (ctxt->comp->stream != NULL) {
6136 xmlFreePatternList(ctxt->comp->stream);
6137 ctxt->comp->stream = NULL;
6138 }
6139#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006140 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00006141 }
Owen Taylor3473f882001-02-23 17:55:21 +00006142 xmlFree(ctxt);
6143}
6144
6145/************************************************************************
6146 * *
6147 * The implicit core function library *
6148 * *
6149 ************************************************************************/
6150
Owen Taylor3473f882001-02-23 17:55:21 +00006151/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006152 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00006153 * @node: a node pointer
6154 *
6155 * Function computing the beginning of the string value of the node,
6156 * used to speed up comparisons
6157 *
6158 * Returns an int usable as a hash
6159 */
6160static unsigned int
6161xmlXPathNodeValHash(xmlNodePtr node) {
6162 int len = 2;
6163 const xmlChar * string = NULL;
6164 xmlNodePtr tmp = NULL;
6165 unsigned int ret = 0;
6166
6167 if (node == NULL)
6168 return(0);
6169
Daniel Veillard9adc0462003-03-24 18:39:54 +00006170 if (node->type == XML_DOCUMENT_NODE) {
6171 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6172 if (tmp == NULL)
6173 node = node->children;
6174 else
6175 node = tmp;
6176
6177 if (node == NULL)
6178 return(0);
6179 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006180
6181 switch (node->type) {
6182 case XML_COMMENT_NODE:
6183 case XML_PI_NODE:
6184 case XML_CDATA_SECTION_NODE:
6185 case XML_TEXT_NODE:
6186 string = node->content;
6187 if (string == NULL)
6188 return(0);
6189 if (string[0] == 0)
6190 return(0);
6191 return(((unsigned int) string[0]) +
6192 (((unsigned int) string[1]) << 8));
6193 case XML_NAMESPACE_DECL:
6194 string = ((xmlNsPtr)node)->href;
6195 if (string == NULL)
6196 return(0);
6197 if (string[0] == 0)
6198 return(0);
6199 return(((unsigned int) string[0]) +
6200 (((unsigned int) string[1]) << 8));
6201 case XML_ATTRIBUTE_NODE:
6202 tmp = ((xmlAttrPtr) node)->children;
6203 break;
6204 case XML_ELEMENT_NODE:
6205 tmp = node->children;
6206 break;
6207 default:
6208 return(0);
6209 }
6210 while (tmp != NULL) {
6211 switch (tmp->type) {
6212 case XML_COMMENT_NODE:
6213 case XML_PI_NODE:
6214 case XML_CDATA_SECTION_NODE:
6215 case XML_TEXT_NODE:
6216 string = tmp->content;
6217 break;
6218 case XML_NAMESPACE_DECL:
6219 string = ((xmlNsPtr)tmp)->href;
6220 break;
6221 default:
6222 break;
6223 }
6224 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006225 if (len == 1) {
6226 return(ret + (((unsigned int) string[0]) << 8));
6227 }
6228 if (string[1] == 0) {
6229 len = 1;
6230 ret = (unsigned int) string[0];
6231 } else {
6232 return(((unsigned int) string[0]) +
6233 (((unsigned int) string[1]) << 8));
6234 }
6235 }
6236 /*
6237 * Skip to next node
6238 */
6239 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6240 if (tmp->children->type != XML_ENTITY_DECL) {
6241 tmp = tmp->children;
6242 continue;
6243 }
6244 }
6245 if (tmp == node)
6246 break;
6247
6248 if (tmp->next != NULL) {
6249 tmp = tmp->next;
6250 continue;
6251 }
6252
6253 do {
6254 tmp = tmp->parent;
6255 if (tmp == NULL)
6256 break;
6257 if (tmp == node) {
6258 tmp = NULL;
6259 break;
6260 }
6261 if (tmp->next != NULL) {
6262 tmp = tmp->next;
6263 break;
6264 }
6265 } while (tmp != NULL);
6266 }
6267 return(ret);
6268}
6269
6270/**
6271 * xmlXPathStringHash:
6272 * @string: a string
6273 *
6274 * Function computing the beginning of the string value of the node,
6275 * used to speed up comparisons
6276 *
6277 * Returns an int usable as a hash
6278 */
6279static unsigned int
6280xmlXPathStringHash(const xmlChar * string) {
6281 if (string == NULL)
6282 return((unsigned int) 0);
6283 if (string[0] == 0)
6284 return(0);
6285 return(((unsigned int) string[0]) +
6286 (((unsigned int) string[1]) << 8));
6287}
6288
6289/**
Owen Taylor3473f882001-02-23 17:55:21 +00006290 * xmlXPathCompareNodeSetFloat:
6291 * @ctxt: the XPath Parser context
6292 * @inf: less than (1) or greater than (0)
6293 * @strict: is the comparison strict
6294 * @arg: the node set
6295 * @f: the value
6296 *
6297 * Implement the compare operation between a nodeset and a number
6298 * @ns < @val (1, 1, ...
6299 * @ns <= @val (1, 0, ...
6300 * @ns > @val (0, 1, ...
6301 * @ns >= @val (0, 0, ...
6302 *
6303 * If one object to be compared is a node-set and the other is a number,
6304 * then the comparison will be true if and only if there is a node in the
6305 * node-set such that the result of performing the comparison on the number
6306 * to be compared and on the result of converting the string-value of that
6307 * node to a number using the number function is true.
6308 *
6309 * Returns 0 or 1 depending on the results of the test.
6310 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006311static int
Owen Taylor3473f882001-02-23 17:55:21 +00006312xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6313 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6314 int i, ret = 0;
6315 xmlNodeSetPtr ns;
6316 xmlChar *str2;
6317
6318 if ((f == NULL) || (arg == NULL) ||
6319 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006320 xmlXPathReleaseObject(ctxt->context, arg);
6321 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006322 return(0);
6323 }
6324 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006325 if (ns != NULL) {
6326 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006327 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006328 if (str2 != NULL) {
6329 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006330 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006331 xmlFree(str2);
6332 xmlXPathNumberFunction(ctxt, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006333 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006334 ret = xmlXPathCompareValues(ctxt, inf, strict);
6335 if (ret)
6336 break;
6337 }
6338 }
Owen Taylor3473f882001-02-23 17:55:21 +00006339 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006340 xmlXPathReleaseObject(ctxt->context, arg);
6341 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006342 return(ret);
6343}
6344
6345/**
6346 * xmlXPathCompareNodeSetString:
6347 * @ctxt: the XPath Parser context
6348 * @inf: less than (1) or greater than (0)
6349 * @strict: is the comparison strict
6350 * @arg: the node set
6351 * @s: the value
6352 *
6353 * Implement the compare operation between a nodeset and a string
6354 * @ns < @val (1, 1, ...
6355 * @ns <= @val (1, 0, ...
6356 * @ns > @val (0, 1, ...
6357 * @ns >= @val (0, 0, ...
6358 *
6359 * If one object to be compared is a node-set and the other is a string,
6360 * then the comparison will be true if and only if there is a node in
6361 * the node-set such that the result of performing the comparison on the
6362 * string-value of the node and the other string is true.
6363 *
6364 * Returns 0 or 1 depending on the results of the test.
6365 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006366static int
Owen Taylor3473f882001-02-23 17:55:21 +00006367xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6368 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6369 int i, ret = 0;
6370 xmlNodeSetPtr ns;
6371 xmlChar *str2;
6372
6373 if ((s == NULL) || (arg == NULL) ||
6374 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006375 xmlXPathReleaseObject(ctxt->context, arg);
6376 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006377 return(0);
6378 }
6379 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006380 if (ns != NULL) {
6381 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006382 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006383 if (str2 != NULL) {
6384 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006385 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006386 xmlFree(str2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006387 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006388 ret = xmlXPathCompareValues(ctxt, inf, strict);
6389 if (ret)
6390 break;
6391 }
6392 }
Owen Taylor3473f882001-02-23 17:55:21 +00006393 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006394 xmlXPathReleaseObject(ctxt->context, arg);
6395 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006396 return(ret);
6397}
6398
6399/**
6400 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006401 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00006402 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006403 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00006404 * @arg2: the second node set object
6405 *
6406 * Implement the compare operation on nodesets:
6407 *
6408 * If both objects to be compared are node-sets, then the comparison
6409 * will be true if and only if there is a node in the first node-set
6410 * and a node in the second node-set such that the result of performing
6411 * the comparison on the string-values of the two nodes is true.
6412 * ....
6413 * When neither object to be compared is a node-set and the operator
6414 * is <=, <, >= or >, then the objects are compared by converting both
6415 * objects to numbers and comparing the numbers according to IEEE 754.
6416 * ....
6417 * The number function converts its argument to a number as follows:
6418 * - a string that consists of optional whitespace followed by an
6419 * optional minus sign followed by a Number followed by whitespace
6420 * is converted to the IEEE 754 number that is nearest (according
6421 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6422 * represented by the string; any other string is converted to NaN
6423 *
6424 * Conclusion all nodes need to be converted first to their string value
6425 * and then the comparison must be done when possible
6426 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006427static int
6428xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00006429 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6430 int i, j, init = 0;
6431 double val1;
6432 double *values2;
6433 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006434 xmlNodeSetPtr ns1;
6435 xmlNodeSetPtr ns2;
6436
6437 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006438 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6439 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006440 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006441 }
Owen Taylor3473f882001-02-23 17:55:21 +00006442 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006443 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6444 xmlXPathFreeObject(arg1);
6445 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006446 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006447 }
Owen Taylor3473f882001-02-23 17:55:21 +00006448
6449 ns1 = arg1->nodesetval;
6450 ns2 = arg2->nodesetval;
6451
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006452 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006453 xmlXPathFreeObject(arg1);
6454 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006455 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006456 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006457 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006458 xmlXPathFreeObject(arg1);
6459 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006460 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006461 }
Owen Taylor3473f882001-02-23 17:55:21 +00006462
6463 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6464 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006465 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00006466 xmlXPathFreeObject(arg1);
6467 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006468 return(0);
6469 }
6470 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006471 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00006472 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00006473 continue;
6474 for (j = 0;j < ns2->nodeNr;j++) {
6475 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006476 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00006477 }
Daniel Veillardcda96922001-08-21 10:56:31 +00006478 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00006479 continue;
6480 if (inf && strict)
6481 ret = (val1 < values2[j]);
6482 else if (inf && !strict)
6483 ret = (val1 <= values2[j]);
6484 else if (!inf && strict)
6485 ret = (val1 > values2[j]);
6486 else if (!inf && !strict)
6487 ret = (val1 >= values2[j]);
6488 if (ret)
6489 break;
6490 }
6491 if (ret)
6492 break;
6493 init = 1;
6494 }
6495 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006496 xmlXPathFreeObject(arg1);
6497 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006498 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006499}
6500
6501/**
6502 * xmlXPathCompareNodeSetValue:
6503 * @ctxt: the XPath Parser context
6504 * @inf: less than (1) or greater than (0)
6505 * @strict: is the comparison strict
6506 * @arg: the node set
6507 * @val: the value
6508 *
6509 * Implement the compare operation between a nodeset and a value
6510 * @ns < @val (1, 1, ...
6511 * @ns <= @val (1, 0, ...
6512 * @ns > @val (0, 1, ...
6513 * @ns >= @val (0, 0, ...
6514 *
6515 * If one object to be compared is a node-set and the other is a boolean,
6516 * then the comparison will be true if and only if the result of performing
6517 * the comparison on the boolean and on the result of converting
6518 * the node-set to a boolean using the boolean function is true.
6519 *
6520 * Returns 0 or 1 depending on the results of the test.
6521 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006522static int
Owen Taylor3473f882001-02-23 17:55:21 +00006523xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6524 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6525 if ((val == NULL) || (arg == NULL) ||
6526 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6527 return(0);
6528
6529 switch(val->type) {
6530 case XPATH_NUMBER:
6531 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6532 case XPATH_NODESET:
6533 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006534 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00006535 case XPATH_STRING:
6536 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6537 case XPATH_BOOLEAN:
6538 valuePush(ctxt, arg);
6539 xmlXPathBooleanFunction(ctxt, 1);
6540 valuePush(ctxt, val);
6541 return(xmlXPathCompareValues(ctxt, inf, strict));
6542 default:
6543 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00006544 }
6545 return(0);
6546}
6547
6548/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006549 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00006550 * @arg: the nodeset object argument
6551 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00006552 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006553 *
6554 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6555 * If one object to be compared is a node-set and the other is a string,
6556 * then the comparison will be true if and only if there is a node in
6557 * the node-set such that the result of performing the comparison on the
6558 * string-value of the node and the other string is true.
6559 *
6560 * Returns 0 or 1 depending on the results of the test.
6561 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006562static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006563xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006564{
Owen Taylor3473f882001-02-23 17:55:21 +00006565 int i;
6566 xmlNodeSetPtr ns;
6567 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006568 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00006569
6570 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00006571 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6572 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006573 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00006574 /*
6575 * A NULL nodeset compared with a string is always false
6576 * (since there is no node equal, and no node not equal)
6577 */
6578 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00006579 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00006580 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006581 for (i = 0; i < ns->nodeNr; i++) {
6582 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6583 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6584 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6585 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006586 if (neq)
6587 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006588 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00006589 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6590 if (neq)
6591 continue;
6592 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006593 } else if (neq) {
6594 if (str2 != NULL)
6595 xmlFree(str2);
6596 return (1);
6597 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006598 if (str2 != NULL)
6599 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006600 } else if (neq)
6601 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00006602 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006603 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006604}
6605
6606/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006607 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00006608 * @arg: the nodeset object argument
6609 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00006610 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006611 *
6612 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6613 * If one object to be compared is a node-set and the other is a number,
6614 * then the comparison will be true if and only if there is a node in
6615 * the node-set such that the result of performing the comparison on the
6616 * number to be compared and on the result of converting the string-value
6617 * of that node to a number using the number function is true.
6618 *
6619 * Returns 0 or 1 depending on the results of the test.
6620 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006621static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006622xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6623 xmlXPathObjectPtr arg, double f, int neq) {
6624 int i, ret=0;
6625 xmlNodeSetPtr ns;
6626 xmlChar *str2;
6627 xmlXPathObjectPtr val;
6628 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00006629
6630 if ((arg == NULL) ||
6631 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6632 return(0);
6633
William M. Brack0c022ad2002-07-12 00:56:01 +00006634 ns = arg->nodesetval;
6635 if (ns != NULL) {
6636 for (i=0;i<ns->nodeNr;i++) {
6637 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6638 if (str2 != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006639 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
William M. Brack0c022ad2002-07-12 00:56:01 +00006640 xmlFree(str2);
6641 xmlXPathNumberFunction(ctxt, 1);
6642 val = valuePop(ctxt);
6643 v = val->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006644 xmlXPathReleaseObject(ctxt->context, val);
William M. Brack0c022ad2002-07-12 00:56:01 +00006645 if (!xmlXPathIsNaN(v)) {
6646 if ((!neq) && (v==f)) {
6647 ret = 1;
6648 break;
6649 } else if ((neq) && (v!=f)) {
6650 ret = 1;
6651 break;
6652 }
William M. Brack32f0f712005-07-14 07:00:33 +00006653 } else { /* NaN is unequal to any value */
6654 if (neq)
6655 ret = 1;
William M. Brack0c022ad2002-07-12 00:56:01 +00006656 }
6657 }
6658 }
6659 }
6660
6661 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006662}
6663
6664
6665/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006666 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00006667 * @arg1: first nodeset object argument
6668 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00006669 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006670 *
William M. Brack0c022ad2002-07-12 00:56:01 +00006671 * Implement the equal / not equal operation on XPath nodesets:
6672 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00006673 * If both objects to be compared are node-sets, then the comparison
6674 * will be true if and only if there is a node in the first node-set and
6675 * a node in the second node-set such that the result of performing the
6676 * comparison on the string-values of the two nodes is true.
6677 *
6678 * (needless to say, this is a costly operation)
6679 *
6680 * Returns 0 or 1 depending on the results of the test.
6681 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006682static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006683xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00006684 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006685 unsigned int *hashs1;
6686 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00006687 xmlChar **values1;
6688 xmlChar **values2;
6689 int ret = 0;
6690 xmlNodeSetPtr ns1;
6691 xmlNodeSetPtr ns2;
6692
6693 if ((arg1 == NULL) ||
6694 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6695 return(0);
6696 if ((arg2 == NULL) ||
6697 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6698 return(0);
6699
6700 ns1 = arg1->nodesetval;
6701 ns2 = arg2->nodesetval;
6702
Daniel Veillard911f49a2001-04-07 15:39:35 +00006703 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006704 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006705 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006706 return(0);
6707
6708 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00006709 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00006710 */
William M. Brack0c022ad2002-07-12 00:56:01 +00006711 if (neq == 0)
6712 for (i = 0;i < ns1->nodeNr;i++)
6713 for (j = 0;j < ns2->nodeNr;j++)
6714 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6715 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006716
6717 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006718 if (values1 == NULL) {
6719 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006720 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006721 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006722 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6723 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006724 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006725 xmlFree(values1);
6726 return(0);
6727 }
Owen Taylor3473f882001-02-23 17:55:21 +00006728 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6729 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6730 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006731 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006732 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00006733 xmlFree(values1);
6734 return(0);
6735 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006736 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6737 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006738 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006739 xmlFree(hashs1);
6740 xmlFree(values1);
6741 xmlFree(values2);
6742 return(0);
6743 }
Owen Taylor3473f882001-02-23 17:55:21 +00006744 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6745 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006746 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006747 for (j = 0;j < ns2->nodeNr;j++) {
6748 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006749 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006750 if (hashs1[i] != hashs2[j]) {
6751 if (neq) {
6752 ret = 1;
6753 break;
6754 }
6755 }
6756 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006757 if (values1[i] == NULL)
6758 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6759 if (values2[j] == NULL)
6760 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006761 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006762 if (ret)
6763 break;
6764 }
Owen Taylor3473f882001-02-23 17:55:21 +00006765 }
6766 if (ret)
6767 break;
6768 }
6769 for (i = 0;i < ns1->nodeNr;i++)
6770 if (values1[i] != NULL)
6771 xmlFree(values1[i]);
6772 for (j = 0;j < ns2->nodeNr;j++)
6773 if (values2[j] != NULL)
6774 xmlFree(values2[j]);
6775 xmlFree(values1);
6776 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006777 xmlFree(hashs1);
6778 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00006779 return(ret);
6780}
6781
William M. Brack0c022ad2002-07-12 00:56:01 +00006782static int
6783xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6784 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00006785 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00006786 /*
6787 *At this point we are assured neither arg1 nor arg2
6788 *is a nodeset, so we can just pick the appropriate routine.
6789 */
Owen Taylor3473f882001-02-23 17:55:21 +00006790 switch (arg1->type) {
6791 case XPATH_UNDEFINED:
6792#ifdef DEBUG_EXPR
6793 xmlGenericError(xmlGenericErrorContext,
6794 "Equal: undefined\n");
6795#endif
6796 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006797 case XPATH_BOOLEAN:
6798 switch (arg2->type) {
6799 case XPATH_UNDEFINED:
6800#ifdef DEBUG_EXPR
6801 xmlGenericError(xmlGenericErrorContext,
6802 "Equal: undefined\n");
6803#endif
6804 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006805 case XPATH_BOOLEAN:
6806#ifdef DEBUG_EXPR
6807 xmlGenericError(xmlGenericErrorContext,
6808 "Equal: %d boolean %d \n",
6809 arg1->boolval, arg2->boolval);
6810#endif
6811 ret = (arg1->boolval == arg2->boolval);
6812 break;
6813 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00006814 ret = (arg1->boolval ==
6815 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006816 break;
6817 case XPATH_STRING:
6818 if ((arg2->stringval == NULL) ||
6819 (arg2->stringval[0] == 0)) ret = 0;
6820 else
6821 ret = 1;
6822 ret = (arg1->boolval == ret);
6823 break;
6824 case XPATH_USERS:
6825 case XPATH_POINT:
6826 case XPATH_RANGE:
6827 case XPATH_LOCATIONSET:
6828 TODO
6829 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006830 case XPATH_NODESET:
6831 case XPATH_XSLT_TREE:
6832 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006833 }
6834 break;
6835 case XPATH_NUMBER:
6836 switch (arg2->type) {
6837 case XPATH_UNDEFINED:
6838#ifdef DEBUG_EXPR
6839 xmlGenericError(xmlGenericErrorContext,
6840 "Equal: undefined\n");
6841#endif
6842 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006843 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00006844 ret = (arg2->boolval==
6845 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006846 break;
6847 case XPATH_STRING:
6848 valuePush(ctxt, arg2);
6849 xmlXPathNumberFunction(ctxt, 1);
6850 arg2 = valuePop(ctxt);
6851 /* no break on purpose */
6852 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006853 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00006854 if (xmlXPathIsNaN(arg1->floatval) ||
6855 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00006856 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006857 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6858 if (xmlXPathIsInf(arg2->floatval) == 1)
6859 ret = 1;
6860 else
6861 ret = 0;
6862 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6863 if (xmlXPathIsInf(arg2->floatval) == -1)
6864 ret = 1;
6865 else
6866 ret = 0;
6867 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6868 if (xmlXPathIsInf(arg1->floatval) == 1)
6869 ret = 1;
6870 else
6871 ret = 0;
6872 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6873 if (xmlXPathIsInf(arg1->floatval) == -1)
6874 ret = 1;
6875 else
6876 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00006877 } else {
6878 ret = (arg1->floatval == arg2->floatval);
6879 }
Owen Taylor3473f882001-02-23 17:55:21 +00006880 break;
6881 case XPATH_USERS:
6882 case XPATH_POINT:
6883 case XPATH_RANGE:
6884 case XPATH_LOCATIONSET:
6885 TODO
6886 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006887 case XPATH_NODESET:
6888 case XPATH_XSLT_TREE:
6889 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006890 }
6891 break;
6892 case XPATH_STRING:
6893 switch (arg2->type) {
6894 case XPATH_UNDEFINED:
6895#ifdef DEBUG_EXPR
6896 xmlGenericError(xmlGenericErrorContext,
6897 "Equal: undefined\n");
6898#endif
6899 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006900 case XPATH_BOOLEAN:
6901 if ((arg1->stringval == NULL) ||
6902 (arg1->stringval[0] == 0)) ret = 0;
6903 else
6904 ret = 1;
6905 ret = (arg2->boolval == ret);
6906 break;
6907 case XPATH_STRING:
6908 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6909 break;
6910 case XPATH_NUMBER:
6911 valuePush(ctxt, arg1);
6912 xmlXPathNumberFunction(ctxt, 1);
6913 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006914 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00006915 if (xmlXPathIsNaN(arg1->floatval) ||
6916 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00006917 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006918 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6919 if (xmlXPathIsInf(arg2->floatval) == 1)
6920 ret = 1;
6921 else
6922 ret = 0;
6923 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6924 if (xmlXPathIsInf(arg2->floatval) == -1)
6925 ret = 1;
6926 else
6927 ret = 0;
6928 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6929 if (xmlXPathIsInf(arg1->floatval) == 1)
6930 ret = 1;
6931 else
6932 ret = 0;
6933 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6934 if (xmlXPathIsInf(arg1->floatval) == -1)
6935 ret = 1;
6936 else
6937 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00006938 } else {
6939 ret = (arg1->floatval == arg2->floatval);
6940 }
Owen Taylor3473f882001-02-23 17:55:21 +00006941 break;
6942 case XPATH_USERS:
6943 case XPATH_POINT:
6944 case XPATH_RANGE:
6945 case XPATH_LOCATIONSET:
6946 TODO
6947 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006948 case XPATH_NODESET:
6949 case XPATH_XSLT_TREE:
6950 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006951 }
6952 break;
6953 case XPATH_USERS:
6954 case XPATH_POINT:
6955 case XPATH_RANGE:
6956 case XPATH_LOCATIONSET:
6957 TODO
6958 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006959 case XPATH_NODESET:
6960 case XPATH_XSLT_TREE:
6961 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006962 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006963 xmlXPathReleaseObject(ctxt->context, arg1);
6964 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006965 return(ret);
6966}
6967
William M. Brack0c022ad2002-07-12 00:56:01 +00006968/**
6969 * xmlXPathEqualValues:
6970 * @ctxt: the XPath Parser context
6971 *
6972 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6973 *
6974 * Returns 0 or 1 depending on the results of the test.
6975 */
6976int
6977xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
6978 xmlXPathObjectPtr arg1, arg2, argtmp;
6979 int ret = 0;
6980
Daniel Veillard6128c012004-11-08 17:16:15 +00006981 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00006982 arg2 = valuePop(ctxt);
6983 arg1 = valuePop(ctxt);
6984 if ((arg1 == NULL) || (arg2 == NULL)) {
6985 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006986 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006987 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006988 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006989 XP_ERROR0(XPATH_INVALID_OPERAND);
6990 }
6991
6992 if (arg1 == arg2) {
6993#ifdef DEBUG_EXPR
6994 xmlGenericError(xmlGenericErrorContext,
6995 "Equal: by pointer\n");
6996#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00006997 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006998 return(1);
6999 }
7000
7001 /*
7002 *If either argument is a nodeset, it's a 'special case'
7003 */
7004 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7005 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7006 /*
7007 *Hack it to assure arg1 is the nodeset
7008 */
7009 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7010 argtmp = arg2;
7011 arg2 = arg1;
7012 arg1 = argtmp;
7013 }
7014 switch (arg2->type) {
7015 case XPATH_UNDEFINED:
7016#ifdef DEBUG_EXPR
7017 xmlGenericError(xmlGenericErrorContext,
7018 "Equal: undefined\n");
7019#endif
7020 break;
7021 case XPATH_NODESET:
7022 case XPATH_XSLT_TREE:
7023 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7024 break;
7025 case XPATH_BOOLEAN:
7026 if ((arg1->nodesetval == NULL) ||
7027 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7028 else
7029 ret = 1;
7030 ret = (ret == arg2->boolval);
7031 break;
7032 case XPATH_NUMBER:
7033 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7034 break;
7035 case XPATH_STRING:
7036 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7037 break;
7038 case XPATH_USERS:
7039 case XPATH_POINT:
7040 case XPATH_RANGE:
7041 case XPATH_LOCATIONSET:
7042 TODO
7043 break;
7044 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007045 xmlXPathReleaseObject(ctxt->context, arg1);
7046 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007047 return(ret);
7048 }
7049
7050 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7051}
7052
7053/**
7054 * xmlXPathNotEqualValues:
7055 * @ctxt: the XPath Parser context
7056 *
7057 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7058 *
7059 * Returns 0 or 1 depending on the results of the test.
7060 */
7061int
7062xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7063 xmlXPathObjectPtr arg1, arg2, argtmp;
7064 int ret = 0;
7065
Daniel Veillard6128c012004-11-08 17:16:15 +00007066 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00007067 arg2 = valuePop(ctxt);
7068 arg1 = valuePop(ctxt);
7069 if ((arg1 == NULL) || (arg2 == NULL)) {
7070 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007071 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007072 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007073 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007074 XP_ERROR0(XPATH_INVALID_OPERAND);
7075 }
7076
7077 if (arg1 == arg2) {
7078#ifdef DEBUG_EXPR
7079 xmlGenericError(xmlGenericErrorContext,
7080 "NotEqual: by pointer\n");
7081#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007082 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007083 return(0);
7084 }
7085
7086 /*
7087 *If either argument is a nodeset, it's a 'special case'
7088 */
7089 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7090 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7091 /*
7092 *Hack it to assure arg1 is the nodeset
7093 */
7094 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7095 argtmp = arg2;
7096 arg2 = arg1;
7097 arg1 = argtmp;
7098 }
7099 switch (arg2->type) {
7100 case XPATH_UNDEFINED:
7101#ifdef DEBUG_EXPR
7102 xmlGenericError(xmlGenericErrorContext,
7103 "NotEqual: undefined\n");
7104#endif
7105 break;
7106 case XPATH_NODESET:
7107 case XPATH_XSLT_TREE:
7108 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7109 break;
7110 case XPATH_BOOLEAN:
7111 if ((arg1->nodesetval == NULL) ||
7112 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7113 else
7114 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00007115 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00007116 break;
7117 case XPATH_NUMBER:
7118 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7119 break;
7120 case XPATH_STRING:
7121 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7122 break;
7123 case XPATH_USERS:
7124 case XPATH_POINT:
7125 case XPATH_RANGE:
7126 case XPATH_LOCATIONSET:
7127 TODO
7128 break;
7129 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007130 xmlXPathReleaseObject(ctxt->context, arg1);
7131 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007132 return(ret);
7133 }
7134
7135 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7136}
Owen Taylor3473f882001-02-23 17:55:21 +00007137
7138/**
7139 * xmlXPathCompareValues:
7140 * @ctxt: the XPath Parser context
7141 * @inf: less than (1) or greater than (0)
7142 * @strict: is the comparison strict
7143 *
7144 * Implement the compare operation on XPath objects:
7145 * @arg1 < @arg2 (1, 1, ...
7146 * @arg1 <= @arg2 (1, 0, ...
7147 * @arg1 > @arg2 (0, 1, ...
7148 * @arg1 >= @arg2 (0, 0, ...
7149 *
7150 * When neither object to be compared is a node-set and the operator is
7151 * <=, <, >=, >, then the objects are compared by converted both objects
7152 * to numbers and comparing the numbers according to IEEE 754. The <
7153 * comparison will be true if and only if the first number is less than the
7154 * second number. The <= comparison will be true if and only if the first
7155 * number is less than or equal to the second number. The > comparison
7156 * will be true if and only if the first number is greater than the second
7157 * number. The >= comparison will be true if and only if the first number
7158 * is greater than or equal to the second number.
7159 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007160 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00007161 */
7162int
7163xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007164 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007165 xmlXPathObjectPtr arg1, arg2;
7166
Daniel Veillard6128c012004-11-08 17:16:15 +00007167 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00007168 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007169 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007170 if ((arg1 == NULL) || (arg2 == NULL)) {
7171 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007172 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007173 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007174 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007175 XP_ERROR0(XPATH_INVALID_OPERAND);
7176 }
7177
William M. Brack0c022ad2002-07-12 00:56:01 +00007178 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7179 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
William M. Brackd6e347e2005-04-15 01:34:41 +00007180 /*
7181 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7182 * are not freed from within this routine; they will be freed from the
7183 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7184 */
William M. Brack0c022ad2002-07-12 00:56:01 +00007185 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7186 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007187 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007188 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00007189 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007190 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7191 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007192 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007193 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7194 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00007195 }
7196 }
7197 return(ret);
7198 }
7199
7200 if (arg1->type != XPATH_NUMBER) {
7201 valuePush(ctxt, arg1);
7202 xmlXPathNumberFunction(ctxt, 1);
7203 arg1 = valuePop(ctxt);
7204 }
7205 if (arg1->type != XPATH_NUMBER) {
7206 xmlXPathFreeObject(arg1);
7207 xmlXPathFreeObject(arg2);
7208 XP_ERROR0(XPATH_INVALID_OPERAND);
7209 }
7210 if (arg2->type != XPATH_NUMBER) {
7211 valuePush(ctxt, arg2);
7212 xmlXPathNumberFunction(ctxt, 1);
7213 arg2 = valuePop(ctxt);
7214 }
7215 if (arg2->type != XPATH_NUMBER) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007216 xmlXPathReleaseObject(ctxt->context, arg1);
7217 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007218 XP_ERROR0(XPATH_INVALID_OPERAND);
7219 }
7220 /*
7221 * Add tests for infinity and nan
7222 * => feedback on 3.4 for Inf and NaN
7223 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007224 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00007225 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007226 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007227 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007228 arg1i=xmlXPathIsInf(arg1->floatval);
7229 arg2i=xmlXPathIsInf(arg2->floatval);
7230 if (inf && strict) {
7231 if ((arg1i == -1 && arg2i != -1) ||
7232 (arg2i == 1 && arg1i != 1)) {
7233 ret = 1;
7234 } else if (arg1i == 0 && arg2i == 0) {
7235 ret = (arg1->floatval < arg2->floatval);
7236 } else {
7237 ret = 0;
7238 }
7239 }
7240 else if (inf && !strict) {
7241 if (arg1i == -1 || arg2i == 1) {
7242 ret = 1;
7243 } else if (arg1i == 0 && arg2i == 0) {
7244 ret = (arg1->floatval <= arg2->floatval);
7245 } else {
7246 ret = 0;
7247 }
7248 }
7249 else if (!inf && strict) {
7250 if ((arg1i == 1 && arg2i != 1) ||
7251 (arg2i == -1 && arg1i != -1)) {
7252 ret = 1;
7253 } else if (arg1i == 0 && arg2i == 0) {
7254 ret = (arg1->floatval > arg2->floatval);
7255 } else {
7256 ret = 0;
7257 }
7258 }
7259 else if (!inf && !strict) {
7260 if (arg1i == 1 || arg2i == -1) {
7261 ret = 1;
7262 } else if (arg1i == 0 && arg2i == 0) {
7263 ret = (arg1->floatval >= arg2->floatval);
7264 } else {
7265 ret = 0;
7266 }
7267 }
Daniel Veillard21458c82002-03-27 16:12:22 +00007268 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007269 xmlXPathReleaseObject(ctxt->context, arg1);
7270 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007271 return(ret);
7272}
7273
7274/**
7275 * xmlXPathValueFlipSign:
7276 * @ctxt: the XPath Parser context
7277 *
7278 * Implement the unary - operation on an XPath object
7279 * The numeric operators convert their operands to numbers as if
7280 * by calling the number function.
7281 */
7282void
7283xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007284 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007285 CAST_TO_NUMBER;
7286 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007287 if (xmlXPathIsNaN(ctxt->value->floatval))
7288 ctxt->value->floatval=xmlXPathNAN;
7289 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7290 ctxt->value->floatval=xmlXPathNINF;
7291 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7292 ctxt->value->floatval=xmlXPathPINF;
7293 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007294 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7295 ctxt->value->floatval = xmlXPathNZERO;
7296 else
7297 ctxt->value->floatval = 0;
7298 }
7299 else
7300 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00007301}
7302
7303/**
7304 * xmlXPathAddValues:
7305 * @ctxt: the XPath Parser context
7306 *
7307 * Implement the add operation on XPath objects:
7308 * The numeric operators convert their operands to numbers as if
7309 * by calling the number function.
7310 */
7311void
7312xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7313 xmlXPathObjectPtr arg;
7314 double val;
7315
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007316 arg = valuePop(ctxt);
7317 if (arg == NULL)
7318 XP_ERROR(XPATH_INVALID_OPERAND);
7319 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007320 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007321 CAST_TO_NUMBER;
7322 CHECK_TYPE(XPATH_NUMBER);
7323 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00007324}
7325
7326/**
7327 * xmlXPathSubValues:
7328 * @ctxt: the XPath Parser context
7329 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007330 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007331 * The numeric operators convert their operands to numbers as if
7332 * by calling the number function.
7333 */
7334void
7335xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7336 xmlXPathObjectPtr arg;
7337 double val;
7338
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007339 arg = valuePop(ctxt);
7340 if (arg == NULL)
7341 XP_ERROR(XPATH_INVALID_OPERAND);
7342 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007343 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007344 CAST_TO_NUMBER;
7345 CHECK_TYPE(XPATH_NUMBER);
7346 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007347}
7348
7349/**
7350 * xmlXPathMultValues:
7351 * @ctxt: the XPath Parser context
7352 *
7353 * Implement the multiply operation on XPath objects:
7354 * The numeric operators convert their operands to numbers as if
7355 * by calling the number function.
7356 */
7357void
7358xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7359 xmlXPathObjectPtr arg;
7360 double val;
7361
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007362 arg = valuePop(ctxt);
7363 if (arg == NULL)
7364 XP_ERROR(XPATH_INVALID_OPERAND);
7365 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007366 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007367 CAST_TO_NUMBER;
7368 CHECK_TYPE(XPATH_NUMBER);
7369 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007370}
7371
7372/**
7373 * xmlXPathDivValues:
7374 * @ctxt: the XPath Parser context
7375 *
7376 * Implement the div operation on XPath objects @arg1 / @arg2:
7377 * The numeric operators convert their operands to numbers as if
7378 * by calling the number function.
7379 */
7380void
7381xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7382 xmlXPathObjectPtr arg;
7383 double val;
7384
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007385 arg = valuePop(ctxt);
7386 if (arg == NULL)
7387 XP_ERROR(XPATH_INVALID_OPERAND);
7388 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007389 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007390 CAST_TO_NUMBER;
7391 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007392 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7393 ctxt->value->floatval = xmlXPathNAN;
7394 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007395 if (ctxt->value->floatval == 0)
7396 ctxt->value->floatval = xmlXPathNAN;
7397 else if (ctxt->value->floatval > 0)
7398 ctxt->value->floatval = xmlXPathNINF;
7399 else if (ctxt->value->floatval < 0)
7400 ctxt->value->floatval = xmlXPathPINF;
7401 }
7402 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007403 if (ctxt->value->floatval == 0)
7404 ctxt->value->floatval = xmlXPathNAN;
7405 else if (ctxt->value->floatval > 0)
7406 ctxt->value->floatval = xmlXPathPINF;
7407 else if (ctxt->value->floatval < 0)
7408 ctxt->value->floatval = xmlXPathNINF;
7409 } else
7410 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007411}
7412
7413/**
7414 * xmlXPathModValues:
7415 * @ctxt: the XPath Parser context
7416 *
7417 * Implement the mod operation on XPath objects: @arg1 / @arg2
7418 * The numeric operators convert their operands to numbers as if
7419 * by calling the number function.
7420 */
7421void
7422xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7423 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00007424 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00007425
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007426 arg = valuePop(ctxt);
7427 if (arg == NULL)
7428 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007429 arg2 = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007430 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007431 CAST_TO_NUMBER;
7432 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007433 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00007434 if (arg2 == 0)
7435 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007436 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00007437 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007438 }
Owen Taylor3473f882001-02-23 17:55:21 +00007439}
7440
7441/************************************************************************
7442 * *
7443 * The traversal functions *
7444 * *
7445 ************************************************************************/
7446
Owen Taylor3473f882001-02-23 17:55:21 +00007447/*
7448 * A traversal function enumerates nodes along an axis.
7449 * Initially it must be called with NULL, and it indicates
7450 * termination on the axis by returning NULL.
7451 */
7452typedef xmlNodePtr (*xmlXPathTraversalFunction)
7453 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7454
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007455/*
7456 * xmlXPathTraversalFunctionExt:
7457 * A traversal function enumerates nodes along an axis.
7458 * Initially it must be called with NULL, and it indicates
7459 * termination on the axis by returning NULL.
7460 * The context node of the traversal is specified via @contextNode.
7461 */
7462typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7463 (xmlNodePtr cur, xmlNodePtr contextNode);
7464
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00007465/*
7466 * xmlXPathNodeSetMergeFunction:
7467 * Used for merging node sets in xmlXPathCollectAndTest().
7468 */
7469typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7470 (xmlNodeSetPtr, xmlNodeSetPtr, int);
7471
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007472
Owen Taylor3473f882001-02-23 17:55:21 +00007473/**
7474 * xmlXPathNextSelf:
7475 * @ctxt: the XPath Parser context
7476 * @cur: the current node in the traversal
7477 *
7478 * Traversal function for the "self" direction
7479 * The self axis contains just the context node itself
7480 *
7481 * Returns the next element following that axis
7482 */
7483xmlNodePtr
7484xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007485 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007486 if (cur == NULL)
7487 return(ctxt->context->node);
7488 return(NULL);
7489}
7490
7491/**
7492 * xmlXPathNextChild:
7493 * @ctxt: the XPath Parser context
7494 * @cur: the current node in the traversal
7495 *
7496 * Traversal function for the "child" direction
7497 * The child axis contains the children of the context node in document order.
7498 *
7499 * Returns the next element following that axis
7500 */
7501xmlNodePtr
7502xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007503 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007504 if (cur == NULL) {
7505 if (ctxt->context->node == NULL) return(NULL);
7506 switch (ctxt->context->node->type) {
7507 case XML_ELEMENT_NODE:
7508 case XML_TEXT_NODE:
7509 case XML_CDATA_SECTION_NODE:
7510 case XML_ENTITY_REF_NODE:
7511 case XML_ENTITY_NODE:
7512 case XML_PI_NODE:
7513 case XML_COMMENT_NODE:
7514 case XML_NOTATION_NODE:
7515 case XML_DTD_NODE:
7516 return(ctxt->context->node->children);
7517 case XML_DOCUMENT_NODE:
7518 case XML_DOCUMENT_TYPE_NODE:
7519 case XML_DOCUMENT_FRAG_NODE:
7520 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007521#ifdef LIBXML_DOCB_ENABLED
7522 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007523#endif
7524 return(((xmlDocPtr) ctxt->context->node)->children);
7525 case XML_ELEMENT_DECL:
7526 case XML_ATTRIBUTE_DECL:
7527 case XML_ENTITY_DECL:
7528 case XML_ATTRIBUTE_NODE:
7529 case XML_NAMESPACE_DECL:
7530 case XML_XINCLUDE_START:
7531 case XML_XINCLUDE_END:
7532 return(NULL);
7533 }
7534 return(NULL);
7535 }
7536 if ((cur->type == XML_DOCUMENT_NODE) ||
7537 (cur->type == XML_HTML_DOCUMENT_NODE))
7538 return(NULL);
7539 return(cur->next);
7540}
7541
7542/**
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007543 * xmlXPathNextChildElement:
7544 * @ctxt: the XPath Parser context
7545 * @cur: the current node in the traversal
7546 *
7547 * Traversal function for the "child" direction and nodes of type element.
7548 * The child axis contains the children of the context node in document order.
7549 *
7550 * Returns the next element following that axis
7551 */
7552static xmlNodePtr
7553xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7554 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7555 if (cur == NULL) {
7556 cur = ctxt->context->node;
7557 if (cur == NULL) return(NULL);
7558 /*
7559 * Get the first element child.
7560 */
7561 switch (cur->type) {
7562 case XML_ELEMENT_NODE:
7563 case XML_DOCUMENT_FRAG_NODE:
7564 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7565 case XML_ENTITY_NODE:
7566 cur = cur->children;
7567 if (cur != NULL) {
7568 if (cur->type == XML_ELEMENT_NODE)
7569 return(cur);
7570 do {
7571 cur = cur->next;
7572 } while ((cur != NULL) &&
7573 (cur->type != XML_ELEMENT_NODE));
7574 return(cur);
7575 }
7576 return(NULL);
7577 case XML_DOCUMENT_NODE:
7578 case XML_HTML_DOCUMENT_NODE:
7579#ifdef LIBXML_DOCB_ENABLED
7580 case XML_DOCB_DOCUMENT_NODE:
7581#endif
7582 return(xmlDocGetRootElement((xmlDocPtr) cur));
7583 default:
7584 return(NULL);
7585 }
7586 return(NULL);
7587 }
7588 /*
7589 * Get the next sibling element node.
7590 */
7591 switch (cur->type) {
7592 case XML_ELEMENT_NODE:
7593 case XML_TEXT_NODE:
7594 case XML_ENTITY_REF_NODE:
7595 case XML_ENTITY_NODE:
7596 case XML_CDATA_SECTION_NODE:
7597 case XML_PI_NODE:
7598 case XML_COMMENT_NODE:
7599 case XML_XINCLUDE_END:
7600 break;
7601 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7602 default:
7603 return(NULL);
7604 }
7605 if (cur->next != NULL) {
7606 if (cur->next->type == XML_ELEMENT_NODE)
7607 return(cur->next);
7608 cur = cur->next;
7609 do {
7610 cur = cur->next;
7611 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7612 return(cur);
7613 }
7614 return(NULL);
7615}
7616
7617/**
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007618 * xmlXPathNextDescendantOrSelfElemParent:
7619 * @ctxt: the XPath Parser context
7620 * @cur: the current node in the traversal
7621 *
7622 * Traversal function for the "descendant-or-self" axis.
7623 * Additionally it returns only nodes which can be parents of
7624 * element nodes.
7625 *
7626 *
7627 * Returns the next element following that axis
7628 */
7629static xmlNodePtr
7630xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7631 xmlNodePtr contextNode)
7632{
7633 if (cur == NULL) {
7634 if (contextNode == NULL)
7635 return(NULL);
7636 switch (contextNode->type) {
7637 case XML_ELEMENT_NODE:
7638 case XML_XINCLUDE_START:
7639 case XML_DOCUMENT_FRAG_NODE:
7640 case XML_DOCUMENT_NODE:
7641#ifdef LIBXML_DOCB_ENABLED
7642 case XML_DOCB_DOCUMENT_NODE:
7643#endif
7644 case XML_HTML_DOCUMENT_NODE:
7645 return(contextNode);
7646 default:
7647 return(NULL);
7648 }
7649 return(NULL);
7650 } else {
7651 xmlNodePtr start = cur;
7652
7653 while (cur != NULL) {
7654 switch (cur->type) {
7655 case XML_ELEMENT_NODE:
7656 /* TODO: OK to have XInclude here? */
7657 case XML_XINCLUDE_START:
7658 case XML_DOCUMENT_FRAG_NODE:
7659 if (cur != start)
7660 return(cur);
7661 if (cur->children != NULL) {
7662 cur = cur->children;
7663 continue;
7664 }
7665 break;
7666#ifdef LIBXML_DOCB_ENABLED
7667 /* Not sure if we need those here. */
7668 case XML_DOCUMENT_NODE:
7669 case XML_DOCB_DOCUMENT_NODE:
7670#endif
7671 case XML_HTML_DOCUMENT_NODE:
7672 if (cur != start)
7673 return(cur);
7674 return(xmlDocGetRootElement((xmlDocPtr) cur));
7675 default:
7676 break;
7677 }
7678
7679next_sibling:
7680 if ((cur == NULL) || (cur == contextNode))
7681 return(NULL);
7682 if (cur->next != NULL) {
7683 cur = cur->next;
7684 } else {
7685 cur = cur->parent;
7686 goto next_sibling;
7687 }
7688 }
7689 }
7690 return(NULL);
7691}
7692
7693/**
Owen Taylor3473f882001-02-23 17:55:21 +00007694 * xmlXPathNextDescendant:
7695 * @ctxt: the XPath Parser context
7696 * @cur: the current node in the traversal
7697 *
7698 * Traversal function for the "descendant" direction
7699 * the descendant axis contains the descendants of the context node in document
7700 * order; a descendant is a child or a child of a child and so on.
7701 *
7702 * Returns the next element following that axis
7703 */
7704xmlNodePtr
7705xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007706 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007707 if (cur == NULL) {
7708 if (ctxt->context->node == NULL)
7709 return(NULL);
7710 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7711 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7712 return(NULL);
7713
7714 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7715 return(ctxt->context->doc->children);
7716 return(ctxt->context->node->children);
7717 }
7718
Daniel Veillard567e1b42001-08-01 15:53:47 +00007719 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007720 /*
7721 * Do not descend on entities declarations
7722 */
7723 if (cur->children->type != XML_ENTITY_DECL) {
7724 cur = cur->children;
7725 /*
7726 * Skip DTDs
7727 */
7728 if (cur->type != XML_DTD_NODE)
7729 return(cur);
7730 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00007731 }
7732
7733 if (cur == ctxt->context->node) return(NULL);
7734
Daniel Veillard68e9e742002-11-16 15:35:11 +00007735 while (cur->next != NULL) {
7736 cur = cur->next;
7737 if ((cur->type != XML_ENTITY_DECL) &&
7738 (cur->type != XML_DTD_NODE))
7739 return(cur);
7740 }
Owen Taylor3473f882001-02-23 17:55:21 +00007741
7742 do {
7743 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00007744 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00007745 if (cur == ctxt->context->node) return(NULL);
7746 if (cur->next != NULL) {
7747 cur = cur->next;
7748 return(cur);
7749 }
7750 } while (cur != NULL);
7751 return(cur);
7752}
7753
7754/**
7755 * xmlXPathNextDescendantOrSelf:
7756 * @ctxt: the XPath Parser context
7757 * @cur: the current node in the traversal
7758 *
7759 * Traversal function for the "descendant-or-self" direction
7760 * the descendant-or-self axis contains the context node and the descendants
7761 * of the context node in document order; thus the context node is the first
7762 * node on the axis, and the first child of the context node is the second node
7763 * on the axis
7764 *
7765 * Returns the next element following that axis
7766 */
7767xmlNodePtr
7768xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007769 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007770 if (cur == NULL) {
7771 if (ctxt->context->node == NULL)
7772 return(NULL);
7773 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7774 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7775 return(NULL);
7776 return(ctxt->context->node);
7777 }
7778
7779 return(xmlXPathNextDescendant(ctxt, cur));
7780}
7781
7782/**
7783 * xmlXPathNextParent:
7784 * @ctxt: the XPath Parser context
7785 * @cur: the current node in the traversal
7786 *
7787 * Traversal function for the "parent" direction
7788 * The parent axis contains the parent of the context node, if there is one.
7789 *
7790 * Returns the next element following that axis
7791 */
7792xmlNodePtr
7793xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007794 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007795 /*
7796 * the parent of an attribute or namespace node is the element
7797 * to which the attribute or namespace node is attached
7798 * Namespace handling !!!
7799 */
7800 if (cur == NULL) {
7801 if (ctxt->context->node == NULL) return(NULL);
7802 switch (ctxt->context->node->type) {
7803 case XML_ELEMENT_NODE:
7804 case XML_TEXT_NODE:
7805 case XML_CDATA_SECTION_NODE:
7806 case XML_ENTITY_REF_NODE:
7807 case XML_ENTITY_NODE:
7808 case XML_PI_NODE:
7809 case XML_COMMENT_NODE:
7810 case XML_NOTATION_NODE:
7811 case XML_DTD_NODE:
7812 case XML_ELEMENT_DECL:
7813 case XML_ATTRIBUTE_DECL:
7814 case XML_XINCLUDE_START:
7815 case XML_XINCLUDE_END:
7816 case XML_ENTITY_DECL:
7817 if (ctxt->context->node->parent == NULL)
7818 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007819 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007820 ((ctxt->context->node->parent->name[0] == ' ') ||
7821 (xmlStrEqual(ctxt->context->node->parent->name,
7822 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007823 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007824 return(ctxt->context->node->parent);
7825 case XML_ATTRIBUTE_NODE: {
7826 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7827
7828 return(att->parent);
7829 }
7830 case XML_DOCUMENT_NODE:
7831 case XML_DOCUMENT_TYPE_NODE:
7832 case XML_DOCUMENT_FRAG_NODE:
7833 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007834#ifdef LIBXML_DOCB_ENABLED
7835 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007836#endif
7837 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007838 case XML_NAMESPACE_DECL: {
7839 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7840
7841 if ((ns->next != NULL) &&
7842 (ns->next->type != XML_NAMESPACE_DECL))
7843 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00007844 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007845 }
Owen Taylor3473f882001-02-23 17:55:21 +00007846 }
7847 }
7848 return(NULL);
7849}
7850
7851/**
7852 * xmlXPathNextAncestor:
7853 * @ctxt: the XPath Parser context
7854 * @cur: the current node in the traversal
7855 *
7856 * Traversal function for the "ancestor" direction
7857 * the ancestor axis contains the ancestors of the context node; the ancestors
7858 * of the context node consist of the parent of context node and the parent's
7859 * parent and so on; the nodes are ordered in reverse document order; thus the
7860 * parent is the first node on the axis, and the parent's parent is the second
7861 * node on the axis
7862 *
7863 * Returns the next element following that axis
7864 */
7865xmlNodePtr
7866xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007867 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007868 /*
7869 * the parent of an attribute or namespace node is the element
7870 * to which the attribute or namespace node is attached
7871 * !!!!!!!!!!!!!
7872 */
7873 if (cur == NULL) {
7874 if (ctxt->context->node == NULL) return(NULL);
7875 switch (ctxt->context->node->type) {
7876 case XML_ELEMENT_NODE:
7877 case XML_TEXT_NODE:
7878 case XML_CDATA_SECTION_NODE:
7879 case XML_ENTITY_REF_NODE:
7880 case XML_ENTITY_NODE:
7881 case XML_PI_NODE:
7882 case XML_COMMENT_NODE:
7883 case XML_DTD_NODE:
7884 case XML_ELEMENT_DECL:
7885 case XML_ATTRIBUTE_DECL:
7886 case XML_ENTITY_DECL:
7887 case XML_NOTATION_NODE:
7888 case XML_XINCLUDE_START:
7889 case XML_XINCLUDE_END:
7890 if (ctxt->context->node->parent == NULL)
7891 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007892 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007893 ((ctxt->context->node->parent->name[0] == ' ') ||
7894 (xmlStrEqual(ctxt->context->node->parent->name,
7895 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007896 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007897 return(ctxt->context->node->parent);
7898 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007899 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00007900
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007901 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00007902 }
7903 case XML_DOCUMENT_NODE:
7904 case XML_DOCUMENT_TYPE_NODE:
7905 case XML_DOCUMENT_FRAG_NODE:
7906 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007907#ifdef LIBXML_DOCB_ENABLED
7908 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007909#endif
7910 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007911 case XML_NAMESPACE_DECL: {
7912 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7913
7914 if ((ns->next != NULL) &&
7915 (ns->next->type != XML_NAMESPACE_DECL))
7916 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00007917 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00007918 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007919 }
Owen Taylor3473f882001-02-23 17:55:21 +00007920 }
7921 return(NULL);
7922 }
7923 if (cur == ctxt->context->doc->children)
7924 return((xmlNodePtr) ctxt->context->doc);
7925 if (cur == (xmlNodePtr) ctxt->context->doc)
7926 return(NULL);
7927 switch (cur->type) {
7928 case XML_ELEMENT_NODE:
7929 case XML_TEXT_NODE:
7930 case XML_CDATA_SECTION_NODE:
7931 case XML_ENTITY_REF_NODE:
7932 case XML_ENTITY_NODE:
7933 case XML_PI_NODE:
7934 case XML_COMMENT_NODE:
7935 case XML_NOTATION_NODE:
7936 case XML_DTD_NODE:
7937 case XML_ELEMENT_DECL:
7938 case XML_ATTRIBUTE_DECL:
7939 case XML_ENTITY_DECL:
7940 case XML_XINCLUDE_START:
7941 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007942 if (cur->parent == NULL)
7943 return(NULL);
7944 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007945 ((cur->parent->name[0] == ' ') ||
7946 (xmlStrEqual(cur->parent->name,
7947 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007948 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007949 return(cur->parent);
7950 case XML_ATTRIBUTE_NODE: {
7951 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7952
7953 return(att->parent);
7954 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00007955 case XML_NAMESPACE_DECL: {
7956 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7957
7958 if ((ns->next != NULL) &&
7959 (ns->next->type != XML_NAMESPACE_DECL))
7960 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00007961 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00007962 return(NULL);
7963 }
Owen Taylor3473f882001-02-23 17:55:21 +00007964 case XML_DOCUMENT_NODE:
7965 case XML_DOCUMENT_TYPE_NODE:
7966 case XML_DOCUMENT_FRAG_NODE:
7967 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007968#ifdef LIBXML_DOCB_ENABLED
7969 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007970#endif
7971 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007972 }
7973 return(NULL);
7974}
7975
7976/**
7977 * xmlXPathNextAncestorOrSelf:
7978 * @ctxt: the XPath Parser context
7979 * @cur: the current node in the traversal
7980 *
7981 * Traversal function for the "ancestor-or-self" direction
7982 * he ancestor-or-self axis contains the context node and ancestors of
7983 * the context node in reverse document order; thus the context node is
7984 * the first node on the axis, and the context node's parent the second;
7985 * parent here is defined the same as with the parent axis.
7986 *
7987 * Returns the next element following that axis
7988 */
7989xmlNodePtr
7990xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007991 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007992 if (cur == NULL)
7993 return(ctxt->context->node);
7994 return(xmlXPathNextAncestor(ctxt, cur));
7995}
7996
7997/**
7998 * xmlXPathNextFollowingSibling:
7999 * @ctxt: the XPath Parser context
8000 * @cur: the current node in the traversal
8001 *
8002 * Traversal function for the "following-sibling" direction
8003 * The following-sibling axis contains the following siblings of the context
8004 * node in document order.
8005 *
8006 * Returns the next element following that axis
8007 */
8008xmlNodePtr
8009xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008010 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008011 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8012 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8013 return(NULL);
8014 if (cur == (xmlNodePtr) ctxt->context->doc)
8015 return(NULL);
8016 if (cur == NULL)
8017 return(ctxt->context->node->next);
8018 return(cur->next);
8019}
8020
8021/**
8022 * xmlXPathNextPrecedingSibling:
8023 * @ctxt: the XPath Parser context
8024 * @cur: the current node in the traversal
8025 *
8026 * Traversal function for the "preceding-sibling" direction
8027 * The preceding-sibling axis contains the preceding siblings of the context
8028 * node in reverse document order; the first preceding sibling is first on the
8029 * axis; the sibling preceding that node is the second on the axis and so on.
8030 *
8031 * Returns the next element following that axis
8032 */
8033xmlNodePtr
8034xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008035 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008036 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8037 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8038 return(NULL);
8039 if (cur == (xmlNodePtr) ctxt->context->doc)
8040 return(NULL);
8041 if (cur == NULL)
8042 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008043 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8044 cur = cur->prev;
8045 if (cur == NULL)
8046 return(ctxt->context->node->prev);
8047 }
Owen Taylor3473f882001-02-23 17:55:21 +00008048 return(cur->prev);
8049}
8050
8051/**
8052 * xmlXPathNextFollowing:
8053 * @ctxt: the XPath Parser context
8054 * @cur: the current node in the traversal
8055 *
8056 * Traversal function for the "following" direction
8057 * The following axis contains all nodes in the same document as the context
8058 * node that are after the context node in document order, excluding any
8059 * descendants and excluding attribute nodes and namespace nodes; the nodes
8060 * are ordered in document order
8061 *
8062 * Returns the next element following that axis
8063 */
8064xmlNodePtr
8065xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008066 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008067 if (cur != NULL && cur->children != NULL)
8068 return cur->children ;
8069 if (cur == NULL) cur = ctxt->context->node;
8070 if (cur == NULL) return(NULL) ; /* ERROR */
8071 if (cur->next != NULL) return(cur->next) ;
8072 do {
8073 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00008074 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00008075 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8076 if (cur->next != NULL) return(cur->next);
8077 } while (cur != NULL);
8078 return(cur);
8079}
8080
8081/*
8082 * xmlXPathIsAncestor:
8083 * @ancestor: the ancestor node
8084 * @node: the current node
8085 *
8086 * Check that @ancestor is a @node's ancestor
8087 *
8088 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8089 */
8090static int
8091xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8092 if ((ancestor == NULL) || (node == NULL)) return(0);
8093 /* nodes need to be in the same document */
8094 if (ancestor->doc != node->doc) return(0);
8095 /* avoid searching if ancestor or node is the root node */
8096 if (ancestor == (xmlNodePtr) node->doc) return(1);
8097 if (node == (xmlNodePtr) ancestor->doc) return(0);
8098 while (node->parent != NULL) {
8099 if (node->parent == ancestor)
8100 return(1);
8101 node = node->parent;
8102 }
8103 return(0);
8104}
8105
8106/**
8107 * xmlXPathNextPreceding:
8108 * @ctxt: the XPath Parser context
8109 * @cur: the current node in the traversal
8110 *
8111 * Traversal function for the "preceding" direction
8112 * the preceding axis contains all nodes in the same document as the context
8113 * node that are before the context node in document order, excluding any
8114 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8115 * ordered in reverse document order
8116 *
8117 * Returns the next element following that axis
8118 */
8119xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00008120xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8121{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008122 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008123 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008124 cur = ctxt->context->node;
8125 if (cur == NULL)
8126 return (NULL);
8127 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8128 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00008129 do {
8130 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008131 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8132 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008133 }
8134
8135 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008136 if (cur == NULL)
8137 return (NULL);
8138 if (cur == ctxt->context->doc->children)
8139 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008140 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00008141 return (cur);
8142}
8143
8144/**
8145 * xmlXPathNextPrecedingInternal:
8146 * @ctxt: the XPath Parser context
8147 * @cur: the current node in the traversal
8148 *
8149 * Traversal function for the "preceding" direction
8150 * the preceding axis contains all nodes in the same document as the context
8151 * node that are before the context node in document order, excluding any
8152 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8153 * ordered in reverse document order
8154 * This is a faster implementation but internal only since it requires a
8155 * state kept in the parser context: ctxt->ancestor.
8156 *
8157 * Returns the next element following that axis
8158 */
8159static xmlNodePtr
8160xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8161 xmlNodePtr cur)
8162{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008163 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008164 if (cur == NULL) {
8165 cur = ctxt->context->node;
8166 if (cur == NULL)
8167 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00008168 if (cur->type == XML_NAMESPACE_DECL)
8169 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008170 ctxt->ancestor = cur->parent;
8171 }
8172 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8173 cur = cur->prev;
8174 while (cur->prev == NULL) {
8175 cur = cur->parent;
8176 if (cur == NULL)
8177 return (NULL);
8178 if (cur == ctxt->context->doc->children)
8179 return (NULL);
8180 if (cur != ctxt->ancestor)
8181 return (cur);
8182 ctxt->ancestor = cur->parent;
8183 }
8184 cur = cur->prev;
8185 while (cur->last != NULL)
8186 cur = cur->last;
8187 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008188}
8189
8190/**
8191 * xmlXPathNextNamespace:
8192 * @ctxt: the XPath Parser context
8193 * @cur: the current attribute in the traversal
8194 *
8195 * Traversal function for the "namespace" direction
8196 * the namespace axis contains the namespace nodes of the context node;
8197 * the order of nodes on this axis is implementation-defined; the axis will
8198 * be empty unless the context node is an element
8199 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008200 * We keep the XML namespace node at the end of the list.
8201 *
Owen Taylor3473f882001-02-23 17:55:21 +00008202 * Returns the next element following that axis
8203 */
8204xmlNodePtr
8205xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008206 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008207 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00008208 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008209 if (ctxt->context->tmpNsList != NULL)
8210 xmlFree(ctxt->context->tmpNsList);
8211 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00008212 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008213 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00008214 if (ctxt->context->tmpNsList != NULL) {
8215 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8216 ctxt->context->tmpNsNr++;
8217 }
8218 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008219 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008220 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00008221 if (ctxt->context->tmpNsNr > 0) {
8222 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8223 } else {
8224 if (ctxt->context->tmpNsList != NULL)
8225 xmlFree(ctxt->context->tmpNsList);
8226 ctxt->context->tmpNsList = NULL;
8227 return(NULL);
8228 }
Owen Taylor3473f882001-02-23 17:55:21 +00008229}
8230
8231/**
8232 * xmlXPathNextAttribute:
8233 * @ctxt: the XPath Parser context
8234 * @cur: the current attribute in the traversal
8235 *
8236 * Traversal function for the "attribute" direction
8237 * TODO: support DTD inherited default attributes
8238 *
8239 * Returns the next element following that axis
8240 */
8241xmlNodePtr
8242xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008243 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00008244 if (ctxt->context->node == NULL)
8245 return(NULL);
8246 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8247 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008248 if (cur == NULL) {
8249 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8250 return(NULL);
8251 return((xmlNodePtr)ctxt->context->node->properties);
8252 }
8253 return((xmlNodePtr)cur->next);
8254}
8255
8256/************************************************************************
8257 * *
8258 * NodeTest Functions *
8259 * *
8260 ************************************************************************/
8261
Owen Taylor3473f882001-02-23 17:55:21 +00008262#define IS_FUNCTION 200
8263
Owen Taylor3473f882001-02-23 17:55:21 +00008264
8265/************************************************************************
8266 * *
8267 * Implicit tree core function library *
8268 * *
8269 ************************************************************************/
8270
8271/**
8272 * xmlXPathRoot:
8273 * @ctxt: the XPath Parser context
8274 *
8275 * Initialize the context to the root of the document
8276 */
8277void
8278xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008279 if ((ctxt == NULL) || (ctxt->context == NULL))
8280 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008281 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008282 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8283 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008284}
8285
8286/************************************************************************
8287 * *
8288 * The explicit core function library *
8289 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8290 * *
8291 ************************************************************************/
8292
8293
8294/**
8295 * xmlXPathLastFunction:
8296 * @ctxt: the XPath Parser context
8297 * @nargs: the number of arguments
8298 *
8299 * Implement the last() XPath function
8300 * number last()
8301 * The last function returns the number of nodes in the context node list.
8302 */
8303void
8304xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8305 CHECK_ARITY(0);
8306 if (ctxt->context->contextSize >= 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008307 valuePush(ctxt,
8308 xmlXPathCacheNewFloat(ctxt->context,
8309 (double) ctxt->context->contextSize));
Owen Taylor3473f882001-02-23 17:55:21 +00008310#ifdef DEBUG_EXPR
8311 xmlGenericError(xmlGenericErrorContext,
8312 "last() : %d\n", ctxt->context->contextSize);
8313#endif
8314 } else {
8315 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8316 }
8317}
8318
8319/**
8320 * xmlXPathPositionFunction:
8321 * @ctxt: the XPath Parser context
8322 * @nargs: the number of arguments
8323 *
8324 * Implement the position() XPath function
8325 * number position()
8326 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008327 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00008328 * will be equal to last().
8329 */
8330void
8331xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8332 CHECK_ARITY(0);
8333 if (ctxt->context->proximityPosition >= 0) {
8334 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008335 xmlXPathCacheNewFloat(ctxt->context,
8336 (double) ctxt->context->proximityPosition));
Owen Taylor3473f882001-02-23 17:55:21 +00008337#ifdef DEBUG_EXPR
8338 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8339 ctxt->context->proximityPosition);
8340#endif
8341 } else {
8342 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8343 }
8344}
8345
8346/**
8347 * xmlXPathCountFunction:
8348 * @ctxt: the XPath Parser context
8349 * @nargs: the number of arguments
8350 *
8351 * Implement the count() XPath function
8352 * number count(node-set)
8353 */
8354void
8355xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8356 xmlXPathObjectPtr cur;
8357
8358 CHECK_ARITY(1);
8359 if ((ctxt->value == NULL) ||
8360 ((ctxt->value->type != XPATH_NODESET) &&
8361 (ctxt->value->type != XPATH_XSLT_TREE)))
8362 XP_ERROR(XPATH_INVALID_TYPE);
8363 cur = valuePop(ctxt);
8364
Daniel Veillard911f49a2001-04-07 15:39:35 +00008365 if ((cur == NULL) || (cur->nodesetval == NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008366 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00008367 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008368 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8369 (double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00008370 } else {
8371 if ((cur->nodesetval->nodeNr != 1) ||
8372 (cur->nodesetval->nodeTab == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008373 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00008374 } else {
8375 xmlNodePtr tmp;
8376 int i = 0;
8377
8378 tmp = cur->nodesetval->nodeTab[0];
8379 if (tmp != NULL) {
8380 tmp = tmp->children;
8381 while (tmp != NULL) {
8382 tmp = tmp->next;
8383 i++;
8384 }
8385 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008386 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
Daniel Veillardfe703322001-08-14 12:18:09 +00008387 }
8388 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008389 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008390}
8391
8392/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008393 * xmlXPathGetElementsByIds:
8394 * @doc: the document
8395 * @ids: a whitespace separated list of IDs
8396 *
8397 * Selects elements by their unique ID.
8398 *
8399 * Returns a node-set of selected elements.
8400 */
8401static xmlNodeSetPtr
8402xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8403 xmlNodeSetPtr ret;
8404 const xmlChar *cur = ids;
8405 xmlChar *ID;
8406 xmlAttrPtr attr;
8407 xmlNodePtr elem = NULL;
8408
Daniel Veillard7a985a12003-07-06 17:57:42 +00008409 if (ids == NULL) return(NULL);
8410
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008411 ret = xmlXPathNodeSetCreate(NULL);
8412
William M. Brack76e95df2003-10-18 16:20:14 +00008413 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008414 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008415 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00008416 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008417
8418 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00008419 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00008420 /*
8421 * We used to check the fact that the value passed
8422 * was an NCName, but this generated much troubles for
8423 * me and Aleksey Sanin, people blatantly violated that
8424 * constaint, like Visa3D spec.
8425 * if (xmlValidateNCName(ID, 1) == 0)
8426 */
8427 attr = xmlGetID(doc, ID);
8428 if (attr != NULL) {
8429 if (attr->type == XML_ATTRIBUTE_NODE)
8430 elem = attr->parent;
8431 else if (attr->type == XML_ELEMENT_NODE)
8432 elem = (xmlNodePtr) attr;
8433 else
8434 elem = NULL;
8435 if (elem != NULL)
8436 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00008437 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008438 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00008439 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008440
William M. Brack76e95df2003-10-18 16:20:14 +00008441 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008442 ids = cur;
8443 }
8444 return(ret);
8445}
8446
8447/**
Owen Taylor3473f882001-02-23 17:55:21 +00008448 * xmlXPathIdFunction:
8449 * @ctxt: the XPath Parser context
8450 * @nargs: the number of arguments
8451 *
8452 * Implement the id() XPath function
8453 * node-set id(object)
8454 * The id function selects elements by their unique ID
8455 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8456 * then the result is the union of the result of applying id to the
8457 * string value of each of the nodes in the argument node-set. When the
8458 * argument to id is of any other type, the argument is converted to a
8459 * string as if by a call to the string function; the string is split
8460 * into a whitespace-separated list of tokens (whitespace is any sequence
8461 * of characters matching the production S); the result is a node-set
8462 * containing the elements in the same document as the context node that
8463 * have a unique ID equal to any of the tokens in the list.
8464 */
8465void
8466xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008467 xmlChar *tokens;
8468 xmlNodeSetPtr ret;
8469 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00008470
8471 CHECK_ARITY(1);
8472 obj = valuePop(ctxt);
8473 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00008474 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008475 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00008476 int i;
8477
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008478 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008479
Daniel Veillard911f49a2001-04-07 15:39:35 +00008480 if (obj->nodesetval != NULL) {
8481 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008482 tokens =
8483 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8484 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8485 ret = xmlXPathNodeSetMerge(ret, ns);
8486 xmlXPathFreeNodeSet(ns);
8487 if (tokens != NULL)
8488 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00008489 }
Owen Taylor3473f882001-02-23 17:55:21 +00008490 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008491 xmlXPathReleaseObject(ctxt->context, obj);
8492 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00008493 return;
8494 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008495 obj = xmlXPathCacheConvertString(ctxt->context, obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008496 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008497 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8498 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00008499 return;
8500}
8501
8502/**
8503 * xmlXPathLocalNameFunction:
8504 * @ctxt: the XPath Parser context
8505 * @nargs: the number of arguments
8506 *
8507 * Implement the local-name() XPath function
8508 * string local-name(node-set?)
8509 * The local-name function returns a string containing the local part
8510 * of the name of the node in the argument node-set that is first in
8511 * document order. If the node-set is empty or the first node has no
8512 * name, an empty string is returned. If the argument is omitted it
8513 * defaults to the context node.
8514 */
8515void
8516xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8517 xmlXPathObjectPtr cur;
8518
Daniel Veillarda82b1822004-11-08 16:24:57 +00008519 if (ctxt == NULL) return;
8520
Owen Taylor3473f882001-02-23 17:55:21 +00008521 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008522 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8523 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008524 nargs = 1;
8525 }
8526
8527 CHECK_ARITY(1);
8528 if ((ctxt->value == NULL) ||
8529 ((ctxt->value->type != XPATH_NODESET) &&
8530 (ctxt->value->type != XPATH_XSLT_TREE)))
8531 XP_ERROR(XPATH_INVALID_TYPE);
8532 cur = valuePop(ctxt);
8533
Daniel Veillard911f49a2001-04-07 15:39:35 +00008534 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008535 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008536 } else {
8537 int i = 0; /* Should be first in document order !!!!! */
8538 switch (cur->nodesetval->nodeTab[i]->type) {
8539 case XML_ELEMENT_NODE:
8540 case XML_ATTRIBUTE_NODE:
8541 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008542 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008543 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008544 else
8545 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008546 xmlXPathCacheNewString(ctxt->context,
8547 cur->nodesetval->nodeTab[i]->name));
Owen Taylor3473f882001-02-23 17:55:21 +00008548 break;
8549 case XML_NAMESPACE_DECL:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008550 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008551 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8552 break;
8553 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008554 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008555 }
8556 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008557 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008558}
8559
8560/**
8561 * xmlXPathNamespaceURIFunction:
8562 * @ctxt: the XPath Parser context
8563 * @nargs: the number of arguments
8564 *
8565 * Implement the namespace-uri() XPath function
8566 * string namespace-uri(node-set?)
8567 * The namespace-uri function returns a string containing the
8568 * namespace URI of the expanded name of the node in the argument
8569 * node-set that is first in document order. If the node-set is empty,
8570 * the first node has no name, or the expanded name has no namespace
8571 * URI, an empty string is returned. If the argument is omitted it
8572 * defaults to the context node.
8573 */
8574void
8575xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8576 xmlXPathObjectPtr cur;
8577
Daniel Veillarda82b1822004-11-08 16:24:57 +00008578 if (ctxt == NULL) return;
8579
Owen Taylor3473f882001-02-23 17:55:21 +00008580 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008581 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8582 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008583 nargs = 1;
8584 }
8585 CHECK_ARITY(1);
8586 if ((ctxt->value == NULL) ||
8587 ((ctxt->value->type != XPATH_NODESET) &&
8588 (ctxt->value->type != XPATH_XSLT_TREE)))
8589 XP_ERROR(XPATH_INVALID_TYPE);
8590 cur = valuePop(ctxt);
8591
Daniel Veillard911f49a2001-04-07 15:39:35 +00008592 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008593 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008594 } else {
8595 int i = 0; /* Should be first in document order !!!!! */
8596 switch (cur->nodesetval->nodeTab[i]->type) {
8597 case XML_ELEMENT_NODE:
8598 case XML_ATTRIBUTE_NODE:
8599 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008600 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008601 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008602 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008603 cur->nodesetval->nodeTab[i]->ns->href));
8604 break;
8605 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008606 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008607 }
8608 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008609 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008610}
8611
8612/**
8613 * xmlXPathNameFunction:
8614 * @ctxt: the XPath Parser context
8615 * @nargs: the number of arguments
8616 *
8617 * Implement the name() XPath function
8618 * string name(node-set?)
8619 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008620 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00008621 * order. The QName must represent the name with respect to the namespace
8622 * declarations in effect on the node whose name is being represented.
8623 * Typically, this will be the form in which the name occurred in the XML
8624 * source. This need not be the case if there are namespace declarations
8625 * in effect on the node that associate multiple prefixes with the same
8626 * namespace. However, an implementation may include information about
8627 * the original prefix in its representation of nodes; in this case, an
8628 * implementation can ensure that the returned string is always the same
8629 * as the QName used in the XML source. If the argument it omitted it
8630 * defaults to the context node.
8631 * Libxml keep the original prefix so the "real qualified name" used is
8632 * returned.
8633 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008634static void
Daniel Veillard04383752001-07-08 14:27:15 +00008635xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8636{
Owen Taylor3473f882001-02-23 17:55:21 +00008637 xmlXPathObjectPtr cur;
8638
8639 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008640 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8641 ctxt->context->node));
Daniel Veillard04383752001-07-08 14:27:15 +00008642 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008643 }
8644
8645 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00008646 if ((ctxt->value == NULL) ||
8647 ((ctxt->value->type != XPATH_NODESET) &&
8648 (ctxt->value->type != XPATH_XSLT_TREE)))
8649 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00008650 cur = valuePop(ctxt);
8651
Daniel Veillard911f49a2001-04-07 15:39:35 +00008652 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008653 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008654 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00008655 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00008656
Daniel Veillard04383752001-07-08 14:27:15 +00008657 switch (cur->nodesetval->nodeTab[i]->type) {
8658 case XML_ELEMENT_NODE:
8659 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008660 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008661 valuePush(ctxt,
8662 xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008663 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8664 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008665 valuePush(ctxt,
8666 xmlXPathCacheNewString(ctxt->context,
8667 cur->nodesetval->nodeTab[i]->name));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008668 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00008669 xmlChar *fullname;
8670
8671 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8672 cur->nodesetval->nodeTab[i]->ns->prefix,
8673 NULL, 0);
8674 if (fullname == cur->nodesetval->nodeTab[i]->name)
8675 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8676 if (fullname == NULL) {
8677 XP_ERROR(XPATH_MEMORY_ERROR);
8678 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008679 valuePush(ctxt, xmlXPathCacheWrapString(
8680 ctxt->context, fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00008681 }
8682 break;
8683 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008684 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8685 cur->nodesetval->nodeTab[i]));
Daniel Veillard04383752001-07-08 14:27:15 +00008686 xmlXPathLocalNameFunction(ctxt, 1);
8687 }
Owen Taylor3473f882001-02-23 17:55:21 +00008688 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008689 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008690}
8691
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008692
8693/**
Owen Taylor3473f882001-02-23 17:55:21 +00008694 * xmlXPathStringFunction:
8695 * @ctxt: the XPath Parser context
8696 * @nargs: the number of arguments
8697 *
8698 * Implement the string() XPath function
8699 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00008700 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00008701 * - A node-set is converted to a string by returning the value of
8702 * the node in the node-set that is first in document order.
8703 * If the node-set is empty, an empty string is returned.
8704 * - A number is converted to a string as follows
8705 * + NaN is converted to the string NaN
8706 * + positive zero is converted to the string 0
8707 * + negative zero is converted to the string 0
8708 * + positive infinity is converted to the string Infinity
8709 * + negative infinity is converted to the string -Infinity
8710 * + if the number is an integer, the number is represented in
8711 * decimal form as a Number with no decimal point and no leading
8712 * zeros, preceded by a minus sign (-) if the number is negative
8713 * + otherwise, the number is represented in decimal form as a
8714 * Number including a decimal point with at least one digit
8715 * before the decimal point and at least one digit after the
8716 * decimal point, preceded by a minus sign (-) if the number
8717 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008718 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00008719 * before the decimal point; beyond the one required digit
8720 * after the decimal point there must be as many, but only as
8721 * many, more digits as are needed to uniquely distinguish the
8722 * number from all other IEEE 754 numeric values.
8723 * - The boolean false value is converted to the string false.
8724 * The boolean true value is converted to the string true.
8725 *
8726 * If the argument is omitted, it defaults to a node-set with the
8727 * context node as its only member.
8728 */
8729void
8730xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8731 xmlXPathObjectPtr cur;
8732
Daniel Veillarda82b1822004-11-08 16:24:57 +00008733 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008734 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008735 valuePush(ctxt,
8736 xmlXPathCacheWrapString(ctxt->context,
8737 xmlXPathCastNodeToString(ctxt->context->node)));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008738 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008739 }
8740
8741 CHECK_ARITY(1);
8742 cur = valuePop(ctxt);
8743 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008744 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00008745}
8746
8747/**
8748 * xmlXPathStringLengthFunction:
8749 * @ctxt: the XPath Parser context
8750 * @nargs: the number of arguments
8751 *
8752 * Implement the string-length() XPath function
8753 * number string-length(string?)
8754 * The string-length returns the number of characters in the string
8755 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8756 * the context node converted to a string, in other words the value
8757 * of the context node.
8758 */
8759void
8760xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8761 xmlXPathObjectPtr cur;
8762
8763 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008764 if ((ctxt == NULL) || (ctxt->context == NULL))
8765 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008766 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008767 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008768 } else {
8769 xmlChar *content;
8770
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008771 content = xmlXPathCastNodeToString(ctxt->context->node);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008772 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8773 xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00008774 xmlFree(content);
8775 }
8776 return;
8777 }
8778 CHECK_ARITY(1);
8779 CAST_TO_STRING;
8780 CHECK_TYPE(XPATH_STRING);
8781 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008782 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8783 xmlUTF8Strlen(cur->stringval)));
8784 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008785}
8786
8787/**
8788 * xmlXPathConcatFunction:
8789 * @ctxt: the XPath Parser context
8790 * @nargs: the number of arguments
8791 *
8792 * Implement the concat() XPath function
8793 * string concat(string, string, string*)
8794 * The concat function returns the concatenation of its arguments.
8795 */
8796void
8797xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8798 xmlXPathObjectPtr cur, newobj;
8799 xmlChar *tmp;
8800
Daniel Veillarda82b1822004-11-08 16:24:57 +00008801 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008802 if (nargs < 2) {
8803 CHECK_ARITY(2);
8804 }
8805
8806 CAST_TO_STRING;
8807 cur = valuePop(ctxt);
8808 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008809 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008810 return;
8811 }
8812 nargs--;
8813
8814 while (nargs > 0) {
8815 CAST_TO_STRING;
8816 newobj = valuePop(ctxt);
8817 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008818 xmlXPathReleaseObject(ctxt->context, newobj);
8819 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008820 XP_ERROR(XPATH_INVALID_TYPE);
8821 }
8822 tmp = xmlStrcat(newobj->stringval, cur->stringval);
8823 newobj->stringval = cur->stringval;
8824 cur->stringval = tmp;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008825 xmlXPathReleaseObject(ctxt->context, newobj);
Owen Taylor3473f882001-02-23 17:55:21 +00008826 nargs--;
8827 }
8828 valuePush(ctxt, cur);
8829}
8830
8831/**
8832 * xmlXPathContainsFunction:
8833 * @ctxt: the XPath Parser context
8834 * @nargs: the number of arguments
8835 *
8836 * Implement the contains() XPath function
8837 * boolean contains(string, string)
8838 * The contains function returns true if the first argument string
8839 * contains the second argument string, and otherwise returns false.
8840 */
8841void
8842xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8843 xmlXPathObjectPtr hay, needle;
8844
8845 CHECK_ARITY(2);
8846 CAST_TO_STRING;
8847 CHECK_TYPE(XPATH_STRING);
8848 needle = valuePop(ctxt);
8849 CAST_TO_STRING;
8850 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008851
Owen Taylor3473f882001-02-23 17:55:21 +00008852 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008853 xmlXPathReleaseObject(ctxt->context, hay);
8854 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008855 XP_ERROR(XPATH_INVALID_TYPE);
8856 }
8857 if (xmlStrstr(hay->stringval, needle->stringval))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008858 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00008859 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008860 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8861 xmlXPathReleaseObject(ctxt->context, hay);
8862 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008863}
8864
8865/**
8866 * xmlXPathStartsWithFunction:
8867 * @ctxt: the XPath Parser context
8868 * @nargs: the number of arguments
8869 *
8870 * Implement the starts-with() XPath function
8871 * boolean starts-with(string, string)
8872 * The starts-with function returns true if the first argument string
8873 * starts with the second argument string, and otherwise returns false.
8874 */
8875void
8876xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8877 xmlXPathObjectPtr hay, needle;
8878 int n;
8879
8880 CHECK_ARITY(2);
8881 CAST_TO_STRING;
8882 CHECK_TYPE(XPATH_STRING);
8883 needle = valuePop(ctxt);
8884 CAST_TO_STRING;
8885 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008886
Owen Taylor3473f882001-02-23 17:55:21 +00008887 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008888 xmlXPathReleaseObject(ctxt->context, hay);
8889 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008890 XP_ERROR(XPATH_INVALID_TYPE);
8891 }
8892 n = xmlStrlen(needle->stringval);
8893 if (xmlStrncmp(hay->stringval, needle->stringval, n))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008894 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008895 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008896 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8897 xmlXPathReleaseObject(ctxt->context, hay);
8898 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008899}
8900
8901/**
8902 * xmlXPathSubstringFunction:
8903 * @ctxt: the XPath Parser context
8904 * @nargs: the number of arguments
8905 *
8906 * Implement the substring() XPath function
8907 * string substring(string, number, number?)
8908 * The substring function returns the substring of the first argument
8909 * starting at the position specified in the second argument with
8910 * length specified in the third argument. For example,
8911 * substring("12345",2,3) returns "234". If the third argument is not
8912 * specified, it returns the substring starting at the position specified
8913 * in the second argument and continuing to the end of the string. For
8914 * example, substring("12345",2) returns "2345". More precisely, each
8915 * character in the string (see [3.6 Strings]) is considered to have a
8916 * numeric position: the position of the first character is 1, the position
8917 * of the second character is 2 and so on. The returned substring contains
8918 * those characters for which the position of the character is greater than
8919 * or equal to the second argument and, if the third argument is specified,
8920 * less than the sum of the second and third arguments; the comparisons
8921 * and addition used for the above follow the standard IEEE 754 rules. Thus:
8922 * - substring("12345", 1.5, 2.6) returns "234"
8923 * - substring("12345", 0, 3) returns "12"
8924 * - substring("12345", 0 div 0, 3) returns ""
8925 * - substring("12345", 1, 0 div 0) returns ""
8926 * - substring("12345", -42, 1 div 0) returns "12345"
8927 * - substring("12345", -1 div 0, 1 div 0) returns ""
8928 */
8929void
8930xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8931 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00008932 double le=0, in;
8933 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00008934 xmlChar *ret;
8935
Owen Taylor3473f882001-02-23 17:55:21 +00008936 if (nargs < 2) {
8937 CHECK_ARITY(2);
8938 }
8939 if (nargs > 3) {
8940 CHECK_ARITY(3);
8941 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008942 /*
8943 * take care of possible last (position) argument
8944 */
Owen Taylor3473f882001-02-23 17:55:21 +00008945 if (nargs == 3) {
8946 CAST_TO_NUMBER;
8947 CHECK_TYPE(XPATH_NUMBER);
8948 len = valuePop(ctxt);
8949 le = len->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008950 xmlXPathReleaseObject(ctxt->context, len);
Owen Taylor3473f882001-02-23 17:55:21 +00008951 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008952
Owen Taylor3473f882001-02-23 17:55:21 +00008953 CAST_TO_NUMBER;
8954 CHECK_TYPE(XPATH_NUMBER);
8955 start = valuePop(ctxt);
8956 in = start->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008957 xmlXPathReleaseObject(ctxt->context, start);
Owen Taylor3473f882001-02-23 17:55:21 +00008958 CAST_TO_STRING;
8959 CHECK_TYPE(XPATH_STRING);
8960 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00008961 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00008962
Daniel Veillard97ac1312001-05-30 19:14:17 +00008963 /*
8964 * If last pos not present, calculate last position
8965 */
Daniel Veillard9e412302002-06-10 15:59:44 +00008966 if (nargs != 3) {
8967 le = (double)m;
8968 if (in < 1.0)
8969 in = 1.0;
8970 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008971
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008972 /* Need to check for the special cases where either
8973 * the index is NaN, the length is NaN, or both
8974 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00008975 */
Daniel Veillard9e412302002-06-10 15:59:44 +00008976 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008977 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00008978 * To meet the requirements of the spec, the arguments
8979 * must be converted to integer format before
8980 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008981 *
Daniel Veillard9e412302002-06-10 15:59:44 +00008982 * First we go to integer form, rounding up
8983 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008984 */
8985 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00008986 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00008987
Daniel Veillard9e412302002-06-10 15:59:44 +00008988 if (xmlXPathIsInf(le) == 1) {
8989 l = m;
8990 if (i < 1)
8991 i = 1;
8992 }
8993 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
8994 l = 0;
8995 else {
8996 l = (int) le;
8997 if (((double)l)+0.5 <= le) l++;
8998 }
8999
9000 /* Now we normalize inidices */
9001 i -= 1;
9002 l += i;
9003 if (i < 0)
9004 i = 0;
9005 if (l > m)
9006 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00009007
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009008 /* number of chars to copy */
9009 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00009010
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009011 ret = xmlUTF8Strsub(str->stringval, i, l);
9012 }
9013 else {
9014 ret = NULL;
9015 }
Owen Taylor3473f882001-02-23 17:55:21 +00009016 if (ret == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009017 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00009018 else {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009019 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009020 xmlFree(ret);
9021 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009022 xmlXPathReleaseObject(ctxt->context, str);
Owen Taylor3473f882001-02-23 17:55:21 +00009023}
9024
9025/**
9026 * xmlXPathSubstringBeforeFunction:
9027 * @ctxt: the XPath Parser context
9028 * @nargs: the number of arguments
9029 *
9030 * Implement the substring-before() XPath function
9031 * string substring-before(string, string)
9032 * The substring-before function returns the substring of the first
9033 * argument string that precedes the first occurrence of the second
9034 * argument string in the first argument string, or the empty string
9035 * if the first argument string does not contain the second argument
9036 * string. For example, substring-before("1999/04/01","/") returns 1999.
9037 */
9038void
9039xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9040 xmlXPathObjectPtr str;
9041 xmlXPathObjectPtr find;
9042 xmlBufferPtr target;
9043 const xmlChar *point;
9044 int offset;
9045
9046 CHECK_ARITY(2);
9047 CAST_TO_STRING;
9048 find = valuePop(ctxt);
9049 CAST_TO_STRING;
9050 str = valuePop(ctxt);
9051
9052 target = xmlBufferCreate();
9053 if (target) {
9054 point = xmlStrstr(str->stringval, find->stringval);
9055 if (point) {
9056 offset = (int)(point - str->stringval);
9057 xmlBufferAdd(target, str->stringval, offset);
9058 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009059 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9060 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00009061 xmlBufferFree(target);
9062 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009063 xmlXPathReleaseObject(ctxt->context, str);
9064 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009065}
9066
9067/**
9068 * xmlXPathSubstringAfterFunction:
9069 * @ctxt: the XPath Parser context
9070 * @nargs: the number of arguments
9071 *
9072 * Implement the substring-after() XPath function
9073 * string substring-after(string, string)
9074 * The substring-after function returns the substring of the first
9075 * argument string that follows the first occurrence of the second
9076 * argument string in the first argument string, or the empty stringi
9077 * if the first argument string does not contain the second argument
9078 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9079 * and substring-after("1999/04/01","19") returns 99/04/01.
9080 */
9081void
9082xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9083 xmlXPathObjectPtr str;
9084 xmlXPathObjectPtr find;
9085 xmlBufferPtr target;
9086 const xmlChar *point;
9087 int offset;
9088
9089 CHECK_ARITY(2);
9090 CAST_TO_STRING;
9091 find = valuePop(ctxt);
9092 CAST_TO_STRING;
9093 str = valuePop(ctxt);
9094
9095 target = xmlBufferCreate();
9096 if (target) {
9097 point = xmlStrstr(str->stringval, find->stringval);
9098 if (point) {
9099 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9100 xmlBufferAdd(target, &str->stringval[offset],
9101 xmlStrlen(str->stringval) - offset);
9102 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009103 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9104 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00009105 xmlBufferFree(target);
9106 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009107 xmlXPathReleaseObject(ctxt->context, str);
9108 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009109}
9110
9111/**
9112 * xmlXPathNormalizeFunction:
9113 * @ctxt: the XPath Parser context
9114 * @nargs: the number of arguments
9115 *
9116 * Implement the normalize-space() XPath function
9117 * string normalize-space(string?)
9118 * The normalize-space function returns the argument string with white
9119 * space normalized by stripping leading and trailing whitespace
9120 * and replacing sequences of whitespace characters by a single
9121 * space. Whitespace characters are the same allowed by the S production
9122 * in XML. If the argument is omitted, it defaults to the context
9123 * node converted to a string, in other words the value of the context node.
9124 */
9125void
9126xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9127 xmlXPathObjectPtr obj = NULL;
9128 xmlChar *source = NULL;
9129 xmlBufferPtr target;
9130 xmlChar blank;
9131
Daniel Veillarda82b1822004-11-08 16:24:57 +00009132 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009133 if (nargs == 0) {
9134 /* Use current context node */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009135 valuePush(ctxt,
9136 xmlXPathCacheWrapString(ctxt->context,
9137 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00009138 nargs = 1;
9139 }
9140
9141 CHECK_ARITY(1);
9142 CAST_TO_STRING;
9143 CHECK_TYPE(XPATH_STRING);
9144 obj = valuePop(ctxt);
9145 source = obj->stringval;
9146
9147 target = xmlBufferCreate();
9148 if (target && source) {
9149
9150 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00009151 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00009152 source++;
9153
9154 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9155 blank = 0;
9156 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00009157 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009158 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00009159 } else {
9160 if (blank) {
9161 xmlBufferAdd(target, &blank, 1);
9162 blank = 0;
9163 }
9164 xmlBufferAdd(target, source, 1);
9165 }
9166 source++;
9167 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009168 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9169 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00009170 xmlBufferFree(target);
9171 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009172 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00009173}
9174
9175/**
9176 * xmlXPathTranslateFunction:
9177 * @ctxt: the XPath Parser context
9178 * @nargs: the number of arguments
9179 *
9180 * Implement the translate() XPath function
9181 * string translate(string, string, string)
9182 * The translate function returns the first argument string with
9183 * occurrences of characters in the second argument string replaced
9184 * by the character at the corresponding position in the third argument
9185 * string. For example, translate("bar","abc","ABC") returns the string
9186 * BAr. If there is a character in the second argument string with no
9187 * character at a corresponding position in the third argument string
9188 * (because the second argument string is longer than the third argument
9189 * string), then occurrences of that character in the first argument
9190 * string are removed. For example, translate("--aaa--","abc-","ABC")
9191 * returns "AAA". If a character occurs more than once in second
9192 * argument string, then the first occurrence determines the replacement
9193 * character. If the third argument string is longer than the second
9194 * argument string, then excess characters are ignored.
9195 */
9196void
9197xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00009198 xmlXPathObjectPtr str;
9199 xmlXPathObjectPtr from;
9200 xmlXPathObjectPtr to;
9201 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009202 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009203 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00009204 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009205 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00009206
Daniel Veillarde043ee12001-04-16 14:08:07 +00009207 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00009208
Daniel Veillarde043ee12001-04-16 14:08:07 +00009209 CAST_TO_STRING;
9210 to = valuePop(ctxt);
9211 CAST_TO_STRING;
9212 from = valuePop(ctxt);
9213 CAST_TO_STRING;
9214 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009215
Daniel Veillarde043ee12001-04-16 14:08:07 +00009216 target = xmlBufferCreate();
9217 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009218 max = xmlUTF8Strlen(to->stringval);
9219 for (cptr = str->stringval; (ch=*cptr); ) {
9220 offset = xmlUTF8Strloc(from->stringval, cptr);
9221 if (offset >= 0) {
9222 if (offset < max) {
9223 point = xmlUTF8Strpos(to->stringval, offset);
9224 if (point)
9225 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
9226 }
9227 } else
9228 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9229
9230 /* Step to next character in input */
9231 cptr++;
9232 if ( ch & 0x80 ) {
9233 /* if not simple ascii, verify proper format */
9234 if ( (ch & 0xc0) != 0xc0 ) {
9235 xmlGenericError(xmlGenericErrorContext,
9236 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9237 break;
9238 }
9239 /* then skip over remaining bytes for this char */
9240 while ( (ch <<= 1) & 0x80 )
9241 if ( (*cptr++ & 0xc0) != 0x80 ) {
9242 xmlGenericError(xmlGenericErrorContext,
9243 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9244 break;
9245 }
9246 if (ch & 0x80) /* must have had error encountered */
9247 break;
9248 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00009249 }
Owen Taylor3473f882001-02-23 17:55:21 +00009250 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009251 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9252 xmlBufferContent(target)));
Daniel Veillarde043ee12001-04-16 14:08:07 +00009253 xmlBufferFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009254 xmlXPathReleaseObject(ctxt->context, str);
9255 xmlXPathReleaseObject(ctxt->context, from);
9256 xmlXPathReleaseObject(ctxt->context, to);
Owen Taylor3473f882001-02-23 17:55:21 +00009257}
9258
9259/**
9260 * xmlXPathBooleanFunction:
9261 * @ctxt: the XPath Parser context
9262 * @nargs: the number of arguments
9263 *
9264 * Implement the boolean() XPath function
9265 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00009266 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00009267 * - a number is true if and only if it is neither positive or
9268 * negative zero nor NaN
9269 * - a node-set is true if and only if it is non-empty
9270 * - a string is true if and only if its length is non-zero
9271 */
9272void
9273xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9274 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00009275
9276 CHECK_ARITY(1);
9277 cur = valuePop(ctxt);
9278 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009279 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009280 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009281}
9282
9283/**
9284 * xmlXPathNotFunction:
9285 * @ctxt: the XPath Parser context
9286 * @nargs: the number of arguments
9287 *
9288 * Implement the not() XPath function
9289 * boolean not(boolean)
9290 * The not function returns true if its argument is false,
9291 * and false otherwise.
9292 */
9293void
9294xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9295 CHECK_ARITY(1);
9296 CAST_TO_BOOLEAN;
9297 CHECK_TYPE(XPATH_BOOLEAN);
9298 ctxt->value->boolval = ! ctxt->value->boolval;
9299}
9300
9301/**
9302 * xmlXPathTrueFunction:
9303 * @ctxt: the XPath Parser context
9304 * @nargs: the number of arguments
9305 *
9306 * Implement the true() XPath function
9307 * boolean true()
9308 */
9309void
9310xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9311 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009312 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009313}
9314
9315/**
9316 * xmlXPathFalseFunction:
9317 * @ctxt: the XPath Parser context
9318 * @nargs: the number of arguments
9319 *
9320 * Implement the false() XPath function
9321 * boolean false()
9322 */
9323void
9324xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9325 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009326 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009327}
9328
9329/**
9330 * xmlXPathLangFunction:
9331 * @ctxt: the XPath Parser context
9332 * @nargs: the number of arguments
9333 *
9334 * Implement the lang() XPath function
9335 * boolean lang(string)
9336 * The lang function returns true or false depending on whether the
9337 * language of the context node as specified by xml:lang attributes
9338 * is the same as or is a sublanguage of the language specified by
9339 * the argument string. The language of the context node is determined
9340 * by the value of the xml:lang attribute on the context node, or, if
9341 * the context node has no xml:lang attribute, by the value of the
9342 * xml:lang attribute on the nearest ancestor of the context node that
9343 * has an xml:lang attribute. If there is no such attribute, then lang
9344 * returns false. If there is such an attribute, then lang returns
9345 * true if the attribute value is equal to the argument ignoring case,
9346 * or if there is some suffix starting with - such that the attribute
9347 * value is equal to the argument ignoring that suffix of the attribute
9348 * value and ignoring case.
9349 */
9350void
9351xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009352 xmlXPathObjectPtr val = NULL;
9353 const xmlChar *theLang = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009354 const xmlChar *lang;
9355 int ret = 0;
9356 int i;
9357
9358 CHECK_ARITY(1);
9359 CAST_TO_STRING;
9360 CHECK_TYPE(XPATH_STRING);
9361 val = valuePop(ctxt);
9362 lang = val->stringval;
9363 theLang = xmlNodeGetLang(ctxt->context->node);
9364 if ((theLang != NULL) && (lang != NULL)) {
9365 for (i = 0;lang[i] != 0;i++)
9366 if (toupper(lang[i]) != toupper(theLang[i]))
9367 goto not_equal;
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009368 if ((theLang[i] == 0) || (theLang[i] == '-'))
9369 ret = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009370 }
9371not_equal:
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009372 if (theLang != NULL)
9373 xmlFree((void *)theLang);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009374
9375 xmlXPathReleaseObject(ctxt->context, val);
9376 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009377}
9378
9379/**
9380 * xmlXPathNumberFunction:
9381 * @ctxt: the XPath Parser context
9382 * @nargs: the number of arguments
9383 *
9384 * Implement the number() XPath function
9385 * number number(object?)
9386 */
9387void
9388xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9389 xmlXPathObjectPtr cur;
9390 double res;
9391
Daniel Veillarda82b1822004-11-08 16:24:57 +00009392 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009393 if (nargs == 0) {
9394 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009395 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
Owen Taylor3473f882001-02-23 17:55:21 +00009396 } else {
9397 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9398
9399 res = xmlXPathStringEvalNumber(content);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009400 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
Owen Taylor3473f882001-02-23 17:55:21 +00009401 xmlFree(content);
9402 }
9403 return;
9404 }
9405
9406 CHECK_ARITY(1);
9407 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009408 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00009409}
9410
9411/**
9412 * xmlXPathSumFunction:
9413 * @ctxt: the XPath Parser context
9414 * @nargs: the number of arguments
9415 *
9416 * Implement the sum() XPath function
9417 * number sum(node-set)
9418 * The sum function returns the sum of the values of the nodes in
9419 * the argument node-set.
9420 */
9421void
9422xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9423 xmlXPathObjectPtr cur;
9424 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009425 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00009426
9427 CHECK_ARITY(1);
9428 if ((ctxt->value == NULL) ||
9429 ((ctxt->value->type != XPATH_NODESET) &&
9430 (ctxt->value->type != XPATH_XSLT_TREE)))
9431 XP_ERROR(XPATH_INVALID_TYPE);
9432 cur = valuePop(ctxt);
9433
William M. Brack08171912003-12-29 02:52:11 +00009434 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009435 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9436 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00009437 }
9438 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009439 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9440 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009441}
9442
William M. Brack3d426662005-04-19 14:40:28 +00009443/*
9444 * To assure working code on multiple platforms, we want to only depend
9445 * upon the characteristic truncation of converting a floating point value
9446 * to an integer. Unfortunately, because of the different storage sizes
9447 * of our internal floating point value (double) and integer (int), we
9448 * can't directly convert (see bug 301162). This macro is a messy
9449 * 'workaround'
9450 */
9451#define XTRUNC(f, v) \
9452 f = fmod((v), INT_MAX); \
9453 f = (v) - (f) + (double)((int)(f));
9454
Owen Taylor3473f882001-02-23 17:55:21 +00009455/**
9456 * xmlXPathFloorFunction:
9457 * @ctxt: the XPath Parser context
9458 * @nargs: the number of arguments
9459 *
9460 * Implement the floor() XPath function
9461 * number floor(number)
9462 * The floor function returns the largest (closest to positive infinity)
9463 * number that is not greater than the argument and that is an integer.
9464 */
9465void
9466xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009467 double f;
9468
Owen Taylor3473f882001-02-23 17:55:21 +00009469 CHECK_ARITY(1);
9470 CAST_TO_NUMBER;
9471 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009472
William M. Brack3d426662005-04-19 14:40:28 +00009473 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009474 if (f != ctxt->value->floatval) {
9475 if (ctxt->value->floatval > 0)
9476 ctxt->value->floatval = f;
9477 else
9478 ctxt->value->floatval = f - 1;
9479 }
Owen Taylor3473f882001-02-23 17:55:21 +00009480}
9481
9482/**
9483 * xmlXPathCeilingFunction:
9484 * @ctxt: the XPath Parser context
9485 * @nargs: the number of arguments
9486 *
9487 * Implement the ceiling() XPath function
9488 * number ceiling(number)
9489 * The ceiling function returns the smallest (closest to negative infinity)
9490 * number that is not less than the argument and that is an integer.
9491 */
9492void
9493xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9494 double f;
9495
9496 CHECK_ARITY(1);
9497 CAST_TO_NUMBER;
9498 CHECK_TYPE(XPATH_NUMBER);
9499
9500#if 0
9501 ctxt->value->floatval = ceil(ctxt->value->floatval);
9502#else
William M. Brack3d426662005-04-19 14:40:28 +00009503 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009504 if (f != ctxt->value->floatval) {
9505 if (ctxt->value->floatval > 0)
9506 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009507 else {
9508 if (ctxt->value->floatval < 0 && f == 0)
9509 ctxt->value->floatval = xmlXPathNZERO;
9510 else
9511 ctxt->value->floatval = f;
9512 }
9513
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009514 }
Owen Taylor3473f882001-02-23 17:55:21 +00009515#endif
9516}
9517
9518/**
9519 * xmlXPathRoundFunction:
9520 * @ctxt: the XPath Parser context
9521 * @nargs: the number of arguments
9522 *
9523 * Implement the round() XPath function
9524 * number round(number)
9525 * The round function returns the number that is closest to the
9526 * argument and that is an integer. If there are two such numbers,
9527 * then the one that is even is returned.
9528 */
9529void
9530xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9531 double f;
9532
9533 CHECK_ARITY(1);
9534 CAST_TO_NUMBER;
9535 CHECK_TYPE(XPATH_NUMBER);
9536
Daniel Veillardcda96922001-08-21 10:56:31 +00009537 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9538 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9539 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009540 (ctxt->value->floatval == 0.0))
9541 return;
9542
William M. Brack3d426662005-04-19 14:40:28 +00009543 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009544 if (ctxt->value->floatval < 0) {
9545 if (ctxt->value->floatval < f - 0.5)
9546 ctxt->value->floatval = f - 1;
9547 else
9548 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009549 if (ctxt->value->floatval == 0)
9550 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009551 } else {
9552 if (ctxt->value->floatval < f + 0.5)
9553 ctxt->value->floatval = f;
9554 else
9555 ctxt->value->floatval = f + 1;
9556 }
Owen Taylor3473f882001-02-23 17:55:21 +00009557}
9558
9559/************************************************************************
9560 * *
9561 * The Parser *
9562 * *
9563 ************************************************************************/
9564
9565/*
William M. Brack08171912003-12-29 02:52:11 +00009566 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00009567 * implementation.
9568 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009569static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009570static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009571static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009572static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00009573static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9574 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00009575
9576/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00009577 * xmlXPathCurrentChar:
9578 * @ctxt: the XPath parser context
9579 * @cur: pointer to the beginning of the char
9580 * @len: pointer to the length of the char read
9581 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009582 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00009583 * bytes in the input buffer.
9584 *
Daniel Veillard60087f32001-10-10 09:45:09 +00009585 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00009586 */
9587
9588static int
9589xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9590 unsigned char c;
9591 unsigned int val;
9592 const xmlChar *cur;
9593
9594 if (ctxt == NULL)
9595 return(0);
9596 cur = ctxt->cur;
9597
9598 /*
9599 * We are supposed to handle UTF8, check it's valid
9600 * From rfc2044: encoding of the Unicode values on UTF-8:
9601 *
9602 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9603 * 0000 0000-0000 007F 0xxxxxxx
9604 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
9605 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
9606 *
9607 * Check for the 0x110000 limit too
9608 */
9609 c = *cur;
9610 if (c & 0x80) {
9611 if ((cur[1] & 0xc0) != 0x80)
9612 goto encoding_error;
9613 if ((c & 0xe0) == 0xe0) {
9614
9615 if ((cur[2] & 0xc0) != 0x80)
9616 goto encoding_error;
9617 if ((c & 0xf0) == 0xf0) {
9618 if (((c & 0xf8) != 0xf0) ||
9619 ((cur[3] & 0xc0) != 0x80))
9620 goto encoding_error;
9621 /* 4-byte code */
9622 *len = 4;
9623 val = (cur[0] & 0x7) << 18;
9624 val |= (cur[1] & 0x3f) << 12;
9625 val |= (cur[2] & 0x3f) << 6;
9626 val |= cur[3] & 0x3f;
9627 } else {
9628 /* 3-byte code */
9629 *len = 3;
9630 val = (cur[0] & 0xf) << 12;
9631 val |= (cur[1] & 0x3f) << 6;
9632 val |= cur[2] & 0x3f;
9633 }
9634 } else {
9635 /* 2-byte code */
9636 *len = 2;
9637 val = (cur[0] & 0x1f) << 6;
9638 val |= cur[1] & 0x3f;
9639 }
9640 if (!IS_CHAR(val)) {
9641 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9642 }
9643 return(val);
9644 } else {
9645 /* 1-byte code */
9646 *len = 1;
9647 return((int) *cur);
9648 }
9649encoding_error:
9650 /*
William M. Brack08171912003-12-29 02:52:11 +00009651 * If we detect an UTF8 error that probably means that the
9652 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00009653 * declaration header. Report the error and switch the encoding
9654 * to ISO-Latin-1 (if you don't like this policy, just declare the
9655 * encoding !)
9656 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00009657 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00009658 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009659}
9660
9661/**
Owen Taylor3473f882001-02-23 17:55:21 +00009662 * xmlXPathParseNCName:
9663 * @ctxt: the XPath Parser context
9664 *
9665 * parse an XML namespace non qualified name.
9666 *
9667 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9668 *
9669 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9670 * CombiningChar | Extender
9671 *
9672 * Returns the namespace name or NULL
9673 */
9674
9675xmlChar *
9676xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00009677 const xmlChar *in;
9678 xmlChar *ret;
9679 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009680
Daniel Veillarda82b1822004-11-08 16:24:57 +00009681 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00009682 /*
9683 * Accelerator for simple ASCII names
9684 */
9685 in = ctxt->cur;
9686 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9687 ((*in >= 0x41) && (*in <= 0x5A)) ||
9688 (*in == '_')) {
9689 in++;
9690 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9691 ((*in >= 0x41) && (*in <= 0x5A)) ||
9692 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00009693 (*in == '_') || (*in == '.') ||
9694 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00009695 in++;
9696 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9697 (*in == '[') || (*in == ']') || (*in == ':') ||
9698 (*in == '@') || (*in == '*')) {
9699 count = in - ctxt->cur;
9700 if (count == 0)
9701 return(NULL);
9702 ret = xmlStrndup(ctxt->cur, count);
9703 ctxt->cur = in;
9704 return(ret);
9705 }
9706 }
9707 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009708}
9709
Daniel Veillard2156a562001-04-28 12:24:34 +00009710
Owen Taylor3473f882001-02-23 17:55:21 +00009711/**
9712 * xmlXPathParseQName:
9713 * @ctxt: the XPath Parser context
9714 * @prefix: a xmlChar **
9715 *
9716 * parse an XML qualified name
9717 *
9718 * [NS 5] QName ::= (Prefix ':')? LocalPart
9719 *
9720 * [NS 6] Prefix ::= NCName
9721 *
9722 * [NS 7] LocalPart ::= NCName
9723 *
9724 * Returns the function returns the local part, and prefix is updated
9725 * to get the Prefix if any.
9726 */
9727
Daniel Veillard56a4cb82001-03-24 17:00:36 +00009728static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00009729xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9730 xmlChar *ret = NULL;
9731
9732 *prefix = NULL;
9733 ret = xmlXPathParseNCName(ctxt);
9734 if (CUR == ':') {
9735 *prefix = ret;
9736 NEXT;
9737 ret = xmlXPathParseNCName(ctxt);
9738 }
9739 return(ret);
9740}
9741
9742/**
9743 * xmlXPathParseName:
9744 * @ctxt: the XPath Parser context
9745 *
9746 * parse an XML name
9747 *
9748 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9749 * CombiningChar | Extender
9750 *
9751 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9752 *
9753 * Returns the namespace name or NULL
9754 */
9755
9756xmlChar *
9757xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009758 const xmlChar *in;
9759 xmlChar *ret;
9760 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009761
Daniel Veillarda82b1822004-11-08 16:24:57 +00009762 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009763 /*
9764 * Accelerator for simple ASCII names
9765 */
9766 in = ctxt->cur;
9767 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9768 ((*in >= 0x41) && (*in <= 0x5A)) ||
9769 (*in == '_') || (*in == ':')) {
9770 in++;
9771 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9772 ((*in >= 0x41) && (*in <= 0x5A)) ||
9773 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00009774 (*in == '_') || (*in == '-') ||
9775 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00009776 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00009777 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009778 count = in - ctxt->cur;
9779 ret = xmlStrndup(ctxt->cur, count);
9780 ctxt->cur = in;
9781 return(ret);
9782 }
9783 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009784 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009785}
9786
Daniel Veillard61d80a22001-04-27 17:13:01 +00009787static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00009788xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009789 xmlChar buf[XML_MAX_NAMELEN + 5];
9790 int len = 0, l;
9791 int c;
9792
9793 /*
9794 * Handler for more complex cases
9795 */
9796 c = CUR_CHAR(l);
9797 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00009798 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9799 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00009800 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00009801 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009802 return(NULL);
9803 }
9804
9805 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9806 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9807 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00009808 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009809 (IS_COMBINING(c)) ||
9810 (IS_EXTENDER(c)))) {
9811 COPY_BUF(l,buf,len,c);
9812 NEXTL(l);
9813 c = CUR_CHAR(l);
9814 if (len >= XML_MAX_NAMELEN) {
9815 /*
9816 * Okay someone managed to make a huge name, so he's ready to pay
9817 * for the processing speed.
9818 */
9819 xmlChar *buffer;
9820 int max = len * 2;
9821
Daniel Veillard3c908dc2003-04-19 00:07:51 +00009822 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009823 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009824 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009825 }
9826 memcpy(buffer, buf, len);
9827 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9828 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00009829 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009830 (IS_COMBINING(c)) ||
9831 (IS_EXTENDER(c))) {
9832 if (len + 10 > max) {
9833 max *= 2;
9834 buffer = (xmlChar *) xmlRealloc(buffer,
9835 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009836 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009837 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009838 }
9839 }
9840 COPY_BUF(l,buffer,len,c);
9841 NEXTL(l);
9842 c = CUR_CHAR(l);
9843 }
9844 buffer[len] = 0;
9845 return(buffer);
9846 }
9847 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009848 if (len == 0)
9849 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009850 return(xmlStrndup(buf, len));
9851}
Daniel Veillard3cd72402002-05-13 10:33:30 +00009852
9853#define MAX_FRAC 20
9854
William M. Brack372a4452004-02-17 13:09:23 +00009855/*
9856 * These are used as divisors for the fractional part of a number.
9857 * Since the table includes 1.0 (representing '0' fractional digits),
9858 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
9859 */
9860static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +00009861 1.0, 10.0, 100.0, 1000.0, 10000.0,
9862 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
9863 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
9864 100000000000000.0,
9865 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +00009866 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +00009867};
9868
Owen Taylor3473f882001-02-23 17:55:21 +00009869/**
9870 * xmlXPathStringEvalNumber:
9871 * @str: A string to scan
9872 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00009873 * [30a] Float ::= Number ('e' Digits?)?
9874 *
Owen Taylor3473f882001-02-23 17:55:21 +00009875 * [30] Number ::= Digits ('.' Digits?)?
9876 * | '.' Digits
9877 * [31] Digits ::= [0-9]+
9878 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009879 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00009880 * In complement of the Number expression, this function also handles
9881 * negative values : '-' Number.
9882 *
9883 * Returns the double value.
9884 */
9885double
9886xmlXPathStringEvalNumber(const xmlChar *str) {
9887 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00009888 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009889 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009890 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009891 int exponent = 0;
9892 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009893#ifdef __GNUC__
9894 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00009895 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009896#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00009897 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00009898 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009899 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9900 return(xmlXPathNAN);
9901 }
9902 if (*cur == '-') {
9903 isneg = 1;
9904 cur++;
9905 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00009906
9907#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009908 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00009909 * tmp/temp is a workaround against a gcc compiler bug
9910 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009911 */
Daniel Veillard7b416132002-03-07 08:36:03 +00009912 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009913 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00009914 ret = ret * 10;
9915 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00009916 ok = 1;
9917 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00009918 temp = (double) tmp;
9919 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00009920 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00009921#else
Daniel Veillard7b416132002-03-07 08:36:03 +00009922 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009923 while ((*cur >= '0') && (*cur <= '9')) {
9924 ret = ret * 10 + (*cur - '0');
9925 ok = 1;
9926 cur++;
9927 }
9928#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009929
Owen Taylor3473f882001-02-23 17:55:21 +00009930 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00009931 int v, frac = 0;
9932 double fraction = 0;
9933
Owen Taylor3473f882001-02-23 17:55:21 +00009934 cur++;
9935 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
9936 return(xmlXPathNAN);
9937 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00009938 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
9939 v = (*cur - '0');
9940 fraction = fraction * 10 + v;
9941 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009942 cur++;
9943 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00009944 fraction /= my_pow10[frac];
9945 ret = ret + fraction;
9946 while ((*cur >= '0') && (*cur <= '9'))
9947 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009948 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00009949 if ((*cur == 'e') || (*cur == 'E')) {
9950 cur++;
9951 if (*cur == '-') {
9952 is_exponent_negative = 1;
9953 cur++;
William M. Brack99127052004-05-24 02:52:28 +00009954 } else if (*cur == '+') {
9955 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009956 }
9957 while ((*cur >= '0') && (*cur <= '9')) {
9958 exponent = exponent * 10 + (*cur - '0');
9959 cur++;
9960 }
9961 }
William M. Brack76e95df2003-10-18 16:20:14 +00009962 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009963 if (*cur != 0) return(xmlXPathNAN);
9964 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009965 if (is_exponent_negative) exponent = -exponent;
9966 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00009967 return(ret);
9968}
9969
9970/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009971 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00009972 * @ctxt: the XPath Parser context
9973 *
9974 * [30] Number ::= Digits ('.' Digits?)?
9975 * | '.' Digits
9976 * [31] Digits ::= [0-9]+
9977 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009978 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00009979 *
9980 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009981static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009982xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
9983{
Owen Taylor3473f882001-02-23 17:55:21 +00009984 double ret = 0.0;
9985 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00009986 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009987 int exponent = 0;
9988 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00009989#ifdef __GNUC__
9990 unsigned long tmp = 0;
9991 double temp;
9992#endif
Owen Taylor3473f882001-02-23 17:55:21 +00009993
9994 CHECK_ERROR;
9995 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
9996 XP_ERROR(XPATH_NUMBER_ERROR);
9997 }
Daniel Veillard7b416132002-03-07 08:36:03 +00009998#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009999 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010000 * tmp/temp is a workaround against a gcc compiler bug
10001 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010002 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010003 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010004 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010005 ret = ret * 10;
10006 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010007 ok = 1;
10008 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +000010009 temp = (double) tmp;
10010 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010011 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010012#else
10013 ret = 0;
10014 while ((CUR >= '0') && (CUR <= '9')) {
10015 ret = ret * 10 + (CUR - '0');
10016 ok = 1;
10017 NEXT;
10018 }
10019#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010020 if (CUR == '.') {
10021 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010022 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10023 XP_ERROR(XPATH_NUMBER_ERROR);
10024 }
10025 while ((CUR >= '0') && (CUR <= '9')) {
10026 mult /= 10;
10027 ret = ret + (CUR - '0') * mult;
10028 NEXT;
10029 }
Owen Taylor3473f882001-02-23 17:55:21 +000010030 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010031 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010032 NEXT;
10033 if (CUR == '-') {
10034 is_exponent_negative = 1;
10035 NEXT;
William M. Brack99127052004-05-24 02:52:28 +000010036 } else if (CUR == '+') {
10037 NEXT;
10038 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010039 while ((CUR >= '0') && (CUR <= '9')) {
10040 exponent = exponent * 10 + (CUR - '0');
10041 NEXT;
10042 }
10043 if (is_exponent_negative)
10044 exponent = -exponent;
10045 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +000010046 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010047 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010048 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010049}
10050
10051/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010052 * xmlXPathParseLiteral:
10053 * @ctxt: the XPath Parser context
10054 *
10055 * Parse a Literal
10056 *
10057 * [29] Literal ::= '"' [^"]* '"'
10058 * | "'" [^']* "'"
10059 *
10060 * Returns the value found or NULL in case of error
10061 */
10062static xmlChar *
10063xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10064 const xmlChar *q;
10065 xmlChar *ret = NULL;
10066
10067 if (CUR == '"') {
10068 NEXT;
10069 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010070 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010071 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010072 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010073 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010074 } else {
10075 ret = xmlStrndup(q, CUR_PTR - q);
10076 NEXT;
10077 }
10078 } else if (CUR == '\'') {
10079 NEXT;
10080 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010081 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010082 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010083 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010084 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010085 } else {
10086 ret = xmlStrndup(q, CUR_PTR - q);
10087 NEXT;
10088 }
10089 } else {
Daniel Veillard24505b02005-07-28 23:49:35 +000010090 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010091 }
10092 return(ret);
10093}
10094
10095/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010096 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +000010097 * @ctxt: the XPath Parser context
10098 *
10099 * Parse a Literal and push it on the stack.
10100 *
10101 * [29] Literal ::= '"' [^"]* '"'
10102 * | "'" [^']* "'"
10103 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010104 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +000010105 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010106static void
10107xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010108 const xmlChar *q;
10109 xmlChar *ret = NULL;
10110
10111 if (CUR == '"') {
10112 NEXT;
10113 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010114 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +000010115 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010116 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010117 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10118 } else {
10119 ret = xmlStrndup(q, CUR_PTR - q);
10120 NEXT;
10121 }
10122 } else if (CUR == '\'') {
10123 NEXT;
10124 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010125 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +000010126 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010127 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010128 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10129 } else {
10130 ret = xmlStrndup(q, CUR_PTR - q);
10131 NEXT;
10132 }
10133 } else {
10134 XP_ERROR(XPATH_START_LITERAL_ERROR);
10135 }
10136 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010137 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010138 xmlXPathCacheNewString(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010139 xmlFree(ret);
10140}
10141
10142/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010143 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +000010144 * @ctxt: the XPath Parser context
10145 *
10146 * Parse a VariableReference, evaluate it and push it on the stack.
10147 *
10148 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +000010149 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +000010150 * of any of the types that are possible for the value of an expression,
10151 * and may also be of additional types not specified here.
10152 *
10153 * Early evaluation is possible since:
10154 * The variable bindings [...] used to evaluate a subexpression are
10155 * always the same as those used to evaluate the containing expression.
10156 *
10157 * [36] VariableReference ::= '$' QName
10158 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010159static void
10160xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010161 xmlChar *name;
10162 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010163
10164 SKIP_BLANKS;
10165 if (CUR != '$') {
10166 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10167 }
10168 NEXT;
10169 name = xmlXPathParseQName(ctxt, &prefix);
10170 if (name == NULL) {
10171 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10172 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010173 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010174 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10175 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010176 SKIP_BLANKS;
Daniel Veillardb3d14912005-09-04 20:47:39 +000010177 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10178 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
10179 }
Owen Taylor3473f882001-02-23 17:55:21 +000010180}
10181
10182/**
10183 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +000010184 * @name: a name string
10185 *
10186 * Is the name given a NodeType one.
10187 *
10188 * [38] NodeType ::= 'comment'
10189 * | 'text'
10190 * | 'processing-instruction'
10191 * | 'node'
10192 *
10193 * Returns 1 if true 0 otherwise
10194 */
10195int
10196xmlXPathIsNodeType(const xmlChar *name) {
10197 if (name == NULL)
10198 return(0);
10199
Daniel Veillard1971ee22002-01-31 20:29:19 +000010200 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +000010201 return(1);
10202 if (xmlStrEqual(name, BAD_CAST "text"))
10203 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010204 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +000010205 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010206 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +000010207 return(1);
10208 return(0);
10209}
10210
10211/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010212 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +000010213 * @ctxt: the XPath Parser context
10214 *
10215 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10216 * [17] Argument ::= Expr
10217 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010218 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +000010219 * pushed on the stack
10220 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010221static void
10222xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010223 xmlChar *name;
10224 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010225 int nbargs = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010226 int sort = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010227
10228 name = xmlXPathParseQName(ctxt, &prefix);
10229 if (name == NULL) {
10230 XP_ERROR(XPATH_EXPR_ERROR);
10231 }
10232 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010233#ifdef DEBUG_EXPR
10234 if (prefix == NULL)
10235 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10236 name);
10237 else
10238 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10239 prefix, name);
10240#endif
10241
Owen Taylor3473f882001-02-23 17:55:21 +000010242 if (CUR != '(') {
10243 XP_ERROR(XPATH_EXPR_ERROR);
10244 }
10245 NEXT;
10246 SKIP_BLANKS;
10247
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010248 /*
10249 * Optimization for count(): we don't need the node-set to be sorted.
10250 */
10251 if ((prefix == NULL) && (name[0] == 'c') &&
10252 xmlStrEqual(name, BAD_CAST "count"))
10253 {
10254 sort = 0;
10255 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010256 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +000010257 if (CUR != ')') {
10258 while (CUR != 0) {
10259 int op1 = ctxt->comp->last;
10260 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010261 xmlXPathCompileExpr(ctxt, sort);
Daniel Veillard71f9d732003-01-14 16:07:16 +000010262 CHECK_ERROR;
10263 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10264 nbargs++;
10265 if (CUR == ')') break;
10266 if (CUR != ',') {
10267 XP_ERROR(XPATH_EXPR_ERROR);
10268 }
10269 NEXT;
10270 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010271 }
Owen Taylor3473f882001-02-23 17:55:21 +000010272 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010273 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10274 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010275 NEXT;
10276 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010277}
10278
10279/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010280 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010281 * @ctxt: the XPath Parser context
10282 *
10283 * [15] PrimaryExpr ::= VariableReference
10284 * | '(' Expr ')'
10285 * | Literal
10286 * | Number
10287 * | FunctionCall
10288 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010289 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010290 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010291static void
10292xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010293 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010294 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010295 else if (CUR == '(') {
10296 NEXT;
10297 SKIP_BLANKS;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010298 xmlXPathCompileExpr(ctxt, 1);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010299 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000010300 if (CUR != ')') {
10301 XP_ERROR(XPATH_EXPR_ERROR);
10302 }
10303 NEXT;
10304 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010305 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010306 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010307 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010308 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010309 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010310 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010311 }
10312 SKIP_BLANKS;
10313}
10314
10315/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010316 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010317 * @ctxt: the XPath Parser context
10318 *
10319 * [20] FilterExpr ::= PrimaryExpr
10320 * | FilterExpr Predicate
10321 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010322 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010323 * Square brackets are used to filter expressions in the same way that
10324 * they are used in location paths. It is an error if the expression to
10325 * be filtered does not evaluate to a node-set. The context node list
10326 * used for evaluating the expression in square brackets is the node-set
10327 * to be filtered listed in document order.
10328 */
10329
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010330static void
10331xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10332 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010333 CHECK_ERROR;
10334 SKIP_BLANKS;
10335
10336 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010337 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +000010338 SKIP_BLANKS;
10339 }
10340
10341
10342}
10343
10344/**
10345 * xmlXPathScanName:
10346 * @ctxt: the XPath Parser context
10347 *
10348 * Trickery: parse an XML name but without consuming the input flow
10349 * Needed to avoid insanity in the parser state.
10350 *
10351 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10352 * CombiningChar | Extender
10353 *
10354 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10355 *
10356 * [6] Names ::= Name (S Name)*
10357 *
10358 * Returns the Name parsed or NULL
10359 */
10360
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010361static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +000010362xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +000010363 int len = 0, l;
10364 int c;
Daniel Veillard03226812004-11-01 14:55:21 +000010365 const xmlChar *cur;
10366 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +000010367
Daniel Veillard03226812004-11-01 14:55:21 +000010368 cur = ctxt->cur;
10369
10370 c = CUR_CHAR(l);
10371 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10372 (!IS_LETTER(c) && (c != '_') &&
10373 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010374 return(NULL);
10375 }
10376
Daniel Veillard03226812004-11-01 14:55:21 +000010377 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10378 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10379 (c == '.') || (c == '-') ||
10380 (c == '_') || (c == ':') ||
10381 (IS_COMBINING(c)) ||
10382 (IS_EXTENDER(c)))) {
10383 len += l;
10384 NEXTL(l);
10385 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +000010386 }
Daniel Veillard03226812004-11-01 14:55:21 +000010387 ret = xmlStrndup(cur, ctxt->cur - cur);
10388 ctxt->cur = cur;
10389 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +000010390}
10391
10392/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010393 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010394 * @ctxt: the XPath Parser context
10395 *
10396 * [19] PathExpr ::= LocationPath
10397 * | FilterExpr
10398 * | FilterExpr '/' RelativeLocationPath
10399 * | FilterExpr '//' RelativeLocationPath
10400 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010401 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010402 * The / operator and // operators combine an arbitrary expression
10403 * and a relative location path. It is an error if the expression
10404 * does not evaluate to a node-set.
10405 * The / operator does composition in the same way as when / is
10406 * used in a location path. As in location paths, // is short for
10407 * /descendant-or-self::node()/.
10408 */
10409
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010410static void
10411xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010412 int lc = 1; /* Should we branch to LocationPath ? */
10413 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10414
10415 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010416 if ((CUR == '$') || (CUR == '(') ||
10417 (IS_ASCII_DIGIT(CUR)) ||
10418 (CUR == '\'') || (CUR == '"') ||
10419 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010420 lc = 0;
10421 } else if (CUR == '*') {
10422 /* relative or absolute location path */
10423 lc = 1;
10424 } else if (CUR == '/') {
10425 /* relative or absolute location path */
10426 lc = 1;
10427 } else if (CUR == '@') {
10428 /* relative abbreviated attribute location path */
10429 lc = 1;
10430 } else if (CUR == '.') {
10431 /* relative abbreviated attribute location path */
10432 lc = 1;
10433 } else {
10434 /*
10435 * Problem is finding if we have a name here whether it's:
10436 * - a nodetype
10437 * - a function call in which case it's followed by '('
10438 * - an axis in which case it's followed by ':'
10439 * - a element name
10440 * We do an a priori analysis here rather than having to
10441 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +000010442 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +000010443 * read/write/debug.
10444 */
10445 SKIP_BLANKS;
10446 name = xmlXPathScanName(ctxt);
10447 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10448#ifdef DEBUG_STEP
10449 xmlGenericError(xmlGenericErrorContext,
10450 "PathExpr: Axis\n");
10451#endif
10452 lc = 1;
10453 xmlFree(name);
10454 } else if (name != NULL) {
10455 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +000010456
10457
10458 while (NXT(len) != 0) {
10459 if (NXT(len) == '/') {
10460 /* element name */
10461#ifdef DEBUG_STEP
10462 xmlGenericError(xmlGenericErrorContext,
10463 "PathExpr: AbbrRelLocation\n");
10464#endif
10465 lc = 1;
10466 break;
William M. Brack76e95df2003-10-18 16:20:14 +000010467 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +000010468 /* ignore blanks */
10469 ;
Owen Taylor3473f882001-02-23 17:55:21 +000010470 } else if (NXT(len) == ':') {
10471#ifdef DEBUG_STEP
10472 xmlGenericError(xmlGenericErrorContext,
10473 "PathExpr: AbbrRelLocation\n");
10474#endif
10475 lc = 1;
10476 break;
10477 } else if ((NXT(len) == '(')) {
10478 /* Note Type or Function */
10479 if (xmlXPathIsNodeType(name)) {
10480#ifdef DEBUG_STEP
10481 xmlGenericError(xmlGenericErrorContext,
10482 "PathExpr: Type search\n");
10483#endif
10484 lc = 1;
10485 } else {
10486#ifdef DEBUG_STEP
10487 xmlGenericError(xmlGenericErrorContext,
10488 "PathExpr: function call\n");
10489#endif
10490 lc = 0;
10491 }
10492 break;
10493 } else if ((NXT(len) == '[')) {
10494 /* element name */
10495#ifdef DEBUG_STEP
10496 xmlGenericError(xmlGenericErrorContext,
10497 "PathExpr: AbbrRelLocation\n");
10498#endif
10499 lc = 1;
10500 break;
10501 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10502 (NXT(len) == '=')) {
10503 lc = 1;
10504 break;
10505 } else {
10506 lc = 1;
10507 break;
10508 }
10509 len++;
10510 }
10511 if (NXT(len) == 0) {
10512#ifdef DEBUG_STEP
10513 xmlGenericError(xmlGenericErrorContext,
10514 "PathExpr: AbbrRelLocation\n");
10515#endif
10516 /* element name */
10517 lc = 1;
10518 }
10519 xmlFree(name);
10520 } else {
William M. Brack08171912003-12-29 02:52:11 +000010521 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +000010522 XP_ERROR(XPATH_EXPR_ERROR);
10523 }
10524 }
10525
10526 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010527 if (CUR == '/') {
10528 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10529 } else {
10530 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010531 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010532 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010533 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010534 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010535 CHECK_ERROR;
10536 if ((CUR == '/') && (NXT(1) == '/')) {
10537 SKIP(2);
10538 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010539
10540 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10541 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10542 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10543
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010544 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010545 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010546 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010547 }
10548 }
10549 SKIP_BLANKS;
10550}
10551
10552/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010553 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010554 * @ctxt: the XPath Parser context
10555 *
10556 * [18] UnionExpr ::= PathExpr
10557 * | UnionExpr '|' PathExpr
10558 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010559 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010560 */
10561
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010562static void
10563xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10564 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010565 CHECK_ERROR;
10566 SKIP_BLANKS;
10567 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010568 int op1 = ctxt->comp->last;
10569 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010570
10571 NEXT;
10572 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010573 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010574
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010575 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10576
Owen Taylor3473f882001-02-23 17:55:21 +000010577 SKIP_BLANKS;
10578 }
Owen Taylor3473f882001-02-23 17:55:21 +000010579}
10580
10581/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010582 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010583 * @ctxt: the XPath Parser context
10584 *
10585 * [27] UnaryExpr ::= UnionExpr
10586 * | '-' UnaryExpr
10587 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010588 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010589 */
10590
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010591static void
10592xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010593 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010594 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010595
10596 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +000010597 while (CUR == '-') {
10598 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010599 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010600 NEXT;
10601 SKIP_BLANKS;
10602 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010603
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010604 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010605 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010606 if (found) {
10607 if (minus)
10608 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10609 else
10610 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010611 }
10612}
10613
10614/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010615 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010616 * @ctxt: the XPath Parser context
10617 *
10618 * [26] MultiplicativeExpr ::= UnaryExpr
10619 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10620 * | MultiplicativeExpr 'div' UnaryExpr
10621 * | MultiplicativeExpr 'mod' UnaryExpr
10622 * [34] MultiplyOperator ::= '*'
10623 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010624 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010625 */
10626
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010627static void
10628xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10629 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010630 CHECK_ERROR;
10631 SKIP_BLANKS;
10632 while ((CUR == '*') ||
10633 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10634 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10635 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010636 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010637
10638 if (CUR == '*') {
10639 op = 0;
10640 NEXT;
10641 } else if (CUR == 'd') {
10642 op = 1;
10643 SKIP(3);
10644 } else if (CUR == 'm') {
10645 op = 2;
10646 SKIP(3);
10647 }
10648 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010649 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010650 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010651 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010652 SKIP_BLANKS;
10653 }
10654}
10655
10656/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010657 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010658 * @ctxt: the XPath Parser context
10659 *
10660 * [25] AdditiveExpr ::= MultiplicativeExpr
10661 * | AdditiveExpr '+' MultiplicativeExpr
10662 * | AdditiveExpr '-' MultiplicativeExpr
10663 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010664 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010665 */
10666
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010667static void
10668xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010669
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010670 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010671 CHECK_ERROR;
10672 SKIP_BLANKS;
10673 while ((CUR == '+') || (CUR == '-')) {
10674 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010675 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010676
10677 if (CUR == '+') plus = 1;
10678 else plus = 0;
10679 NEXT;
10680 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010681 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010682 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010683 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010684 SKIP_BLANKS;
10685 }
10686}
10687
10688/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010689 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010690 * @ctxt: the XPath Parser context
10691 *
10692 * [24] RelationalExpr ::= AdditiveExpr
10693 * | RelationalExpr '<' AdditiveExpr
10694 * | RelationalExpr '>' AdditiveExpr
10695 * | RelationalExpr '<=' AdditiveExpr
10696 * | RelationalExpr '>=' AdditiveExpr
10697 *
10698 * A <= B > C is allowed ? Answer from James, yes with
10699 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10700 * which is basically what got implemented.
10701 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010702 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +000010703 * on the stack
10704 */
10705
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010706static void
10707xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10708 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010709 CHECK_ERROR;
10710 SKIP_BLANKS;
10711 while ((CUR == '<') ||
10712 (CUR == '>') ||
10713 ((CUR == '<') && (NXT(1) == '=')) ||
10714 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010715 int inf, strict;
10716 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010717
10718 if (CUR == '<') inf = 1;
10719 else inf = 0;
10720 if (NXT(1) == '=') strict = 0;
10721 else strict = 1;
10722 NEXT;
10723 if (!strict) NEXT;
10724 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010725 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010726 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010727 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +000010728 SKIP_BLANKS;
10729 }
10730}
10731
10732/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010733 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010734 * @ctxt: the XPath Parser context
10735 *
10736 * [23] EqualityExpr ::= RelationalExpr
10737 * | EqualityExpr '=' RelationalExpr
10738 * | EqualityExpr '!=' RelationalExpr
10739 *
10740 * A != B != C is allowed ? Answer from James, yes with
10741 * (RelationalExpr = RelationalExpr) = RelationalExpr
10742 * (RelationalExpr != RelationalExpr) != RelationalExpr
10743 * which is basically what got implemented.
10744 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010745 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010746 *
10747 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010748static void
10749xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10750 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010751 CHECK_ERROR;
10752 SKIP_BLANKS;
10753 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010754 int eq;
10755 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010756
10757 if (CUR == '=') eq = 1;
10758 else eq = 0;
10759 NEXT;
10760 if (!eq) NEXT;
10761 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010762 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010763 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010764 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010765 SKIP_BLANKS;
10766 }
10767}
10768
10769/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010770 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010771 * @ctxt: the XPath Parser context
10772 *
10773 * [22] AndExpr ::= EqualityExpr
10774 * | AndExpr 'and' EqualityExpr
10775 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010776 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010777 *
10778 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010779static void
10780xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10781 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010782 CHECK_ERROR;
10783 SKIP_BLANKS;
10784 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010785 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010786 SKIP(3);
10787 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010788 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010789 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010790 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010791 SKIP_BLANKS;
10792 }
10793}
10794
10795/**
Daniel Veillard591b4be2003-02-09 23:33:36 +000010796 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010797 * @ctxt: the XPath Parser context
10798 *
10799 * [14] Expr ::= OrExpr
10800 * [21] OrExpr ::= AndExpr
10801 * | OrExpr 'or' AndExpr
10802 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010803 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +000010804 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010805static void
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010806xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010807 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010808 CHECK_ERROR;
10809 SKIP_BLANKS;
10810 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010811 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010812 SKIP(2);
10813 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010814 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010815 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010816 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10817 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +000010818 SKIP_BLANKS;
10819 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010820 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010821 /* more ops could be optimized too */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010822 /*
10823 * This is the main place to eliminate sorting for
10824 * operations which don't require a sorted node-set.
10825 * E.g. count().
10826 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010827 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10828 }
Owen Taylor3473f882001-02-23 17:55:21 +000010829}
10830
10831/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010832 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +000010833 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010834 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +000010835 *
10836 * [8] Predicate ::= '[' PredicateExpr ']'
10837 * [9] PredicateExpr ::= Expr
10838 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010839 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +000010840 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010841static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010842xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010843 int op1 = ctxt->comp->last;
10844
10845 SKIP_BLANKS;
10846 if (CUR != '[') {
10847 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10848 }
10849 NEXT;
10850 SKIP_BLANKS;
10851
10852 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010853 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010854 CHECK_ERROR;
10855
10856 if (CUR != ']') {
10857 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10858 }
10859
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010860 if (filter)
10861 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10862 else
10863 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010864
10865 NEXT;
10866 SKIP_BLANKS;
10867}
10868
10869/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010870 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +000010871 * @ctxt: the XPath Parser context
10872 * @test: pointer to a xmlXPathTestVal
10873 * @type: pointer to a xmlXPathTypeVal
10874 * @prefix: placeholder for a possible name prefix
10875 *
10876 * [7] NodeTest ::= NameTest
10877 * | NodeType '(' ')'
10878 * | 'processing-instruction' '(' Literal ')'
10879 *
10880 * [37] NameTest ::= '*'
10881 * | NCName ':' '*'
10882 * | QName
10883 * [38] NodeType ::= 'comment'
10884 * | 'text'
10885 * | 'processing-instruction'
10886 * | 'node'
10887 *
William M. Brack08171912003-12-29 02:52:11 +000010888 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +000010889 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010890static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010891xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10892 xmlXPathTypeVal *type, const xmlChar **prefix,
10893 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +000010894 int blanks;
10895
10896 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10897 STRANGE;
10898 return(NULL);
10899 }
William M. Brack78637da2003-07-31 14:47:38 +000010900 *type = (xmlXPathTypeVal) 0;
10901 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010902 *prefix = NULL;
10903 SKIP_BLANKS;
10904
10905 if ((name == NULL) && (CUR == '*')) {
10906 /*
10907 * All elements
10908 */
10909 NEXT;
10910 *test = NODE_TEST_ALL;
10911 return(NULL);
10912 }
10913
10914 if (name == NULL)
10915 name = xmlXPathParseNCName(ctxt);
10916 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010917 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010918 }
10919
William M. Brack76e95df2003-10-18 16:20:14 +000010920 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +000010921 SKIP_BLANKS;
10922 if (CUR == '(') {
10923 NEXT;
10924 /*
10925 * NodeType or PI search
10926 */
10927 if (xmlStrEqual(name, BAD_CAST "comment"))
10928 *type = NODE_TYPE_COMMENT;
10929 else if (xmlStrEqual(name, BAD_CAST "node"))
10930 *type = NODE_TYPE_NODE;
10931 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10932 *type = NODE_TYPE_PI;
10933 else if (xmlStrEqual(name, BAD_CAST "text"))
10934 *type = NODE_TYPE_TEXT;
10935 else {
10936 if (name != NULL)
10937 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000010938 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010939 }
10940
10941 *test = NODE_TEST_TYPE;
10942
10943 SKIP_BLANKS;
10944 if (*type == NODE_TYPE_PI) {
10945 /*
10946 * Specific case: search a PI by name.
10947 */
Owen Taylor3473f882001-02-23 17:55:21 +000010948 if (name != NULL)
10949 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +000010950 name = NULL;
10951 if (CUR != ')') {
10952 name = xmlXPathParseLiteral(ctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000010953 CHECK_ERROR NULL;
Daniel Veillarded23b7d2002-05-27 12:16:02 +000010954 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +000010955 SKIP_BLANKS;
10956 }
Owen Taylor3473f882001-02-23 17:55:21 +000010957 }
10958 if (CUR != ')') {
10959 if (name != NULL)
10960 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000010961 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010962 }
10963 NEXT;
10964 return(name);
10965 }
10966 *test = NODE_TEST_NAME;
10967 if ((!blanks) && (CUR == ':')) {
10968 NEXT;
10969
10970 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010971 * Since currently the parser context don't have a
10972 * namespace list associated:
10973 * The namespace name for this prefix can be computed
10974 * only at evaluation time. The compilation is done
10975 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +000010976 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010977#if 0
Owen Taylor3473f882001-02-23 17:55:21 +000010978 *prefix = xmlXPathNsLookup(ctxt->context, name);
10979 if (name != NULL)
10980 xmlFree(name);
10981 if (*prefix == NULL) {
10982 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
10983 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010984#else
10985 *prefix = name;
10986#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010987
10988 if (CUR == '*') {
10989 /*
10990 * All elements
10991 */
10992 NEXT;
10993 *test = NODE_TEST_ALL;
10994 return(NULL);
10995 }
10996
10997 name = xmlXPathParseNCName(ctxt);
10998 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010999 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011000 }
11001 }
11002 return(name);
11003}
11004
11005/**
11006 * xmlXPathIsAxisName:
11007 * @name: a preparsed name token
11008 *
11009 * [6] AxisName ::= 'ancestor'
11010 * | 'ancestor-or-self'
11011 * | 'attribute'
11012 * | 'child'
11013 * | 'descendant'
11014 * | 'descendant-or-self'
11015 * | 'following'
11016 * | 'following-sibling'
11017 * | 'namespace'
11018 * | 'parent'
11019 * | 'preceding'
11020 * | 'preceding-sibling'
11021 * | 'self'
11022 *
11023 * Returns the axis or 0
11024 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011025static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +000011026xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +000011027 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011028 switch (name[0]) {
11029 case 'a':
11030 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11031 ret = AXIS_ANCESTOR;
11032 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11033 ret = AXIS_ANCESTOR_OR_SELF;
11034 if (xmlStrEqual(name, BAD_CAST "attribute"))
11035 ret = AXIS_ATTRIBUTE;
11036 break;
11037 case 'c':
11038 if (xmlStrEqual(name, BAD_CAST "child"))
11039 ret = AXIS_CHILD;
11040 break;
11041 case 'd':
11042 if (xmlStrEqual(name, BAD_CAST "descendant"))
11043 ret = AXIS_DESCENDANT;
11044 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11045 ret = AXIS_DESCENDANT_OR_SELF;
11046 break;
11047 case 'f':
11048 if (xmlStrEqual(name, BAD_CAST "following"))
11049 ret = AXIS_FOLLOWING;
11050 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11051 ret = AXIS_FOLLOWING_SIBLING;
11052 break;
11053 case 'n':
11054 if (xmlStrEqual(name, BAD_CAST "namespace"))
11055 ret = AXIS_NAMESPACE;
11056 break;
11057 case 'p':
11058 if (xmlStrEqual(name, BAD_CAST "parent"))
11059 ret = AXIS_PARENT;
11060 if (xmlStrEqual(name, BAD_CAST "preceding"))
11061 ret = AXIS_PRECEDING;
11062 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11063 ret = AXIS_PRECEDING_SIBLING;
11064 break;
11065 case 's':
11066 if (xmlStrEqual(name, BAD_CAST "self"))
11067 ret = AXIS_SELF;
11068 break;
11069 }
11070 return(ret);
11071}
11072
11073/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011074 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +000011075 * @ctxt: the XPath Parser context
11076 *
11077 * [4] Step ::= AxisSpecifier NodeTest Predicate*
11078 * | AbbreviatedStep
11079 *
11080 * [12] AbbreviatedStep ::= '.' | '..'
11081 *
11082 * [5] AxisSpecifier ::= AxisName '::'
11083 * | AbbreviatedAxisSpecifier
11084 *
11085 * [13] AbbreviatedAxisSpecifier ::= '@'?
11086 *
11087 * Modified for XPtr range support as:
11088 *
11089 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11090 * | AbbreviatedStep
11091 * | 'range-to' '(' Expr ')' Predicate*
11092 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011093 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +000011094 * A location step of . is short for self::node(). This is
11095 * particularly useful in conjunction with //. For example, the
11096 * location path .//para is short for
11097 * self::node()/descendant-or-self::node()/child::para
11098 * and so will select all para descendant elements of the context
11099 * node.
11100 * Similarly, a location step of .. is short for parent::node().
11101 * For example, ../title is short for parent::node()/child::title
11102 * and so will select the title children of the parent of the context
11103 * node.
11104 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011105static void
11106xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011107#ifdef LIBXML_XPTR_ENABLED
11108 int rangeto = 0;
11109 int op2 = -1;
11110#endif
11111
Owen Taylor3473f882001-02-23 17:55:21 +000011112 SKIP_BLANKS;
11113 if ((CUR == '.') && (NXT(1) == '.')) {
11114 SKIP(2);
11115 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011116 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11117 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011118 } else if (CUR == '.') {
11119 NEXT;
11120 SKIP_BLANKS;
11121 } else {
11122 xmlChar *name = NULL;
11123 const xmlChar *prefix = NULL;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011124 xmlXPathTestVal test = (xmlXPathTestVal) 0;
William M. Brack78637da2003-07-31 14:47:38 +000011125 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011126 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011127 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +000011128
11129 /*
11130 * The modification needed for XPointer change to the production
11131 */
11132#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011133 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +000011134 name = xmlXPathParseNCName(ctxt);
11135 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011136 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011137 xmlFree(name);
11138 SKIP_BLANKS;
11139 if (CUR != '(') {
11140 XP_ERROR(XPATH_EXPR_ERROR);
11141 }
11142 NEXT;
11143 SKIP_BLANKS;
11144
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011145 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011146 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +000011147 CHECK_ERROR;
11148
11149 SKIP_BLANKS;
11150 if (CUR != ')') {
11151 XP_ERROR(XPATH_EXPR_ERROR);
11152 }
11153 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011154 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000011155 goto eval_predicates;
11156 }
11157 }
11158#endif
Daniel Veillard2156a562001-04-28 12:24:34 +000011159 if (CUR == '*') {
11160 axis = AXIS_CHILD;
11161 } else {
11162 if (name == NULL)
11163 name = xmlXPathParseNCName(ctxt);
11164 if (name != NULL) {
11165 axis = xmlXPathIsAxisName(name);
11166 if (axis != 0) {
11167 SKIP_BLANKS;
11168 if ((CUR == ':') && (NXT(1) == ':')) {
11169 SKIP(2);
11170 xmlFree(name);
11171 name = NULL;
11172 } else {
11173 /* an element name can conflict with an axis one :-\ */
11174 axis = AXIS_CHILD;
11175 }
Owen Taylor3473f882001-02-23 17:55:21 +000011176 } else {
Owen Taylor3473f882001-02-23 17:55:21 +000011177 axis = AXIS_CHILD;
11178 }
Daniel Veillard2156a562001-04-28 12:24:34 +000011179 } else if (CUR == '@') {
11180 NEXT;
11181 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +000011182 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +000011183 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +000011184 }
Owen Taylor3473f882001-02-23 17:55:21 +000011185 }
11186
11187 CHECK_ERROR;
11188
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011189 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +000011190 if (test == 0)
11191 return;
11192
Daniel Veillarded6c5492005-07-23 15:00:22 +000011193 if ((prefix != NULL) && (ctxt->context != NULL) &&
11194 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11195 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11196 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11197 }
11198 }
Owen Taylor3473f882001-02-23 17:55:21 +000011199#ifdef DEBUG_STEP
11200 xmlGenericError(xmlGenericErrorContext,
11201 "Basis : computing new set\n");
11202#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011203
Owen Taylor3473f882001-02-23 17:55:21 +000011204#ifdef DEBUG_STEP
11205 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011206 if (ctxt->value == NULL)
11207 xmlGenericError(xmlGenericErrorContext, "no value\n");
11208 else if (ctxt->value->nodesetval == NULL)
11209 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11210 else
11211 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011212#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011213
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011214#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +000011215eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011216#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011217 op1 = ctxt->comp->last;
11218 ctxt->comp->last = -1;
11219
Owen Taylor3473f882001-02-23 17:55:21 +000011220 SKIP_BLANKS;
11221 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011222 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011223 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011224
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011225#ifdef LIBXML_XPTR_ENABLED
11226 if (rangeto) {
11227 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11228 } else
11229#endif
11230 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11231 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011232
Owen Taylor3473f882001-02-23 17:55:21 +000011233 }
11234#ifdef DEBUG_STEP
11235 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011236 if (ctxt->value == NULL)
11237 xmlGenericError(xmlGenericErrorContext, "no value\n");
11238 else if (ctxt->value->nodesetval == NULL)
11239 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11240 else
11241 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11242 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011243#endif
11244}
11245
11246/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011247 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011248 * @ctxt: the XPath Parser context
11249 *
11250 * [3] RelativeLocationPath ::= Step
11251 * | RelativeLocationPath '/' Step
11252 * | AbbreviatedRelativeLocationPath
11253 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
11254 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011255 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +000011256 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011257static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011258xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011259(xmlXPathParserContextPtr ctxt) {
11260 SKIP_BLANKS;
11261 if ((CUR == '/') && (NXT(1) == '/')) {
11262 SKIP(2);
11263 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011264 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11265 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011266 } else if (CUR == '/') {
11267 NEXT;
11268 SKIP_BLANKS;
11269 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011270 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011271 SKIP_BLANKS;
11272 while (CUR == '/') {
11273 if ((CUR == '/') && (NXT(1) == '/')) {
11274 SKIP(2);
11275 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011276 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +000011277 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011278 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011279 } else if (CUR == '/') {
11280 NEXT;
11281 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011282 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011283 }
11284 SKIP_BLANKS;
11285 }
11286}
11287
11288/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011289 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011290 * @ctxt: the XPath Parser context
11291 *
11292 * [1] LocationPath ::= RelativeLocationPath
11293 * | AbsoluteLocationPath
11294 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
11295 * | AbbreviatedAbsoluteLocationPath
11296 * [10] AbbreviatedAbsoluteLocationPath ::=
11297 * '//' RelativeLocationPath
11298 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011299 * Compile a location path
11300 *
Owen Taylor3473f882001-02-23 17:55:21 +000011301 * // is short for /descendant-or-self::node()/. For example,
11302 * //para is short for /descendant-or-self::node()/child::para and
11303 * so will select any para element in the document (even a para element
11304 * that is a document element will be selected by //para since the
11305 * document element node is a child of the root node); div//para is
11306 * short for div/descendant-or-self::node()/child::para and so will
11307 * select all para descendants of div children.
11308 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011309static void
11310xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000011311 SKIP_BLANKS;
11312 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011313 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011314 } else {
11315 while (CUR == '/') {
11316 if ((CUR == '/') && (NXT(1) == '/')) {
11317 SKIP(2);
11318 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011319 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11320 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011321 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011322 } else if (CUR == '/') {
11323 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +000011324 SKIP_BLANKS;
11325 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +000011326 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +000011327 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011328 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011329 }
11330 }
11331 }
11332}
11333
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011334/************************************************************************
11335 * *
11336 * XPath precompiled expression evaluation *
11337 * *
11338 ************************************************************************/
11339
Daniel Veillardf06307e2001-07-03 10:35:50 +000011340static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011341xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11342
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011343#ifdef DEBUG_STEP
11344static void
11345xmlXPathDebugDumpStepAxis(xmlXPathAxisVal axis,
11346 xmlXPathTestVal test,
11347 int nbNodes)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011348{
Daniel Veillardf06307e2001-07-03 10:35:50 +000011349 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011350 switch (axis) {
11351 case AXIS_ANCESTOR:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011352 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011353 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011354 case AXIS_ANCESTOR_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011355 xmlGenericError(xmlGenericErrorContext,
11356 "axis 'ancestors-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011357 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011358 case AXIS_ATTRIBUTE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011359 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011360 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011361 case AXIS_CHILD:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011362 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011363 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011364 case AXIS_DESCENDANT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011365 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011366 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011367 case AXIS_DESCENDANT_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011368 xmlGenericError(xmlGenericErrorContext,
11369 "axis 'descendant-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011370 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011371 case AXIS_FOLLOWING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011372 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011373 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011374 case AXIS_FOLLOWING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011375 xmlGenericError(xmlGenericErrorContext,
11376 "axis 'following-siblings' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011377 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011378 case AXIS_NAMESPACE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011379 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011380 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011381 case AXIS_PARENT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011382 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011383 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011384 case AXIS_PRECEDING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011385 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011386 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011387 case AXIS_PRECEDING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011388 xmlGenericError(xmlGenericErrorContext,
11389 "axis 'preceding-sibling' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011390 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011391 case AXIS_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011392 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011393 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011394 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011395 xmlGenericError(xmlGenericErrorContext,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011396 " context contains %d nodes\n", nbNodes);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011397 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011398 case NODE_TEST_NONE:
11399 xmlGenericError(xmlGenericErrorContext,
11400 " searching for none !!!\n");
11401 break;
11402 case NODE_TEST_TYPE:
11403 xmlGenericError(xmlGenericErrorContext,
11404 " searching for type %d\n", type);
11405 break;
11406 case NODE_TEST_PI:
11407 xmlGenericError(xmlGenericErrorContext,
11408 " searching for PI !!!\n");
11409 break;
11410 case NODE_TEST_ALL:
11411 xmlGenericError(xmlGenericErrorContext,
11412 " searching for *\n");
11413 break;
11414 case NODE_TEST_NS:
11415 xmlGenericError(xmlGenericErrorContext,
11416 " searching for namespace %s\n",
11417 prefix);
11418 break;
11419 case NODE_TEST_NAME:
11420 xmlGenericError(xmlGenericErrorContext,
11421 " searching for name %s\n", name);
11422 if (prefix != NULL)
11423 xmlGenericError(xmlGenericErrorContext,
11424 " with namespace %s\n", prefix);
11425 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011426 }
11427 xmlGenericError(xmlGenericErrorContext, "Testing : ");
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011428}
11429#endif /* DEBUG_STEP */
11430
11431static int
11432xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11433 xmlXPathStepOpPtr op,
11434 xmlNodeSetPtr set,
11435 int contextSize,
11436 int hasNsNodes)
11437{
11438 if (op->ch1 != -1) {
11439 xmlXPathCompExprPtr comp = ctxt->comp;
11440 /*
11441 * Process inner predicates first.
11442 */
11443 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11444 /*
11445 * TODO: raise an internal error.
11446 */
11447 }
11448 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11449 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11450 CHECK_ERROR0;
11451 if (contextSize <= 0)
11452 return(0);
11453 }
11454 if (op->ch2 != -1) {
11455 xmlXPathContextPtr xpctxt = ctxt->context;
11456 xmlNodePtr contextNode, oldContextNode;
11457 xmlDocPtr oldContextDoc;
11458 int i, contextPos = 0, newContextSize;
11459 xmlXPathStepOpPtr exprOp;
11460 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11461
11462#ifdef LIBXML_XPTR_ENABLED
11463 /*
11464 * URGENT TODO: Check the following:
11465 * We don't expect location sets if evaluating prediates, right?
11466 * Only filters should expect location sets, right?
11467 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011468#endif
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011469 /*
11470 * SPEC XPath 1.0:
11471 * "For each node in the node-set to be filtered, the
11472 * PredicateExpr is evaluated with that node as the
11473 * context node, with the number of nodes in the
11474 * node-set as the context size, and with the proximity
11475 * position of the node in the node-set with respect to
11476 * the axis as the context position;"
11477 * @oldset is the node-set" to be filtered.
11478 *
11479 * SPEC XPath 1.0:
11480 * "only predicates change the context position and
11481 * context size (see [2.4 Predicates])."
11482 * Example:
11483 * node-set context pos
11484 * nA 1
11485 * nB 2
11486 * nC 3
11487 * After applying predicate [position() > 1] :
11488 * node-set context pos
11489 * nB 1
11490 * nC 2
11491 */
11492 oldContextNode = xpctxt->node;
11493 oldContextDoc = xpctxt->doc;
11494 /*
11495 * Get the expression of this predicate.
11496 */
11497 exprOp = &ctxt->comp->steps[op->ch2];
11498 newContextSize = 0;
11499 for (i = 0; i < set->nodeNr; i++) {
11500 if (set->nodeTab[i] == NULL)
11501 continue;
11502
11503 contextNode = set->nodeTab[i];
11504 xpctxt->node = contextNode;
11505 xpctxt->contextSize = contextSize;
11506 xpctxt->proximityPosition = ++contextPos;
11507
11508 /*
11509 * Also set the xpath document in case things like
11510 * key() are evaluated in the predicate.
11511 */
11512 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11513 (contextNode->doc != NULL))
11514 xpctxt->doc = contextNode->doc;
11515 /*
11516 * Evaluate the predicate expression with 1 context node
11517 * at a time; this node is packaged into a node set; this
11518 * node set is handed over to the evaluation mechanism.
11519 */
11520 if (contextObj == NULL)
11521 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11522 else
11523 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11524 contextNode);
11525
11526 valuePush(ctxt, contextObj);
11527 xmlXPathCompOpEval(ctxt, exprOp);
11528
11529 if (ctxt->error != XPATH_EXPRESSION_OK)
11530 goto evaluation_error;
11531
11532 exprRes = valuePop(ctxt);
11533 /*
11534 * This checks if the result of the evaluation is 'true'.
11535 */
11536 if (! xmlXPathEvaluatePredicateResult(ctxt, exprRes)) {
11537 /*
11538 * Remove the entry from the initial node set.
11539 */
11540 set->nodeTab[i] = NULL;
11541 if (contextNode->type == XML_NAMESPACE_DECL)
11542 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11543 } else
11544 newContextSize++;
11545
11546 if (exprRes != NULL) {
11547 xmlXPathReleaseObject(ctxt->context, exprRes);
11548 exprRes = NULL;
11549 }
11550 if (ctxt->value == contextObj) {
11551 /*
11552 * Don't free the temporary XPath object holding the
11553 * context node, in order to avoid massive recreation
11554 * inside this loop.
11555 */
11556 valuePop(ctxt);
11557 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11558 } else {
11559 /*
11560 * TODO: The object was lost in the evaluation machinery.
11561 * Can this happen? Maybe in internal-error cases.
11562 */
11563 contextObj = NULL;
11564 }
11565 }
11566 goto evaluation_exit;
11567
11568evaluation_error:
11569 xmlXPathNodeSetClear(set, hasNsNodes);
11570 newContextSize = 0;
11571
11572evaluation_exit:
11573 if (contextObj != NULL) {
11574 if (ctxt->value == contextObj)
11575 valuePop(ctxt);
11576 xmlXPathReleaseObject(xpctxt, contextObj);
11577 }
11578 if (exprRes != NULL)
11579 xmlXPathReleaseObject(ctxt->context, exprRes);
11580 /*
11581 * Reset/invalidate the context.
11582 */
11583 xpctxt->node = oldContextNode;
11584 xpctxt->doc = oldContextDoc;
11585 xpctxt->contextSize = -1;
11586 xpctxt->proximityPosition = -1;
11587 return(newContextSize);
11588 }
11589 return(contextSize);
11590}
11591
11592static int
11593xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11594 xmlXPathStepOpPtr op,
11595 xmlNodeSetPtr set,
11596 int contextSize,
11597 int minPos,
11598 int maxPos,
11599 int hasNsNodes)
11600{
11601 if (op->ch1 != -1) {
11602 xmlXPathCompExprPtr comp = ctxt->comp;
11603 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11604 /*
11605 * TODO: raise an internal error.
11606 */
11607 }
11608 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11609 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11610 CHECK_ERROR0;
11611 if (contextSize <= 0)
11612 return(0);
11613 }
11614 /*
11615 * Check if the node set contains a sufficient number of nodes for
11616 * the requested range.
11617 */
11618 if (contextSize < minPos) {
11619 xmlXPathNodeSetClear(set, hasNsNodes);
11620 return(0);
11621 }
11622 if (op->ch2 == -1) {
11623 /*
11624 * TODO: Can this ever happen?
11625 */
11626 return (contextSize);
11627 } else {
11628 xmlDocPtr oldContextDoc;
11629 int i, pos = 0, newContextSize = 0, contextPos = 0, isTrue;
11630 xmlXPathStepOpPtr exprOp;
11631 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11632 xmlNodePtr oldContextNode, contextNode = NULL;
11633 xmlXPathContextPtr xpctxt = ctxt->context;
11634
11635#ifdef LIBXML_XPTR_ENABLED
11636 /*
11637 * URGENT TODO: Check the following:
11638 * We don't expect location sets if evaluating prediates, right?
11639 * Only filters should expect location sets, right?
11640 */
11641#endif /* LIBXML_XPTR_ENABLED */
11642
11643 /*
11644 * Save old context.
11645 */
11646 oldContextNode = xpctxt->node;
11647 oldContextDoc = xpctxt->doc;
11648 /*
11649 * Get the expression of this predicate.
11650 */
11651 exprOp = &ctxt->comp->steps[op->ch2];
11652 for (i = 0; i < set->nodeNr; i++) {
11653 if (set->nodeTab[i] == NULL)
11654 continue;
11655
11656 contextNode = set->nodeTab[i];
11657 xpctxt->node = contextNode;
11658 xpctxt->contextSize = contextSize;
11659 xpctxt->proximityPosition = ++contextPos;
11660
11661 /*
11662 * Initialize the new set.
11663 * Also set the xpath document in case things like
11664 * key() evaluation are attempted on the predicate
11665 */
11666 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11667 (contextNode->doc != NULL))
11668 xpctxt->doc = contextNode->doc;
11669 /*
11670 * Evaluate the predicate expression with 1 context node
11671 * at a time; this node is packaged into a node set; this
11672 * node set is handed over to the evaluation mechanism.
11673 */
11674 if (contextObj == NULL)
11675 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11676 else
11677 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11678 contextNode);
11679
11680 valuePush(ctxt, contextObj);
11681 xmlXPathCompOpEval(ctxt, exprOp);
11682
11683 if (ctxt->error != XPATH_EXPRESSION_OK)
11684 goto evaluation_error;
11685 /*
11686 * The result of the evaluation needs to be tested to
11687 * decide whether the filter succeeded or not
11688 */
11689 exprRes = valuePop(ctxt);
11690 /*
11691 * This checks if the result of the evaluate is 'true'.
11692 */
11693 if (xmlXPathEvaluatePredicateResult(ctxt, exprRes)) {
11694 pos++;
11695 isTrue = 1;
11696 } else
11697 isTrue = 0;
11698 if (isTrue && (pos >= minPos) && (pos <= maxPos)) {
11699 /*
11700 * Fits in the requested range.
11701 */
11702 newContextSize++;
11703 if (minPos == maxPos) {
11704 /*
11705 * Only 1 node was requested.
11706 */
11707 if (contextNode->type == XML_NAMESPACE_DECL) {
11708 /*
11709 * As always: take care of those nasty
11710 * namespace nodes.
11711 */
11712 set->nodeTab[i] = NULL;
11713 }
11714 xmlXPathNodeSetClear(set, hasNsNodes);
11715 set->nodeNr = 1;
11716 set->nodeTab[0] = contextNode;
11717 goto evaluation_exit;
11718 }
11719 if (pos == maxPos) {
11720 /*
11721 * We are done.
11722 */
11723 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11724 goto evaluation_exit;
11725 }
11726 } else {
11727 /*
11728 * Remove the entry from the initial node set.
11729 */
11730 set->nodeTab[i] = NULL;
11731 if (contextNode->type == XML_NAMESPACE_DECL)
11732 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11733 }
11734 if (exprRes != NULL) {
11735 xmlXPathReleaseObject(ctxt->context, exprRes);
11736 exprRes = NULL;
11737 }
11738 if (ctxt->value == contextObj) {
11739 /*
11740 * Don't free the temporary XPath object holding the
11741 * context node, in order to avoid massive recreation
11742 * inside this loop.
11743 */
11744 valuePop(ctxt);
11745 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11746 } else {
11747 /*
11748 * The object was lost in the evaluation machinery.
11749 * Can this happen? Maybe in case of internal-errors.
11750 */
11751 contextObj = NULL;
11752 }
11753 }
11754 goto evaluation_exit;
11755
11756evaluation_error:
11757 xmlXPathNodeSetClear(set, hasNsNodes);
11758 newContextSize = 0;
11759
11760evaluation_exit:
11761 if (contextObj != NULL) {
11762 if (ctxt->value == contextObj)
11763 valuePop(ctxt);
11764 xmlXPathReleaseObject(xpctxt, contextObj);
11765 }
11766 if (exprRes != NULL)
11767 xmlXPathReleaseObject(ctxt->context, exprRes);
11768 /*
11769 * Reset/invalidate the context.
11770 */
11771 xpctxt->node = oldContextNode;
11772 xpctxt->doc = oldContextDoc;
11773 xpctxt->contextSize = -1;
11774 xpctxt->proximityPosition = -1;
11775 return(newContextSize);
11776 }
11777 return(contextSize);
11778}
11779
11780static int
11781xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11782 xmlXPathStepOpPtr op,
11783 int *maxPos)
11784{
11785
11786 xmlXPathStepOpPtr exprOp;
11787
11788 /*
11789 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11790 */
11791
11792 /*
11793 * If not -1, then ch1 will point to:
11794 * 1) For predicates (XPATH_OP_PREDICATE):
11795 * - an inner predicate operator
11796 * 2) For filters (XPATH_OP_FILTER):
11797 * - an inner filter operater OR
11798 * - an expression selecting the node set.
11799 * E.g. "key('a', 'b')" or "(//foo | //bar)".
11800 */
11801 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11802 return(0);
11803
11804 if (op->ch2 != -1) {
11805 exprOp = &ctxt->comp->steps[op->ch2];
11806 } else
11807 return(0);
11808
11809 if ((exprOp != NULL) &&
11810 (exprOp->op == XPATH_OP_VALUE) &&
11811 (exprOp->value4 != NULL) &&
11812 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11813 {
11814 /*
11815 * We have a "[n]" predicate here.
11816 * TODO: Unfortunately this simplistic test here is not
11817 * able to detect a position() predicate in compound
11818 * expressions like "[@attr = 'a" and position() = 1],
11819 * and even not the usage of position() in
11820 * "[position() = 1]"; thus - obviously - a position-range,
11821 * like it "[position() < 5]", is also not detected.
11822 * Maybe we could rewrite the AST to ease the optimization.
11823 */
11824 *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11825
11826 if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
11827 (float) *maxPos)
11828 {
11829 return(1);
11830 }
11831 }
11832 return(0);
11833}
11834
11835static int
11836xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11837 xmlXPathStepOpPtr op,
11838 xmlNodePtr * first, xmlNodePtr * last)
11839{
11840
11841#define XP_TEST_HIT \
11842 if (hasAxisRange != 0) { \
11843 if (++pos == maxPos) { \
11844 addNode(seq, cur); \
11845 goto axis_range_end; } \
11846 } else addNode(seq, cur);
11847
11848#define XP_TEST_HIT_NS \
11849 if (hasAxisRange != 0) { \
11850 if (++pos == maxPos) { \
11851 hasNsNodes = 1; \
11852 xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
11853 goto axis_range_end; } \
11854 } else { \
11855 hasNsNodes = 1; \
11856 xmlXPathNodeSetAddNs(seq, \
11857 xpctxt->node, (xmlNsPtr) cur); }
11858
11859 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11860 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11861 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11862 const xmlChar *prefix = op->value4;
11863 const xmlChar *name = op->value5;
11864 const xmlChar *URI = NULL;
11865
11866#ifdef DEBUG_STEP
11867 int nbMatches = 0, prevMatches = 0;
11868#endif
11869 int total = 0, hasNsNodes = 0;
11870 /* The popped object holding the context nodes */
11871 xmlXPathObjectPtr obj;
11872 /* The set of context nodes for the node tests */
11873 xmlNodeSetPtr contextSeq;
11874 int contextIdx;
11875 xmlNodePtr contextNode;
11876 /* The context node for a compound traversal */
11877 xmlNodePtr outerContextNode;
11878 /* The final resulting node set wrt to all context nodes */
11879 xmlNodeSetPtr outSeq;
11880 /*
11881 * The temporary resulting node set wrt 1 context node.
11882 * Used to feed predicate evaluation.
11883 */
11884 xmlNodeSetPtr seq;
11885 xmlNodePtr cur;
11886 /* First predicate operator */
11887 xmlXPathStepOpPtr predOp;
11888 int maxPos; /* The requested position() (when a "[n]" predicate) */
11889 int hasPredicateRange, hasAxisRange, pos, size, newSize;
11890
11891 xmlXPathTraversalFunction next = NULL;
11892 /* compound axis traversal */
11893 xmlXPathTraversalFunctionExt outerNext = NULL;
11894 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
11895 xmlXPathNodeSetMergeFunction mergeAndClear;
11896 xmlNodePtr oldContextNode;
11897 xmlXPathContextPtr xpctxt = ctxt->context;
11898
11899
11900 CHECK_TYPE0(XPATH_NODESET);
11901 obj = valuePop(ctxt);
11902 /*
11903 * Setup namespaces.
11904 */
11905 if (prefix != NULL) {
11906 URI = xmlXPathNsLookup(xpctxt, prefix);
11907 if (URI == NULL) {
11908 xmlXPathReleaseObject(xpctxt, obj);
11909 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11910 }
11911 }
11912 /*
11913 * Setup axis.
11914 *
11915 * MAYBE FUTURE TODO: merging optimizations:
11916 * - If the nodes to be traversed wrt to the initial nodes and
11917 * the current axis cannot overlap, then we could avoid searching
11918 * for duplicates during the merge.
11919 * But the question is how/when to evaluate if they cannot overlap.
11920 * Example: if we know that for two initial nodes, the one is
11921 * not in the ancestor-or-self axis of the other, then we could safely
11922 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
11923 * the descendant-or-self axis.
11924 */
11925 addNode = xmlXPathNodeSetAdd;
11926 mergeAndClear = xmlXPathNodeSetMergeAndClear;
11927 switch (axis) {
11928 case AXIS_ANCESTOR:
11929 first = NULL;
11930 next = xmlXPathNextAncestor;
11931 break;
11932 case AXIS_ANCESTOR_OR_SELF:
11933 first = NULL;
11934 next = xmlXPathNextAncestorOrSelf;
11935 break;
11936 case AXIS_ATTRIBUTE:
11937 first = NULL;
11938 last = NULL;
11939 next = xmlXPathNextAttribute;
11940 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11941 break;
11942 case AXIS_CHILD:
11943 last = NULL;
11944 if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
11945 /*
11946 * This iterator will give us only nodes which can
11947 * hold element nodes.
11948 */
11949 outerNext = xmlXPathNextDescendantOrSelfElemParent;
11950 }
11951 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
11952 (type == NODE_TYPE_NODE))
11953 {
11954 /*
11955 * Optimization if an element node type is 'element'.
11956 */
11957 next = xmlXPathNextChildElement;
11958 } else
11959 next = xmlXPathNextChild;
11960 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11961 break;
11962 case AXIS_DESCENDANT:
11963 last = NULL;
11964 next = xmlXPathNextDescendant;
11965 break;
11966 case AXIS_DESCENDANT_OR_SELF:
11967 last = NULL;
11968 next = xmlXPathNextDescendantOrSelf;
11969 break;
11970 case AXIS_FOLLOWING:
11971 last = NULL;
11972 next = xmlXPathNextFollowing;
11973 break;
11974 case AXIS_FOLLOWING_SIBLING:
11975 last = NULL;
11976 next = xmlXPathNextFollowingSibling;
11977 break;
11978 case AXIS_NAMESPACE:
11979 first = NULL;
11980 last = NULL;
11981 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
11982 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11983 break;
11984 case AXIS_PARENT:
11985 first = NULL;
11986 next = xmlXPathNextParent;
11987 break;
11988 case AXIS_PRECEDING:
11989 first = NULL;
11990 next = xmlXPathNextPrecedingInternal;
11991 break;
11992 case AXIS_PRECEDING_SIBLING:
11993 first = NULL;
11994 next = xmlXPathNextPrecedingSibling;
11995 break;
11996 case AXIS_SELF:
11997 first = NULL;
11998 last = NULL;
11999 next = xmlXPathNextSelf;
12000 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12001 break;
12002 }
12003
12004#ifdef DEBUG_STEP
12005 xmlXPathDebugDumpStepAxis(axis, test,
12006 (obj->nodesetval != NULL) ? obj->nodsetval->nodeNr : 0);
12007#endif
12008
12009 if (next == NULL) {
12010 xmlXPathReleaseObject(xpctxt, obj);
12011 return(0);
12012 }
12013 contextSeq = obj->nodesetval;
12014 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12015 xmlXPathReleaseObject(xpctxt, obj);
12016 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12017 return(0);
12018 }
12019 /*
12020 * Predicate optimization ---------------------------------------------
12021 * If this step has a last predicate, which contains a position(),
12022 * then we'll optimize (although not exactly "position()", but only
12023 * the short-hand form, i.e., "[n]".
12024 *
12025 * Example - expression "/foo[parent::bar][1]":
12026 *
12027 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12028 * ROOT -- op->ch1
12029 * PREDICATE -- op->ch2 (predOp)
12030 * PREDICATE -- predOp->ch1 = [parent::bar]
12031 * SORT
12032 * COLLECT 'parent' 'name' 'node' bar
12033 * NODE
12034 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12035 *
12036 */
12037 maxPos = 0;
12038 predOp = NULL;
12039 hasPredicateRange = 0;
12040 hasAxisRange = 0;
12041 if (op->ch2 != -1) {
12042 /*
12043 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12044 */
12045 predOp = &ctxt->comp->steps[op->ch2];
12046 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12047 if (predOp->ch1 != -1) {
12048 /*
12049 * Use the next inner predicate operator.
12050 */
12051 predOp = &ctxt->comp->steps[predOp->ch1];
12052 hasPredicateRange = 1;
12053 } else {
12054 /*
12055 * There's no other predicate than the [n] predicate.
12056 */
12057 predOp = NULL;
12058 hasAxisRange = 1;
12059 }
12060 }
12061 }
12062 /*
12063 * Axis traversal -----------------------------------------------------
12064 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012065 /*
12066 * 2.3 Node Tests
12067 * - For the attribute axis, the principal node type is attribute.
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012068 * - For the namespace axis, the principal node type is namespace.
12069 * - For other axes, the principal node type is element.
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012070 *
12071 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012072 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012073 * select all element children of the context node
12074 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012075 oldContextNode = xpctxt->node;
12076 addNode = xmlXPathNodeSetAddUnique;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012077 outSeq = NULL;
12078 seq = NULL;
12079 outerContextNode = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012080 contextNode = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012081 contextIdx = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012082
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012083
12084 while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
12085 if (outerNext != NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012086 /*
12087 * This is a compound traversal.
12088 */
12089 if (contextNode == NULL) {
12090 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012091 * Set the context for the outer traversal.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012092 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012093 outerContextNode = contextSeq->nodeTab[contextIdx++];
12094 contextNode = outerNext(NULL, outerContextNode);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012095 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012096 contextNode = outerNext(contextNode, outerContextNode);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012097 if (contextNode == NULL)
12098 continue;
12099 /*
12100 * Set the context for the main traversal.
12101 */
12102 xpctxt->node = contextNode;
12103 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012104 xpctxt->node = contextSeq->nodeTab[contextIdx++];
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012105
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012106 if (seq == NULL) {
12107 seq = xmlXPathNodeSetCreate(NULL);
12108 if (seq == NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012109 total = 0;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012110 goto error;
12111 }
12112 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012113 /*
12114 * Traverse the axis and test the nodes.
12115 */
12116 pos = 0;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012117 cur = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012118 hasNsNodes = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012119 do {
12120 cur = next(ctxt, cur);
12121 if (cur == NULL)
12122 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012123
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012124 /*
12125 * QUESTION TODO: What does the "first" and "last" stuff do?
12126 */
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012127 if (first != NULL) {
12128 if (*first == cur)
12129 break;
12130 if ((*first != NULL) &&
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012131 ((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012132#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012133 (xmlXPathCmpNodesExt(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012134#else
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012135 (xmlXPathCmpNodes(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012136#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012137 {
12138 break;
12139 }
12140 }
12141 if (last != NULL) {
12142 if (*last == cur)
12143 break;
12144 if ((*last != NULL) &&
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012145 ((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012146#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012147 (xmlXPathCmpNodesExt(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012148#else
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012149 (xmlXPathCmpNodes(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012150#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012151 {
12152 break;
12153 }
12154 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012155
12156 total++;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012157
Daniel Veillardf06307e2001-07-03 10:35:50 +000012158#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012159 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12160#endif
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012161 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012162 case NODE_TEST_NONE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012163 total = 0;
12164 STRANGE
12165 goto error;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012166 case NODE_TEST_TYPE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012167 /*
12168 * TODO: Don't we need to use
12169 * xmlXPathNodeSetAddNs() for namespace nodes here?
12170 * Surprisingly, some c14n tests fail, if we do this.
12171 */
12172 if (type == NODE_TYPE_NODE) {
12173 switch (cur->type) {
12174 case XML_DOCUMENT_NODE:
12175 case XML_HTML_DOCUMENT_NODE:
12176#ifdef LIBXML_DOCB_ENABLED
12177 case XML_DOCB_DOCUMENT_NODE:
12178#endif
12179 case XML_ELEMENT_NODE:
12180 case XML_ATTRIBUTE_NODE:
12181 case XML_PI_NODE:
12182 case XML_COMMENT_NODE:
12183 case XML_CDATA_SECTION_NODE:
12184 case XML_TEXT_NODE:
12185 case XML_NAMESPACE_DECL:
12186 XP_TEST_HIT
12187 break;
12188 default:
12189 break;
12190 }
12191 } else if (cur->type == type) {
12192 XP_TEST_HIT
12193 } else if ((type == NODE_TYPE_TEXT) &&
12194 (cur->type == XML_CDATA_SECTION_NODE))
12195 {
12196 XP_TEST_HIT
12197 }
12198 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012199 case NODE_TEST_PI:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012200 if ((cur->type == XML_PI_NODE) &&
12201 ((name == NULL) || xmlStrEqual(name, cur->name)))
12202 {
12203 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012204 }
12205 break;
12206 case NODE_TEST_ALL:
12207 if (axis == AXIS_ATTRIBUTE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012208 if (cur->type == XML_ATTRIBUTE_NODE)
12209 {
12210 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012211 }
12212 } else if (axis == AXIS_NAMESPACE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012213 if (cur->type == XML_NAMESPACE_DECL)
12214 {
12215 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012216 }
12217 } else {
12218 if (cur->type == XML_ELEMENT_NODE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012219 if (prefix == NULL)
12220 {
12221 XP_TEST_HIT
12222
Daniel Veillardf06307e2001-07-03 10:35:50 +000012223 } else if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012224 (xmlStrEqual(URI, cur->ns->href)))
12225 {
12226 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012227 }
12228 }
12229 }
12230 break;
12231 case NODE_TEST_NS:{
12232 TODO;
12233 break;
12234 }
12235 case NODE_TEST_NAME:
12236 switch (cur->type) {
12237 case XML_ELEMENT_NODE:
12238 if (xmlStrEqual(name, cur->name)) {
12239 if (prefix == NULL) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012240 if (cur->ns == NULL)
12241 {
12242 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012243 }
12244 } else {
12245 if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012246 (xmlStrEqual(URI, cur->ns->href)))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012247 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012248 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012249 }
12250 }
12251 }
12252 break;
12253 case XML_ATTRIBUTE_NODE:{
12254 xmlAttrPtr attr = (xmlAttrPtr) cur;
12255
12256 if (xmlStrEqual(name, attr->name)) {
12257 if (prefix == NULL) {
12258 if ((attr->ns == NULL) ||
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012259 (attr->ns->prefix == NULL))
12260 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012261 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012262 }
12263 } else {
12264 if ((attr->ns != NULL) &&
12265 (xmlStrEqual(URI,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012266 attr->ns->href)))
12267 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012268 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012269 }
12270 }
12271 }
12272 break;
12273 }
12274 case XML_NAMESPACE_DECL:
12275 if (cur->type == XML_NAMESPACE_DECL) {
12276 xmlNsPtr ns = (xmlNsPtr) cur;
12277
12278 if ((ns->prefix != NULL) && (name != NULL)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012279 && (xmlStrEqual(ns->prefix, name)))
12280 {
12281 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012282 }
12283 }
12284 break;
12285 default:
12286 break;
12287 }
12288 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012289 } /* switch(test) */
12290 } while (cur != NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012291
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012292 goto apply_predicates;
12293
12294axis_range_end: /* ----------------------------------------------------- */
12295
12296 /*
12297 * We have a "/foo[n]", and position() = n was reached.
12298 * Note that we can have as well "/foo/::parent::foo[1]", so
12299 * a duplicate-aware merge is still needed.
12300 * Merge with the result.
12301 */
12302 if (outSeq == NULL) {
12303 outSeq = seq;
12304 seq = NULL;
12305 } else
12306 outSeq = mergeAndClear(outSeq, seq, 0);
12307 continue;
12308
12309#ifdef DEBUG_STEP
12310 if (seq != NULL)
12311 nbMatches += seq->nodeNr;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012312#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012313
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012314apply_predicates: /* --------------------------------------------------- */
12315 /*
12316 * Apply predicates.
12317 */
12318 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12319 /*
12320 * E.g. when we have a "/foo[some expression][n]".
12321 */
12322 /*
12323 * QUESTION TODO: The old predicate evaluation took into
12324 * account location-sets.
12325 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12326 * Do we expect such a set here?
12327 * All what I learned now from the evaluation semantics
12328 * does not indicate that a location-set will be processed
12329 * here, so this looks OK.
12330 */
12331 /*
12332 * Iterate over all predicates, starting with the outermost
12333 * predicate.
12334 * TODO: Problem: we cannot execute the inner predicates first
12335 * since we cannot go back *up* the operator tree!
12336 * Options we have:
12337 * 1) Use of recursive functions (like is it currently done
12338 * via xmlXPathCompOpEval())
12339 * 2) Add a predicate evaluation information stack to the
12340 * context struct
12341 * 3) Change the way the operators are linked; we need a
12342 * "parent" field on xmlXPathStepOp
12343 *
12344 * For the moment, I'll try to solve this with a recursive
12345 * function: xmlXPathCompOpEvalPredicate().
12346 */
12347 size = seq->nodeNr;
12348 if (hasPredicateRange != 0)
12349 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12350 predOp, seq, size, maxPos, maxPos, hasNsNodes);
12351 else
12352 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12353 predOp, seq, size, hasNsNodes);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012354
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012355 if (ctxt->error != XPATH_EXPRESSION_OK) {
12356 total = 0;
12357 goto error;
12358 }
12359 /*
12360 * Add the filtered set of nodes to the result node set.
12361 */
12362 if (newSize == 0) {
12363 /*
12364 * The predicates filtered all nodes out.
12365 */
12366 xmlXPathNodeSetClear(seq, hasNsNodes);
12367 } else if (seq->nodeNr > 0) {
12368 /*
12369 * Add to result set.
12370 */
12371 if (outSeq == NULL) {
12372 if (size != newSize) {
12373 /*
12374 * We need to merge and clear here, since
12375 * the sequence will contained NULLed entries.
12376 */
12377 outSeq = mergeAndClear(NULL, seq, 1);
12378 } else {
12379 outSeq = seq;
12380 seq = NULL;
12381 }
12382 } else
12383 outSeq = mergeAndClear(outSeq, seq,
12384 (size != newSize) ? 1: 0);
12385 }
12386 } else if (seq->nodeNr > 0) {
12387 /*
12388 * Add to result set.
12389 */
12390 if (outSeq == NULL) {
12391 outSeq = seq;
12392 seq = NULL;
12393 } else {
12394 outSeq = mergeAndClear(outSeq, seq, 0);
12395 }
12396 }
12397 }
12398
12399error:
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012400 if ((obj->boolval) && (obj->user != NULL)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012401 /*
12402 * QUESTION TODO: What does this do and why?
12403 * TODO: Do we have to do this also for the "error"
12404 * cleanup further down?
12405 */
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012406 ctxt->value->boolval = 1;
12407 ctxt->value->user = obj->user;
12408 obj->user = NULL;
12409 obj->boolval = 0;
12410 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012411 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012412
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012413 /*
12414 * Ensure we return at least an emtpy set.
12415 */
12416 if (outSeq == NULL) {
12417 if ((seq != NULL) && (seq->nodeNr == 0))
12418 outSeq = seq;
12419 else
12420 outSeq = xmlXPathNodeSetCreate(NULL);
12421 }
12422 if ((seq != NULL) && (seq != outSeq)) {
12423 xmlXPathFreeNodeSet(seq);
12424 }
12425 /*
12426 * Hand over the result. Better to push the set also in
12427 * case of errors.
12428 */
12429 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12430 /*
12431 * Reset the context node.
12432 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012433 xpctxt->node = oldContextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012434
12435#ifdef DEBUG_STEP
12436 xmlGenericError(xmlGenericErrorContext,
12437 "\nExamined %d nodes, found %d nodes at that step\n",
12438 total, nbMatches);
12439#endif
12440
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012441 return(total);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012442}
12443
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012444static int
12445xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12446 xmlXPathStepOpPtr op, xmlNodePtr * first);
12447
Daniel Veillardf06307e2001-07-03 10:35:50 +000012448/**
12449 * xmlXPathCompOpEvalFirst:
12450 * @ctxt: the XPath parser context with the compiled expression
12451 * @op: an XPath compiled operation
12452 * @first: the first elem found so far
12453 *
12454 * Evaluate the Precompiled XPath operation searching only the first
12455 * element in document order
12456 *
12457 * Returns the number of examined objects.
12458 */
12459static int
12460xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12461 xmlXPathStepOpPtr op, xmlNodePtr * first)
12462{
12463 int total = 0, cur;
12464 xmlXPathCompExprPtr comp;
12465 xmlXPathObjectPtr arg1, arg2;
12466
Daniel Veillard556c6682001-10-06 09:59:51 +000012467 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012468 comp = ctxt->comp;
12469 switch (op->op) {
12470 case XPATH_OP_END:
12471 return (0);
12472 case XPATH_OP_UNION:
12473 total =
12474 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12475 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012476 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012477 if ((ctxt->value != NULL)
12478 && (ctxt->value->type == XPATH_NODESET)
12479 && (ctxt->value->nodesetval != NULL)
12480 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12481 /*
12482 * limit tree traversing to first node in the result
12483 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012484 /*
12485 * OPTIMIZE TODO: This implicitely sorts
12486 * the result, even if not needed. E.g. if the argument
12487 * of the count() function, no sorting is needed.
12488 * OPTIMIZE TODO: How do we know if the node-list wasn't
12489 * aready sorted?
12490 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012491 if (ctxt->value->nodesetval->nodeNr > 1)
12492 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012493 *first = ctxt->value->nodesetval->nodeTab[0];
12494 }
12495 cur =
12496 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12497 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012498 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012499 CHECK_TYPE0(XPATH_NODESET);
12500 arg2 = valuePop(ctxt);
12501
12502 CHECK_TYPE0(XPATH_NODESET);
12503 arg1 = valuePop(ctxt);
12504
12505 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12506 arg2->nodesetval);
12507 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012508 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012509 /* optimizer */
12510 if (total > cur)
12511 xmlXPathCompSwap(op);
12512 return (total + cur);
12513 case XPATH_OP_ROOT:
12514 xmlXPathRoot(ctxt);
12515 return (0);
12516 case XPATH_OP_NODE:
12517 if (op->ch1 != -1)
12518 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012519 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012520 if (op->ch2 != -1)
12521 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012522 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012523 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12524 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012525 return (total);
12526 case XPATH_OP_RESET:
12527 if (op->ch1 != -1)
12528 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012529 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012530 if (op->ch2 != -1)
12531 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012532 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012533 ctxt->context->node = NULL;
12534 return (total);
12535 case XPATH_OP_COLLECT:{
12536 if (op->ch1 == -1)
12537 return (total);
12538
12539 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012540 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012541
Daniel Veillardf06307e2001-07-03 10:35:50 +000012542 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
12543 return (total);
12544 }
12545 case XPATH_OP_VALUE:
12546 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012547 xmlXPathCacheObjectCopy(ctxt->context,
12548 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012549 return (0);
12550 case XPATH_OP_SORT:
12551 if (op->ch1 != -1)
12552 total +=
12553 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12554 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012555 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012556 if ((ctxt->value != NULL)
12557 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012558 && (ctxt->value->nodesetval != NULL)
12559 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012560 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12561 return (total);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012562#ifdef XP_OPTIMIZED_FILTER_FIRST
12563 case XPATH_OP_FILTER:
12564 total =+ xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12565 return (total);
12566#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000012567 default:
12568 return (xmlXPathCompOpEval(ctxt, op));
12569 }
12570}
12571
12572/**
12573 * xmlXPathCompOpEvalLast:
12574 * @ctxt: the XPath parser context with the compiled expression
12575 * @op: an XPath compiled operation
12576 * @last: the last elem found so far
12577 *
12578 * Evaluate the Precompiled XPath operation searching only the last
12579 * element in document order
12580 *
William M. Brack08171912003-12-29 02:52:11 +000012581 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000012582 */
12583static int
12584xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12585 xmlNodePtr * last)
12586{
12587 int total = 0, cur;
12588 xmlXPathCompExprPtr comp;
12589 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +000012590 xmlNodePtr bak;
12591 xmlDocPtr bakd;
12592 int pp;
12593 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012594
Daniel Veillard556c6682001-10-06 09:59:51 +000012595 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012596 comp = ctxt->comp;
12597 switch (op->op) {
12598 case XPATH_OP_END:
12599 return (0);
12600 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +000012601 bakd = ctxt->context->doc;
12602 bak = ctxt->context->node;
12603 pp = ctxt->context->proximityPosition;
12604 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012605 total =
12606 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012607 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012608 if ((ctxt->value != NULL)
12609 && (ctxt->value->type == XPATH_NODESET)
12610 && (ctxt->value->nodesetval != NULL)
12611 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12612 /*
12613 * limit tree traversing to first node in the result
12614 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012615 if (ctxt->value->nodesetval->nodeNr > 1)
12616 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012617 *last =
12618 ctxt->value->nodesetval->nodeTab[ctxt->value->
12619 nodesetval->nodeNr -
12620 1];
12621 }
William M. Brackce4fc562004-01-22 02:47:18 +000012622 ctxt->context->doc = bakd;
12623 ctxt->context->node = bak;
12624 ctxt->context->proximityPosition = pp;
12625 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012626 cur =
12627 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012628 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012629 if ((ctxt->value != NULL)
12630 && (ctxt->value->type == XPATH_NODESET)
12631 && (ctxt->value->nodesetval != NULL)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012632 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012633 }
12634 CHECK_TYPE0(XPATH_NODESET);
12635 arg2 = valuePop(ctxt);
12636
12637 CHECK_TYPE0(XPATH_NODESET);
12638 arg1 = valuePop(ctxt);
12639
12640 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12641 arg2->nodesetval);
12642 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012643 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012644 /* optimizer */
12645 if (total > cur)
12646 xmlXPathCompSwap(op);
12647 return (total + cur);
12648 case XPATH_OP_ROOT:
12649 xmlXPathRoot(ctxt);
12650 return (0);
12651 case XPATH_OP_NODE:
12652 if (op->ch1 != -1)
12653 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012654 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012655 if (op->ch2 != -1)
12656 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012657 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012658 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12659 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012660 return (total);
12661 case XPATH_OP_RESET:
12662 if (op->ch1 != -1)
12663 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012664 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012665 if (op->ch2 != -1)
12666 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012667 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012668 ctxt->context->node = NULL;
12669 return (total);
12670 case XPATH_OP_COLLECT:{
12671 if (op->ch1 == -1)
12672 return (0);
12673
12674 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012675 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012676
Daniel Veillardf06307e2001-07-03 10:35:50 +000012677 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
12678 return (total);
12679 }
12680 case XPATH_OP_VALUE:
12681 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012682 xmlXPathCacheObjectCopy(ctxt->context,
12683 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012684 return (0);
12685 case XPATH_OP_SORT:
12686 if (op->ch1 != -1)
12687 total +=
12688 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12689 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012690 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012691 if ((ctxt->value != NULL)
12692 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012693 && (ctxt->value->nodesetval != NULL)
12694 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012695 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12696 return (total);
12697 default:
12698 return (xmlXPathCompOpEval(ctxt, op));
12699 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012700}
12701
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012702#ifdef XP_OPTIMIZED_FILTER_FIRST
12703static int
12704xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12705 xmlXPathStepOpPtr op, xmlNodePtr * first)
12706{
12707 int total = 0;
12708 xmlXPathCompExprPtr comp;
12709 xmlXPathObjectPtr res;
12710 xmlXPathObjectPtr obj;
12711 xmlNodeSetPtr oldset;
12712 xmlNodePtr oldnode;
12713 xmlDocPtr oldDoc;
12714 int i;
12715
12716 CHECK_ERROR0;
12717 comp = ctxt->comp;
12718 /*
12719 * Optimization for ()[last()] selection i.e. the last elem
12720 */
12721 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12722 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12723 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12724 int f = comp->steps[op->ch2].ch1;
12725
12726 if ((f != -1) &&
12727 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12728 (comp->steps[f].value5 == NULL) &&
12729 (comp->steps[f].value == 0) &&
12730 (comp->steps[f].value4 != NULL) &&
12731 (xmlStrEqual
12732 (comp->steps[f].value4, BAD_CAST "last"))) {
12733 xmlNodePtr last = NULL;
12734
12735 total +=
12736 xmlXPathCompOpEvalLast(ctxt,
12737 &comp->steps[op->ch1],
12738 &last);
12739 CHECK_ERROR0;
12740 /*
12741 * The nodeset should be in document order,
12742 * Keep only the last value
12743 */
12744 if ((ctxt->value != NULL) &&
12745 (ctxt->value->type == XPATH_NODESET) &&
12746 (ctxt->value->nodesetval != NULL) &&
12747 (ctxt->value->nodesetval->nodeTab != NULL) &&
12748 (ctxt->value->nodesetval->nodeNr > 1)) {
12749 ctxt->value->nodesetval->nodeTab[0] =
12750 ctxt->value->nodesetval->nodeTab[ctxt->
12751 value->
12752 nodesetval->
12753 nodeNr -
12754 1];
12755 ctxt->value->nodesetval->nodeNr = 1;
12756 *first = *(ctxt->value->nodesetval->nodeTab);
12757 }
12758 return (total);
12759 }
12760 }
12761
12762 if (op->ch1 != -1)
12763 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12764 CHECK_ERROR0;
12765 if (op->ch2 == -1)
12766 return (total);
12767 if (ctxt->value == NULL)
12768 return (total);
12769
12770#ifdef LIBXML_XPTR_ENABLED
12771 oldnode = ctxt->context->node;
12772 /*
12773 * Hum are we filtering the result of an XPointer expression
12774 */
12775 if (ctxt->value->type == XPATH_LOCATIONSET) {
12776 xmlXPathObjectPtr tmp = NULL;
12777 xmlLocationSetPtr newlocset = NULL;
12778 xmlLocationSetPtr oldlocset;
12779
12780 /*
12781 * Extract the old locset, and then evaluate the result of the
12782 * expression for all the element in the locset. use it to grow
12783 * up a new locset.
12784 */
12785 CHECK_TYPE0(XPATH_LOCATIONSET);
12786 obj = valuePop(ctxt);
12787 oldlocset = obj->user;
12788 ctxt->context->node = NULL;
12789
12790 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12791 ctxt->context->contextSize = 0;
12792 ctxt->context->proximityPosition = 0;
12793 if (op->ch2 != -1)
12794 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12795 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012796 if (res != NULL) {
12797 xmlXPathReleaseObject(ctxt->context, res);
12798 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012799 valuePush(ctxt, obj);
12800 CHECK_ERROR0;
12801 return (total);
12802 }
12803 newlocset = xmlXPtrLocationSetCreate(NULL);
12804
12805 for (i = 0; i < oldlocset->locNr; i++) {
12806 /*
12807 * Run the evaluation with a node list made of a
12808 * single item in the nodelocset.
12809 */
12810 ctxt->context->node = oldlocset->locTab[i]->user;
12811 ctxt->context->contextSize = oldlocset->locNr;
12812 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012813 if (tmp == NULL) {
12814 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12815 ctxt->context->node);
12816 } else {
12817 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12818 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012819 }
12820 valuePush(ctxt, tmp);
12821 if (op->ch2 != -1)
12822 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12823 if (ctxt->error != XPATH_EXPRESSION_OK) {
12824 xmlXPathFreeObject(obj);
12825 return(0);
12826 }
12827 /*
12828 * The result of the evaluation need to be tested to
12829 * decided whether the filter succeeded or not
12830 */
12831 res = valuePop(ctxt);
12832 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12833 xmlXPtrLocationSetAdd(newlocset,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012834 xmlXPathCacheObjectCopy(ctxt->context,
12835 oldlocset->locTab[i]));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012836 }
12837 /*
12838 * Cleanup
12839 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012840 if (res != NULL) {
12841 xmlXPathReleaseObject(ctxt->context, res);
12842 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012843 if (ctxt->value == tmp) {
12844 valuePop(ctxt);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012845 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012846 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012847 * REVISIT TODO: Don't create a temporary nodeset
12848 * for everly iteration.
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012849 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012850 /* OLD: xmlXPathFreeObject(res); */
12851 } else
12852 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012853 ctxt->context->node = NULL;
12854 /*
12855 * Only put the first node in the result, then leave.
12856 */
12857 if (newlocset->locNr > 0) {
12858 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
12859 break;
12860 }
12861 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012862 if (tmp != NULL) {
12863 xmlXPathReleaseObject(ctxt->context, tmp);
12864 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012865 /*
12866 * The result is used as the new evaluation locset.
12867 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012868 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012869 ctxt->context->node = NULL;
12870 ctxt->context->contextSize = -1;
12871 ctxt->context->proximityPosition = -1;
12872 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12873 ctxt->context->node = oldnode;
12874 return (total);
12875 }
12876#endif /* LIBXML_XPTR_ENABLED */
12877
12878 /*
12879 * Extract the old set, and then evaluate the result of the
12880 * expression for all the element in the set. use it to grow
12881 * up a new set.
12882 */
12883 CHECK_TYPE0(XPATH_NODESET);
12884 obj = valuePop(ctxt);
12885 oldset = obj->nodesetval;
12886
12887 oldnode = ctxt->context->node;
12888 oldDoc = ctxt->context->doc;
12889 ctxt->context->node = NULL;
12890
12891 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
12892 ctxt->context->contextSize = 0;
12893 ctxt->context->proximityPosition = 0;
12894 /* QUESTION TODO: Why was this code commented out?
12895 if (op->ch2 != -1)
12896 total +=
12897 xmlXPathCompOpEval(ctxt,
12898 &comp->steps[op->ch2]);
12899 CHECK_ERROR0;
12900 res = valuePop(ctxt);
12901 if (res != NULL)
12902 xmlXPathFreeObject(res);
12903 */
12904 valuePush(ctxt, obj);
12905 ctxt->context->node = oldnode;
12906 CHECK_ERROR0;
12907 } else {
12908 xmlNodeSetPtr newset;
12909 xmlXPathObjectPtr tmp = NULL;
12910 /*
12911 * Initialize the new set.
12912 * Also set the xpath document in case things like
12913 * key() evaluation are attempted on the predicate
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012914 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012915 newset = xmlXPathNodeSetCreate(NULL);
12916
12917 for (i = 0; i < oldset->nodeNr; i++) {
12918 /*
12919 * Run the evaluation with a node list made of
12920 * a single item in the nodeset.
12921 */
12922 ctxt->context->node = oldset->nodeTab[i];
12923 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
12924 (oldset->nodeTab[i]->doc != NULL))
12925 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012926 if (tmp == NULL) {
12927 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12928 ctxt->context->node);
12929 } else {
12930 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12931 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012932 }
12933 valuePush(ctxt, tmp);
12934 ctxt->context->contextSize = oldset->nodeNr;
12935 ctxt->context->proximityPosition = i + 1;
12936 if (op->ch2 != -1)
12937 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12938 if (ctxt->error != XPATH_EXPRESSION_OK) {
12939 xmlXPathFreeNodeSet(newset);
12940 xmlXPathFreeObject(obj);
12941 return(0);
12942 }
12943 /*
12944 * The result of the evaluation needs to be tested to
12945 * decide whether the filter succeeded or not
12946 */
12947 res = valuePop(ctxt);
12948 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12949 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
12950 }
12951 /*
12952 * Cleanup
12953 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012954 if (res != NULL) {
12955 xmlXPathReleaseObject(ctxt->context, res);
12956 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012957 if (ctxt->value == tmp) {
12958 valuePop(ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012959 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012960 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012961 * in order to avoid massive recreation inside this
12962 * loop.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012963 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012964 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012965 } else
12966 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012967 ctxt->context->node = NULL;
12968 /*
12969 * Only put the first node in the result, then leave.
12970 */
12971 if (newset->nodeNr > 0) {
12972 *first = *(newset->nodeTab);
12973 break;
12974 }
12975 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012976 if (tmp != NULL) {
12977 xmlXPathReleaseObject(ctxt->context, tmp);
12978 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012979 /*
12980 * The result is used as the new evaluation set.
12981 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012982 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012983 ctxt->context->node = NULL;
12984 ctxt->context->contextSize = -1;
12985 ctxt->context->proximityPosition = -1;
12986 /* may want to move this past the '}' later */
12987 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012988 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012989 }
12990 ctxt->context->node = oldnode;
12991 return(total);
12992}
12993#endif /* XP_OPTIMIZED_FILTER_FIRST */
12994
Owen Taylor3473f882001-02-23 17:55:21 +000012995/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012996 * xmlXPathCompOpEval:
12997 * @ctxt: the XPath parser context with the compiled expression
12998 * @op: an XPath compiled operation
12999 *
13000 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000013001 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013002 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013003static int
13004xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13005{
13006 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013007 int equal, ret;
13008 xmlXPathCompExprPtr comp;
13009 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013010 xmlNodePtr bak;
13011 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000013012 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000013013 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013014
Daniel Veillard556c6682001-10-06 09:59:51 +000013015 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013016 comp = ctxt->comp;
13017 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013018 case XPATH_OP_END:
13019 return (0);
13020 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013021 bakd = ctxt->context->doc;
13022 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013023 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013024 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013025 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013026 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013027 xmlXPathBooleanFunction(ctxt, 1);
13028 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13029 return (total);
13030 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013031 ctxt->context->doc = bakd;
13032 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013033 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013034 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013035 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013036 if (ctxt->error) {
13037 xmlXPathFreeObject(arg2);
13038 return(0);
13039 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013040 xmlXPathBooleanFunction(ctxt, 1);
13041 arg1 = valuePop(ctxt);
13042 arg1->boolval &= arg2->boolval;
13043 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013044 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013045 return (total);
13046 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013047 bakd = ctxt->context->doc;
13048 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013049 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013050 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013051 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013052 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013053 xmlXPathBooleanFunction(ctxt, 1);
13054 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13055 return (total);
13056 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013057 ctxt->context->doc = bakd;
13058 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013059 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013060 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013061 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013062 if (ctxt->error) {
13063 xmlXPathFreeObject(arg2);
13064 return(0);
13065 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013066 xmlXPathBooleanFunction(ctxt, 1);
13067 arg1 = valuePop(ctxt);
13068 arg1->boolval |= arg2->boolval;
13069 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013070 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013071 return (total);
13072 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013073 bakd = ctxt->context->doc;
13074 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013075 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013076 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013077 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013078 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013079 ctxt->context->doc = bakd;
13080 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013081 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013082 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013083 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013084 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000013085 if (op->value)
13086 equal = xmlXPathEqualValues(ctxt);
13087 else
13088 equal = xmlXPathNotEqualValues(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013089 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013090 return (total);
13091 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013092 bakd = ctxt->context->doc;
13093 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013094 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013095 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013096 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013097 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013098 ctxt->context->doc = bakd;
13099 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013100 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013101 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013102 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013103 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013104 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013105 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013106 return (total);
13107 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013108 bakd = ctxt->context->doc;
13109 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013110 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013111 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013112 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013113 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013114 if (op->ch2 != -1) {
13115 ctxt->context->doc = bakd;
13116 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013117 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013118 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013119 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013120 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013121 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013122 if (op->value == 0)
13123 xmlXPathSubValues(ctxt);
13124 else if (op->value == 1)
13125 xmlXPathAddValues(ctxt);
13126 else if (op->value == 2)
13127 xmlXPathValueFlipSign(ctxt);
13128 else if (op->value == 3) {
13129 CAST_TO_NUMBER;
13130 CHECK_TYPE0(XPATH_NUMBER);
13131 }
13132 return (total);
13133 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013134 bakd = ctxt->context->doc;
13135 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013136 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013137 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013138 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013139 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013140 ctxt->context->doc = bakd;
13141 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013142 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013143 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013144 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013145 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013146 if (op->value == 0)
13147 xmlXPathMultValues(ctxt);
13148 else if (op->value == 1)
13149 xmlXPathDivValues(ctxt);
13150 else if (op->value == 2)
13151 xmlXPathModValues(ctxt);
13152 return (total);
13153 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013154 bakd = ctxt->context->doc;
13155 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013156 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013157 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013158 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013159 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013160 ctxt->context->doc = bakd;
13161 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013162 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013163 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013164 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013165 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013166 CHECK_TYPE0(XPATH_NODESET);
13167 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013168
Daniel Veillardf06307e2001-07-03 10:35:50 +000013169 CHECK_TYPE0(XPATH_NODESET);
13170 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013171
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013172 if ((arg1->nodesetval == NULL) ||
13173 ((arg2->nodesetval != NULL) &&
13174 (arg2->nodesetval->nodeNr != 0)))
13175 {
13176 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13177 arg2->nodesetval);
13178 }
13179
Daniel Veillardf06307e2001-07-03 10:35:50 +000013180 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013181 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013182 return (total);
13183 case XPATH_OP_ROOT:
13184 xmlXPathRoot(ctxt);
13185 return (total);
13186 case XPATH_OP_NODE:
13187 if (op->ch1 != -1)
13188 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013189 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013190 if (op->ch2 != -1)
13191 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013192 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013193 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13194 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013195 return (total);
13196 case XPATH_OP_RESET:
13197 if (op->ch1 != -1)
13198 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013199 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013200 if (op->ch2 != -1)
13201 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013202 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013203 ctxt->context->node = NULL;
13204 return (total);
13205 case XPATH_OP_COLLECT:{
13206 if (op->ch1 == -1)
13207 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000013208
Daniel Veillardf06307e2001-07-03 10:35:50 +000013209 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013210 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013211
Daniel Veillardf06307e2001-07-03 10:35:50 +000013212 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
13213 return (total);
13214 }
13215 case XPATH_OP_VALUE:
13216 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013217 xmlXPathCacheObjectCopy(ctxt->context,
13218 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013219 return (total);
13220 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000013221 xmlXPathObjectPtr val;
13222
Daniel Veillardf06307e2001-07-03 10:35:50 +000013223 if (op->ch1 != -1)
13224 total +=
13225 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013226 if (op->value5 == NULL) {
13227 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13228 if (val == NULL) {
13229 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13230 return(0);
13231 }
13232 valuePush(ctxt, val);
13233 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013234 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013235
Daniel Veillardf06307e2001-07-03 10:35:50 +000013236 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13237 if (URI == NULL) {
13238 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013239 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000013240 op->value4, op->value5);
13241 return (total);
13242 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013243 val = xmlXPathVariableLookupNS(ctxt->context,
13244 op->value4, URI);
13245 if (val == NULL) {
13246 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13247 return(0);
13248 }
13249 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013250 }
13251 return (total);
13252 }
13253 case XPATH_OP_FUNCTION:{
13254 xmlXPathFunction func;
13255 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000013256 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013257
13258 if (op->ch1 != -1)
13259 total +=
13260 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013261 if (ctxt->valueNr < op->value) {
13262 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013263 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013264 ctxt->error = XPATH_INVALID_OPERAND;
13265 return (total);
13266 }
13267 for (i = 0; i < op->value; i++)
13268 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13269 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013270 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013271 ctxt->error = XPATH_INVALID_OPERAND;
13272 return (total);
13273 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013274 if (op->cache != NULL)
William M. Brackad0e67c2004-12-01 14:35:10 +000013275 XML_CAST_FPTR(func) = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013276 else {
13277 const xmlChar *URI = NULL;
13278
13279 if (op->value5 == NULL)
13280 func =
13281 xmlXPathFunctionLookup(ctxt->context,
13282 op->value4);
13283 else {
13284 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13285 if (URI == NULL) {
13286 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013287 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000013288 op->value4, op->value5);
13289 return (total);
13290 }
13291 func = xmlXPathFunctionLookupNS(ctxt->context,
13292 op->value4, URI);
13293 }
13294 if (func == NULL) {
13295 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013296 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000013297 op->value4);
13298 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013299 }
William M. Brackad0e67c2004-12-01 14:35:10 +000013300 op->cache = XML_CAST_FPTR(func);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013301 op->cacheURI = (void *) URI;
13302 }
13303 oldFunc = ctxt->context->function;
13304 oldFuncURI = ctxt->context->functionURI;
13305 ctxt->context->function = op->value4;
13306 ctxt->context->functionURI = op->cacheURI;
13307 func(ctxt, op->value);
13308 ctxt->context->function = oldFunc;
13309 ctxt->context->functionURI = oldFuncURI;
13310 return (total);
13311 }
13312 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000013313 bakd = ctxt->context->doc;
13314 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000013315 pp = ctxt->context->proximityPosition;
13316 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013317 if (op->ch1 != -1)
13318 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
William M. Brack645a9242004-11-09 12:20:42 +000013319 ctxt->context->contextSize = cs;
13320 ctxt->context->proximityPosition = pp;
Daniel Veillard088bf112002-05-14 11:03:59 +000013321 ctxt->context->node = bak;
William M. Brack645a9242004-11-09 12:20:42 +000013322 ctxt->context->doc = bakd;
Daniel Veillard556c6682001-10-06 09:59:51 +000013323 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000013324 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013325 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000013326 ctxt->context->doc = bakd;
13327 ctxt->context->node = bak;
13328 CHECK_ERROR0;
13329 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013330 return (total);
13331 case XPATH_OP_PREDICATE:
13332 case XPATH_OP_FILTER:{
13333 xmlXPathObjectPtr res;
13334 xmlXPathObjectPtr obj, tmp;
13335 xmlNodeSetPtr newset = NULL;
13336 xmlNodeSetPtr oldset;
13337 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000013338 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013339 int i;
13340
13341 /*
13342 * Optimization for ()[1] selection i.e. the first elem
13343 */
13344 if ((op->ch1 != -1) && (op->ch2 != -1) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013345#ifdef XP_OPTIMIZED_FILTER_FIRST
13346 /*
13347 * FILTER TODO: Can we assume that the inner processing
13348 * will result in an ordered list if we have an
13349 * XPATH_OP_FILTER?
13350 * What about an additional field or flag on
13351 * xmlXPathObject like @sorted ? This way we wouln'd need
13352 * to assume anything, so it would be more robust and
13353 * easier to optimize.
13354 */
13355 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13356 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13357#else
13358 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13359#endif
13360 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013361 xmlXPathObjectPtr val;
13362
13363 val = comp->steps[op->ch2].value4;
13364 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13365 (val->floatval == 1.0)) {
13366 xmlNodePtr first = NULL;
13367
13368 total +=
13369 xmlXPathCompOpEvalFirst(ctxt,
13370 &comp->steps[op->ch1],
13371 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000013372 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013373 /*
13374 * The nodeset should be in document order,
13375 * Keep only the first value
13376 */
13377 if ((ctxt->value != NULL) &&
13378 (ctxt->value->type == XPATH_NODESET) &&
13379 (ctxt->value->nodesetval != NULL) &&
13380 (ctxt->value->nodesetval->nodeNr > 1))
13381 ctxt->value->nodesetval->nodeNr = 1;
13382 return (total);
13383 }
13384 }
13385 /*
13386 * Optimization for ()[last()] selection i.e. the last elem
13387 */
13388 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13389 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13390 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13391 int f = comp->steps[op->ch2].ch1;
13392
13393 if ((f != -1) &&
13394 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13395 (comp->steps[f].value5 == NULL) &&
13396 (comp->steps[f].value == 0) &&
13397 (comp->steps[f].value4 != NULL) &&
13398 (xmlStrEqual
13399 (comp->steps[f].value4, BAD_CAST "last"))) {
13400 xmlNodePtr last = NULL;
13401
13402 total +=
13403 xmlXPathCompOpEvalLast(ctxt,
13404 &comp->steps[op->ch1],
13405 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000013406 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013407 /*
13408 * The nodeset should be in document order,
13409 * Keep only the last value
13410 */
13411 if ((ctxt->value != NULL) &&
13412 (ctxt->value->type == XPATH_NODESET) &&
13413 (ctxt->value->nodesetval != NULL) &&
13414 (ctxt->value->nodesetval->nodeTab != NULL) &&
13415 (ctxt->value->nodesetval->nodeNr > 1)) {
13416 ctxt->value->nodesetval->nodeTab[0] =
13417 ctxt->value->nodesetval->nodeTab[ctxt->
13418 value->
13419 nodesetval->
13420 nodeNr -
13421 1];
13422 ctxt->value->nodesetval->nodeNr = 1;
13423 }
13424 return (total);
13425 }
13426 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013427 /*
13428 * Process inner predicates first.
13429 * Example "index[parent::book][1]":
13430 * ...
13431 * PREDICATE <-- we are here "[1]"
13432 * PREDICATE <-- process "[parent::book]" first
13433 * SORT
13434 * COLLECT 'parent' 'name' 'node' book
13435 * NODE
13436 * ELEM Object is a number : 1
13437 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013438 if (op->ch1 != -1)
13439 total +=
13440 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013441 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013442 if (op->ch2 == -1)
13443 return (total);
13444 if (ctxt->value == NULL)
13445 return (total);
13446
13447 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013448
13449#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013450 /*
13451 * Hum are we filtering the result of an XPointer expression
13452 */
13453 if (ctxt->value->type == XPATH_LOCATIONSET) {
13454 xmlLocationSetPtr newlocset = NULL;
13455 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013456
Daniel Veillardf06307e2001-07-03 10:35:50 +000013457 /*
13458 * Extract the old locset, and then evaluate the result of the
13459 * expression for all the element in the locset. use it to grow
13460 * up a new locset.
13461 */
13462 CHECK_TYPE0(XPATH_LOCATIONSET);
13463 obj = valuePop(ctxt);
13464 oldlocset = obj->user;
13465 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013466
Daniel Veillardf06307e2001-07-03 10:35:50 +000013467 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13468 ctxt->context->contextSize = 0;
13469 ctxt->context->proximityPosition = 0;
13470 if (op->ch2 != -1)
13471 total +=
13472 xmlXPathCompOpEval(ctxt,
13473 &comp->steps[op->ch2]);
13474 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013475 if (res != NULL) {
13476 xmlXPathReleaseObject(ctxt->context, res);
13477 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013478 valuePush(ctxt, obj);
13479 CHECK_ERROR0;
13480 return (total);
13481 }
13482 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013483
Daniel Veillardf06307e2001-07-03 10:35:50 +000013484 for (i = 0; i < oldlocset->locNr; i++) {
13485 /*
13486 * Run the evaluation with a node list made of a
13487 * single item in the nodelocset.
13488 */
13489 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013490 ctxt->context->contextSize = oldlocset->locNr;
13491 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013492 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13493 ctxt->context->node);
William M. Brackf7eb7942003-12-31 07:59:17 +000013494 valuePush(ctxt, tmp);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013495
Daniel Veillardf06307e2001-07-03 10:35:50 +000013496 if (op->ch2 != -1)
13497 total +=
13498 xmlXPathCompOpEval(ctxt,
13499 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013500 if (ctxt->error != XPATH_EXPRESSION_OK) {
13501 xmlXPathFreeObject(obj);
13502 return(0);
13503 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013504
Daniel Veillardf06307e2001-07-03 10:35:50 +000013505 /*
13506 * The result of the evaluation need to be tested to
13507 * decided whether the filter succeeded or not
13508 */
13509 res = valuePop(ctxt);
13510 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13511 xmlXPtrLocationSetAdd(newlocset,
13512 xmlXPathObjectCopy
13513 (oldlocset->locTab[i]));
13514 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013515
Daniel Veillardf06307e2001-07-03 10:35:50 +000013516 /*
13517 * Cleanup
13518 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013519 if (res != NULL) {
13520 xmlXPathReleaseObject(ctxt->context, res);
13521 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013522 if (ctxt->value == tmp) {
13523 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013524 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013525 }
13526
13527 ctxt->context->node = NULL;
13528 }
13529
13530 /*
13531 * The result is used as the new evaluation locset.
13532 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013533 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013534 ctxt->context->node = NULL;
13535 ctxt->context->contextSize = -1;
13536 ctxt->context->proximityPosition = -1;
13537 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13538 ctxt->context->node = oldnode;
13539 return (total);
13540 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013541#endif /* LIBXML_XPTR_ENABLED */
13542
Daniel Veillardf06307e2001-07-03 10:35:50 +000013543 /*
13544 * Extract the old set, and then evaluate the result of the
13545 * expression for all the element in the set. use it to grow
13546 * up a new set.
13547 */
13548 CHECK_TYPE0(XPATH_NODESET);
13549 obj = valuePop(ctxt);
13550 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000013551
Daniel Veillardf06307e2001-07-03 10:35:50 +000013552 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000013553 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013554 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013555
Daniel Veillardf06307e2001-07-03 10:35:50 +000013556 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13557 ctxt->context->contextSize = 0;
13558 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000013559/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000013560 if (op->ch2 != -1)
13561 total +=
13562 xmlXPathCompOpEval(ctxt,
13563 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013564 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013565 res = valuePop(ctxt);
13566 if (res != NULL)
13567 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000013568*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000013569 valuePush(ctxt, obj);
13570 ctxt->context->node = oldnode;
13571 CHECK_ERROR0;
13572 } else {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013573 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013574 /*
13575 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000013576 * Also set the xpath document in case things like
13577 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000013578 */
13579 newset = xmlXPathNodeSetCreate(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013580 /*
13581 * SPEC XPath 1.0:
13582 * "For each node in the node-set to be filtered, the
13583 * PredicateExpr is evaluated with that node as the
13584 * context node, with the number of nodes in the
13585 * node-set as the context size, and with the proximity
13586 * position of the node in the node-set with respect to
13587 * the axis as the context position;"
13588 * @oldset is the node-set" to be filtered.
13589 *
13590 * SPEC XPath 1.0:
13591 * "only predicates change the context position and
13592 * context size (see [2.4 Predicates])."
13593 * Example:
13594 * node-set context pos
13595 * nA 1
13596 * nB 2
13597 * nC 3
13598 * After applying predicate [position() > 1] :
13599 * node-set context pos
13600 * nB 1
13601 * nC 2
13602 *
13603 * removed the first node in the node-set, then
13604 * the context position of the
13605 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013606 for (i = 0; i < oldset->nodeNr; i++) {
13607 /*
13608 * Run the evaluation with a node list made of
13609 * a single item in the nodeset.
13610 */
13611 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000013612 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13613 (oldset->nodeTab[i]->doc != NULL))
13614 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013615 if (tmp == NULL) {
13616 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13617 ctxt->context->node);
13618 } else {
13619 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13620 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013621 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013622 valuePush(ctxt, tmp);
13623 ctxt->context->contextSize = oldset->nodeNr;
13624 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013625 /*
13626 * Evaluate the predicate against the context node.
13627 * Can/should we optimize position() predicates
13628 * here (e.g. "[1]")?
13629 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013630 if (op->ch2 != -1)
13631 total +=
13632 xmlXPathCompOpEval(ctxt,
13633 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013634 if (ctxt->error != XPATH_EXPRESSION_OK) {
13635 xmlXPathFreeNodeSet(newset);
13636 xmlXPathFreeObject(obj);
13637 return(0);
13638 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013639
Daniel Veillardf06307e2001-07-03 10:35:50 +000013640 /*
William M. Brack08171912003-12-29 02:52:11 +000013641 * The result of the evaluation needs to be tested to
13642 * decide whether the filter succeeded or not
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013643 */
13644 /*
13645 * OPTIMIZE TODO: Can we use
13646 * xmlXPathNodeSetAdd*Unique()* instead?
13647 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013648 res = valuePop(ctxt);
13649 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13650 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13651 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013652
Daniel Veillardf06307e2001-07-03 10:35:50 +000013653 /*
13654 * Cleanup
13655 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013656 if (res != NULL) {
13657 xmlXPathReleaseObject(ctxt->context, res);
13658 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013659 if (ctxt->value == tmp) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013660 valuePop(ctxt);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000013661 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013662 /*
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013663 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013664 * in order to avoid massive recreation inside this
13665 * loop.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013666 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013667 } else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013668 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013669 ctxt->context->node = NULL;
13670 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013671 if (tmp != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013672 xmlXPathReleaseObject(ctxt->context, tmp);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013673 /*
13674 * The result is used as the new evaluation set.
13675 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013676 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013677 ctxt->context->node = NULL;
13678 ctxt->context->contextSize = -1;
13679 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000013680 /* may want to move this past the '}' later */
13681 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013682 valuePush(ctxt,
13683 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013684 }
13685 ctxt->context->node = oldnode;
13686 return (total);
13687 }
13688 case XPATH_OP_SORT:
13689 if (op->ch1 != -1)
13690 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013691 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013692 if ((ctxt->value != NULL) &&
13693 (ctxt->value->type == XPATH_NODESET) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013694 (ctxt->value->nodesetval != NULL) &&
13695 (ctxt->value->nodesetval->nodeNr > 1))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013696 {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013697 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013698 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013699 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013700#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013701 case XPATH_OP_RANGETO:{
13702 xmlXPathObjectPtr range;
13703 xmlXPathObjectPtr res, obj;
13704 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000013705 xmlLocationSetPtr newlocset = NULL;
13706 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013707 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000013708 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013709
Daniel Veillardf06307e2001-07-03 10:35:50 +000013710 if (op->ch1 != -1)
13711 total +=
13712 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13713 if (op->ch2 == -1)
13714 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013715
William M. Brack08171912003-12-29 02:52:11 +000013716 if (ctxt->value->type == XPATH_LOCATIONSET) {
13717 /*
13718 * Extract the old locset, and then evaluate the result of the
13719 * expression for all the element in the locset. use it to grow
13720 * up a new locset.
13721 */
13722 CHECK_TYPE0(XPATH_LOCATIONSET);
13723 obj = valuePop(ctxt);
13724 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013725
William M. Brack08171912003-12-29 02:52:11 +000013726 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000013727 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000013728 ctxt->context->contextSize = 0;
13729 ctxt->context->proximityPosition = 0;
13730 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13731 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013732 if (res != NULL) {
13733 xmlXPathReleaseObject(ctxt->context, res);
13734 }
William M. Brack08171912003-12-29 02:52:11 +000013735 valuePush(ctxt, obj);
13736 CHECK_ERROR0;
13737 return (total);
13738 }
13739 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013740
William M. Brack08171912003-12-29 02:52:11 +000013741 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013742 /*
William M. Brack08171912003-12-29 02:52:11 +000013743 * Run the evaluation with a node list made of a
13744 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000013745 */
William M. Brackf7eb7942003-12-31 07:59:17 +000013746 ctxt->context->node = oldlocset->locTab[i]->user;
13747 ctxt->context->contextSize = oldlocset->locNr;
13748 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013749 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13750 ctxt->context->node);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013751 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013752
Daniel Veillardf06307e2001-07-03 10:35:50 +000013753 if (op->ch2 != -1)
13754 total +=
13755 xmlXPathCompOpEval(ctxt,
13756 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013757 if (ctxt->error != XPATH_EXPRESSION_OK) {
13758 xmlXPathFreeObject(obj);
13759 return(0);
13760 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013761
Daniel Veillardf06307e2001-07-03 10:35:50 +000013762 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000013763 if (res->type == XPATH_LOCATIONSET) {
13764 xmlLocationSetPtr rloc =
13765 (xmlLocationSetPtr)res->user;
13766 for (j=0; j<rloc->locNr; j++) {
13767 range = xmlXPtrNewRange(
13768 oldlocset->locTab[i]->user,
13769 oldlocset->locTab[i]->index,
13770 rloc->locTab[j]->user2,
13771 rloc->locTab[j]->index2);
13772 if (range != NULL) {
13773 xmlXPtrLocationSetAdd(newlocset, range);
13774 }
13775 }
13776 } else {
13777 range = xmlXPtrNewRangeNodeObject(
13778 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13779 if (range != NULL) {
13780 xmlXPtrLocationSetAdd(newlocset,range);
13781 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013782 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013783
Daniel Veillardf06307e2001-07-03 10:35:50 +000013784 /*
13785 * Cleanup
13786 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013787 if (res != NULL) {
13788 xmlXPathReleaseObject(ctxt->context, res);
13789 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013790 if (ctxt->value == tmp) {
13791 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013792 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013793 }
13794
13795 ctxt->context->node = NULL;
13796 }
William M. Brack72ee48d2003-12-30 08:30:19 +000013797 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000013798 CHECK_TYPE0(XPATH_NODESET);
13799 obj = valuePop(ctxt);
13800 oldset = obj->nodesetval;
13801 ctxt->context->node = NULL;
13802
13803 newlocset = xmlXPtrLocationSetCreate(NULL);
13804
13805 if (oldset != NULL) {
13806 for (i = 0; i < oldset->nodeNr; i++) {
13807 /*
13808 * Run the evaluation with a node list made of a single item
13809 * in the nodeset.
13810 */
13811 ctxt->context->node = oldset->nodeTab[i];
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013812 /*
13813 * OPTIMIZE TODO: Avoid recreation for every iteration.
13814 */
13815 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13816 ctxt->context->node);
William M. Brack08171912003-12-29 02:52:11 +000013817 valuePush(ctxt, tmp);
13818
13819 if (op->ch2 != -1)
13820 total +=
13821 xmlXPathCompOpEval(ctxt,
13822 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013823 if (ctxt->error != XPATH_EXPRESSION_OK) {
13824 xmlXPathFreeObject(obj);
13825 return(0);
13826 }
William M. Brack08171912003-12-29 02:52:11 +000013827
William M. Brack08171912003-12-29 02:52:11 +000013828 res = valuePop(ctxt);
13829 range =
13830 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13831 res);
13832 if (range != NULL) {
13833 xmlXPtrLocationSetAdd(newlocset, range);
13834 }
13835
13836 /*
13837 * Cleanup
13838 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013839 if (res != NULL) {
13840 xmlXPathReleaseObject(ctxt->context, res);
13841 }
William M. Brack08171912003-12-29 02:52:11 +000013842 if (ctxt->value == tmp) {
13843 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013844 xmlXPathReleaseObject(ctxt->context, res);
William M. Brack08171912003-12-29 02:52:11 +000013845 }
13846
13847 ctxt->context->node = NULL;
13848 }
13849 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013850 }
13851
13852 /*
13853 * The result is used as the new evaluation set.
13854 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013855 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013856 ctxt->context->node = NULL;
13857 ctxt->context->contextSize = -1;
13858 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000013859 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013860 return (total);
13861 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013862#endif /* LIBXML_XPTR_ENABLED */
13863 }
13864 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000013865 "XPath: unknown precompiled operation %d\n", op->op);
13866 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013867}
13868
Daniel Veillard56de87e2005-02-16 00:22:29 +000013869#ifdef XPATH_STREAMING
13870/**
13871 * xmlXPathRunStreamEval:
13872 * @ctxt: the XPath parser context with the compiled expression
13873 *
13874 * Evaluate the Precompiled Streamable XPath expression in the given context.
13875 */
13876static xmlXPathObjectPtr
13877xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp) {
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013878 int max_depth, min_depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013879 int from_root;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013880 int ret, depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013881#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
13882 int eval_all_nodes;
13883#endif
William M. Brack12d37ab2005-02-21 13:54:07 +000013884 xmlNodePtr cur = NULL, limit = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013885 xmlXPathObjectPtr retval;
13886 xmlStreamCtxtPtr patstream;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013887
13888 int nb_nodes = 0;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013889
13890 if ((ctxt == NULL) || (comp == NULL))
13891 return(NULL);
13892 max_depth = xmlPatternMaxDepth(comp);
13893 if (max_depth == -1)
13894 return(NULL);
13895 if (max_depth == -2)
13896 max_depth = 10000;
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013897 min_depth = xmlPatternMinDepth(comp);
13898 if (min_depth == -1)
13899 return(NULL);
Daniel Veillard56de87e2005-02-16 00:22:29 +000013900 from_root = xmlPatternFromRoot(comp);
13901 if (from_root < 0)
13902 return(NULL);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000013903#if 0
13904 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
13905#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000013906
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013907 retval = xmlXPathCacheNewNodeSet(ctxt, NULL);
Daniel Veillard56de87e2005-02-16 00:22:29 +000013908 if (retval == NULL)
13909 return(NULL);
13910
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013911 /*
13912 * handle the special cases of / amd . being matched
13913 */
13914 if (min_depth == 0) {
13915 if (from_root) {
13916 xmlXPathNodeSetAddUnique(retval->nodesetval, (xmlNodePtr) ctxt->doc);
13917 } else {
13918 xmlXPathNodeSetAddUnique(retval->nodesetval, ctxt->node);
13919 }
13920 }
13921 if (max_depth == 0) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000013922 return(retval);
13923 }
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013924
Daniel Veillard56de87e2005-02-16 00:22:29 +000013925 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000013926 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013927 } else if (ctxt->node != NULL) {
13928 switch (ctxt->node->type) {
13929 case XML_ELEMENT_NODE:
13930 case XML_DOCUMENT_NODE:
13931 case XML_DOCUMENT_FRAG_NODE:
13932 case XML_HTML_DOCUMENT_NODE:
13933#ifdef LIBXML_DOCB_ENABLED
13934 case XML_DOCB_DOCUMENT_NODE:
13935#endif
13936 cur = ctxt->node;
13937 break;
13938 case XML_ATTRIBUTE_NODE:
13939 case XML_TEXT_NODE:
13940 case XML_CDATA_SECTION_NODE:
13941 case XML_ENTITY_REF_NODE:
13942 case XML_ENTITY_NODE:
13943 case XML_PI_NODE:
13944 case XML_COMMENT_NODE:
13945 case XML_NOTATION_NODE:
13946 case XML_DTD_NODE:
13947 case XML_DOCUMENT_TYPE_NODE:
13948 case XML_ELEMENT_DECL:
13949 case XML_ATTRIBUTE_DECL:
13950 case XML_ENTITY_DECL:
13951 case XML_NAMESPACE_DECL:
13952 case XML_XINCLUDE_START:
13953 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000013954 break;
13955 }
13956 limit = cur;
13957 }
13958 if (cur == NULL)
13959 return(retval);
13960
13961 patstream = xmlPatternGetStreamCtxt(comp);
13962 if (patstream == NULL) {
13963 return(retval);
13964 }
13965
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013966#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
13967 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
13968#endif
13969
Daniel Veillard56de87e2005-02-16 00:22:29 +000013970 if (from_root) {
13971 ret = xmlStreamPush(patstream, NULL, NULL);
13972 if (ret < 0) {
13973 } else if (ret == 1) {
13974 xmlXPathNodeSetAddUnique(retval->nodesetval, cur);
13975 }
13976 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000013977 depth = 0;
13978 goto scan_children;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013979next_node:
Daniel Veillardd3ff7ef2006-02-27 19:43:17 +000013980 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000013981 nb_nodes++;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013982
13983 switch (cur->type) {
13984 case XML_ELEMENT_NODE:
13985#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
13986 case XML_TEXT_NODE:
13987 case XML_CDATA_SECTION_NODE:
13988 case XML_COMMENT_NODE:
13989 case XML_PI_NODE:
13990#endif
13991 if (cur->type == XML_ELEMENT_NODE) {
13992 ret = xmlStreamPush(patstream, cur->name,
Daniel Veillard56de87e2005-02-16 00:22:29 +000013993 (cur->ns ? cur->ns->href : NULL));
William M. Brackfbb619f2005-06-06 13:49:18 +000013994 }
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013995#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
13996 else if (eval_all_nodes)
13997 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
13998 else
13999 break;
14000#endif
14001
14002 if (ret < 0) {
14003 /* NOP. */
14004 } else if (ret == 1) {
14005 xmlXPathNodeSetAddUnique(retval->nodesetval, cur);
14006 }
14007 if ((cur->children == NULL) || (depth >= max_depth)) {
14008 ret = xmlStreamPop(patstream);
14009 while (cur->next != NULL) {
14010 cur = cur->next;
14011 if ((cur->type != XML_ENTITY_DECL) &&
14012 (cur->type != XML_DTD_NODE))
14013 goto next_node;
14014 }
14015 }
14016 default:
14017 break;
14018 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014019
14020scan_children:
14021 if ((cur->children != NULL) && (depth < max_depth)) {
14022 /*
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014023 * Do not descend on entities declarations
Daniel Veillard56de87e2005-02-16 00:22:29 +000014024 */
14025 if (cur->children->type != XML_ENTITY_DECL) {
14026 cur = cur->children;
14027 depth++;
14028 /*
14029 * Skip DTDs
14030 */
14031 if (cur->type != XML_DTD_NODE)
14032 continue;
14033 }
14034 }
14035
14036 if (cur == limit)
14037 break;
14038
14039 while (cur->next != NULL) {
14040 cur = cur->next;
14041 if ((cur->type != XML_ENTITY_DECL) &&
14042 (cur->type != XML_DTD_NODE))
14043 goto next_node;
14044 }
14045
14046 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014047 cur = cur->parent;
14048 depth--;
14049 if ((cur == NULL) || (cur == limit))
14050 goto done;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014051 if (cur->type == XML_ELEMENT_NODE) {
14052 ret = xmlStreamPop(patstream);
14053 }
14054#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
14055 else if ((eval_all_nodes) &&
14056 ((cur->type == XML_TEXT_NODE) ||
14057 (cur->type == XML_CDATA_SECTION_NODE) ||
14058 (cur->type == XML_COMMENT_NODE) ||
14059 (cur->type == XML_PI_NODE)))
14060 {
14061 ret = xmlStreamPop(patstream);
14062 }
14063#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000014064 if (cur->next != NULL) {
14065 cur = cur->next;
14066 break;
14067 }
14068 } while (cur != NULL);
14069
14070 } while ((cur != NULL) && (depth >= 0));
14071done:
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014072#if 0
14073 printf("stream eval: checked %d nodes selected %d\n",
14074 nb_nodes, retval->nodesetval->nodeNr);
14075#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000014076 xmlFreeStreamCtxt(patstream);
14077 return(retval);
14078}
14079#endif /* XPATH_STREAMING */
14080
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014081/**
14082 * xmlXPathRunEval:
14083 * @ctxt: the XPath parser context with the compiled expression
14084 *
14085 * Evaluate the Precompiled XPath expression in the given context.
14086 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014087static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014088xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
14089 xmlXPathCompExprPtr comp;
14090
14091 if ((ctxt == NULL) || (ctxt->comp == NULL))
14092 return;
14093
14094 if (ctxt->valueTab == NULL) {
14095 /* Allocate the value stack */
14096 ctxt->valueTab = (xmlXPathObjectPtr *)
14097 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14098 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000014099 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014100 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014101 }
14102 ctxt->valueNr = 0;
14103 ctxt->valueMax = 10;
14104 ctxt->value = NULL;
14105 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014106#ifdef XPATH_STREAMING
14107 if (ctxt->comp->stream) {
14108 xmlXPathObjectPtr ret;
14109 ret = xmlXPathRunStreamEval(ctxt->context, ctxt->comp->stream);
14110 if (ret != NULL) {
14111 valuePush(ctxt, ret);
14112 return;
14113 }
14114 }
14115#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014116 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014117 if(comp->last < 0) {
14118 xmlGenericError(xmlGenericErrorContext,
14119 "xmlXPathRunEval: last is less than zero\n");
14120 return;
14121 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014122 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14123}
14124
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014125/************************************************************************
14126 * *
14127 * Public interfaces *
14128 * *
14129 ************************************************************************/
14130
14131/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014132 * xmlXPathEvalPredicate:
14133 * @ctxt: the XPath context
14134 * @res: the Predicate Expression evaluation result
14135 *
14136 * Evaluate a predicate result for the current node.
14137 * A PredicateExpr is evaluated by evaluating the Expr and converting
14138 * the result to a boolean. If the result is a number, the result will
14139 * be converted to true if the number is equal to the position of the
14140 * context node in the context node list (as returned by the position
14141 * function) and will be converted to false otherwise; if the result
14142 * is not a number, then the result will be converted as if by a call
14143 * to the boolean function.
14144 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014145 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014146 */
14147int
14148xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014149 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014150 switch (res->type) {
14151 case XPATH_BOOLEAN:
14152 return(res->boolval);
14153 case XPATH_NUMBER:
14154 return(res->floatval == ctxt->proximityPosition);
14155 case XPATH_NODESET:
14156 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000014157 if (res->nodesetval == NULL)
14158 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014159 return(res->nodesetval->nodeNr != 0);
14160 case XPATH_STRING:
14161 return((res->stringval != NULL) &&
14162 (xmlStrlen(res->stringval) != 0));
14163 default:
14164 STRANGE
14165 }
14166 return(0);
14167}
14168
14169/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014170 * xmlXPathEvaluatePredicateResult:
14171 * @ctxt: the XPath Parser context
14172 * @res: the Predicate Expression evaluation result
14173 *
14174 * Evaluate a predicate result for the current node.
14175 * A PredicateExpr is evaluated by evaluating the Expr and converting
14176 * the result to a boolean. If the result is a number, the result will
14177 * be converted to true if the number is equal to the position of the
14178 * context node in the context node list (as returned by the position
14179 * function) and will be converted to false otherwise; if the result
14180 * is not a number, then the result will be converted as if by a call
14181 * to the boolean function.
14182 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014183 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014184 */
14185int
14186xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14187 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014188 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014189 switch (res->type) {
14190 case XPATH_BOOLEAN:
14191 return(res->boolval);
14192 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000014193#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000014194 return((res->floatval == ctxt->context->proximityPosition) &&
14195 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000014196#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014197 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000014198#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014199 case XPATH_NODESET:
14200 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000014201 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000014202 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014203 return(res->nodesetval->nodeNr != 0);
14204 case XPATH_STRING:
14205 return((res->stringval != NULL) &&
14206 (xmlStrlen(res->stringval) != 0));
William M. Brack08171912003-12-29 02:52:11 +000014207#ifdef LIBXML_XPTR_ENABLED
14208 case XPATH_LOCATIONSET:{
14209 xmlLocationSetPtr ptr = res->user;
14210 if (ptr == NULL)
14211 return(0);
14212 return (ptr->locNr != 0);
14213 }
14214#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014215 default:
14216 STRANGE
14217 }
14218 return(0);
14219}
14220
Daniel Veillard56de87e2005-02-16 00:22:29 +000014221#ifdef XPATH_STREAMING
14222/**
14223 * xmlXPathTryStreamCompile:
14224 * @ctxt: an XPath context
14225 * @str: the XPath expression
14226 *
14227 * Try to compile the XPath expression as a streamable subset.
14228 *
14229 * Returns the compiled expression or NULL if failed to compile.
14230 */
14231static xmlXPathCompExprPtr
14232xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14233 /*
14234 * Optimization: use streaming patterns when the XPath expression can
14235 * be compiled to a stream lookup
14236 */
14237 xmlPatternPtr stream;
14238 xmlXPathCompExprPtr comp;
14239 xmlDictPtr dict = NULL;
14240 const xmlChar **namespaces = NULL;
14241 xmlNsPtr ns;
14242 int i, j;
14243
14244 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14245 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014246 const xmlChar *tmp;
14247
14248 /*
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014249 * We don't try to handle expressions using the verbose axis
14250 * specifiers ("::"), just the simplied form at this point.
14251 * Additionally, if there is no list of namespaces available and
14252 * there's a ":" in the expression, indicating a prefixed QName,
14253 * then we won't try to compile either. xmlPatterncompile() needs
14254 * to have a list of namespaces at compilation time in order to
14255 * compile prefixed name tests.
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014256 */
14257 tmp = xmlStrchr(str, ':');
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014258 if ((tmp != NULL) &&
14259 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14260 return(NULL);
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014261
Daniel Veillard56de87e2005-02-16 00:22:29 +000014262 if (ctxt != NULL) {
14263 dict = ctxt->dict;
14264 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000014265 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000014266 if (namespaces == NULL) {
14267 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14268 return(NULL);
14269 }
14270 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14271 ns = ctxt->namespaces[j];
14272 namespaces[i++] = ns->href;
14273 namespaces[i++] = ns->prefix;
14274 }
14275 namespaces[i++] = NULL;
14276 namespaces[i++] = NULL;
14277 }
14278 }
14279
William M. Brackea152c02005-06-09 18:12:28 +000014280 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14281 &namespaces[0]);
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014282 if (namespaces != NULL) {
14283 xmlFree((xmlChar **)namespaces);
14284 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014285 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14286 comp = xmlXPathNewCompExpr();
14287 if (comp == NULL) {
14288 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14289 return(NULL);
14290 }
14291 comp->stream = stream;
14292 comp->dict = dict;
14293 if (comp->dict)
14294 xmlDictReference(comp->dict);
14295 return(comp);
14296 }
14297 xmlFreePattern(stream);
14298 }
14299 return(NULL);
14300}
14301#endif /* XPATH_STREAMING */
14302
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014303static int
14304xmlXPathCanRewriteDosExpression(xmlChar *expr)
14305{
14306 if (expr == NULL)
14307 return(0);
14308 do {
14309 if ((*expr == '/') && (*(++expr) == '/'))
14310 return(1);
14311 } while (*expr++);
14312 return(0);
14313}
14314static void
14315xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14316{
14317 /*
14318 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14319 * internal representation.
14320 */
14321 if (op->ch1 != -1) {
14322 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14323 ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
14324 ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14325 ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14326 {
14327 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014328 * This is a "child::foo"
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014329 */
14330 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14331
14332 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14333 (prevop->ch1 != -1) &&
14334 ((xmlXPathAxisVal) prevop->value ==
14335 AXIS_DESCENDANT_OR_SELF) &&
14336 (prevop->ch2 == -1) &&
14337 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014338 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
14339 (comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014340 {
14341 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014342 * This is a "/descendant-or-self::node()" without predicates.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014343 * Eliminate it.
14344 */
14345 op->ch1 = prevop->ch1;
14346 op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
14347 }
14348 }
14349 if (op->ch1 != -1)
14350 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14351 }
14352 if (op->ch2 != -1)
14353 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14354}
14355
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014356/**
Daniel Veillard4773df22004-01-23 13:15:13 +000014357 * xmlXPathCtxtCompile:
14358 * @ctxt: an XPath context
14359 * @str: the XPath expression
14360 *
14361 * Compile an XPath expression
14362 *
14363 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14364 * the caller has to free the object.
14365 */
14366xmlXPathCompExprPtr
14367xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14368 xmlXPathParserContextPtr pctxt;
14369 xmlXPathCompExprPtr comp;
14370
Daniel Veillard56de87e2005-02-16 00:22:29 +000014371#ifdef XPATH_STREAMING
14372 comp = xmlXPathTryStreamCompile(ctxt, str);
14373 if (comp != NULL)
14374 return(comp);
14375#endif
14376
Daniel Veillard4773df22004-01-23 13:15:13 +000014377 xmlXPathInit();
14378
14379 pctxt = xmlXPathNewParserContext(str, ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014380 xmlXPathCompileExpr(pctxt, 1);
Daniel Veillard4773df22004-01-23 13:15:13 +000014381
14382 if( pctxt->error != XPATH_EXPRESSION_OK )
14383 {
14384 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000014385 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000014386 }
14387
14388 if (*pctxt->cur != 0) {
14389 /*
14390 * aleksey: in some cases this line prints *second* error message
14391 * (see bug #78858) and probably this should be fixed.
14392 * However, we are not sure that all error messages are printed
14393 * out in other places. It's not critical so we leave it as-is for now
14394 */
14395 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14396 comp = NULL;
14397 } else {
14398 comp = pctxt->comp;
14399 pctxt->comp = NULL;
14400 }
14401 xmlXPathFreeParserContext(pctxt);
14402 if (comp != NULL) {
14403 comp->expr = xmlStrdup(str);
14404#ifdef DEBUG_EVAL_COUNTS
14405 comp->string = xmlStrdup(str);
14406 comp->nb = 0;
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014407#endif
14408 if ((comp->expr != NULL) &&
14409 (comp->nbStep > 2) &&
14410 (comp->last >= 0) &&
Kasimier T. Buchcik7cb3fa92006-06-06 15:27:46 +000014411 (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14412 {
14413 xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014414 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014415 }
Daniel Veillard4773df22004-01-23 13:15:13 +000014416 return(comp);
14417}
14418
14419/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014420 * xmlXPathCompile:
14421 * @str: the XPath expression
14422 *
14423 * Compile an XPath expression
14424 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000014425 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014426 * the caller has to free the object.
14427 */
14428xmlXPathCompExprPtr
14429xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000014430 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014431}
14432
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014433/**
14434 * xmlXPathCompiledEval:
14435 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000014436 * @ctx: the XPath context
14437 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014438 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000014439 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014440 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000014441 * the caller has to free the object.
14442 */
14443xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014444xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000014445 xmlXPathParserContextPtr ctxt;
14446 xmlXPathObjectPtr res, tmp, init = NULL;
14447 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000014448#ifndef LIBXML_THREAD_ENABLED
14449 static int reentance = 0;
14450#endif
Owen Taylor3473f882001-02-23 17:55:21 +000014451
William M. Brackf13f77f2004-11-12 16:03:48 +000014452 CHECK_CTXT(ctx)
14453
14454 if (comp == NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014455 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000014456 xmlXPathInit();
14457
Daniel Veillard81463942001-10-16 12:34:39 +000014458#ifndef LIBXML_THREAD_ENABLED
14459 reentance++;
14460 if (reentance > 1)
14461 xmlXPathDisableOptimizer = 1;
14462#endif
14463
Daniel Veillardf06307e2001-07-03 10:35:50 +000014464#ifdef DEBUG_EVAL_COUNTS
14465 comp->nb++;
14466 if ((comp->string != NULL) && (comp->nb > 100)) {
14467 fprintf(stderr, "100 x %s\n", comp->string);
14468 comp->nb = 0;
14469 }
14470#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014471 ctxt = xmlXPathCompParserContext(comp, ctx);
14472 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000014473
14474 if (ctxt->value == NULL) {
14475 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014476 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000014477 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000014478 } else {
14479 res = valuePop(ctxt);
14480 }
14481
Daniel Veillardf06307e2001-07-03 10:35:50 +000014482
Owen Taylor3473f882001-02-23 17:55:21 +000014483 do {
14484 tmp = valuePop(ctxt);
14485 if (tmp != NULL) {
14486 if (tmp != init)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014487 stack++;
14488 xmlXPathReleaseObject(ctx, tmp);
Owen Taylor3473f882001-02-23 17:55:21 +000014489 }
14490 } while (tmp != NULL);
14491 if ((stack != 0) && (res != NULL)) {
14492 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014493 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000014494 stack);
14495 }
14496 if (ctxt->error != XPATH_EXPRESSION_OK) {
14497 xmlXPathFreeObject(res);
14498 res = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014499 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014500 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014501 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000014502#ifndef LIBXML_THREAD_ENABLED
14503 reentance--;
14504#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014505 return(res);
14506}
14507
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014508/**
14509 * xmlXPathEvalExpr:
14510 * @ctxt: the XPath Parser context
14511 *
14512 * Parse and evaluate an XPath expression in the given context,
14513 * then push the result on the context stack
14514 */
14515void
14516xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014517#ifdef XPATH_STREAMING
14518 xmlXPathCompExprPtr comp;
14519#endif
14520
Daniel Veillarda82b1822004-11-08 16:24:57 +000014521 if (ctxt == NULL) return;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014522
14523#ifdef XPATH_STREAMING
14524 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14525 if (comp != NULL) {
14526 if (ctxt->comp != NULL)
14527 xmlXPathFreeCompExpr(ctxt->comp);
14528 ctxt->comp = comp;
14529 if (ctxt->cur != NULL)
14530 while (*ctxt->cur != 0) ctxt->cur++;
14531 } else
14532#endif
14533 {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014534 xmlXPathCompileExpr(ctxt, 1);
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014535 /*
14536 * In this scenario the expression string will sit in ctxt->base.
14537 */
14538 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14539 (ctxt->comp != NULL) &&
14540 (ctxt->base != NULL) &&
Kasimier T. Buchcik7cb3fa92006-06-06 15:27:46 +000014541 (ctxt->comp->nbStep > 2) &&
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014542 (ctxt->comp->last >= 0) &&
14543 (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014544 {
14545 xmlXPathRewriteDOSExpression(ctxt->comp,
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014546 &ctxt->comp->steps[ctxt->comp->last]);
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014547 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014548 }
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000014549 CHECK_ERROR;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000014550 xmlXPathRunEval(ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014551}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014552
14553/**
14554 * xmlXPathEval:
14555 * @str: the XPath expression
14556 * @ctx: the XPath context
14557 *
14558 * Evaluate the XPath Location Path in the given context.
14559 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014560 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014561 * the caller has to free the object.
14562 */
14563xmlXPathObjectPtr
14564xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14565 xmlXPathParserContextPtr ctxt;
14566 xmlXPathObjectPtr res, tmp, init = NULL;
14567 int stack = 0;
14568
William M. Brackf13f77f2004-11-12 16:03:48 +000014569 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014570
William M. Brackf13f77f2004-11-12 16:03:48 +000014571 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014572
14573 ctxt = xmlXPathNewParserContext(str, ctx);
14574 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014575
14576 if (ctxt->value == NULL) {
14577 xmlGenericError(xmlGenericErrorContext,
14578 "xmlXPathEval: evaluation failed\n");
14579 res = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014580 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
14581#ifdef XPATH_STREAMING
14582 && (ctxt->comp->stream == NULL)
14583#endif
14584 ) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014585 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14586 res = NULL;
14587 } else {
14588 res = valuePop(ctxt);
14589 }
14590
14591 do {
14592 tmp = valuePop(ctxt);
14593 if (tmp != NULL) {
14594 if (tmp != init)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014595 stack++;
14596 xmlXPathReleaseObject(ctx, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014597 }
14598 } while (tmp != NULL);
14599 if ((stack != 0) && (res != NULL)) {
14600 xmlGenericError(xmlGenericErrorContext,
14601 "xmlXPathEval: %d object left on the stack\n",
14602 stack);
14603 }
14604 if (ctxt->error != XPATH_EXPRESSION_OK) {
14605 xmlXPathFreeObject(res);
14606 res = NULL;
14607 }
14608
Owen Taylor3473f882001-02-23 17:55:21 +000014609 xmlXPathFreeParserContext(ctxt);
14610 return(res);
14611}
14612
14613/**
14614 * xmlXPathEvalExpression:
14615 * @str: the XPath expression
14616 * @ctxt: the XPath context
14617 *
14618 * Evaluate the XPath expression in the given context.
14619 *
14620 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14621 * the caller has to free the object.
14622 */
14623xmlXPathObjectPtr
14624xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14625 xmlXPathParserContextPtr pctxt;
14626 xmlXPathObjectPtr res, tmp;
14627 int stack = 0;
14628
William M. Brackf13f77f2004-11-12 16:03:48 +000014629 CHECK_CTXT(ctxt)
Owen Taylor3473f882001-02-23 17:55:21 +000014630
William M. Brackf13f77f2004-11-12 16:03:48 +000014631 xmlXPathInit();
Owen Taylor3473f882001-02-23 17:55:21 +000014632
14633 pctxt = xmlXPathNewParserContext(str, ctxt);
14634 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000014635
14636 if (*pctxt->cur != 0) {
14637 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14638 res = NULL;
14639 } else {
14640 res = valuePop(pctxt);
14641 }
14642 do {
14643 tmp = valuePop(pctxt);
14644 if (tmp != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014645 xmlXPathReleaseObject(ctxt, tmp);
Owen Taylor3473f882001-02-23 17:55:21 +000014646 stack++;
14647 }
14648 } while (tmp != NULL);
14649 if ((stack != 0) && (res != NULL)) {
14650 xmlGenericError(xmlGenericErrorContext,
14651 "xmlXPathEvalExpression: %d object left on the stack\n",
14652 stack);
14653 }
14654 xmlXPathFreeParserContext(pctxt);
14655 return(res);
14656}
14657
Daniel Veillard42766c02002-08-22 20:52:17 +000014658/************************************************************************
14659 * *
14660 * Extra functions not pertaining to the XPath spec *
14661 * *
14662 ************************************************************************/
14663/**
14664 * xmlXPathEscapeUriFunction:
14665 * @ctxt: the XPath Parser context
14666 * @nargs: the number of arguments
14667 *
14668 * Implement the escape-uri() XPath function
14669 * string escape-uri(string $str, bool $escape-reserved)
14670 *
14671 * This function applies the URI escaping rules defined in section 2 of [RFC
14672 * 2396] to the string supplied as $uri-part, which typically represents all
14673 * or part of a URI. The effect of the function is to replace any special
14674 * character in the string by an escape sequence of the form %xx%yy...,
14675 * where xxyy... is the hexadecimal representation of the octets used to
14676 * represent the character in UTF-8.
14677 *
14678 * The set of characters that are escaped depends on the setting of the
14679 * boolean argument $escape-reserved.
14680 *
14681 * If $escape-reserved is true, all characters are escaped other than lower
14682 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14683 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14684 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14685 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14686 * A-F).
14687 *
14688 * If $escape-reserved is false, the behavior differs in that characters
14689 * referred to in [RFC 2396] as reserved characters are not escaped. These
14690 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14691 *
14692 * [RFC 2396] does not define whether escaped URIs should use lower case or
14693 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14694 * compared using string comparison functions, this function must always use
14695 * the upper-case letters A-F.
14696 *
14697 * Generally, $escape-reserved should be set to true when escaping a string
14698 * that is to form a single part of a URI, and to false when escaping an
14699 * entire URI or URI reference.
14700 *
14701 * In the case of non-ascii characters, the string is encoded according to
14702 * utf-8 and then converted according to RFC 2396.
14703 *
14704 * Examples
14705 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14706 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14707 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14708 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14709 *
14710 */
Daniel Veillard118aed72002-09-24 14:13:13 +000014711static void
Daniel Veillard42766c02002-08-22 20:52:17 +000014712xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14713 xmlXPathObjectPtr str;
14714 int escape_reserved;
14715 xmlBufferPtr target;
14716 xmlChar *cptr;
14717 xmlChar escape[4];
14718
14719 CHECK_ARITY(2);
14720
14721 escape_reserved = xmlXPathPopBoolean(ctxt);
14722
14723 CAST_TO_STRING;
14724 str = valuePop(ctxt);
14725
14726 target = xmlBufferCreate();
14727
14728 escape[0] = '%';
14729 escape[3] = 0;
14730
14731 if (target) {
14732 for (cptr = str->stringval; *cptr; cptr++) {
14733 if ((*cptr >= 'A' && *cptr <= 'Z') ||
14734 (*cptr >= 'a' && *cptr <= 'z') ||
14735 (*cptr >= '0' && *cptr <= '9') ||
14736 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
14737 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
14738 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14739 (*cptr == '%' &&
14740 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14741 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14742 (cptr[1] >= '0' && cptr[1] <= '9')) &&
14743 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14744 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14745 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14746 (!escape_reserved &&
14747 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14748 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14749 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14750 *cptr == ','))) {
14751 xmlBufferAdd(target, cptr, 1);
14752 } else {
14753 if ((*cptr >> 4) < 10)
14754 escape[1] = '0' + (*cptr >> 4);
14755 else
14756 escape[1] = 'A' - 10 + (*cptr >> 4);
14757 if ((*cptr & 0xF) < 10)
14758 escape[2] = '0' + (*cptr & 0xF);
14759 else
14760 escape[2] = 'A' - 10 + (*cptr & 0xF);
14761
14762 xmlBufferAdd(target, &escape[0], 3);
14763 }
14764 }
14765 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014766 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
14767 xmlBufferContent(target)));
Daniel Veillard42766c02002-08-22 20:52:17 +000014768 xmlBufferFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014769 xmlXPathReleaseObject(ctxt->context, str);
Daniel Veillard42766c02002-08-22 20:52:17 +000014770}
14771
Owen Taylor3473f882001-02-23 17:55:21 +000014772/**
14773 * xmlXPathRegisterAllFunctions:
14774 * @ctxt: the XPath context
14775 *
14776 * Registers all default XPath functions in this context
14777 */
14778void
14779xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
14780{
14781 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
14782 xmlXPathBooleanFunction);
14783 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
14784 xmlXPathCeilingFunction);
14785 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
14786 xmlXPathCountFunction);
14787 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
14788 xmlXPathConcatFunction);
14789 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
14790 xmlXPathContainsFunction);
14791 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
14792 xmlXPathIdFunction);
14793 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
14794 xmlXPathFalseFunction);
14795 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
14796 xmlXPathFloorFunction);
14797 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
14798 xmlXPathLastFunction);
14799 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
14800 xmlXPathLangFunction);
14801 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
14802 xmlXPathLocalNameFunction);
14803 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
14804 xmlXPathNotFunction);
14805 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
14806 xmlXPathNameFunction);
14807 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
14808 xmlXPathNamespaceURIFunction);
14809 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
14810 xmlXPathNormalizeFunction);
14811 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
14812 xmlXPathNumberFunction);
14813 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
14814 xmlXPathPositionFunction);
14815 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
14816 xmlXPathRoundFunction);
14817 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
14818 xmlXPathStringFunction);
14819 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
14820 xmlXPathStringLengthFunction);
14821 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
14822 xmlXPathStartsWithFunction);
14823 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
14824 xmlXPathSubstringFunction);
14825 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
14826 xmlXPathSubstringBeforeFunction);
14827 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
14828 xmlXPathSubstringAfterFunction);
14829 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
14830 xmlXPathSumFunction);
14831 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
14832 xmlXPathTrueFunction);
14833 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
14834 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000014835
14836 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
14837 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
14838 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000014839}
14840
14841#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000014842#define bottom_xpath
14843#include "elfgcchack.h"